lkml.org 
[lkml]   [2019]   [Jan]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
SubjectRe: [PATCH v7 1/5] spi: spi-mem: Add driver for NXP FlexSPI controller
Date
Hi Yogesh,

On 15.01.19 10:50, Yogesh Narayan Gaur wrote:
> - Add driver for NXP FlexSPI host controller
>
> (0) What is the FlexSPI controller?
> FlexSPI is a flexsible SPI host controller which supports two SPI
> channels and up to 4 external devices. Each channel supports
> Single/Dual/Quad/Octal mode data transfer (1/2/4/8 bidirectional
> data lines) i.e. FlexSPI acts as an interface to external devices,
> maximum 4, each with up to 8 bidirectional data lines.
>
> It uses new SPI memory interface of the SPI framework to issue
> flash memory operations to up to four connected flash
> devices (2 buses with 2 CS each).
>
> (1) Tested this driver with the mtd_debug and JFFS2 filesystem utility
> on NXP LX2160ARDB and LX2160AQDS targets.
> LX2160ARDB is having two NOR slave device connected on single bus A
> i.e. A0 and A1 (CS0 and CS1).
> LX2160AQDS is having two NOR slave device connected on separate buses
> one flash on A0 and second on B1 i.e. (CS0 and CS3).
> Verified this driver on following SPI NOR flashes:
> Micron, mt35xu512ab, [Read - 1 bit mode]
> Cypress, s25fl512s, [Read - 1/2/4 bit mode]
>
> Signed-off-by: Yogesh Narayan Gaur <yogeshnarayan.gaur@nxp.com>
> ---
> Changes for v7:
> - Add func pointer for '.get_name' for struct spi_controller_mem_ops
> - Add input address range check as per controller memory mapped space
> - Update _fill_txfifo/_read_rxfifo funcs as per Frieder review comments
> Changes for v6:
> - Rebase on top of v5.0-rc1
> - Updated as per Frieder review comments and perform code cleanup
> - Updated _fill_txfifo/_read_rxfifo func write/read logic
> Changes for v5:
> - Rebase on top of v4.20-rc2
> - Modified fspi_readl_poll_tout() as per review comments
> - Arrange header file in alphabetical order
> - Removed usage of read()/write() function callback pointer
> - Add support for 1 and 2 byte address length
> - Change Frieder e-mail to new e-mail address
> Changes for v4:
> - Incorporate Boris review comments
> * Use readl_poll_timeout() instead of busy looping.
> * Re-define register masking as per comment.
> * Drop fspi_devtype enum.
> Changes for v3:
> - Added endianness flag in platform specific structure instead of DTS.
> - Modified nxp_fspi_read_ahb(), removed remapping code.
> - Added Boris and Frieder as Author and provided reference of spi-fsl-qspi.c
> Changes for v2:
> - Incorporated Boris review comments.
> - Remove dependency of driver over connected flash device size.
> - Modified the logic to select requested CS.
> - Remove SPI-Octal Macros.
>
> drivers/spi/Kconfig | 10 +
> drivers/spi/Makefile | 1 +
> drivers/spi/spi-nxp-fspi.c | 1105 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 1116 insertions(+)
> create mode 100644 drivers/spi/spi-nxp-fspi.c
>
[...]
> +
> +static bool nxp_fspi_supports_op(struct spi_mem *mem,
> + const struct spi_mem_op *op)
> +{
> + struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master);
> + int ret;
> +
> + ret = nxp_fspi_check_buswidth(f, op->cmd.buswidth);
> +
> + if (op->addr.nbytes)
> + ret |= nxp_fspi_check_buswidth(f, op->addr.buswidth);
> +
> + if (op->dummy.nbytes)
> + ret |= nxp_fspi_check_buswidth(f, op->dummy.buswidth);
> +
> + if (op->data.nbytes)
> + ret |= nxp_fspi_check_buswidth(f, op->data.buswidth);
> +
> + if (ret)
> + return false;
> +
> + /*
> + * The number of address bytes should be equal to and less than 4bytes.

Nitpick: use "or" instead of "and", add a space between "4" and "bytes".

> + */
> + if (op->addr.nbytes > 4)
> + return false;
> +
> + /*
> + * If requested address value is greater than controller assigned
> + * memory mapped space, return error as it didn't fit in the range
> + * of assigned address space.
> + */
> + if (op->addr.val >= f->memmap_phy_size)
> + return false;
> +
> + /* Max 64 dummy clock cycles supported */
> + if (op->dummy.buswidth &&
> + (op->dummy.nbytes * 8 / op->dummy.buswidth > 64))
> + return false;
> +
> + /* Max data length, check controller limits and alignment */
> + if (op->data.dir == SPI_MEM_DATA_IN &&
> + (op->data.nbytes > f->devtype_data->ahb_buf_size ||
> + (op->data.nbytes > f->devtype_data->rxfifo - 4 &&
> + !IS_ALIGNED(op->data.nbytes, 8))))
> + return false;
> +
> + if (op->data.dir == SPI_MEM_DATA_OUT &&
> + op->data.nbytes > f->devtype_data->txfifo)
> + return false;
> +
> + return true;
> +}
[...]
> +static void nxp_fspi_fill_txfifo(struct nxp_fspi *f,
> + const struct spi_mem_op *op)
> +{
> + void __iomem *base = f->iobase;
> + int i, ret;
> +
> + /* clear the TX FIFO. */
> + fspi_writel(f, FSPI_IPTXFCR_CLR, base + FSPI_IPTXFCR);
> +
> + /*
> + * Default value of water mark level is 8 bytes, hence in single
> + * write request controller can write max 8 bytes of data.
> + */
> +
> + for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 8); i += 8) {
> + /* Wait for TXFIFO empty */
> + ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR,
> + FSPI_INTR_IPTXWE, 0,
> + POLL_TOUT, true);
> + WARN_ON(ret);
> +
> + fspi_writel(f, *(u32 *) ((u8 *)op->data.buf.out + i),
> + base + FSPI_TFDR);
> + fspi_writel(f, *(u32 *) ((u8 *)op->data.buf.out + i + 4),
> + base + FSPI_TFDR + 4);

