[U-Boot] [PATCH v2] spi: kirkwood_spi: implement workaround for FE-9144572

Jagan Teki jagannadh.teki at gmail.com
Mon Oct 16 21:46:17 UTC 2017


On Tue, Oct 17, 2017 at 3:07 AM, Chris Packham <judge.packham at gmail.com> wrote:
> Erratum NO. FE-9144572: The device SPI interface supports frequencies of
> up to 50 MHz.  However, due to this erratum, when the device core clock
> is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and
> CPOL=CPHA=1 there might occur data corruption on reads from the SPI
> device.
>
> Implement the workaround by setting the TMISO_SAMPLE value to 0x2
> in the timing1 register.
>
> Signed-off-by: Chris Packham <judge.packham at gmail.com>
> Reviewed-by: Stefan Roese <sr at denx.de>
> ---
> I've based this as much as I can on the equivalent implementation in the
> Linux kernel[1], but there are differences in the u-boot spi
> infrastructure that means I can't be as specific when qualifying whether
> the workaround is needed.
>
> [1] - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/spi/spi-orion.c#n248
>
> Changes in v2:
> - collect reviewed-by from Stefan
> - remove mvebu_spi_type
> - describe errata above mvebu_spi_50mhz_ac_timing_erratum
>
>  arch/arm/include/asm/arch-mvebu/spi.h |  6 ++++
>  drivers/spi/kirkwood_spi.c            | 61 +++++++++++++++++++++++++++++++++--
>  2 files changed, 64 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/include/asm/arch-mvebu/spi.h b/arch/arm/include/asm/arch-mvebu/spi.h
> index 3545aed17347..1de510ea6da9 100644
> --- a/arch/arm/include/asm/arch-mvebu/spi.h
> +++ b/arch/arm/include/asm/arch-mvebu/spi.h
> @@ -57,6 +57,12 @@ struct kwspi_registers {
>  #define KWSPI_TXLSBF           (1 << 13)
>  #define KWSPI_RXLSBF           (1 << 14)
>
> +/* Timing Parameters 1 Register */
> +#define KW_SPI_TMISO_SAMPLE_OFFSET     6
> +#define KW_SPI_TMISO_SAMPLE_MASK       (0x3 << KW_SPI_TMISO_SAMPLE_OFFSET)
> +#define KW_SPI_TMISO_SAMPLE_1          (1 << KW_SPI_TMISO_SAMPLE_OFFSET)
> +#define KW_SPI_TMISO_SAMPLE_2          (2 << KW_SPI_TMISO_SAMPLE_OFFSET)
> +
>  #define KWSPI_IRQUNMASK                1 /* unmask SPI interrupt */
>  #define KWSPI_IRQMASK          0 /* mask SPI interrupt */
>  #define KWSPI_SMEMRDIRQ                1 /* SerMem data xfer ready irq */
> diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
> index 0c6bd295cde9..5b1ac0eed634 100644
> --- a/drivers/spi/kirkwood_spi.c
> +++ b/drivers/spi/kirkwood_spi.c
> @@ -243,6 +243,10 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>
>  /* Here now the DM part */
>
> +struct mvebu_spi_dev {
> +       bool                    is_errata_50mhz_ac;
> +};
> +
>  struct mvebu_spi_platdata {
>         struct kwspi_registers *spireg;
>  };
> @@ -269,10 +273,38 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
>         return 0;
>  }
>
> +/*
> + * FE-9144572: The device SPI interface supports frequencies of up to 50 MHz.
> + * However, due to this erratum, when the device core clock is 250 MHz and the
> + * SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might
> + * occur data corruption on reads from the SPI device.
> + *
> + * Workaround: Set the TMISO_SAMPLE value to 0x2 in the SPI Timing Parameters 1
> + * register
> + */
> +static void mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode)
> +{
> +       struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
> +       struct kwspi_registers *reg = plat->spireg;
> +       u32 data = readl(&reg->timing1);
> +
> +       data &= ~KW_SPI_TMISO_SAMPLE_MASK;
> +
> +       if (CONFIG_SYS_TCLK == 250000000 &&
> +           mode & SPI_CPOL &&
> +           mode & SPI_CPHA)
> +               data |= KW_SPI_TMISO_SAMPLE_2;
> +       else
> +               data |= KW_SPI_TMISO_SAMPLE_1;
> +
> +       writel(data, &reg->timing1);
> +}
> +
>  static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
>  {
>         struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
>         struct kwspi_registers *reg = plat->spireg;
> +       const struct mvebu_spi_dev *drvdata;
>         u32 data = readl(&reg->cfg);
>
>         data &= ~(KWSPI_CPHA | KWSPI_CPOL | KWSPI_RXLSBF | KWSPI_TXLSBF);
> @@ -286,6 +318,10 @@ static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
>
>         writel(data, &reg->cfg);
>
> +       drvdata = (struct mvebu_spi_dev *)dev_get_driver_data(bus);
> +       if (drvdata->is_errata_50mhz_ac)
> +               mvebu_spi_50mhz_ac_timing_erratum(bus, mode);
> +
>         return 0;
>  }
>
> @@ -343,10 +379,29 @@ static const struct dm_spi_ops mvebu_spi_ops = {
>          */
>  };
>
> +static const struct mvebu_spi_dev armada_xp_spi_dev_data = {
> +};
> +
> +static const struct mvebu_spi_dev armada_375_spi_dev_data = {
> +};

Unused, may be we can drop these and add NULL or equivalent to data

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


More information about the U-Boot mailing list