Nitpick: Add a "u8 *buf = (u8 *)op->data.buf.out" to the top of the
function and use it here...

> + fspi_writel(f, FSPI_INTR_IPTXWE, base + FSPI_INTR);
> + }
> +
> + if (i < op->data.nbytes) {
> + u32 data = 0;
> + int j;
> + /* Wait for TXFIFO empty */
> + ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR,
> + FSPI_INTR_IPTXWE, 0,
> + POLL_TOUT, true);
> + WARN_ON(ret);
> +
> + for (j = 0; j < ALIGN(op->data.nbytes - i, 4); j += 4) {
> + memcpy(&data, op->data.buf.out + i + j, 4);

...and also here.

> + fspi_writel(f, data, base + FSPI_TFDR + j);
> + }
> + fspi_writel(f, FSPI_INTR_IPTXWE, base + FSPI_INTR);
> + }
> +}
> +
> +static void nxp_fspi_read_rxfifo(struct nxp_fspi *f,
> + const struct spi_mem_op *op)
> +{
> + void __iomem *base = f->iobase;
> + int i, ret;
> + int len = op->data.nbytes;
> + u8 *buf = (u8 *) op->data.buf.in;
> +
> + /*
> + * Default value of water mark level is 8 bytes, hence in single
> + * read request controller can read max 8 bytes of data.
> + */
> + for (i = 0; i < ALIGN_DOWN(len, 8); i += 8) {
> + /* Wait for RXFIFO available */
> + ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR,
> + FSPI_INTR_IPRXWA, 0,
> + POLL_TOUT, true);
> + WARN_ON(ret);
> +
> + *(u32 *)(buf + i) = fspi_readl(f, base + FSPI_RFDR);
> + *(u32 *)(buf + i + 4) = fspi_readl(f, base + FSPI_RFDR + 4);
> + /* move the FIFO pointer */
> + fspi_writel(f, FSPI_INTR_IPRXWA, base + FSPI_INTR);
> + }
> +
> + if (i < len) {
> + u32 tmp;
> + int size, j;
> +
> + buf = op->data.buf.in + i;
> + /* Wait for RXFIFO available */
> + ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR,
> + FSPI_INTR_IPRXWA, 0,
> + POLL_TOUT, true);
> + WARN_ON(ret);
> +
> + len = op->data.nbytes - i;
> + for (j = 0; j < (ALIGN(len, 4))/4; j++, buf += size) {
> + tmp = fspi_readl(f, base + FSPI_RFDR + j * 4);
> + size = min(len, 4);
> + memcpy(buf, &tmp, size);
> + }

In the second iteration of this loop, the calculation of size seems
wrong, as len has not changed.

Maybe this could work?:

len = op->data.nbytes - i;
for (j = 0; j < op->data.nbytes - i; j += 4) {
tmp = fspi_readl(f, base + FSPI_RFDR + j);
size = min(len, 4);
memcpy(buf + j, &tmp, size);
len -= size;
}

When this is fixed and tested you can add:

Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>

Thanks,
Frieder
\
 
 \ /
  Last update: 2019-01-15 11:36    [W:0.106 / U:0.088 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site