From d650d1c46d8471bf8ebf556629ac13077f13e647 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 Mar 2024 18:27:46 +0200 Subject: [PATCH 01/89] spi: xilinx: Fix kernel documentation in the xilinx_spi.h While updating the data structure layout the kernel documentation became outdated. Synchronize kernel documentation with the actual data structure layout. Fixes: 1dd46599f83a ("spi: xilinx: add force_irq for QSPI mode") Fixes: 082339bc63cc ("spi: spi-xilinx: Add run run-time endian detection") Reviewed-by: Michal Simek Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240308162920.46816-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/spi/xilinx_spi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h index 3934ce789d87..fd6add419e94 100644 --- a/include/linux/spi/xilinx_spi.h +++ b/include/linux/spi/xilinx_spi.h @@ -5,10 +5,10 @@ /** * struct xspi_platform_data - Platform data of the Xilinx SPI driver * @num_chipselect: Number of chip select by the IP. - * @little_endian: If registers should be accessed little endian or not. * @bits_per_word: Number of bits per word. * @devices: Devices to add when the driver is probed. * @num_devices: Number of devices in the devices array. + * @force_irq: If set, forces QSPI transaction requirements. */ struct xspi_platform_data { u16 num_chipselect; From 8f40647d87610ecff6637d673024fe7bd045c913 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 Mar 2024 18:27:47 +0200 Subject: [PATCH 02/89] spi: xilinx: Add necessary inclusion and forward declaration xilinx_spi.h is mnissing inclusion and forward declaration, add them. Signed-off-by: Andy Shevchenko Acked-by: Michal Simek Link: https://msgid.link/r/20240308162920.46816-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/spi/xilinx_spi.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h index fd6add419e94..4ba8f53ce570 100644 --- a/include/linux/spi/xilinx_spi.h +++ b/include/linux/spi/xilinx_spi.h @@ -2,6 +2,10 @@ #ifndef __LINUX_SPI_XILINX_SPI_H #define __LINUX_SPI_XILINX_SPI_H +#include + +struct spi_board_info; + /** * struct xspi_platform_data - Platform data of the Xilinx SPI driver * @num_chipselect: Number of chip select by the IP. From a39111b1cf0864b1782f30f9a1fa65260d057327 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 Mar 2024 18:27:48 +0200 Subject: [PATCH 03/89] spi: xilinx: Make num_chipselect 8-bit in the struct xspi_platform_data There is no use for whole 16-bit for the number of chip select pins. Drop it to 8 bits and reshuffle the data structure layout to avoid unnecessary paddings. Signed-off-by: Andy Shevchenko Reviewed-by: Michal Simek Link: https://msgid.link/r/20240308162920.46816-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/spi/xilinx_spi.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h index 4ba8f53ce570..1b8d984668b6 100644 --- a/include/linux/spi/xilinx_spi.h +++ b/include/linux/spi/xilinx_spi.h @@ -8,17 +8,17 @@ struct spi_board_info; /** * struct xspi_platform_data - Platform data of the Xilinx SPI driver - * @num_chipselect: Number of chip select by the IP. - * @bits_per_word: Number of bits per word. * @devices: Devices to add when the driver is probed. * @num_devices: Number of devices in the devices array. + * @num_chipselect: Number of chip select by the IP. + * @bits_per_word: Number of bits per word. * @force_irq: If set, forces QSPI transaction requirements. */ struct xspi_platform_data { - u16 num_chipselect; - u8 bits_per_word; struct spi_board_info *devices; u8 num_devices; + u8 num_chipselect; + u8 bits_per_word; bool force_irq; }; From 7fd54c205f104317b853fc417ac7e9d0b9531ddb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 21:47:45 +0200 Subject: [PATCH 04/89] spi: pxa2xx: Kill pxa2xx_set_spi_info() There is the only one user of the pxa2xx_set_spi_info(). Unexport it and inline to the actual user. Signed-off-by: Andy Shevchenko Acked-by: Arnd Bergmann Link: https://msgid.link/r/20240307195056.4059864-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- arch/arm/mach-pxa/devices.c | 18 ------------------ arch/arm/mach-pxa/spitz.c | 14 +++++++++++++- include/linux/spi/pxa2xx_spi.h | 8 -------- 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 661b3fc43275..1e4cd502340e 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -665,23 +664,6 @@ struct platform_device pxa27x_device_gpio = { .resource = pxa_resource_gpio, }; -/* pxa2xx-spi platform-device ID equals respective SSP platform-device ID + 1. - * See comment in arch/arm/mach-pxa/ssp.c::ssp_probe() */ -void __init pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_controller *info) -{ - struct platform_device *pd; - - pd = platform_device_alloc("pxa2xx-spi", id); - if (pd == NULL) { - printk(KERN_ERR "pxa2xx-spi: failed to allocate device id %d\n", - id); - return; - } - - pd->dev.platform_data = info; - platform_device_add(pd); -} - static struct resource pxa_dma_resource[] = { [0] = { .start = 0x40000000, diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index cc691b199429..318402ad685e 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -585,6 +585,9 @@ static struct gpiod_lookup_table spitz_spi_gpio_table = { static void __init spitz_spi_init(void) { + struct platform_device *pd; + int id = 2; + if (machine_is_akita()) gpiod_add_lookup_table(&akita_lcdcon_gpio_table); else @@ -592,7 +595,16 @@ static void __init spitz_spi_init(void) gpiod_add_lookup_table(&spitz_ads7846_gpio_table); gpiod_add_lookup_table(&spitz_spi_gpio_table); - pxa2xx_set_spi_info(2, &spitz_spi_info); + + /* pxa2xx-spi platform-device ID equals respective SSP platform-device ID + 1 */ + pd = platform_device_alloc("pxa2xx-spi", id); + if (pd == NULL) { + pr_err("pxa2xx-spi: failed to allocate device id %d\n", id); + } else { + pd->dev.platform_data = &spitz_spi_info; + platform_device_add(pd); + } + spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices)); } #else diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index ca2cd4e30ead..56aba2f737b1 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -45,12 +45,4 @@ struct pxa2xx_spi_chip { u32 timeout; }; -#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) - -#include - -extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_controller *info); - -#endif - #endif /* __LINUX_SPI_PXA2XX_SPI_H */ From e3f209e269d32ebc0ba7f497f5d2af21ed4f0dd0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 21:47:46 +0200 Subject: [PATCH 05/89] spi: pxa2xx: Make num_chipselect 8-bit in the struct pxa2xx_spi_controller There is no use for whole 16-bit for the number of chip select pins. Drop it to 8 bits. Acked-by: Arnd Bergmann Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240307195056.4059864-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 2 +- include/linux/spi/pxa2xx_spi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 19479b801826..0997d8eaf190 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -24,7 +24,7 @@ arch/.../mach-*/board-*.c as a "platform device". The host controller configurat is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h:: struct pxa2xx_spi_controller { - u16 num_chipselect; + u8 num_chipselect; u8 enable_dma; ... }; diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 56aba2f737b1..e5a4a045fb67 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -17,7 +17,7 @@ struct dma_chan; * (resides in device.platform_data). */ struct pxa2xx_spi_controller { - u16 num_chipselect; + u8 num_chipselect; u8 enable_dma; u8 dma_burst_size; bool is_target; From b5867a5c0d7a6bf36f59f3d472c7aed33ca4d02c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 21:47:47 +0200 Subject: [PATCH 06/89] spi: pxa2xx: Use proper SSP header in soc/pxa/ssp.c There is nothing from pxa2xx_spi.h used by soc/pxa/ssp.c. Replace it with pxa2xx_ssp.h. Signed-off-by: Andy Shevchenko Acked-by: Arnd Bergmann Link: https://msgid.link/r/20240307195056.4059864-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/soc/pxa/ssp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/pxa/ssp.c b/drivers/soc/pxa/ssp.c index 7af04e8b8163..854d32e04558 100644 --- a/drivers/soc/pxa/ssp.c +++ b/drivers/soc/pxa/ssp.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include From 2a741cd6ec5899cec054ae27120f490ad57bc6bb Mon Sep 17 00:00:00 2001 From: Justin Swartz Date: Sat, 16 Mar 2024 03:03:01 +0200 Subject: [PATCH 07/89] spi: mt7621: allow GPIO chip select lines Extract a magic number, from mt7621_spi_probe(), used to declare the number of chip select lines (which co-incides with the native chip select count of 2) to a macro. Use the newly defined MT7621_NATIVE_CS_COUNT macro to instead populate both the spi_controller's max_native_cs and num_chipselect members. Declare that the spi_controller should use_gpio_descriptors if present in the device properties (such as those declared in the cs-gpio property of a "ralink,mt7621-spi" compatible device-tree node) so that the SPI core will recalculcate num_chipselect to account for the GPIO descriptors that it should have populated in the cs_gpiod array member. Remove the assignment of mt7621_spi_transfer_one_message() to the spi_controller's transfer_one_message hook. Refactor the mt7621_spi_transfer_one_message() logic into mt7621_spi_prepare_message() and mt7621_spi_transfer_one() and assign both to the spi_controller's prepare_message and transfer_one hooks respectively. Migrate the call mt7621_spi_transfer_one_message() made to mt7621_spi_flush() just before chip select deactivation, to the end of mt7621_spi_write_half_duplex() to ensure that any pending data is shifted out of MOSI before the SPI core deactivates the chip select line. As chip select activation is now taken care of by the SPI core, due to the use of the transfer_one hook instead of transfer_one_message, the calls to mt7621_spi_set_cs() from mt7621_spi_transfer_one_message() have fallen away. And although the SPI core will handle activation for GPIO chip select lines behind the scenes, it requires a callback to allow the driver to perform controller-specific operations to control its native chip select lines. Rename mt7621_spi_set_cs() to mt7621_spi_set_native_cs() and make sure that it takes into account the activation polarity of the chip select line it's acting upon, as the passed enable parameter represents the desired line level and not the desired activation state, and then assign mt7621_set_cs() to the spi_controller's set_cs hook. Signed-off-by: Justin Swartz Link: https://msgid.link/r/20240316010302.20776-1-justin.swartz@risingedge.co.za Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Mark Brown --- drivers/spi/spi-mt7621.c | 95 +++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c index 4e9053d03d5a..3770b8e096a4 100644 --- a/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c @@ -52,6 +52,8 @@ #define MT7621_CPOL BIT(4) #define MT7621_LSB_FIRST BIT(3) +#define MT7621_NATIVE_CS_COUNT 2 + struct mt7621_spi { struct spi_controller *host; void __iomem *base; @@ -75,10 +77,11 @@ static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val) iowrite32(val, rs->base + reg); } -static void mt7621_spi_set_cs(struct spi_device *spi, int enable) +static void mt7621_spi_set_native_cs(struct spi_device *spi, bool enable) { struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); int cs = spi_get_chipselect(spi, 0); + bool active = spi->mode & SPI_CS_HIGH ? enable : !enable; u32 polar = 0; u32 host; @@ -94,7 +97,7 @@ static void mt7621_spi_set_cs(struct spi_device *spi, int enable) rs->pending_write = 0; - if (enable) + if (active) polar = BIT(cs); mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); } @@ -154,6 +157,23 @@ static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs) return -ETIMEDOUT; } +static int mt7621_spi_prepare_message(struct spi_controller *host, + struct spi_message *m) +{ + struct mt7621_spi *rs = spi_controller_get_devdata(host); + struct spi_device *spi = m->spi; + unsigned int speed = spi->max_speed_hz; + struct spi_transfer *t = NULL; + + mt7621_spi_wait_till_ready(rs); + + list_for_each_entry(t, &m->transfers, transfer_list) + if (t->speed_hz < speed) + speed = t->speed_hz; + + return mt7621_spi_prepare(spi, speed); +} + static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, int rx_len, u8 *buf) { @@ -243,59 +263,30 @@ static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs, } rs->pending_write = len; + mt7621_spi_flush(rs); } -static int mt7621_spi_transfer_one_message(struct spi_controller *host, - struct spi_message *m) +static int mt7621_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) { struct mt7621_spi *rs = spi_controller_get_devdata(host); - struct spi_device *spi = m->spi; - unsigned int speed = spi->max_speed_hz; - struct spi_transfer *t = NULL; - int status = 0; - mt7621_spi_wait_till_ready(rs); - - list_for_each_entry(t, &m->transfers, transfer_list) - if (t->speed_hz < speed) - speed = t->speed_hz; - - if (mt7621_spi_prepare(spi, speed)) { - status = -EIO; - goto msg_done; + if ((t->rx_buf) && (t->tx_buf)) { + /* + * This controller will shift some extra data out + * of spi_opcode if (mosi_bit_cnt > 0) && + * (cmd_bit_cnt == 0). So the claimed full-duplex + * support is broken since we have no way to read + * the MISO value during that bit. + */ + return -EIO; + } else if (t->rx_buf) { + mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); + } else if (t->tx_buf) { + mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); } - /* Assert CS */ - mt7621_spi_set_cs(spi, 1); - - m->actual_length = 0; - list_for_each_entry(t, &m->transfers, transfer_list) { - if ((t->rx_buf) && (t->tx_buf)) { - /* - * This controller will shift some extra data out - * of spi_opcode if (mosi_bit_cnt > 0) && - * (cmd_bit_cnt == 0). So the claimed full-duplex - * support is broken since we have no way to read - * the MISO value during that bit. - */ - status = -EIO; - goto msg_done; - } else if (t->rx_buf) { - mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); - } else if (t->tx_buf) { - mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); - } - m->actual_length += t->len; - } - - /* Flush data and deassert CS */ - mt7621_spi_flush(rs); - mt7621_spi_set_cs(spi, 0); - -msg_done: - m->status = status; - spi_finalize_current_message(host); - return 0; } @@ -353,10 +344,14 @@ static int mt7621_spi_probe(struct platform_device *pdev) host->mode_bits = SPI_LSB_FIRST; host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->setup = mt7621_spi_setup; - host->transfer_one_message = mt7621_spi_transfer_one_message; + host->prepare_message = mt7621_spi_prepare_message; + host->set_cs = mt7621_spi_set_native_cs; + host->transfer_one = mt7621_spi_transfer_one; host->bits_per_word_mask = SPI_BPW_MASK(8); host->dev.of_node = pdev->dev.of_node; - host->num_chipselect = 2; + host->max_native_cs = MT7621_NATIVE_CS_COUNT; + host->num_chipselect = MT7621_NATIVE_CS_COUNT; + host->use_gpio_descriptors = true; dev_set_drvdata(&pdev->dev, host); From 10402419f2d60890525f590b54d0eaec3de0d87a Mon Sep 17 00:00:00 2001 From: Fei Shao Date: Thu, 21 Mar 2024 15:08:58 +0800 Subject: [PATCH 08/89] spi: spi-mt65xx: Rename a variable in interrupt handler All the spi_transfer variables in this file use the name "xfer" except the one in mtk_spi_interrupt(). Align the naming for consistency and easier searching. While at it, reformat one memcpy() usage since the coding style allows 100 column lines today. This commit has no functional change. Signed-off-by: Fei Shao Reviewed-by: AngeloGioacchino Del Regno Link: https://msgid.link/r/20240321070942.1587146-3-fshao@chromium.org Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index e4cb22fe0075..36c2f52cd6b8 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -748,7 +748,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) u32 cmd, reg_val, cnt, remainder, len; struct spi_controller *host = dev_id; struct mtk_spi *mdata = spi_controller_get_devdata(host); - struct spi_transfer *trans = mdata->cur_transfer; + struct spi_transfer *xfer = mdata->cur_transfer; reg_val = readl(mdata->base + SPI_STATUS0_REG); if (reg_val & MTK_SPI_PAUSE_INT_STATUS) @@ -762,42 +762,40 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - if (!host->can_dma(host, NULL, trans)) { - if (trans->rx_buf) { + if (!host->can_dma(host, NULL, xfer)) { + if (xfer->rx_buf) { cnt = mdata->xfer_len / 4; ioread32_rep(mdata->base + SPI_RX_DATA_REG, - trans->rx_buf + mdata->num_xfered, cnt); + xfer->rx_buf + mdata->num_xfered, cnt); remainder = mdata->xfer_len % 4; if (remainder > 0) { reg_val = readl(mdata->base + SPI_RX_DATA_REG); - memcpy(trans->rx_buf + - mdata->num_xfered + - (cnt * 4), + memcpy(xfer->rx_buf + (cnt * 4) + mdata->num_xfered, ®_val, remainder); } } mdata->num_xfered += mdata->xfer_len; - if (mdata->num_xfered == trans->len) { + if (mdata->num_xfered == xfer->len) { spi_finalize_current_transfer(host); return IRQ_HANDLED; } - len = trans->len - mdata->num_xfered; + len = xfer->len - mdata->num_xfered; mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len); mtk_spi_setup_packet(host); - if (trans->tx_buf) { + if (xfer->tx_buf) { cnt = mdata->xfer_len / 4; iowrite32_rep(mdata->base + SPI_TX_DATA_REG, - trans->tx_buf + mdata->num_xfered, cnt); + xfer->tx_buf + mdata->num_xfered, cnt); remainder = mdata->xfer_len % 4; if (remainder > 0) { reg_val = 0; memcpy(®_val, - trans->tx_buf + (cnt * 4) + mdata->num_xfered, + xfer->tx_buf + (cnt * 4) + mdata->num_xfered, remainder); writel(reg_val, mdata->base + SPI_TX_DATA_REG); } @@ -809,21 +807,21 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) } if (mdata->tx_sgl) - trans->tx_dma += mdata->xfer_len; + xfer->tx_dma += mdata->xfer_len; if (mdata->rx_sgl) - trans->rx_dma += mdata->xfer_len; + xfer->rx_dma += mdata->xfer_len; if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) { mdata->tx_sgl = sg_next(mdata->tx_sgl); if (mdata->tx_sgl) { - trans->tx_dma = sg_dma_address(mdata->tx_sgl); + xfer->tx_dma = sg_dma_address(mdata->tx_sgl); mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl); } } if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) { mdata->rx_sgl = sg_next(mdata->rx_sgl); if (mdata->rx_sgl) { - trans->rx_dma = sg_dma_address(mdata->rx_sgl); + xfer->rx_dma = sg_dma_address(mdata->rx_sgl); mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl); } } @@ -841,7 +839,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) mtk_spi_update_mdata_len(host); mtk_spi_setup_packet(host); - mtk_spi_setup_dma_addr(host, trans); + mtk_spi_setup_dma_addr(host, xfer); mtk_spi_enable_transfer(host); return IRQ_HANDLED; From bdeef5dcea6b164f4bd614655821b1ef12ebec9a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Mar 2024 16:20:04 +0200 Subject: [PATCH 09/89] spi: rspi: Get rid of unused struct rspi_plat_data No in-kernel users of struct rspi_plat_data. If required, the software nodes should be used for such users. For now just get rid of it. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240325142118.3210915-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 12 +----------- include/linux/spi/rspi.h | 18 ------------------ 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 include/linux/spi/rspi.h diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 8e81f1a8623f..7f95d22fb1ac 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #define RSPI_SPCR 0x00 /* Control Register */ @@ -1131,16 +1130,12 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev, static int rspi_request_dma(struct device *dev, struct spi_controller *ctlr, const struct resource *res) { - const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); unsigned int dma_tx_id, dma_rx_id; if (dev->of_node) { /* In the OF case we will get the slave IDs from the DT */ dma_tx_id = 0; dma_rx_id = 0; - } else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) { - dma_tx_id = rspi_pd->dma_tx_id; - dma_rx_id = rspi_pd->dma_rx_id; } else { /* The driver assumes no error. */ return 0; @@ -1290,7 +1285,6 @@ static int rspi_probe(struct platform_device *pdev) struct spi_controller *ctlr; struct rspi_data *rspi; int ret; - const struct rspi_plat_data *rspi_pd; const struct spi_ops *ops; unsigned long clksrc; @@ -1305,11 +1299,7 @@ static int rspi_probe(struct platform_device *pdev) goto error1; } else { ops = (struct spi_ops *)pdev->id_entry->driver_data; - rspi_pd = dev_get_platdata(&pdev->dev); - if (rspi_pd && rspi_pd->num_chipselect) - ctlr->num_chipselect = rspi_pd->num_chipselect; - else - ctlr->num_chipselect = 2; /* default */ + ctlr->num_chipselect = 2; /* default */ } rspi = spi_controller_get_devdata(ctlr); diff --git a/include/linux/spi/rspi.h b/include/linux/spi/rspi.h deleted file mode 100644 index dbdfcc7a3db2..000000000000 --- a/include/linux/spi/rspi.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Renesas SPI driver - * - * Copyright (C) 2012 Renesas Solutions Corp. - */ - -#ifndef __LINUX_SPI_RENESAS_SPI_H__ -#define __LINUX_SPI_RENESAS_SPI_H__ - -struct rspi_plat_data { - unsigned int dma_tx_id; - unsigned int dma_rx_id; - - u16 num_chipselect; -}; - -#endif From 6defadbe6cbc3a87dc39c119a6748d19bfba0544 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Thu, 29 Feb 2024 19:15:44 +0530 Subject: [PATCH 10/89] spi: spi_amd: Add support for SPI MEM framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support to the SPI controller driver to use SPI MEM framework. SPI subsystem utilizing the SPI memory operations allows to re-use SPI controller drivers for both SPI NOR devices, regular SPI devices as well as SPI NAND devices. Add below functions of spi_mem_ops to support SPI MEM framework - exec-op(): to execute the memory operations. - supports_op(): to check if the memory operation is supported. - adjust_op_size(): to split data transfers so that they don’t exceed the max transfer size supported by the controller. Suggested-by: Sudheesh Mavila Co-developed-by: Krishnamoorthi M Signed-off-by: Krishnamoorthi M Co-developed-by: Akshata MukundShetty Signed-off-by: Akshata MukundShetty Signed-off-by: Raju Rangoju Link: https://msgid.link/r/20240229134544.3461757-1-Raju.Rangoju@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 5d9b246b6963..2245ad54b03a 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -13,6 +13,7 @@ #include #include #include +#include #define AMD_SPI_CTRL0_REG 0x00 #define AMD_SPI_EXEC_CMD BIT(16) @@ -35,6 +36,7 @@ #define AMD_SPI_FIFO_SIZE 70 #define AMD_SPI_MEM_SIZE 200 +#define AMD_SPI_MAX_DATA 64 #define AMD_SPI_ENA_REG 0x20 #define AMD_SPI_ALT_SPD_SHIFT 20 @@ -358,6 +360,115 @@ fin_msg: return message->status; } +static bool amd_spi_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + /* bus width is number of IO lines used to transmit */ + if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 || + op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA) + return false; + + return spi_mem_default_supports_op(mem, op); +} + +static int amd_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA); + return 0; +} + +static void amd_spi_set_addr(struct amd_spi *amd_spi, + const struct spi_mem_op *op) +{ + u8 nbytes = op->addr.nbytes; + u64 addr_val = op->addr.val; + int base_addr, i; + + base_addr = AMD_SPI_FIFO_BASE + nbytes; + + for (i = 0; i < nbytes; i++) { + amd_spi_writereg8(amd_spi, base_addr - i - 1, addr_val & + GENMASK(7, 0)); + addr_val >>= 8; + } +} + +static void amd_spi_mem_data_out(struct amd_spi *amd_spi, + const struct spi_mem_op *op) +{ + int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes; + u8 *buf = (u8 *)op->data.buf.out; + u32 nbytes = op->data.nbytes; + int i; + + amd_spi_set_opcode(amd_spi, op->cmd.opcode); + amd_spi_set_addr(amd_spi, op); + + for (i = 0; i < nbytes; i++) + amd_spi_writereg8(amd_spi, (base_addr + i), buf[i]); + + amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes); + amd_spi_set_rx_count(amd_spi, 0); + amd_spi_clear_fifo_ptr(amd_spi); + amd_spi_execute_opcode(amd_spi); +} + +static void amd_spi_mem_data_in(struct amd_spi *amd_spi, + const struct spi_mem_op *op) +{ + int offset = (op->addr.nbytes == 0) ? 0 : 1; + u8 *buf = (u8 *)op->data.buf.in; + u32 nbytes = op->data.nbytes; + int base_addr, i; + + base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes + offset; + + amd_spi_set_opcode(amd_spi, op->cmd.opcode); + amd_spi_set_addr(amd_spi, op); + amd_spi_set_tx_count(amd_spi, op->addr.nbytes); + amd_spi_set_rx_count(amd_spi, op->data.nbytes + 1); + amd_spi_clear_fifo_ptr(amd_spi); + amd_spi_execute_opcode(amd_spi); + amd_spi_busy_wait(amd_spi); + + for (i = 0; i < nbytes; i++) + buf[i] = amd_spi_readreg8(amd_spi, base_addr + i); +} + +static int amd_spi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct amd_spi *amd_spi; + int ret; + + amd_spi = spi_controller_get_devdata(mem->spi->controller); + + ret = amd_set_spi_freq(amd_spi, mem->spi->max_speed_hz); + if (ret) + return ret; + + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + amd_spi_mem_data_in(amd_spi, op); + break; + case SPI_MEM_DATA_OUT: + fallthrough; + case SPI_MEM_NO_DATA: + amd_spi_mem_data_out(amd_spi, op); + break; + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static const struct spi_controller_mem_ops amd_spi_mem_ops = { + .exec_op = amd_spi_exec_mem_op, + .adjust_op_size = amd_spi_adjust_op_size, + .supports_op = amd_spi_supports_op, +}; + static int amd_spi_host_transfer(struct spi_controller *host, struct spi_message *msg) { @@ -409,6 +520,7 @@ static int amd_spi_probe(struct platform_device *pdev) host->min_speed_hz = AMD_SPI_MIN_HZ; host->setup = amd_spi_host_setup; host->transfer_one_message = amd_spi_host_transfer; + host->mem_ops = &amd_spi_mem_ops; host->max_transfer_size = amd_spi_max_transfer_size; host->max_message_size = amd_spi_max_transfer_size; From 9b163e0d330debbf7dcc14b2c3e2dc19a3b50a1d Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 25 Mar 2024 14:22:53 -0500 Subject: [PATCH 11/89] spi: remove struct spi_message::is_dma_mapped There are no more users of the deprecated is_dma_mapped in struct spi_message so it can be removed. References in documentation and comments are also removed. A few similar checks if xfer->tx_dma or xfer->rx_dma are not NULL are also removed since these are now guaranteed to be NULL because they were previously set only if is_dma_mapped was true. Signed-off-by: David Lechner Link: https://msgid.link/r/20240325-spi-remove-is_dma_mapped-v2-1-d08d62b61f1c@baylibre.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 3 --- Documentation/spi/spi-summary.rst | 4 ---- drivers/spi/spi-atmel.c | 8 ++------ drivers/spi/spi-pxa2xx.c | 11 ----------- drivers/spi/spi.c | 7 ------- include/linux/spi/spi.h | 11 +++-------- 6 files changed, 5 insertions(+), 39 deletions(-) diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 19479b801826..43e0b758803a 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -194,9 +194,6 @@ The following logic is used to determine the type of I/O to be used on a per "spi_transfer" basis:: if spi_message.len > 65536 then - if spi_message.is_dma_mapped or rx_dma_buf != 0 or tx_dma_buf != 0 then - reject premapped transfers - print "rate limited" warning use PIO transfers diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst index 546de37d6caf..f7f8b1573f25 100644 --- a/Documentation/spi/spi-summary.rst +++ b/Documentation/spi/spi-summary.rst @@ -419,10 +419,6 @@ any more such messages. to make extra copies unless the hardware requires it (e.g. working around hardware errata that force the use of bounce buffering). - If standard dma_map_single() handling of these buffers is inappropriate, - you can use spi_message.is_dma_mapped to tell the controller driver - that you've already provided the relevant DMA addresses. - - The basic I/O primitive is spi_async(). Async requests may be issued in any context (irq handler, task, etc) and completion is reported using a callback provided with the message. diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index bad34998454a..b62f57390d8f 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -987,8 +987,6 @@ static void atmel_spi_pdc_next_xfer(struct spi_controller *host, * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma: * - The buffer is either valid for CPU access, else NULL * - If the buffer is valid, so is its DMA address - * - * This driver manages the dma address unless message->is_dma_mapped. */ static int atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) @@ -1374,8 +1372,7 @@ static int atmel_spi_one_transfer(struct spi_controller *host, * DMA map early, for performance (empties dcache ASAP) and * better fault reporting. */ - if ((!host->cur_msg->is_dma_mapped) - && as->use_pdc) { + if (as->use_pdc) { if (atmel_spi_dma_map_xfer(as, xfer) < 0) return -ENOMEM; } @@ -1454,8 +1451,7 @@ static int atmel_spi_one_transfer(struct spi_controller *host, } } - if (!host->cur_msg->is_dma_mapped - && as->use_pdc) + if (as->use_pdc) atmel_spi_dma_unmap_xfer(host, xfer); if (as->use_pdc) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f2a856f6a99e..6c2a14418972 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -944,7 +944,6 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, struct spi_transfer *transfer) { struct driver_data *drv_data = spi_controller_get_devdata(controller); - struct spi_message *message = controller->cur_msg; struct chip_data *chip = spi_get_ctldata(spi); u32 dma_thresh = chip->dma_threshold; u32 dma_burst = chip->dma_burst_size; @@ -959,16 +958,6 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, /* Check if we can DMA this transfer */ if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { - - /* Reject already-mapped transfers; PIO won't always work */ - if (message->is_dma_mapped - || transfer->rx_dma || transfer->tx_dma) { - dev_err(&spi->dev, - "Mapped transfer length of %u is greater than %d\n", - transfer->len, MAX_DMA_LEN); - return -EINVAL; - } - /* Warn ... we force this to PIO mode */ dev_warn_ratelimited(&spi->dev, "DMA disabled for transfer length %u greater than %d\n", diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ff75838c1b5d..a2f01116ba09 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3709,9 +3709,6 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, * to the same values as *xferp, so tx_buf, rx_buf and len * are all identical (as well as most others) * so we just have to fix up len and the pointers. - * - * This also includes support for the depreciated - * spi_message.is_dma_mapped interface. */ /* @@ -3725,12 +3722,8 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, /* Update rx_buf, tx_buf and DMA */ if (xfers[i].rx_buf) xfers[i].rx_buf += offset; - if (xfers[i].rx_dma) - xfers[i].rx_dma += offset; if (xfers[i].tx_buf) xfers[i].tx_buf += offset; - if (xfers[i].tx_dma) - xfers[i].tx_dma += offset; /* Update length */ xfers[i].len = min(maxsize, xfers[i].len - offset); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index c459809efee4..b589e2547439 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -955,8 +955,8 @@ struct spi_res { * struct spi_transfer - a read/write buffer pair * @tx_buf: data to be written (DMA-safe memory), or NULL * @rx_buf: data to be read (DMA-safe memory), or NULL - * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped - * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped + * @tx_dma: DMA address of tx_buf, currently not for client use + * @rx_dma: DMA address of rx_buf, currently not for client use * @tx_nbits: number of bits used for writing. If 0 the default * (SPI_NBITS_SINGLE) is used. * @rx_nbits: number of bits used for reading. If 0 the default @@ -1066,8 +1066,7 @@ struct spi_transfer { /* * It's okay if tx_buf == rx_buf (right?). * For MicroWire, one buffer must be NULL. - * Buffers must work with dma_*map_single() calls, unless - * spi_message.is_dma_mapped reports a pre-existing mapping. + * Buffers must work with dma_*map_single() calls. */ const void *tx_buf; void *rx_buf; @@ -1111,8 +1110,6 @@ struct spi_transfer { * struct spi_message - one multi-segment SPI transaction * @transfers: list of transfer segments in this transaction * @spi: SPI device to which the transaction is queued - * @is_dma_mapped: if true, the caller provided both DMA and CPU virtual - * addresses for each transfer buffer * @pre_optimized: peripheral driver pre-optimized the message * @optimized: the message is in the optimized state * @prepared: spi_prepare_message was called for the this message @@ -1146,8 +1143,6 @@ struct spi_message { struct spi_device *spi; - unsigned is_dma_mapped:1; - /* spi_optimize_message() was called for this message */ bool pre_optimized; /* __spi_optimize_message() was called for this message */ From dad983d8812975b53db83f02ae6b0ad15f018a9e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Mar 2024 20:07:52 +0200 Subject: [PATCH 12/89] spi: pxa2xx: Keep PXA*_SSP types together Keep the PXA*_SSP types together in enum pxa_ssp_type for better maintenance. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240326181027.1418989-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/pxa2xx_ssp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index cd1973e6ac4b..844a2743ca94 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -217,9 +217,9 @@ enum pxa_ssp_type { PXA27x_SSP, PXA3xx_SSP, PXA168_SSP, - MMP2_SSP, PXA910_SSP, CE4100_SSP, + MMP2_SSP, MRFLD_SSP, QUARK_X1000_SSP, /* Keep LPSS types sorted with lpss_platforms[] */ From d5449432f794e75cd4f5e46bc33bfe6ce20b657d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Mar 2024 20:07:53 +0200 Subject: [PATCH 13/89] spi: pxa2xx: Switch to use dev_err_probe() Switch to use dev_err_probe() to simplify the error path and unify a message template. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240326181027.1418989-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 6c2a14418972..1d43346b4436 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1435,20 +1435,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) platform_info = dev_get_platdata(dev); if (!platform_info) { platform_info = pxa2xx_spi_init_pdata(pdev); - if (IS_ERR(platform_info)) { - dev_err(&pdev->dev, "missing platform data\n"); - return PTR_ERR(platform_info); - } + if (IS_ERR(platform_info)) + return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); } ssp = pxa_ssp_request(pdev->id, pdev->name); if (!ssp) ssp = &platform_info->ssp; - if (!ssp->mmio_base) { - dev_err(&pdev->dev, "failed to get SSP\n"); - return -ENODEV; - } + if (!ssp->mmio_base) + return dev_err_probe(dev, -ENODEV, "failed to get SSP\n"); if (platform_info->is_target) controller = devm_spi_alloc_target(dev, sizeof(*drv_data)); @@ -1456,8 +1452,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) controller = devm_spi_alloc_host(dev, sizeof(*drv_data)); if (!controller) { - dev_err(&pdev->dev, "cannot alloc spi_controller\n"); - status = -ENOMEM; + status = dev_err_probe(dev, -ENOMEM, "cannot alloc spi_controller\n"); goto out_error_controller_alloc; } drv_data = spi_controller_get_devdata(controller); @@ -1511,7 +1506,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev), drv_data); if (status < 0) { - dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq); + dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq); goto out_error_controller_alloc; } @@ -1627,7 +1622,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drv_data); status = spi_register_controller(controller); if (status) { - dev_err(&pdev->dev, "problem registering SPI controller\n"); + dev_err_probe(dev, status, "problem registering SPI controller\n"); goto out_error_pm_runtime_enabled; } From f04cff14e2a4fff4068bd25455531e01089103a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:47:35 +0100 Subject: [PATCH 14/89] spi: loopback-test: drop driver owner assignment Core in spi_register_driver() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240327174737.519637-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index fee8893d2751..31a878d9458d 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -396,7 +396,6 @@ MODULE_DEVICE_TABLE(of, spi_loopback_test_of_match); static struct spi_driver spi_loopback_test_driver = { .driver = { .name = "spi-loopback-test", - .owner = THIS_MODULE, .of_match_table = spi_loopback_test_of_match, }, .probe = spi_loopback_test_probe, From 6c360d3e4962dfb5a525dfef1fe75620f6a29bc8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:47:36 +0100 Subject: [PATCH 15/89] spi: coldfire-qspi: drop driver owner assignment Core in platform_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240327174737.519637-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index b341b6908df0..e83cd0510f20 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -500,7 +500,6 @@ static const struct dev_pm_ops mcfqspi_pm = { static struct platform_driver mcfqspi_driver = { .driver.name = DRIVER_NAME, - .driver.owner = THIS_MODULE, .driver.pm = &mcfqspi_pm, .probe = mcfqspi_probe, .remove_new = mcfqspi_remove, From a5bef84422eb066ee8fa5c13960657a79b3cc1e7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:47:37 +0100 Subject: [PATCH 16/89] spi: fsl-dspi: drop driver owner assignment Core in platform_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240327174737.519637-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 38defdcf9370..0a2730cd07c6 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1458,7 +1458,6 @@ static void dspi_shutdown(struct platform_device *pdev) static struct platform_driver fsl_dspi_driver = { .driver.name = DRIVER_NAME, .driver.of_match_table = fsl_dspi_dt_ids, - .driver.owner = THIS_MODULE, .driver.pm = &dspi_pm, .probe = dspi_probe, .remove_new = dspi_remove, From 67bb37c05a6b56e0e1f804706145a52f655af3f1 Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Wed, 27 Mar 2024 09:43:36 +0100 Subject: [PATCH 17/89] spi: spi-omap2-mcspi.c: revert "Toggle CS after each word" Commit 5cbc7ca987fb ("spi: spi-omap2-mcspi.c: Toggle CS after each word") introduced the toggling of CS after each word for the omap2-mcspi controller. The implementation is not respectful of the actual spi_message content, so the CS can be raised after each word even if the transfer structure asks to keep the CS active for the whole operation. As it is not used anyway in the current Linux tree, it can be safely removed. Signed-off-by: Louis Chauvet Link: https://msgid.link/r/20240327-spi-omap2-mcspi-multi-mode-v3-1-c4ac329dd5a2@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 15 --------------- include/linux/platform_data/spi-omap2-mcspi.h | 3 --- 2 files changed, 18 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index ddf1c684bcc7..601acec37eca 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1175,13 +1175,6 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, t->bits_per_word == spi->bits_per_word) par_override = 0; } - if (cd && cd->cs_per_word) { - chconf = mcspi->ctx.modulctrl; - chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; - mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf); - mcspi->ctx.modulctrl = - mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); - } chconf = mcspi_cached_chconf0(spi); chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; @@ -1240,14 +1233,6 @@ out: status = omap2_mcspi_setup_transfer(spi, NULL); } - if (cd && cd->cs_per_word) { - chconf = mcspi->ctx.modulctrl; - chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE; - mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf); - mcspi->ctx.modulctrl = - mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); - } - omap2_mcspi_set_enable(spi, 0); if (spi_get_csgpiod(spi, 0)) diff --git a/include/linux/platform_data/spi-omap2-mcspi.h b/include/linux/platform_data/spi-omap2-mcspi.h index 3b400b1919a9..9e3c15b4ac91 100644 --- a/include/linux/platform_data/spi-omap2-mcspi.h +++ b/include/linux/platform_data/spi-omap2-mcspi.h @@ -16,9 +16,6 @@ struct omap2_mcspi_platform_config { struct omap2_mcspi_device_config { unsigned turbo_mode:1; - - /* toggle chip select after every word */ - unsigned cs_per_word:1; }; #endif From d153ff4056cb346fd6182a8a1bea6e12b714b64f Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Wed, 27 Mar 2024 09:43:37 +0100 Subject: [PATCH 18/89] spi: omap2-mcspi: Add support for MULTI-mode Introduce support for MULTI-mode in the OMAP2 MCSPI driver. Currently, the driver always uses SINGLE mode to handle the chip select (CS). With this enhancement, MULTI-mode is enabled for specific messages, allowing for a shorter delay between CS enable and the message (some FPGA devices are sensitive to this delay). The OMAP2 MCSPI device can use two different mode to send messages, SINGLE and MULTI: In SINGLE mode, the controller only leverages one single FIFO, and the host system has to manually select the CS it wants to enable. In MULTI mode, each CS is bound to a FIFO, the host system then writes the data to the relevant FIFO, as the hardware will take care of the CS The drawback of multi-mode is that it's not possible to keep the CS enabled between each words. Therefore, this patch enables multi-mode only for specific messages: the spi_message must contain only spi_transfer of 1 word (of any size) with cs_change enabled. A new member is introduced in the omap2_mcspi structure to keep track of the current used mode. Signed-off-by: Louis Chauvet Link: https://msgid.link/r/20240327-spi-omap2-mcspi-multi-mode-v3-2-c4ac329dd5a2@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 67 +++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 601acec37eca..002f29dbcea6 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -131,6 +131,7 @@ struct omap2_mcspi { unsigned int pin_dir:1; size_t max_xfer_len; u32 ref_clk_hz; + bool use_multi_mode; }; struct omap2_mcspi_cs { @@ -256,10 +257,15 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) l = mcspi_cached_chconf0(spi); - if (enable) + /* Only enable chip select manually if single mode is used */ + if (mcspi->use_multi_mode) { l &= ~OMAP2_MCSPI_CHCONF_FORCE; - else - l |= OMAP2_MCSPI_CHCONF_FORCE; + } else { + if (enable) + l &= ~OMAP2_MCSPI_CHCONF_FORCE; + else + l |= OMAP2_MCSPI_CHCONF_FORCE; + } mcspi_write_chconf0(spi, l); @@ -283,7 +289,12 @@ static void omap2_mcspi_set_mode(struct spi_controller *ctlr) l |= (OMAP2_MCSPI_MODULCTRL_MS); } else { l &= ~(OMAP2_MCSPI_MODULCTRL_MS); - l |= OMAP2_MCSPI_MODULCTRL_SINGLE; + + /* Enable single mode if needed */ + if (mcspi->use_multi_mode) + l &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; + else + l |= OMAP2_MCSPI_MODULCTRL_SINGLE; } mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l); @@ -1250,15 +1261,59 @@ static int omap2_mcspi_prepare_message(struct spi_controller *ctlr, struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_cs *cs; + struct spi_transfer *tr; + u8 bits_per_word; - /* Only a single channel can have the FORCE bit enabled + /* + * The conditions are strict, it is mandatory to check each transfer of the list to see if + * multi-mode is applicable. + */ + mcspi->use_multi_mode = true; + list_for_each_entry(tr, &msg->transfers, transfer_list) { + if (!tr->bits_per_word) + bits_per_word = msg->spi->bits_per_word; + else + bits_per_word = tr->bits_per_word; + + /* + * Check if this transfer contains only one word; + */ + if (bits_per_word < 8 && tr->len == 1) { + /* multi-mode is applicable, only one word (1..7 bits) */ + } else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) { + /* multi-mode is applicable, only one word (8..32 bits) */ + } else { + /* multi-mode is not applicable: more than one word in the transfer */ + mcspi->use_multi_mode = false; + } + + /* Check if transfer asks to change the CS status after the transfer */ + if (!tr->cs_change) + mcspi->use_multi_mode = false; + + /* + * If at least one message is not compatible, switch back to single mode + * + * The bits_per_word of certain transfer can be different, but it will have no + * impact on the signal itself. + */ + if (!mcspi->use_multi_mode) + break; + } + + omap2_mcspi_set_mode(ctlr); + + /* In single mode only a single channel can have the FORCE bit enabled * in its chconf0 register. * Scan all channels and disable them except the current one. * A FORCE can remain from a last transfer having cs_change enabled + * + * In multi mode all FORCE bits must be disabled. */ list_for_each_entry(cs, &ctx->cs, node) { - if (msg->spi->controller_state == cs) + if (msg->spi->controller_state == cs && !mcspi->use_multi_mode) { continue; + } if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) { cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; From e64d3b6fc9a388d7dc516668651cf4404bffec9b Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Wed, 27 Mar 2024 09:43:38 +0100 Subject: [PATCH 19/89] spi: omap2-mcpsi: Enable MULTI-mode in more situations Enable multimode when a transfer of multiple small words can be transformed in a transfer with a single bigger word. This is allowed as long as the result on the cable is the same, so word_delay must be zero. Signed-off-by: Louis Chauvet Link: https://msgid.link/r/20240327-spi-omap2-mcspi-multi-mode-v3-3-c4ac329dd5a2@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 002f29dbcea6..7e3083b83534 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1277,11 +1277,24 @@ static int omap2_mcspi_prepare_message(struct spi_controller *ctlr, /* * Check if this transfer contains only one word; + * OR contains 1 to 4 words, with bits_per_word == 8 and no delay between each word + * OR contains 1 to 2 words, with bits_per_word == 16 and no delay between each word + * + * If one of the two last case is true, this also change the bits_per_word of this + * transfer to make it a bit faster. + * It's not an issue to change the bits_per_word here even if the multi-mode is not + * applicable for this message, the signal on the wire will be the same. */ if (bits_per_word < 8 && tr->len == 1) { /* multi-mode is applicable, only one word (1..7 bits) */ + } else if (tr->word_delay.value == 0 && bits_per_word == 8 && tr->len <= 4) { + /* multi-mode is applicable, only one "bigger" word (8,16,24,32 bits) */ + tr->bits_per_word = tr->len * bits_per_word; + } else if (tr->word_delay.value == 0 && bits_per_word == 16 && tr->len <= 2) { + /* multi-mode is applicable, only one "bigger" word (16,32 bits) */ + tr->bits_per_word = tr->len * bits_per_word / 2; } else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) { - /* multi-mode is applicable, only one word (8..32 bits) */ + /* multi-mode is applicable, only one word (9..15,17..32 bits) */ } else { /* multi-mode is not applicable: more than one word in the transfer */ mcspi->use_multi_mode = false; From 3af201a405b3e5abee65102b062c309fff68cc0e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Mar 2024 21:29:20 +0200 Subject: [PATCH 20/89] spi: pxa2xx: Narrow the Kconfig option visibility The PCI || ACPI dependency is the historical part of the x86 support. Narrow the Kconfig option visibility by limiting this dependency to x86. The drop of x86 for PCI case had happened in the commit 2b49ebda39d6 ("spi/pxa2xx: allow building on a 64-bit kernel"), while the ACPI was specifically added for Intel Lynx Point in the commit a3496855d9f1 ("spi/pxa2xx: add support for Lynxpoint SPI controllers"). Note that X86 covers both 32- and 64-bit variants. Suggested-by: Mark Brown Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240327193138.2385910-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index bc7021da2fe9..6e4b5f7e8adc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -817,7 +817,7 @@ config SPI_PPC4xx config SPI_PXA2XX tristate "PXA2xx SSP SPI master" - depends on ARCH_PXA || ARCH_MMP || PCI || ACPI || COMPILE_TEST + depends on ARCH_PXA || ARCH_MMP || (X86 && (PCI || ACPI)) || COMPILE_TEST select PXA_SSP if ARCH_PXA || ARCH_MMP help This enables using a PXA2xx or Sodaville SSP port as a SPI master From 9907c475dcab9b269422972577360122129ac84c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Mar 2024 21:29:21 +0200 Subject: [PATCH 21/89] spi: pxa2xx: Drop ACPI_PTR() and of_match_ptr() Drop rather useless use of ACPI_PTR() and of_match_ptr(). It also removes the necessity to be dependent of.h inclusion. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240327193138.2385910-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 1d43346b4436..75d208087748 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -1725,7 +1724,6 @@ static const struct dev_pm_ops pxa2xx_spi_pm_ops = { RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, pxa2xx_spi_runtime_resume, NULL) }; -#ifdef CONFIG_ACPI static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { { "80860F0E", LPSS_BYT_SSP }, { "8086228E", LPSS_BSW_SSP }, @@ -1736,9 +1734,8 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { {} }; MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); -#endif -static const struct of_device_id pxa2xx_spi_of_match[] __maybe_unused = { +static const struct of_device_id pxa2xx_spi_of_match[] = { { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, {} }; @@ -1748,8 +1745,8 @@ static struct platform_driver driver = { .driver = { .name = "pxa2xx-spi", .pm = pm_ptr(&pxa2xx_spi_pm_ops), - .acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match), - .of_match_table = of_match_ptr(pxa2xx_spi_of_match), + .acpi_match_table = pxa2xx_spi_acpi_match, + .of_match_table = pxa2xx_spi_of_match, }, .probe = pxa2xx_spi_probe, .remove_new = pxa2xx_spi_remove, From 7290f1e4075d28ab961df5a454503296fa289271 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Mar 2024 21:29:22 +0200 Subject: [PATCH 22/89] spi: pxa2xx: Extract pxa2xx_spi_init_ssp() helper Refactor pxa2xx_spi_init_pdata() by extracting a new pxa2xx_spi_init_ssp() helper which makes code less twisted. It will be easier to continue refactoring for a new coming modification. Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240327193138.2385910-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 66 +++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 75d208087748..e7072727c25c 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1314,19 +1314,50 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) return param == chan->device->dev; } +static int +pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int status; + u64 uid; + + ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(ssp->mmio_base)) + return PTR_ERR(ssp->mmio_base); + + ssp->phys_base = res->start; + + ssp->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ssp->clk)) + return PTR_ERR(ssp->clk); + + ssp->irq = platform_get_irq(pdev, 0); + if (ssp->irq < 0) + return ssp->irq; + + ssp->type = type; + ssp->dev = dev; + + status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid); + if (status) + ssp->port_id = -1; + else + ssp->port_id = uid; + + return 0; +} + static struct pxa2xx_spi_controller * pxa2xx_spi_init_pdata(struct platform_device *pdev) { struct pxa2xx_spi_controller *pdata; struct device *dev = &pdev->dev; struct device *parent = dev->parent; - struct ssp_device *ssp; - struct resource *res; enum pxa_ssp_type type = SSP_UNDEFINED; const void *match; bool is_lpss_priv; int status; - u64 uid; is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); @@ -1351,14 +1382,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) if (!pdata) return ERR_PTR(-ENOMEM); - ssp = &pdata->ssp; - - ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(ssp->mmio_base)) - return ERR_CAST(ssp->mmio_base); - - ssp->phys_base = res->start; - /* Platforms with iDMA 64-bit */ if (is_lpss_priv) { pdata->tx_param = parent; @@ -1366,28 +1389,15 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) pdata->dma_filter = pxa2xx_spi_idma_filter; } - ssp->clk = devm_clk_get(dev, NULL); - if (IS_ERR(ssp->clk)) - return ERR_CAST(ssp->clk); - - ssp->irq = platform_get_irq(pdev, 0); - if (ssp->irq < 0) - return ERR_PTR(ssp->irq); - - ssp->type = type; - ssp->dev = dev; - - status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid); - if (status) - ssp->port_id = -1; - else - ssp->port_id = uid; - pdata->is_target = device_property_read_bool(dev, "spi-slave"); pdata->num_chipselect = 1; pdata->enable_dma = true; pdata->dma_burst_size = 1; + status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type); + if (status) + return ERR_PTR(status); + return pdata; } From bb77c99ee6d3d704086acf141d3ec92601747809 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Mar 2024 21:29:23 +0200 Subject: [PATCH 23/89] spi: pxa2xx: Skip SSP initialization if it's done elsewhere If SSP has been enumerated elsewhere, skip its initialization in pxa2xx_spi_init_pdata(). Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240327193138.2385910-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e7072727c25c..b01a18c89b6b 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1355,6 +1355,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device *parent = dev->parent; enum pxa_ssp_type type = SSP_UNDEFINED; + struct ssp_device *ssp = NULL; const void *match; bool is_lpss_priv; int status; @@ -1372,6 +1373,10 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) return ERR_PTR(status); type = (enum pxa_ssp_type)value; + } else { + ssp = pxa_ssp_request(pdev->id, pdev->name); + if (ssp) + type = ssp->type; } /* Validate the SSP type correctness */ @@ -1394,6 +1399,10 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) pdata->enable_dma = true; pdata->dma_burst_size = 1; + /* If SSP has been already enumerated, use it */ + if (ssp) + return pdata; + status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type); if (status) return ERR_PTR(status); From c2064672f13344586234183e276cc4e0f2cfb70a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Mar 2024 15:51:45 -0500 Subject: [PATCH 24/89] spi: au1550: t->{tx,rx}_dma checks There are no more peripheral drivers that set t->tx_dma or t->rx_dma so these will always == 0. Therefore, we can remove these checks since they are always true. Signed-off-by: David Lechner Link: https://msgid.link/r/20240328-spi-more-tx-rx-buf-cleanup-v1-1-9ec1ceedf08c@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-au1550.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 825d2f1cdff8..16f200bb3d17 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -314,11 +314,8 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) hw->tx = t->tx_buf; hw->rx = t->rx_buf; - dma_tx_addr = t->tx_dma; - dma_rx_addr = t->rx_dma; /* - * check if buffers are already dma mapped, map them otherwise: * - first map the TX buffer, so cache data gets written to memory * - then map the RX buffer, so that cache entries (with * soon-to-be-stale data) get removed @@ -326,23 +323,17 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) * use temp rx buffer (preallocated or realloc to fit) for rx dma */ if (t->tx_buf) { - if (t->tx_dma == 0) { /* if DMA_ADDR_INVALID, map it */ - dma_tx_addr = dma_map_single(hw->dev, - (void *)t->tx_buf, - t->len, DMA_TO_DEVICE); - if (dma_mapping_error(hw->dev, dma_tx_addr)) - dev_err(hw->dev, "tx dma map error\n"); - } + dma_tx_addr = dma_map_single(hw->dev, (void *)t->tx_buf, + t->len, DMA_TO_DEVICE); + if (dma_mapping_error(hw->dev, dma_tx_addr)) + dev_err(hw->dev, "tx dma map error\n"); } if (t->rx_buf) { - if (t->rx_dma == 0) { /* if DMA_ADDR_INVALID, map it */ - dma_rx_addr = dma_map_single(hw->dev, - (void *)t->rx_buf, - t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(hw->dev, dma_rx_addr)) - dev_err(hw->dev, "rx dma map error\n"); - } + dma_rx_addr = dma_map_single(hw->dev, (void *)t->rx_buf, + t->len, DMA_FROM_DEVICE); + if (dma_mapping_error(hw->dev, dma_rx_addr)) + dev_err(hw->dev, "rx dma map error\n"); } else { if (t->len > hw->dma_rx_tmpbuf_size) { int ret; @@ -398,10 +389,10 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) DMA_FROM_DEVICE); } /* unmap buffers if mapped above */ - if (t->rx_buf && t->rx_dma == 0) + if (t->rx_buf) dma_unmap_single(hw->dev, dma_rx_addr, t->len, DMA_FROM_DEVICE); - if (t->tx_buf && t->tx_dma == 0) + if (t->tx_buf) dma_unmap_single(hw->dev, dma_tx_addr, t->len, DMA_TO_DEVICE); From 64fe73d10323e399b2e8eb5407390bcb302a046c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Mar 2024 15:51:46 -0500 Subject: [PATCH 25/89] spi: fsl: remove is_dma_mapped checks There are no more peripheral drivers that set t->tx_dma or t->rx_dma. Therefore, is_dma_mapped is always false and can be removed. Signed-off-by: David Lechner Link: https://msgid.link/r/20240328-spi-more-tx-rx-buf-cleanup-v1-2-9ec1ceedf08c@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-cpm.c | 14 ++++---------- drivers/spi/spi-fsl-cpm.h | 5 ++--- drivers/spi/spi-fsl-spi.c | 7 +++---- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 47c7a5c6257f..e335132080bf 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -98,19 +98,13 @@ static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) mpc8xxx_spi_write_reg(®_base->command, SPCOM_STR); } -int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, - struct spi_transfer *t, bool is_dma_mapped) +int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t) { struct device *dev = mspi->dev; struct fsl_spi_reg __iomem *reg_base = mspi->reg_base; - if (is_dma_mapped) { - mspi->map_tx_dma = 0; - mspi->map_rx_dma = 0; - } else { - mspi->map_tx_dma = 1; - mspi->map_rx_dma = 1; - } + mspi->map_tx_dma = 1; + mspi->map_rx_dma = 1; if (!t->tx_buf) { mspi->tx_dma = mspi->dma_dummy_tx; @@ -147,7 +141,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, return -ENOMEM; } } else if (t->tx_buf) { - mspi->tx_dma = t->tx_dma; + mspi->tx_dma = 0; } if (mspi->map_rx_dma) { diff --git a/drivers/spi/spi-fsl-cpm.h b/drivers/spi/spi-fsl-cpm.h index 160f999708b6..e012abba055f 100644 --- a/drivers/spi/spi-fsl-cpm.h +++ b/drivers/spi/spi-fsl-cpm.h @@ -20,7 +20,7 @@ #ifdef CONFIG_FSL_SOC extern void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi); extern int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, - struct spi_transfer *t, bool is_dma_mapped); + struct spi_transfer *t); extern void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi); extern void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events); extern int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi); @@ -28,8 +28,7 @@ extern void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi); #else static inline void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) { } static inline int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, - struct spi_transfer *t, - bool is_dma_mapped) { return 0; } + struct spi_transfer *t) { return 0; } static inline void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { } static inline void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { } static inline int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) { return 0; } diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 97faf984801f..997e07c0a24a 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -249,8 +249,7 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi, return 0; } -static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, - bool is_dma_mapped) +static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller); struct fsl_spi_reg __iomem *reg_base; @@ -274,7 +273,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, reinit_completion(&mpc8xxx_spi->done); if (mpc8xxx_spi->flags & SPI_CPM_MODE) - ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); + ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t); else ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len); if (ret) @@ -353,7 +352,7 @@ static int fsl_spi_transfer_one(struct spi_controller *controller, if (status < 0) return status; if (t->len) - status = fsl_spi_bufs(spi, t, !!t->tx_dma || !!t->rx_dma); + status = fsl_spi_bufs(spi, t); if (status > 0) return -EMSGSIZE; From ba5206881843e16b74a07c37970dcc44d22f8f6f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 28 Mar 2024 15:33:40 -0700 Subject: [PATCH 26/89] spi: spi.h: add missing kernel-doc for @last_cs_index_mask kernel-doc complains about last_cs_index_mask not described, so add its description. spi.h:778: warning: Function parameter or struct member 'last_cs_index_mask' not described in 'spi_controller' Fixes: 4d8ff6b0991d ("spi: Add multi-cs memories support in SPI core") Signed-off-by: Randy Dunlap Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240328223340.17159-1-rdunlap@infradead.org Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index b589e2547439..e8e1e798924f 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -453,6 +453,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. * @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip * selected + * @last_cs_index_mask: bit mask the last chip selects that were used * @xfer_completion: used by core transfer_one_message() * @busy: message pump is busy * @running: message pump is running From 5da57c7ca9eabccd89087ed2fdac31a79b1504d8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 28 Mar 2024 21:39:27 +0100 Subject: [PATCH 27/89] spi: docs: drop driver owner initialization Core in spi_register_driver() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240328203927.156184-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- Documentation/spi/spi-summary.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst index f7f8b1573f25..7f8accfae6f9 100644 --- a/Documentation/spi/spi-summary.rst +++ b/Documentation/spi/spi-summary.rst @@ -348,7 +348,6 @@ SPI protocol drivers somewhat resemble platform device drivers:: static struct spi_driver CHIP_driver = { .driver = { .name = "CHIP", - .owner = THIS_MODULE, .pm = &CHIP_pm_ops, }, From 33aa27a09e9df5860fe495032a067504d025db77 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 17:45:23 +0300 Subject: [PATCH 28/89] spi: pxa2xx: Call pxa_ssp_free() after getting the SSP type pxa_ssp_request() implies a reference counting, hence the pxa_ssp_free() must be called when we are done. Add missed call. Fixes: bb77c99ee6d3 ("spi: pxa2xx: Skip SSP initialization if it's done elsewhere") Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240402144523.3402063-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index b01a18c89b6b..2d128ddf18ab 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1375,8 +1375,10 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) type = (enum pxa_ssp_type)value; } else { ssp = pxa_ssp_request(pdev->id, pdev->name); - if (ssp) + if (ssp) { type = ssp->type; + pxa_ssp_free(ssp); + } } /* Validate the SSP type correctness */ From 708eafeba9eec51c5bde8efef2a7c22d7113b771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Fri, 5 Apr 2024 17:02:13 +0200 Subject: [PATCH 29/89] spi: cadence-qspi: allow building for MIPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Cadence QSPI Controller driver is used on Mobileye EyeQ5 platform. Allow building on MIPS. Signed-off-by: Théo Lebrun Link: https://msgid.link/r/20240405-cdns-qspi-mbly-v2-3-956679866d6d@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6e4b5f7e8adc..554664efda86 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -246,7 +246,7 @@ config SPI_CADENCE config SPI_CADENCE_QUADSPI tristate "Cadence Quad SPI controller" - depends on OF && (ARM || ARM64 || X86 || RISCV || COMPILE_TEST) + depends on OF && (ARM || ARM64 || X86 || RISCV || MIPS || COMPILE_TEST) help Enable support for the Cadence Quad SPI Flash controller. From dcc594aef1bf3a6a49b77ad2c0348d894b7cd956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Fri, 5 Apr 2024 17:02:14 +0200 Subject: [PATCH 30/89] spi: cadence-qspi: store device data pointer in private struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid of_device_get_match_data() call on each IRQ and each read operation. Store pointer in `struct cqspi_st` device instance. End-to-end performance measurements improve with this patch. On a given octal flash, reading 235M over UBIFS is ~3.4% faster. During that read, the average cqspi_exec_mem_op() call goes from 85.4µs to 80.7µs according to ftrace. The worst case goes from 622.4µs to 615.2µs. Signed-off-by: Théo Lebrun Link: https://msgid.link/r/20240405-cdns-qspi-mbly-v2-4-956679866d6d@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 350b3dab3a05..abc1c35929cc 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -102,6 +102,8 @@ struct cqspi_st { bool apb_ahb_hazard; bool is_jh7110; /* Flag for StarFive JH7110 SoC */ + + const struct cqspi_driver_platdata *ddata; }; struct cqspi_driver_platdata { @@ -334,11 +336,8 @@ static u32 cqspi_get_versal_dma_status(struct cqspi_st *cqspi) static irqreturn_t cqspi_irq_handler(int this_irq, void *dev) { struct cqspi_st *cqspi = dev; + const struct cqspi_driver_platdata *ddata = cqspi->ddata; unsigned int irq_status; - struct device *device = &cqspi->pdev->dev; - const struct cqspi_driver_platdata *ddata; - - ddata = of_device_get_match_data(device); /* Read interrupt status */ irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS); @@ -1358,16 +1357,13 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata, const struct spi_mem_op *op) { struct cqspi_st *cqspi = f_pdata->cqspi; - struct device *dev = &cqspi->pdev->dev; - const struct cqspi_driver_platdata *ddata; + const struct cqspi_driver_platdata *ddata = cqspi->ddata; loff_t from = op->addr.val; size_t len = op->data.nbytes; u_char *buf = op->data.buf.in; u64 dma_align = (u64)(uintptr_t)buf; int ret; - ddata = of_device_get_match_data(dev); - ret = cqspi_read_setup(f_pdata, op); if (ret) return ret; @@ -1822,7 +1818,8 @@ static int cqspi_probe(struct platform_device *pdev) /* write completion is supported by default */ cqspi->wr_completion = true; - ddata = of_device_get_match_data(dev); + ddata = of_device_get_match_data(dev); + cqspi->ddata = ddata; if (ddata) { if (ddata->quirks & CQSPI_NEEDS_WR_DELAY) cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, From 563f8598cbc246a81d256e0e888dc085504caa90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Fri, 5 Apr 2024 17:02:16 +0200 Subject: [PATCH 31/89] spi: cadence-qspi: minimise register accesses on each op if !DTR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cqspi_enable_dtr() is called for each operation, commands or not, reads or writes. It writes CQSPI_REG_CONFIG then waits for idle (three successful reads). Skip that in the no-DTR case if DTR is already disabled. It cannot be skipped in the DTR case as cqspi_setup_opcode_ext() writes to a register and we must wait for idle state. According to ftrace, the average cqspi_exec_mem_op() call goes from 85.4µs to 83.6µs when reading 235M over UBIFS on an octal flash. Signed-off-by: Théo Lebrun Link: https://msgid.link/r/20240405-cdns-qspi-mbly-v2-6-956679866d6d@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index abc1c35929cc..9896e9fe7ffb 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -491,8 +491,11 @@ static int cqspi_enable_dtr(struct cqspi_flash_pdata *f_pdata, if (ret) return ret; } else { - reg &= ~CQSPI_REG_CONFIG_DTR_PROTO; - reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE; + unsigned int mask = CQSPI_REG_CONFIG_DTR_PROTO | CQSPI_REG_CONFIG_DUAL_OPCODE; + /* Shortcut if DTR is already disabled. */ + if ((reg & mask) == 0) + return 0; + reg &= ~mask; } writel(reg, reg_base + CQSPI_REG_CONFIG); From b0f3e56938f8cc8c4d606846270b879650ae7741 Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Wed, 10 Apr 2024 18:31:16 +0530 Subject: [PATCH 32/89] spi: cadence-xspi: use for_each_available_child_of_node_scoped() Refactor code for "is the node's child available?" check by using the corresponding macro instead, which reads more clearly. While at it, use scope-based cleanup instead of manual of_node_put() calls when getting platform data through cdns_xspi_of_get_plat_data(). This removes the unnecessary "node_child" declaration out of the loop's scope and auto cleans up "node_child" when it goes out of scope, even when we return early due to error. Signed-off-by: Kousik Sanagavarapu Link: https://msgid.link/r/20240410130205.179069-1-five231003@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 8648b8eb080d..2209e9fc378f 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -486,20 +486,14 @@ static irqreturn_t cdns_xspi_irq_handler(int this_irq, void *dev) static int cdns_xspi_of_get_plat_data(struct platform_device *pdev) { struct device_node *node_prop = pdev->dev.of_node; - struct device_node *node_child; unsigned int cs; - for_each_child_of_node(node_prop, node_child) { - if (!of_device_is_available(node_child)) - continue; - + for_each_available_child_of_node_scoped(node_prop, node_child) { if (of_property_read_u32(node_child, "reg", &cs)) { dev_err(&pdev->dev, "Couldn't get memory chip select\n"); - of_node_put(node_child); return -ENXIO; } else if (cs >= CDNS_XSPI_MAX_BANKS) { dev_err(&pdev->dev, "reg (cs) parameter value too large\n"); - of_node_put(node_child); return -ENXIO; } } From 002514d91fccde2adbe750c9ec5c6207d56c890b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 10 Apr 2024 11:29:04 +0200 Subject: [PATCH 33/89] spi: dt-bindings: cdns,qspi-nor: sort compatibles alphabetically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compatibles are ordered by date of addition. Switch to (deterministic) alphabetical ordering. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Théo Lebrun Link: https://msgid.link/r/20240410-cdns-qspi-mbly-v3-1-7b7053449cf7@bootlin.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml index cca81f89e252..b865d4cc25cc 100644 --- a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml @@ -68,12 +68,12 @@ properties: - items: - enum: - amd,pensando-elba-qspi - - ti,k2g-qspi - - ti,am654-ospi - intel,lgm-qspi - - xlnx,versal-ospi-1.0 - intel,socfpga-qspi - starfive,jh7110-qspi + - ti,am654-ospi + - ti,k2g-qspi + - xlnx,versal-ospi-1.0 - const: cdns,qspi-nor - const: cdns,qspi-nor From 52826aee484b3ebb6ed94c1ae89c0944110ed8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 10 Apr 2024 11:29:05 +0200 Subject: [PATCH 34/89] spi: dt-bindings: cdns,qspi-nor: add mobileye,eyeq5-ospi compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Mobileye EyeQ5 compatible. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Théo Lebrun Link: https://msgid.link/r/20240410-cdns-qspi-mbly-v3-2-7b7053449cf7@bootlin.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml index b865d4cc25cc..587baf35e4e3 100644 --- a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml @@ -70,6 +70,7 @@ properties: - amd,pensando-elba-qspi - intel,lgm-qspi - intel,socfpga-qspi + - mobileye,eyeq5-ospi - starfive,jh7110-qspi - ti,am654-ospi - ti,k2g-qspi From eb4fdb4bf46f875eac3c093f7ff43a223985f7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 10 Apr 2024 11:29:06 +0200 Subject: [PATCH 35/89] spi: dt-bindings: cdns,qspi-nor: make cdns,fifo-depth optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make cdns,fifo-depth devicetree property optional. Value can be detected at runtime. Upper SRAMPARTITION register bits are read-only. Procedure to find FIFO depth is therefore to write 0xFFFFFFFF and read back to get amount of writeable bits. Signed-off-by: Théo Lebrun Link: https://msgid.link/r/20240410-cdns-qspi-mbly-v3-3-7b7053449cf7@bootlin.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml index 587baf35e4e3..d48ecd6cd5ad 100644 --- a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml @@ -146,7 +146,6 @@ required: - reg - interrupts - clocks - - cdns,fifo-depth - cdns,fifo-width - cdns,trigger-address - '#address-cells' From 82116e539ffb7ce0c317c208d53d2126cdcee687 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 11 Apr 2024 09:58:03 +0200 Subject: [PATCH 36/89] MAINTAINERS: adjust file entry in TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS Commit 8167bd1c8a45 ("ASoC: dt-bindings: ti,pcm1681: Convert to dtschema") converts ti,pcm1681.txt to ti,pcm1681.yaml, but misses to adjust the file entry in TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Adjust the file entry in TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS after this conversion. Signed-off-by: Lukas Bulwahn Link: https://msgid.link/r/20240411075803.53657-1-lukas.bulwahn@redhat.com Signed-off-by: Mark Brown --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..7fce3c646cef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21818,7 +21818,7 @@ F: Documentation/devicetree/bindings/sound/tas2552.txt F: Documentation/devicetree/bindings/sound/tas2562.yaml F: Documentation/devicetree/bindings/sound/tas2770.yaml F: Documentation/devicetree/bindings/sound/tas27xx.yaml -F: Documentation/devicetree/bindings/sound/ti,pcm1681.txt +F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml F: Documentation/devicetree/bindings/sound/tlv320adcx140.yaml From 770e3da3fe7ee7ffca745b7ac300ce39fe40f465 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 14 Apr 2024 17:48:59 +0200 Subject: [PATCH 37/89] spi: altera: Drop unneeded MODULE_ALIAS The ID table already has respective entry and MODULE_DEVICE_TABLE and creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240414154859.126931-1-krzk@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-altera-platform.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c index 72e7a0f21793..585393802e9f 100644 --- a/drivers/spi/spi-altera-platform.c +++ b/drivers/spi/spi-altera-platform.c @@ -169,4 +169,3 @@ module_platform_driver(altera_spi_driver); MODULE_DESCRIPTION("Altera SPI driver"); MODULE_AUTHOR("Thomas Chou "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); From df3431fd379dcc3b231bd109a55948c27474478d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 3 Apr 2024 20:06:35 +0300 Subject: [PATCH 38/89] spi: pxa2xx: Move number of CS pins validation out of condition There is no need to allocate chip_data and then validate number of CS pins as it will have the same effect. Hence move number of CS pins validation out of condition in setup(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240403171550.1074644-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 2d128ddf18ab..2f60b2fde8d5 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1197,6 +1197,13 @@ static int setup(struct spi_device *spi) break; } + if (drv_data->ssp_type == CE4100_SSP) { + if (spi_get_chipselect(spi, 0) > 4) { + dev_err(&spi->dev, "failed setup: cs number must not be > 4.\n"); + return -EINVAL; + } + } + /* Only allocate on the first setup */ chip = spi_get_ctldata(spi); if (!chip) { @@ -1204,14 +1211,6 @@ static int setup(struct spi_device *spi) if (!chip) return -ENOMEM; - if (drv_data->ssp_type == CE4100_SSP) { - if (spi_get_chipselect(spi, 0) > 4) { - dev_err(&spi->dev, - "failed setup: cs number must not be > 4.\n"); - kfree(chip); - return -EINVAL; - } - } chip->enable_dma = drv_data->controller_info->enable_dma; chip->timeout = TIMOUT_DFLT; } From e81582c080ddec3359bc6726291e62a1ba8b7350 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Apr 2024 22:31:19 +0300 Subject: [PATCH 39/89] spi: Extract spi_toggle_csgpiod() helper for better maintanance The multi-CS support splits the comment and the code in the spi_set_cs(). To avoid this in the future extract spi_toggle_csgpiod() helper. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240415193340.1279360-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 49 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a2f01116ba09..63abe4320ab4 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1036,6 +1036,29 @@ static inline bool spi_is_last_cs(struct spi_device *spi) return last; } +static void spi_toggle_csgpiod(struct spi_device *spi, u8 idx, bool enable, bool activate) +{ + /* + * Historically ACPI has no means of the GPIO polarity and + * thus the SPISerialBus() resource defines it on the per-chip + * basis. In order to avoid a chain of negations, the GPIO + * polarity is considered being Active High. Even for the cases + * when _DSD() is involved (in the updated versions of ACPI) + * the GPIO CS polarity must be defined Active High to avoid + * ambiguity. That's why we use enable, that takes SPI_CS_HIGH + * into account. + */ + if (has_acpi_companion(&spi->dev)) + gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), !enable); + else + /* Polarity handled by GPIO library */ + gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), activate); + + if (activate) + spi_delay_exec(&spi->cs_setup, NULL); + else + spi_delay_exec(&spi->cs_inactive, NULL); +} static void spi_set_cs(struct spi_device *spi, bool enable, bool force) { @@ -1072,31 +1095,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) if (spi_is_csgpiod(spi)) { if (!(spi->mode & SPI_NO_CS)) { - /* - * Historically ACPI has no means of the GPIO polarity and - * thus the SPISerialBus() resource defines it on the per-chip - * basis. In order to avoid a chain of negations, the GPIO - * polarity is considered being Active High. Even for the cases - * when _DSD() is involved (in the updated versions of ACPI) - * the GPIO CS polarity must be defined Active High to avoid - * ambiguity. That's why we use enable, that takes SPI_CS_HIGH - * into account. - */ for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { - if ((spi->cs_index_mask & BIT(idx)) && spi_get_csgpiod(spi, idx)) { - if (has_acpi_companion(&spi->dev)) - gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), - !enable); - else - /* Polarity handled by GPIO library */ - gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), - activate); - - if (activate) - spi_delay_exec(&spi->cs_setup, NULL); - else - spi_delay_exec(&spi->cs_inactive, NULL); - } + if ((spi->cs_index_mask & BIT(idx)) && spi_get_csgpiod(spi, idx)) + spi_toggle_csgpiod(spi, idx, enable, activate); } } /* Some SPI masters need both GPIO CS & slave_select */ From d707530b1ea518e23c7aa7b50ee79231f2964da0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Apr 2024 22:31:20 +0300 Subject: [PATCH 40/89] spi: Introduce spi_for_each_valid_cs() in order of deduplication In order of deduplication and better maintenance introduce a new spi_for_each_valid_cs() helper macro. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240415193340.1279360-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 63abe4320ab4..b5b24d91bd50 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1022,16 +1022,18 @@ static void spi_res_release(struct spi_controller *ctlr, struct spi_message *mes } /*-------------------------------------------------------------------------*/ +#define spi_for_each_valid_cs(spi, idx) \ + for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) \ + if (!(spi->cs_index_mask & BIT(idx))) {} else + static inline bool spi_is_last_cs(struct spi_device *spi) { u8 idx; bool last = false; - for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { - if (spi->cs_index_mask & BIT(idx)) { - if (spi->controller->last_cs[idx] == spi_get_chipselect(spi, idx)) - last = true; - } + spi_for_each_valid_cs(spi, idx) { + if (spi->controller->last_cs[idx] == spi_get_chipselect(spi, idx)) + last = true; } return last; } @@ -1095,8 +1097,8 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) if (spi_is_csgpiod(spi)) { if (!(spi->mode & SPI_NO_CS)) { - for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { - if ((spi->cs_index_mask & BIT(idx)) && spi_get_csgpiod(spi, idx)) + spi_for_each_valid_cs(spi, idx) { + if (spi_get_csgpiod(spi, idx)) spi_toggle_csgpiod(spi, idx, enable, activate); } } From bb40996267670862544cb8e740afb77cbf3a7949 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Apr 2024 21:47:57 +0300 Subject: [PATCH 41/89] spi: Consistently use BIT for cs_index_mask (part 2) For some reason the commit 1209c5566f9b ("spi: Consistently use BIT for cs_index_mask") missed one place to change, do it here to finish the job. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240415184757.1198149-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a2f01116ba09..6eb8583f5e40 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -822,14 +822,10 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr, proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; /* - * spi->chip_select[i] gives the corresponding physical CS for logical CS i - * logical CS number is represented by setting the ith bit in spi->cs_index_mask - * So, for example, if spi->cs_index_mask = 0x01 then logical CS number is 0 and - * spi->chip_select[0] will give the physical CS. - * By default spi->chip_select[0] will hold the physical CS number so, set - * spi->cs_index_mask as 0x01. + * By default spi->chip_select[0] will hold the physical CS number, + * so set bit 0 in spi->cs_index_mask. */ - proxy->cs_index_mask = 0x01; + proxy->cs_index_mask = BIT(0); if (chip->swnode) { status = device_add_software_node(&proxy->dev, chip->swnode); From 9d50f95bc0d5df56f2591b950a251d90bffad094 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 16 Apr 2024 11:09:01 +0100 Subject: [PATCH 42/89] gpio: swnode: Add ability to specify native chip selects for SPI SPI devices can specify a cs-gpios property to enumerate their chip selects. Under device tree, a zero entry in this property can be used to specify that a particular chip select is using the SPI controllers native chip select, for example: cs-gpios = <&gpio1 0 0>, <0>; Here, the second chip select is native. However, when using swnodes there is currently no way to specify a native chip select. The proposal here is to register a swnode_gpio_undefined software node, that can be specified to allow the indication of a native chip select. For example: static const struct software_node_ref_args device_cs_refs[] = { { .node = &device_gpiochip_swnode, .nargs = 2, .args = { 0, GPIO_ACTIVE_LOW }, }, { .node = &swnode_gpio_undefined, .nargs = 0, }, }; Register the swnode as the gpiolib is initialised and check in swnode_get_gpio_device() if the returned node matches swnode_gpio_undefined and return -ENOENT, which matches the behaviour of the device tree system when it encounters a 0 phandle. Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20240416100904.3738093-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/gpio/Kconfig | 9 +++++++ drivers/gpio/gpiolib-swnode.c | 44 +++++++++++++++++++++++++++++++++++ include/linux/gpio/property.h | 4 ++++ 3 files changed, 57 insertions(+) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b50d0b470849..00b5c007a2bb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -103,6 +103,15 @@ config GPIO_REGMAP select REGMAP tristate +config GPIO_SWNODE_UNDEFINED + bool + help + This adds a special place holder for software nodes to contain an + undefined GPIO reference, this is primarily used by SPI to allow a + list of GPIO chip selects to mark a certain chip select as being + controlled the SPI device's internal chip select mechanism and not + a GPIO. + # put drivers in the right section, in alphabetical order # This symbol is selected by both I2C and SPI expanders diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c index fa52bdb1a29a..cec1ab878af8 100644 --- a/drivers/gpio/gpiolib-swnode.c +++ b/drivers/gpio/gpiolib-swnode.c @@ -4,8 +4,13 @@ * * Copyright 2022 Google LLC */ + +#define pr_fmt(fmt) "gpiolib: swnode: " fmt + #include #include +#include +#include #include #include #include @@ -17,6 +22,8 @@ #include "gpiolib.h" #include "gpiolib-swnode.h" +#define GPIOLIB_SWNODE_UNDEFINED_NAME "swnode-gpio-undefined" + static void swnode_format_propname(const char *con_id, char *propname, size_t max_size) { @@ -40,6 +47,14 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) if (!gdev_node || !gdev_node->name) return ERR_PTR(-EINVAL); + /* + * Check for a special node that identifies undefined GPIOs, this is + * primarily used as a key for internal chip selects in SPI bindings. + */ + if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) && + !strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME)) + return ERR_PTR(-ENOENT); + gdev = gpio_device_find_by_label(gdev_node->name); return gdev ?: ERR_PTR(-EPROBE_DEFER); } @@ -121,3 +136,32 @@ int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id) return count ?: -ENOENT; } + +#if IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) +/* + * A special node that identifies undefined GPIOs, this is primarily used as + * a key for internal chip selects in SPI bindings. + */ +const struct software_node swnode_gpio_undefined = { + .name = GPIOLIB_SWNODE_UNDEFINED_NAME, +}; +EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, GPIO_SWNODE); + +static int __init swnode_gpio_init(void) +{ + int ret; + + ret = software_node_register(&swnode_gpio_undefined); + if (ret < 0) + pr_err("failed to register swnode: %d\n", ret); + + return ret; +} +subsys_initcall(swnode_gpio_init); + +static void __exit swnode_gpio_cleanup(void) +{ + software_node_unregister(&swnode_gpio_undefined); +} +__exitcall(swnode_gpio_cleanup); +#endif diff --git a/include/linux/gpio/property.h b/include/linux/gpio/property.h index 6c75c8bd44a0..832a60c2e0b9 100644 --- a/include/linux/gpio/property.h +++ b/include/linux/gpio/property.h @@ -5,7 +5,11 @@ #include /* for GPIO_* flags */ #include +struct software_node; + #define PROPERTY_ENTRY_GPIO(_name_, _chip_node_, _idx_, _flags_) \ PROPERTY_ENTRY_REF(_name_, _chip_node_, _idx_, _flags_) +extern const struct software_node swnode_gpio_undefined; + #endif /* __LINUX_GPIO_PROPERTY_H */ From 8a101146bcf014060530d71eba8edc52eca257f7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 16 Apr 2024 11:09:02 +0100 Subject: [PATCH 43/89] spi: Switch to using is_acpi_device_node() in spi_dev_set_name() Use is_acpi_device_node() rather than checking ACPI_COMPANION(), such that when checking for other types of firmware node, the code can consistently do checks against the fwnode. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20240416100904.3738093-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ff75838c1b5d..26f287d8d946 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -597,10 +597,11 @@ EXPORT_SYMBOL_GPL(spi_alloc_device); static void spi_dev_set_name(struct spi_device *spi) { - struct acpi_device *adev = ACPI_COMPANION(&spi->dev); + struct device *dev = &spi->dev; + struct fwnode_handle *fwnode = dev_fwnode(dev); - if (adev) { - dev_set_name(&spi->dev, "spi-%s", acpi_dev_name(adev)); + if (is_acpi_device_node(fwnode)) { + dev_set_name(dev, "spi-%s", acpi_dev_name(to_acpi_device_node(fwnode))); return; } From ed8921188f3568ba1659ff041f21e83565c74ec2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 16 Apr 2024 11:09:03 +0100 Subject: [PATCH 44/89] spi: Update swnode based SPI devices to use the fwnode name Update the name for software node based SPI devices to use the fwnode name as the device name. This is helpful since swnode devices are usually added within the kernel, and the kernel often then requires a predictable name such that it can refer back to the device. Reviewed-by: Andy Shevchenko Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20240416100904.3738093-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 26f287d8d946..555fbe200733 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -605,6 +605,11 @@ static void spi_dev_set_name(struct spi_device *spi) return; } + if (is_software_node(fwnode)) { + dev_set_name(dev, "spi-%pfwP", fwnode); + return; + } + dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev), spi_get_chipselect(spi, 0)); } From 439fbc97502ae16f3e54e05d266d103674cc4f06 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Tue, 16 Apr 2024 11:09:04 +0100 Subject: [PATCH 45/89] spi: cs42l43: Add bridged cs35l56 amplifiers On some cs42l43 systems a couple of cs35l56 amplifiers are attached to the cs42l43's SPI and I2S. On Windows the cs42l43 is controlled by a SDCA class driver and these two amplifiers are controlled by firmware running on the cs42l43. However, under Linux the decision was made to interact with the cs42l43 directly, affording the user greater control over the audio system. However, this has resulted in an issue where these two bridged cs35l56 amplifiers are not populated in ACPI and must be added manually. Check for the presence of the "01fa-cirrus-sidecar-instances" property in the SDCA extension unit's ACPI properties to confirm the presence of these two amplifiers and if they exist add them manually onto the SPI bus. Reviewed-by: Andy Shevchenko Signed-off-by: Maciej Strozek Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20240416100904.3738093-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 + drivers/spi/spi-cs42l43.c | 125 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index bc7021da2fe9..555df2f07b3a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -284,6 +284,7 @@ config SPI_COLDFIRE_QSPI config SPI_CS42L43 tristate "Cirrus Logic CS42L43 SPI controller" depends on MFD_CS42L43 && PINCTRL_CS42L43 + select GPIO_SWNODE_UNDEFINED help This enables support for the SPI controller inside the Cirrus Logic CS42L43 audio codec. diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index aabef9fc84bd..cffd9a177808 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -5,10 +5,14 @@ // Copyright (C) 2022-2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -16,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +44,44 @@ static const unsigned int cs42l43_clock_divs[] = { 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; +static const struct software_node ampl = { + .name = "cs35l56-left", +}; + +static const struct software_node ampr = { + .name = "cs35l56-right", +}; + +static struct spi_board_info ampl_info = { + .modalias = "cs35l56", + .max_speed_hz = 20 * HZ_PER_MHZ, + .chip_select = 0, + .mode = SPI_MODE_0, + .swnode = &l, +}; + +static struct spi_board_info ampr_info = { + .modalias = "cs35l56", + .max_speed_hz = 20 * HZ_PER_MHZ, + .chip_select = 1, + .mode = SPI_MODE_0, + .swnode = &r, +}; + +static const struct software_node cs42l43_gpiochip_swnode = { + .name = "cs42l43-pinctrl", +}; + +static const struct software_node_ref_args cs42l43_cs_refs[] = { + SOFTWARE_NODE_REFERENCE(&cs42l43_gpiochip_swnode, 0, GPIO_ACTIVE_LOW), + SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined), +}; + +static const struct property_entry cs42l43_cs_props[] = { + PROPERTY_ENTRY_REF_ARRAY("cs-gpios", cs42l43_cs_refs), + {} +}; + static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len) { const u8 *end = buf + len; @@ -203,16 +246,59 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) return CS42L43_SPI_MAX_LENGTH; } +static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode) +{ + static const u32 func_smart_amp = 0x1; + struct fwnode_handle *child_fwnode, *ext_fwnode; + unsigned int val; + u32 function; + int ret; + + fwnode_for_each_child_node(fwnode, child_fwnode) { + acpi_handle handle = ACPI_HANDLE_FWNODE(child_fwnode); + + ret = acpi_get_local_address(handle, &function); + if (ret || function != func_smart_amp) + continue; + + ext_fwnode = fwnode_get_named_child_node(child_fwnode, + "mipi-sdca-function-expansion-subproperties"); + if (!ext_fwnode) + continue; + + ret = fwnode_property_read_u32(ext_fwnode, + "01fa-cirrus-sidecar-instances", + &val); + + fwnode_handle_put(ext_fwnode); + + if (ret) + continue; + + fwnode_handle_put(child_fwnode); + + return !!val; + } + + return false; +} + static void cs42l43_release_of_node(void *data) { fwnode_handle_put(data); } +static void cs42l43_release_sw_node(void *data) +{ + software_node_unregister(&cs42l43_gpiochip_swnode); +} + static int cs42l43_spi_probe(struct platform_device *pdev) { struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); struct cs42l43_spi *priv; struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); + bool has_sidecar = cs42l43_has_sidecar(fwnode); int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -266,14 +352,42 @@ static int cs42l43_spi_probe(struct platform_device *pdev) } } - device_set_node(&priv->ctlr->dev, fwnode); + if (has_sidecar) { + ret = software_node_register(&cs42l43_gpiochip_swnode); + if (ret) + return dev_err_probe(priv->dev, ret, + "Failed to register gpio swnode\n"); - ret = devm_spi_register_controller(priv->dev, priv->ctlr); - if (ret) { - dev_err(priv->dev, "Failed to register SPI controller: %d\n", ret); + ret = devm_add_action(priv->dev, cs42l43_release_sw_node, NULL); + if (ret) { + software_node_unregister(&cs42l43_gpiochip_swnode); + return ret; + } + + ret = device_create_managed_software_node(&priv->ctlr->dev, + cs42l43_cs_props, NULL); + if (ret) + return dev_err_probe(priv->dev, ret, "Failed to add swnode\n"); + } else { + device_set_node(&priv->ctlr->dev, fwnode); } - return ret; + ret = devm_spi_register_controller(priv->dev, priv->ctlr); + if (ret) + return dev_err_probe(priv->dev, ret, + "Failed to register SPI controller\n"); + + if (has_sidecar) { + if (!spi_new_device(priv->ctlr, &l_info)) + return dev_err_probe(priv->dev, -ENODEV, + "Failed to create left amp slave\n"); + + if (!spi_new_device(priv->ctlr, &r_info)) + return dev_err_probe(priv->dev, -ENODEV, + "Failed to create right amp slave\n"); + } + + return 0; } static const struct platform_device_id cs42l43_spi_id_table[] = { @@ -291,6 +405,7 @@ static struct platform_driver cs42l43_spi_driver = { }; module_platform_driver(cs42l43_spi_driver); +MODULE_IMPORT_NS(GPIO_SWNODE); MODULE_DESCRIPTION("CS42L43 SPI Driver"); MODULE_AUTHOR("Lucas Tanure "); MODULE_AUTHOR("Maciej Strozek "); From 1f48cbd6f00f2d1442ac8757ae8c32b672073927 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 16 Apr 2024 17:11:48 +0200 Subject: [PATCH 46/89] spi: renesas,sh-msiof: Add r8a779h0 support Document support for the Clock-Synchronized Serial Interface with FIFO (MSIOF) in the Renesas R-Car V4M (R8A779H0) SoC. Signed-off-by: Geert Uytterhoeven Acked-by: Conor Dooley Link: https://lore.kernel.org/r/68a4d8ad8638c1133e21d0eef87e8982ddea3dd8.1713279687.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml b/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml index 00acbbb0f65d..49649fc3f95a 100644 --- a/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml +++ b/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml @@ -54,6 +54,7 @@ properties: - renesas,msiof-r8a779a0 # R-Car V3U - renesas,msiof-r8a779f0 # R-Car S4-8 - renesas,msiof-r8a779g0 # R-Car V4H + - renesas,msiof-r8a779h0 # R-Car V4M - const: renesas,rcar-gen4-msiof # generic R-Car Gen4 # compatible device - items: From 719af321a84b9b6669a82a94708e7ca574971331 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Apr 2024 10:30:26 +0100 Subject: [PATCH 47/89] spi: cs42l43: Use devm_add_action_or_reset() Use devm_add_action_or_reset() rather than manually cleaning up on the error path. Suggested-by: Andy Shevchenko Signed-off-by: Charles Keepax Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240417093026.79396-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi-cs42l43.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index cffd9a177808..cdc61cd089ad 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -345,11 +345,9 @@ static int cs42l43_spi_probe(struct platform_device *pdev) if (is_of_node(fwnode)) { fwnode = fwnode_get_named_child_node(fwnode, "spi"); - ret = devm_add_action(priv->dev, cs42l43_release_of_node, fwnode); - if (ret) { - fwnode_handle_put(fwnode); + ret = devm_add_action_or_reset(priv->dev, cs42l43_release_of_node, fwnode); + if (ret) return ret; - } } if (has_sidecar) { @@ -358,11 +356,9 @@ static int cs42l43_spi_probe(struct platform_device *pdev) return dev_err_probe(priv->dev, ret, "Failed to register gpio swnode\n"); - ret = devm_add_action(priv->dev, cs42l43_release_sw_node, NULL); - if (ret) { - software_node_unregister(&cs42l43_gpiochip_swnode); + ret = devm_add_action_or_reset(priv->dev, cs42l43_release_sw_node, NULL); + if (ret) return ret; - } ret = device_create_managed_software_node(&priv->ctlr->dev, cs42l43_cs_props, NULL); From 037c633df6680500f35a9e9a06286d4e1401897e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:47:30 +0300 Subject: [PATCH 48/89] spi: oc-tiny: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The driver doesn't use it, simply remove the unused header. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240417104730.2510856-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-oc-tiny.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 6ea38f5e7d64..7d8c5cd680d1 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -184,8 +184,6 @@ static irqreturn_t tiny_spi_irq(int irq, void *dev) } #ifdef CONFIG_OF -#include - static int tiny_spi_of_probe(struct platform_device *pdev) { struct tiny_spi *hw = platform_get_drvdata(pdev); From 4fbf4e3ea666653b02fe55a63f8dae11ebaaa271 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Thu, 18 Apr 2024 11:33:15 +0100 Subject: [PATCH 49/89] spi: cs42l43: Correct name of ACPI property Fixes: 439fbc97502a ("spi: cs42l43: Add bridged cs35l56 amplifiers") Signed-off-by: Maciej Strozek Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240418103315.1487267-1-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi-cs42l43.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index cdc61cd089ad..9d747ea69926 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -267,7 +267,7 @@ static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode) continue; ret = fwnode_property_read_u32(ext_fwnode, - "01fa-cirrus-sidecar-instances", + "01fa-sidecar-instances", &val); fwnode_handle_put(ext_fwnode); From f63175733f91da6b668018c1c31786ec448adaed Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Wed, 17 Apr 2024 10:57:06 +0530 Subject: [PATCH 50/89] spi: dt-bindings: armada-3700: convert to dtschema Convert txt binding of marvell armada 3700 SoC spi controller to dtschema to allow for validation. Signed-off-by: Kousik Sanagavarapu Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240417052729.6612-1-five231003@gmail.com Signed-off-by: Mark Brown --- .../bindings/spi/marvell,armada-3700-spi.yaml | 55 +++++++++++++++++++ .../bindings/spi/spi-armada-3700.txt | 25 --------- 2 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/marvell,armada-3700-spi.yaml delete mode 100644 Documentation/devicetree/bindings/spi/spi-armada-3700.txt diff --git a/Documentation/devicetree/bindings/spi/marvell,armada-3700-spi.yaml b/Documentation/devicetree/bindings/spi/marvell,armada-3700-spi.yaml new file mode 100644 index 000000000000..61caa1d86188 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/marvell,armada-3700-spi.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/marvell,armada-3700-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Armada 3700 SPI Controller + +description: + The SPI controller on Marvell Armada 3700 SoC. + +maintainers: + - Kousik Sanagavarapu + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + const: marvell,armada-3700-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + num-cs: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + + spi0: spi@10600 { + compatible = "marvell,armada-3700-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10600 0x5d>; + clocks = <&nb_perih_clk 7>; + interrupts = ; + num-cs = <4>; + }; +... diff --git a/Documentation/devicetree/bindings/spi/spi-armada-3700.txt b/Documentation/devicetree/bindings/spi/spi-armada-3700.txt deleted file mode 100644 index 1564aa8c02cd..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-armada-3700.txt +++ /dev/null @@ -1,25 +0,0 @@ -* Marvell Armada 3700 SPI Controller - -Required Properties: - -- compatible: should be "marvell,armada-3700-spi" -- reg: physical base address of the controller and length of memory mapped - region. -- interrupts: The interrupt number. The interrupt specifier format depends on - the interrupt controller and of its driver. -- clocks: Must contain the clock source, usually from the North Bridge clocks. -- num-cs: The number of chip selects that is supported by this SPI Controller -- #address-cells: should be 1. -- #size-cells: should be 0. - -Example: - - spi0: spi@10600 { - compatible = "marvell,armada-3700-spi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x10600 0x5d>; - clocks = <&nb_perih_clk 7>; - interrupts = ; - num-cs = <4>; - }; From 856d9e8e9d42759b7fe6c6e13a2d6ff325b65f91 Mon Sep 17 00:00:00 2001 From: Heikki Keranen Date: Mon, 22 Apr 2024 14:41:50 +0300 Subject: [PATCH 51/89] spi: mux: Fix master controller settings after mux select In some cases SPI child devices behind spi-mux require different settings like: max_speed_hz, mode and bits_per_word. Typically the slave device driver puts the settings in place and calls spi_setup() once during probe and assumes they stay in place for all following spi transfers. However spi-mux forwarded spi_setup() -call to SPI master driver only when slave driver calls spi_setup(). If second slave device was accessed meanwhile and that driver called spi_setup(), the settings did not change back to the first spi device. In case of wrong max_speed_hz this caused spi trasfers to fail. This commit adds spi_setup() call after mux is changed. This way the right device specific parameters are set to the master driver. The fix has been tested by using custom hardware and debugging spi master driver speed settings. Co-authored-by: Petri Tauriainen Signed-off-by: Heikki Keranen Link: https://lore.kernel.org/r/20240422114150.84426-1-heikki.keranen@bittium.com Signed-off-by: Mark Brown --- drivers/spi/spi-mux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c index bd988f53753e..5d72e3d59df8 100644 --- a/drivers/spi/spi-mux.c +++ b/drivers/spi/spi-mux.c @@ -68,6 +68,8 @@ static int spi_mux_select(struct spi_device *spi) priv->current_cs = spi_get_chipselect(spi, 0); + spi_setup(priv->spi); + return 0; } From abba116f601800a0c74b9a9c2c91e2eebca791c1 Mon Sep 17 00:00:00 2001 From: Shivani Gupta Date: Thu, 18 Apr 2024 00:05:05 +0000 Subject: [PATCH 52/89] spi: spi-s3c64xx.c: Remove of_node_put for auto cleanup Use the scope based of_node_put() cleanup in s3c64xx_spi_csinfo to automatically release the device node with the __free() cleanup handler Initialize data_np at the point of declaration for clarity of scope. This change reduces the risk of memory leaks and simplifies the code by removing manual node put call. Suggested-by: Julia Lawall Signed-off-by: Shivani Gupta Link: https://lore.kernel.org/r/20240418000505.731724-1-shivani07g@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index f726d8670428..833c58c88e40 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -950,7 +950,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata( struct spi_device *spi) { struct s3c64xx_spi_csinfo *cs; - struct device_node *target_np, *data_np = NULL; + struct device_node *target_np; u32 fb_delay = 0; target_np = spi->dev.of_node; @@ -963,7 +963,8 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata( if (!cs) return ERR_PTR(-ENOMEM); - data_np = of_get_child_by_name(target_np, "controller-data"); + struct device_node *data_np __free(device_node) = + of_get_child_by_name(target_np, "controller-data"); if (!data_np) { dev_info(&spi->dev, "feedback delay set to default (0)\n"); return cs; @@ -971,7 +972,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata( of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); cs->fb_delay = fb_delay; - of_node_put(data_np); return cs; } From 3bf64a2b66edffd28614b004648ccd60e3139c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Tue, 23 Apr 2024 12:01:40 +0200 Subject: [PATCH 53/89] spi: cadence-qspi: allow FIFO depth detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If FIFO depth DT property is provided, check it matches what hardware reports and warn otherwise. Else, use hardware provided value. Hardware exposes FIFO depth indirectly because CQSPI_REG_SRAMPARTITION is partially read-only. Move probe cqspi->ddata assignment prior to cqspi_of_get_pdata() call. Signed-off-by: Théo Lebrun Link: https://lore.kernel.org/r/20240423-cdns-qspi-mbly-v4-1-3d2a7b535ad0@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 37 +++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 9896e9fe7ffb..5a83940220a9 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1510,8 +1510,8 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi) cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs"); if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { - dev_err(dev, "couldn't determine fifo-depth\n"); - return -ENXIO; + /* Zero signals FIFO depth should be runtime detected. */ + cqspi->fifo_depth = 0; } if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) { @@ -1541,8 +1541,6 @@ static void cqspi_controller_init(struct cqspi_st *cqspi) { u32 reg; - cqspi_controller_enable(cqspi, 0); - /* Configure the remap address register, no remap */ writel(0, cqspi->iobase + CQSPI_REG_REMAP); @@ -1576,8 +1574,29 @@ static void cqspi_controller_init(struct cqspi_st *cqspi) reg |= CQSPI_REG_CONFIG_DMA_MASK; writel(reg, cqspi->iobase + CQSPI_REG_CONFIG); } +} - cqspi_controller_enable(cqspi, 1); +static void cqspi_controller_detect_fifo_depth(struct cqspi_st *cqspi) +{ + struct device *dev = &cqspi->pdev->dev; + u32 reg, fifo_depth; + + /* + * Bits N-1:0 are writable while bits 31:N are read as zero, with 2^N + * the FIFO depth. + */ + writel(U32_MAX, cqspi->iobase + CQSPI_REG_SRAMPARTITION); + reg = readl(cqspi->iobase + CQSPI_REG_SRAMPARTITION); + fifo_depth = reg + 1; + + /* FIFO depth of zero means no value from devicetree was provided. */ + if (cqspi->fifo_depth == 0) { + cqspi->fifo_depth = fifo_depth; + dev_dbg(dev, "using FIFO depth of %u\n", fifo_depth); + } else if (fifo_depth != cqspi->fifo_depth) { + dev_warn(dev, "detected FIFO depth (%u) different from config (%u)\n", + fifo_depth, cqspi->fifo_depth); + } } static int cqspi_request_mmap_dma(struct cqspi_st *cqspi) @@ -1730,6 +1749,7 @@ static int cqspi_probe(struct platform_device *pdev) cqspi->pdev = pdev; cqspi->host = host; cqspi->is_jh7110 = false; + cqspi->ddata = ddata = of_device_get_match_data(dev); platform_set_drvdata(pdev, cqspi); /* Obtain configuration from OF. */ @@ -1821,8 +1841,6 @@ static int cqspi_probe(struct platform_device *pdev) /* write completion is supported by default */ cqspi->wr_completion = true; - ddata = of_device_get_match_data(dev); - cqspi->ddata = ddata; if (ddata) { if (ddata->quirks & CQSPI_NEEDS_WR_DELAY) cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, @@ -1864,7 +1882,10 @@ static int cqspi_probe(struct platform_device *pdev) } cqspi_wait_idle(cqspi); + cqspi_controller_enable(cqspi, 0); + cqspi_controller_detect_fifo_depth(cqspi); cqspi_controller_init(cqspi); + cqspi_controller_enable(cqspi, 1); cqspi->current_cs = -1; cqspi->sclk = 0; @@ -1947,7 +1968,9 @@ static int cqspi_runtime_resume(struct device *dev) clk_prepare_enable(cqspi->clk); cqspi_wait_idle(cqspi); + cqspi_controller_enable(cqspi, 0); cqspi_controller_init(cqspi); + cqspi_controller_enable(cqspi, 1); cqspi->current_cs = -1; cqspi->sclk = 0; From 1f257b92e6330d576cc826fb8f0b74fe0e8209de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Tue, 23 Apr 2024 12:01:41 +0200 Subject: [PATCH 54/89] spi: cadence-qspi: add no-IRQ mode to indirect reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support reads through polling, without any IRQ. The main reason is performance; profiling shows that the first IRQ comes quickly on our specific hardware. Once this IRQ arrives, we poll until all data is retrieved. Avoid initial sleep to reduce IRQ count. Hide this behavior behind a quirk flag. This is confirmed through micro-benchmarks, but also end-to-end performance tests. Mobileye EyeQ5, octal flash, reading 235M on a UBIFS filesystem: - No optimizations, ~10.34s, ~22.7 MB/s, 199230 IRQs - CQSPI_SLOW_SRAM, ~10.34s, ~22.7 MB/s, 70284 IRQs - CQSPI_RD_NO_IRQ, ~9.37s, ~25.1 MB/s, 521 IRQs Signed-off-by: Théo Lebrun Link: https://lore.kernel.org/r/20240423-cdns-qspi-mbly-v4-2-3d2a7b535ad0@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 5a83940220a9..a82e23526a6f 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -42,6 +42,7 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_CS_CNT_MAX); #define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3) #define CQSPI_SLOW_SRAM BIT(4) #define CQSPI_NEEDS_APB_AHB_HAZARD_WAR BIT(5) +#define CQSPI_RD_NO_IRQ BIT(6) /* Capabilities */ #define CQSPI_SUPPORTS_OCTAL BIT(0) @@ -702,6 +703,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, const size_t n_rx) { struct cqspi_st *cqspi = f_pdata->cqspi; + bool use_irq = !(cqspi->ddata && cqspi->ddata->quirks & CQSPI_RD_NO_IRQ); struct device *dev = &cqspi->pdev->dev; void __iomem *reg_base = cqspi->iobase; void __iomem *ahb_base = cqspi->ahb_base; @@ -725,17 +727,20 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, * all the read interrupts disabled for max performance. */ - if (!cqspi->slow_sram) + if (use_irq && cqspi->slow_sram) + writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); + else if (use_irq) writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); else - writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); + writel(0, reg_base + CQSPI_REG_IRQMASK); reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTRD_START_MASK, reg_base + CQSPI_REG_INDIRECTRD); while (remaining > 0) { - if (!wait_for_completion_timeout(&cqspi->transfer_complete, + if (use_irq && + !wait_for_completion_timeout(&cqspi->transfer_complete, msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) ret = -ETIMEDOUT; @@ -777,7 +782,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, bytes_to_read = cqspi_get_rd_sram_level(cqspi); } - if (remaining > 0) { + if (use_irq && remaining > 0) { reinit_completion(&cqspi->transfer_complete); if (cqspi->slow_sram) writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); From c1887396373b8faecef61d352bd521ac66162706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Tue, 23 Apr 2024 12:01:42 +0200 Subject: [PATCH 55/89] spi: cadence-qspi: add early busywait to cqspi_wait_for_bit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call readl_relaxed_poll_timeout() with no sleep at the start of cqspi_wait_for_bit(). If its short timeout expires, a sleeping readl_relaxed_poll_timeout() call takes the relay. The reason is to avoid hrtimer interrupts on the system. All read operations are expected to take less than 100µs. Signed-off-by: Théo Lebrun Link: https://lore.kernel.org/r/20240423-cdns-qspi-mbly-v4-3-3d2a7b535ad0@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index a82e23526a6f..87c88ee708e4 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -120,6 +120,7 @@ struct cqspi_driver_platdata { /* Operation timeout value */ #define CQSPI_TIMEOUT_MS 500 #define CQSPI_READ_TIMEOUT_MS 10 +#define CQSPI_BUSYWAIT_TIMEOUT_US 500 /* Runtime_pm autosuspend delay */ #define CQSPI_AUTOSUSPEND_TIMEOUT 2000 @@ -298,13 +299,27 @@ struct cqspi_driver_platdata { #define CQSPI_REG_VERSAL_DMA_VAL 0x602 -static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr) +static int cqspi_wait_for_bit(const struct cqspi_driver_platdata *ddata, + void __iomem *reg, const u32 mask, bool clr, + bool busywait) { + u64 timeout_us = CQSPI_TIMEOUT_MS * USEC_PER_MSEC; u32 val; + if (busywait) { + int ret = readl_relaxed_poll_timeout(reg, val, + (((clr ? ~val : val) & mask) == mask), + 0, CQSPI_BUSYWAIT_TIMEOUT_US); + + if (ret != -ETIMEDOUT) + return ret; + + timeout_us -= CQSPI_BUSYWAIT_TIMEOUT_US; + } + return readl_relaxed_poll_timeout(reg, val, (((clr ? ~val : val) & mask) == mask), - 10, CQSPI_TIMEOUT_MS * 1000); + 10, timeout_us); } static bool cqspi_is_idle(struct cqspi_st *cqspi) @@ -434,8 +449,8 @@ static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg) writel(reg, reg_base + CQSPI_REG_CMDCTRL); /* Polling for completion. */ - ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL, - CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1); + ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_CMDCTRL, + CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1, true); if (ret) { dev_err(&cqspi->pdev->dev, "Flash command execution timed out.\n"); @@ -790,8 +805,8 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, } /* Check indirect done status */ - ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD, - CQSPI_REG_INDIRECTRD_DONE_MASK, 0); + ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_INDIRECTRD, + CQSPI_REG_INDIRECTRD_DONE_MASK, 0, true); if (ret) { dev_err(dev, "Indirect read completion error (%i)\n", ret); goto failrd; @@ -1091,8 +1106,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, } /* Check indirect done status */ - ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR, - CQSPI_REG_INDIRECTWR_DONE_MASK, 0); + ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_INDIRECTWR, + CQSPI_REG_INDIRECTWR_DONE_MASK, 0, false); if (ret) { dev_err(dev, "Indirect write completion error (%i)\n", ret); goto failwr; From 47766799f546249813e97a0ccde8978ba114e89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Tue, 23 Apr 2024 12:01:43 +0200 Subject: [PATCH 56/89] spi: cadence-qspi: add mobileye,eyeq5-ospi compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare a new mobileye,eyeq5-ospi compatible. Signed-off-by: Théo Lebrun Link: https://lore.kernel.org/r/20240423-cdns-qspi-mbly-v4-4-3d2a7b535ad0@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 87c88ee708e4..05ebb03d319f 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -2055,6 +2055,12 @@ static const struct cqspi_driver_platdata pensando_cdns_qspi = { .quirks = CQSPI_NEEDS_APB_AHB_HAZARD_WAR | CQSPI_DISABLE_DAC_MODE, }; +static const struct cqspi_driver_platdata mobileye_eyeq5_ospi = { + .hwcaps_mask = CQSPI_SUPPORTS_OCTAL, + .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION | + CQSPI_RD_NO_IRQ, +}; + static const struct of_device_id cqspi_dt_ids[] = { { .compatible = "cdns,qspi-nor", @@ -2088,6 +2094,10 @@ static const struct of_device_id cqspi_dt_ids[] = { .compatible = "amd,pensando-elba-qspi", .data = &pensando_cdns_qspi, }, + { + .compatible = "mobileye,eyeq5-ospi", + .data = &mobileye_eyeq5_ospi, + }, { /* end of table */ } }; From a403997c12019d0f82a9480207bf85985b8de5e7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 29 Apr 2024 10:13:10 +0200 Subject: [PATCH 57/89] spi: airoha: add SPI-NAND Flash controller driver Introduce support for SPI-NAND driver of the Airoha NAND Flash Interface found on Airoha ARM SoCs. Tested-by: Rajeev Kumar Signed-off-by: Lorenzo Bianconi Reviewed-by: Andy Shevchenko Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/6c9db20505b01a66807995374f2af475a23ce5b2.1714377864.git.lorenzo@kernel.org Signed-off-by: Mark Brown --- MAINTAINERS | 9 + drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/spi-airoha-snfi.c | 1129 +++++++++++++++++++++++++++++++++ 4 files changed, 1149 insertions(+) create mode 100644 drivers/spi/spi-airoha-snfi.c diff --git a/MAINTAINERS b/MAINTAINERS index 2b63ed114532..dde7dd956156 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -653,6 +653,15 @@ S: Supported F: fs/aio.c F: include/linux/*aio*.h +AIROHA SPI SNFI DRIVER +M: Lorenzo Bianconi +M: Ray Liu +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-spi@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml +F: drivers/spi/spi-airoha.c + AIRSPY MEDIA DRIVER L: linux-media@vger.kernel.org S: Orphan diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 17325e0b7bd5..86f6115f417c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -57,6 +57,16 @@ config SPI_MEM comment "SPI Master Controller Drivers" +config SPI_AIROHA_SNFI + tristate "Airoha SPI NAND Flash Interface" + depends on ARCH_AIROHA || COMPILE_TEST + depends on SPI_MASTER + select REGMAP_MMIO + help + This enables support for SPI-NAND mode on the Airoha NAND + Flash Interface found on Airoha ARM SoCs. This controller + is implemented as a SPI-MEM controller. + config SPI_ALTERA tristate "Altera SPI Controller platform driver" select SPI_ALTERA_CORE diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 4ff8d725ba5e..e694254dec04 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_SPIDEV) += spidev.o obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o # SPI master controller drivers (bus) +obj-$(CONFIG_SPI_AIROHA_SNFI) += spi-airoha-snfi.o obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c new file mode 100644 index 000000000000..9d97ec98881c --- /dev/null +++ b/drivers/spi/spi-airoha-snfi.c @@ -0,0 +1,1129 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 AIROHA Inc + * Author: Lorenzo Bianconi + * Author: Ray Liu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SPI */ +#define REG_SPI_CTRL_BASE 0x1FA10000 + +#define REG_SPI_CTRL_READ_MODE 0x0000 +#define REG_SPI_CTRL_READ_IDLE_EN 0x0004 +#define REG_SPI_CTRL_SIDLY 0x0008 +#define REG_SPI_CTRL_CSHEXT 0x000c +#define REG_SPI_CTRL_CSLEXT 0x0010 + +#define REG_SPI_CTRL_MTX_MODE_TOG 0x0014 +#define SPI_CTRL_MTX_MODE_TOG GENMASK(3, 0) + +#define REG_SPI_CTRL_RDCTL_FSM 0x0018 +#define SPI_CTRL_RDCTL_FSM GENMASK(3, 0) + +#define REG_SPI_CTRL_MACMUX_SEL 0x001c + +#define REG_SPI_CTRL_MANUAL_EN 0x0020 +#define SPI_CTRL_MANUAL_EN BIT(0) + +#define REG_SPI_CTRL_OPFIFO_EMPTY 0x0024 +#define SPI_CTRL_OPFIFO_EMPTY BIT(0) + +#define REG_SPI_CTRL_OPFIFO_WDATA 0x0028 +#define SPI_CTRL_OPFIFO_LEN GENMASK(8, 0) +#define SPI_CTRL_OPFIFO_OP GENMASK(13, 9) + +#define REG_SPI_CTRL_OPFIFO_FULL 0x002c +#define SPI_CTRL_OPFIFO_FULL BIT(0) + +#define REG_SPI_CTRL_OPFIFO_WR 0x0030 +#define SPI_CTRL_OPFIFO_WR BIT(0) + +#define REG_SPI_CTRL_DFIFO_FULL 0x0034 +#define SPI_CTRL_DFIFO_FULL BIT(0) + +#define REG_SPI_CTRL_DFIFO_WDATA 0x0038 +#define SPI_CTRL_DFIFO_WDATA GENMASK(7, 0) + +#define REG_SPI_CTRL_DFIFO_EMPTY 0x003c +#define SPI_CTRL_DFIFO_EMPTY BIT(0) + +#define REG_SPI_CTRL_DFIFO_RD 0x0040 +#define SPI_CTRL_DFIFO_RD BIT(0) + +#define REG_SPI_CTRL_DFIFO_RDATA 0x0044 +#define SPI_CTRL_DFIFO_RDATA GENMASK(7, 0) + +#define REG_SPI_CTRL_DUMMY 0x0080 +#define SPI_CTRL_CTRL_DUMMY GENMASK(3, 0) + +#define REG_SPI_CTRL_PROBE_SEL 0x0088 +#define REG_SPI_CTRL_INTERRUPT 0x0090 +#define REG_SPI_CTRL_INTERRUPT_EN 0x0094 +#define REG_SPI_CTRL_SI_CK_SEL 0x009c +#define REG_SPI_CTRL_SW_CFGNANDADDR_VAL 0x010c +#define REG_SPI_CTRL_SW_CFGNANDADDR_EN 0x0110 +#define REG_SPI_CTRL_SFC_STRAP 0x0114 + +#define REG_SPI_CTRL_NFI2SPI_EN 0x0130 +#define SPI_CTRL_NFI2SPI_EN BIT(0) + +/* NFI2SPI */ +#define REG_SPI_NFI_CNFG 0x0000 +#define SPI_NFI_DMA_MODE BIT(0) +#define SPI_NFI_READ_MODE BIT(1) +#define SPI_NFI_DMA_BURST_EN BIT(2) +#define SPI_NFI_HW_ECC_EN BIT(8) +#define SPI_NFI_AUTO_FDM_EN BIT(9) +#define SPI_NFI_OPMODE GENMASK(14, 12) + +#define REG_SPI_NFI_PAGEFMT 0x0004 +#define SPI_NFI_PAGE_SIZE GENMASK(1, 0) +#define SPI_NFI_SPARE_SIZE GENMASK(5, 4) + +#define REG_SPI_NFI_CON 0x0008 +#define SPI_NFI_FIFO_FLUSH BIT(0) +#define SPI_NFI_RST BIT(1) +#define SPI_NFI_RD_TRIG BIT(8) +#define SPI_NFI_WR_TRIG BIT(9) +#define SPI_NFI_SEC_NUM GENMASK(15, 12) + +#define REG_SPI_NFI_INTR_EN 0x0010 +#define SPI_NFI_RD_DONE_EN BIT(0) +#define SPI_NFI_WR_DONE_EN BIT(1) +#define SPI_NFI_RST_DONE_EN BIT(2) +#define SPI_NFI_ERASE_DONE_EN BIT(3) +#define SPI_NFI_BUSY_RETURN_EN BIT(4) +#define SPI_NFI_ACCESS_LOCK_EN BIT(5) +#define SPI_NFI_AHB_DONE_EN BIT(6) +#define SPI_NFI_ALL_IRQ_EN \ + (SPI_NFI_RD_DONE_EN | SPI_NFI_WR_DONE_EN | \ + SPI_NFI_RST_DONE_EN | SPI_NFI_ERASE_DONE_EN | \ + SPI_NFI_BUSY_RETURN_EN | SPI_NFI_ACCESS_LOCK_EN | \ + SPI_NFI_AHB_DONE_EN) + +#define REG_SPI_NFI_INTR 0x0014 +#define SPI_NFI_AHB_DONE BIT(6) + +#define REG_SPI_NFI_CMD 0x0020 + +#define REG_SPI_NFI_ADDR_NOB 0x0030 +#define SPI_NFI_ROW_ADDR_NOB GENMASK(6, 4) + +#define REG_SPI_NFI_STA 0x0060 +#define REG_SPI_NFI_FIFOSTA 0x0064 +#define REG_SPI_NFI_STRADDR 0x0080 +#define REG_SPI_NFI_FDM0L 0x00a0 +#define REG_SPI_NFI_FDM0M 0x00a4 +#define REG_SPI_NFI_FDM7L 0x00d8 +#define REG_SPI_NFI_FDM7M 0x00dc +#define REG_SPI_NFI_FIFODATA0 0x0190 +#define REG_SPI_NFI_FIFODATA1 0x0194 +#define REG_SPI_NFI_FIFODATA2 0x0198 +#define REG_SPI_NFI_FIFODATA3 0x019c +#define REG_SPI_NFI_MASTERSTA 0x0224 + +#define REG_SPI_NFI_SECCUS_SIZE 0x022c +#define SPI_NFI_CUS_SEC_SIZE GENMASK(12, 0) +#define SPI_NFI_CUS_SEC_SIZE_EN BIT(16) + +#define REG_SPI_NFI_RD_CTL2 0x0510 +#define REG_SPI_NFI_RD_CTL3 0x0514 + +#define REG_SPI_NFI_PG_CTL1 0x0524 +#define SPI_NFI_PG_LOAD_CMD GENMASK(15, 8) + +#define REG_SPI_NFI_PG_CTL2 0x0528 +#define REG_SPI_NFI_NOR_PROG_ADDR 0x052c +#define REG_SPI_NFI_NOR_RD_ADDR 0x0534 + +#define REG_SPI_NFI_SNF_MISC_CTL 0x0538 +#define SPI_NFI_DATA_READ_WR_MODE GENMASK(18, 16) + +#define REG_SPI_NFI_SNF_MISC_CTL2 0x053c +#define SPI_NFI_READ_DATA_BYTE_NUM GENMASK(12, 0) +#define SPI_NFI_PROG_LOAD_BYTE_NUM GENMASK(28, 16) + +#define REG_SPI_NFI_SNF_STA_CTL1 0x0550 +#define SPI_NFI_READ_FROM_CACHE_DONE BIT(25) +#define SPI_NFI_LOAD_TO_CACHE_DONE BIT(26) + +#define REG_SPI_NFI_SNF_STA_CTL2 0x0554 + +#define REG_SPI_NFI_SNF_NFI_CNFG 0x055c +#define SPI_NFI_SPI_MODE BIT(0) + +/* SPI NAND Protocol OP */ +#define SPI_NAND_OP_GET_FEATURE 0x0f +#define SPI_NAND_OP_SET_FEATURE 0x1f +#define SPI_NAND_OP_PAGE_READ 0x13 +#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03 +#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b +#define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b +#define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b +#define SPI_NAND_OP_WRITE_ENABLE 0x06 +#define SPI_NAND_OP_WRITE_DISABLE 0x04 +#define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02 +#define SPI_NAND_OP_PROGRAM_LOAD_QUAD 0x32 +#define SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE 0x84 +#define SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD 0x34 +#define SPI_NAND_OP_PROGRAM_EXECUTE 0x10 +#define SPI_NAND_OP_READ_ID 0x9f +#define SPI_NAND_OP_BLOCK_ERASE 0xd8 +#define SPI_NAND_OP_RESET 0xff +#define SPI_NAND_OP_DIE_SELECT 0xc2 + +#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256) +#define SPI_MAX_TRANSFER_SIZE 511 + +enum airoha_snand_mode { + SPI_MODE_AUTO, + SPI_MODE_MANUAL, + SPI_MODE_DMA, +}; + +enum airoha_snand_cs { + SPI_CHIP_SEL_HIGH, + SPI_CHIP_SEL_LOW, +}; + +struct airoha_snand_dev { + size_t buf_len; + + u8 *txrx_buf; + dma_addr_t dma_addr; + + u64 cur_page_num; + bool data_need_update; +}; + +struct airoha_snand_ctrl { + struct device *dev; + struct regmap *regmap_ctrl; + struct regmap *regmap_nfi; + struct clk *spi_clk; + + struct { + size_t page_size; + size_t sec_size; + u8 sec_num; + u8 spare_size; + } nfi_cfg; +}; + +static int airoha_snand_set_fifo_op(struct airoha_snand_ctrl *as_ctrl, + u8 op_cmd, int op_len) +{ + int err; + u32 val; + + err = regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_OPFIFO_WDATA, + FIELD_PREP(SPI_CTRL_OPFIFO_LEN, op_len) | + FIELD_PREP(SPI_CTRL_OPFIFO_OP, op_cmd)); + if (err) + return err; + + err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_OPFIFO_FULL, + val, !(val & SPI_CTRL_OPFIFO_FULL), + 0, 250 * USEC_PER_MSEC); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_OPFIFO_WR, + SPI_CTRL_OPFIFO_WR); + if (err) + return err; + + return regmap_read_poll_timeout(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_OPFIFO_EMPTY, + val, (val & SPI_CTRL_OPFIFO_EMPTY), + 0, 250 * USEC_PER_MSEC); +} + +static int airoha_snand_set_cs(struct airoha_snand_ctrl *as_ctrl, u8 cs) +{ + return airoha_snand_set_fifo_op(as_ctrl, cs, sizeof(cs)); +} + +static int airoha_snand_write_data_to_fifo(struct airoha_snand_ctrl *as_ctrl, + const u8 *data, int len) +{ + int i; + + for (i = 0; i < len; i++) { + int err; + u32 val; + + /* 1. Wait until dfifo is not full */ + err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_DFIFO_FULL, val, + !(val & SPI_CTRL_DFIFO_FULL), + 0, 250 * USEC_PER_MSEC); + if (err) + return err; + + /* 2. Write data to register DFIFO_WDATA */ + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_DFIFO_WDATA, + FIELD_PREP(SPI_CTRL_DFIFO_WDATA, data[i])); + if (err) + return err; + + /* 3. Wait until dfifo is not full */ + err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_DFIFO_FULL, val, + !(val & SPI_CTRL_DFIFO_FULL), + 0, 250 * USEC_PER_MSEC); + if (err) + return err; + } + + return 0; +} + +static int airoha_snand_read_data_from_fifo(struct airoha_snand_ctrl *as_ctrl, + u8 *ptr, int len) +{ + int i; + + for (i = 0; i < len; i++) { + int err; + u32 val; + + /* 1. wait until dfifo is not empty */ + err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_DFIFO_EMPTY, val, + !(val & SPI_CTRL_DFIFO_EMPTY), + 0, 250 * USEC_PER_MSEC); + if (err) + return err; + + /* 2. read from dfifo to register DFIFO_RDATA */ + err = regmap_read(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_DFIFO_RDATA, &val); + if (err) + return err; + + ptr[i] = FIELD_GET(SPI_CTRL_DFIFO_RDATA, val); + /* 3. enable register DFIFO_RD to read next byte */ + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_DFIFO_RD, SPI_CTRL_DFIFO_RD); + if (err) + return err; + } + + return 0; +} + +static int airoha_snand_set_mode(struct airoha_snand_ctrl *as_ctrl, + enum airoha_snand_mode mode) +{ + int err; + + switch (mode) { + case SPI_MODE_MANUAL: { + u32 val; + + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_NFI2SPI_EN, 0); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_READ_IDLE_EN, 0); + if (err) + return err; + + err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_RDCTL_FSM, val, + !(val & SPI_CTRL_RDCTL_FSM), + 0, 250 * USEC_PER_MSEC); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_MTX_MODE_TOG, 9); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_MANUAL_EN, SPI_CTRL_MANUAL_EN); + if (err) + return err; + break; + } + case SPI_MODE_DMA: + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_NFI2SPI_EN, + SPI_CTRL_MANUAL_EN); + if (err < 0) + return err; + + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_MTX_MODE_TOG, 0x0); + if (err < 0) + return err; + + err = regmap_write(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_MANUAL_EN, 0x0); + if (err < 0) + return err; + break; + case SPI_MODE_AUTO: + default: + break; + } + + return regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0); +} + +static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd, + const u8 *data, int len) +{ + int i, data_len; + + for (i = 0; i < len; i += data_len) { + int err; + + data_len = min(len, SPI_MAX_TRANSFER_SIZE); + err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len); + if (err) + return err; + + err = airoha_snand_write_data_to_fifo(as_ctrl, &data[i], + data_len); + if (err < 0) + return err; + } + + return 0; +} + +static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl, u8 *data, + int len) +{ + int i, data_len; + + for (i = 0; i < len; i += data_len) { + int err; + + data_len = min(len, SPI_MAX_TRANSFER_SIZE); + err = airoha_snand_set_fifo_op(as_ctrl, 0xc, data_len); + if (err) + return err; + + err = airoha_snand_read_data_from_fifo(as_ctrl, &data[i], + data_len); + if (err < 0) + return err; + } + + return 0; +} + +static int airoha_snand_nfi_init(struct airoha_snand_ctrl *as_ctrl) +{ + int err; + + /* switch to SNFI mode */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_NFI_CNFG, + SPI_NFI_SPI_MODE); + if (err) + return err; + + /* Enable DMA */ + return regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR_EN, + SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN); +} + +static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl) +{ + int err; + u32 val; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); + if (err) + return err; + + /* auto FDM */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_AUTO_FDM_EN); + if (err) + return err; + + /* HW ECC */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_HW_ECC_EN); + if (err) + return err; + + /* DMA Burst */ + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_BURST_EN); + if (err) + return err; + + /* page format */ + switch (as_ctrl->nfi_cfg.spare_size) { + case 26: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); + break; + case 27: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); + break; + case 28: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); + break; + default: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); + break; + } + + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, + SPI_NFI_SPARE_SIZE, val); + if (err) + return err; + + switch (as_ctrl->nfi_cfg.page_size) { + case 2048: + val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); + break; + case 4096: + val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); + break; + default: + val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); + break; + } + + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, + SPI_NFI_PAGE_SIZE, val); + if (err) + return err; + + /* sec num */ + val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, val); + if (err) + return err; + + /* enable cust sec size */ + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + return err; + + /* set cust sec size */ + val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, as_ctrl->nfi_cfg.sec_size); + return regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE, val); +} + +static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) +{ + if (op->addr.nbytes != 2) + return false; + + if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && + op->addr.buswidth != 4) + return false; + + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + if (op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth > 0xf) + return false; + + /* quad in / quad out */ + if (op->addr.buswidth == 4) + return op->data.buswidth == 4; + + if (op->addr.buswidth == 2) + return op->data.buswidth == 2; + + /* standard spi */ + return op->data.buswidth == 4 || op->data.buswidth == 2 || + op->data.buswidth == 1; + case SPI_MEM_DATA_OUT: + return !op->dummy.nbytes && op->addr.buswidth == 1 && + (op->data.buswidth == 4 || op->data.buswidth == 1); + default: + return false; + } +} + +static int airoha_snand_adjust_op_size(struct spi_mem *mem, + struct spi_mem_op *op) +{ + size_t max_len; + + if (airoha_snand_is_page_ops(op)) { + struct airoha_snand_ctrl *as_ctrl; + + as_ctrl = spi_controller_get_devdata(mem->spi->controller); + max_len = as_ctrl->nfi_cfg.sec_size; + max_len += as_ctrl->nfi_cfg.spare_size; + max_len *= as_ctrl->nfi_cfg.sec_num; + + if (op->data.nbytes > max_len) + op->data.nbytes = max_len; + } else { + max_len = 1 + op->addr.nbytes + op->dummy.nbytes; + if (max_len >= 160) + return -EOPNOTSUPP; + + if (op->data.nbytes > 160 - max_len) + op->data.nbytes = 160 - max_len; + } + + return 0; +} + +static bool airoha_snand_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(mem, op)) + return false; + + if (op->cmd.buswidth != 1) + return false; + + if (airoha_snand_is_page_ops(op)) + return true; + + return (!op->addr.nbytes || op->addr.buswidth == 1) && + (!op->dummy.nbytes || op->dummy.buswidth == 1) && + (!op->data.nbytes || op->data.buswidth == 1); +} + +static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct airoha_snand_dev *as_dev = spi_get_ctldata(desc->mem->spi); + + if (!as_dev->txrx_buf) + return -EINVAL; + + if (desc->info.offset + desc->info.length > U32_MAX) + return -EINVAL; + + if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl)) + return -EOPNOTSUPP; + + return 0; +} + +static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) +{ + struct spi_device *spi = desc->mem->spi; + struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); + struct spi_mem_op *op = &desc->info.op_tmpl; + struct airoha_snand_ctrl *as_ctrl; + u32 val, rd_mode; + int err; + + if (!as_dev->data_need_update) + return len; + + as_dev->data_need_update = false; + + switch (op->cmd.opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + rd_mode = 1; + break; + case SPI_NAND_OP_READ_FROM_CACHE_QUAD: + rd_mode = 2; + break; + default: + rd_mode = 0; + break; + } + + as_ctrl = spi_controller_get_devdata(spi->controller); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) + return err; + + err = airoha_snand_nfi_config(as_ctrl); + if (err) + return err; + + dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr, + as_dev->buf_len, DMA_BIDIRECTIONAL); + + /* set dma addr */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, + as_dev->dma_addr); + if (err) + return err; + + /* set cust sec size */ + val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; + val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_READ_DATA_BYTE_NUM, val); + if (err) + return err; + + /* set read command */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, + op->cmd.opcode); + if (err) + return err; + + /* set read mode */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode)); + if (err) + return err; + + /* set read addr */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0); + if (err) + return err; + + /* set nfi read */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_OPMODE, + FIELD_PREP(SPI_NFI_OPMODE, 6)); + if (err) + return err; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0); + if (err) + return err; + + /* trigger dma start read */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) + return err; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) + return err; + + err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_STA_CTL1, val, + (val & SPI_NFI_READ_FROM_CACHE_DONE), + 0, 1 * USEC_PER_SEC); + if (err) + return err; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, + SPI_NFI_READ_FROM_CACHE_DONE); + if (err) + return err; + + err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR, + val, (val & SPI_NFI_AHB_DONE), 0, + 1 * USEC_PER_SEC); + if (err) + return err; + + /* DMA read need delay for data ready from controller to DRAM */ + udelay(1); + + dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr, + as_dev->buf_len, DMA_BIDIRECTIONAL); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + if (err < 0) + return err; + + memcpy(buf, as_dev->txrx_buf + offs, len); + + return len; +} + +static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf) +{ + struct spi_device *spi = desc->mem->spi; + struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); + struct spi_mem_op *op = &desc->info.op_tmpl; + struct airoha_snand_ctrl *as_ctrl; + u32 wr_mode, val; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + if (err < 0) + return err; + + dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr, + as_dev->buf_len, DMA_BIDIRECTIONAL); + memcpy(as_dev->txrx_buf + offs, buf, len); + dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr, + as_dev->buf_len, DMA_BIDIRECTIONAL); + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) + return err; + + err = airoha_snand_nfi_config(as_ctrl); + if (err) + return err; + + if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || + op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) + wr_mode = BIT(1); + else + wr_mode = 0; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, + as_dev->dma_addr); + if (err) + return err; + + val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, + as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_PROG_LOAD_BYTE_NUM, val); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, + FIELD_PREP(SPI_NFI_PG_LOAD_CMD, + op->cmd.opcode)); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0); + if (err) + return err; + + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_READ_MODE); + if (err) + return err; + + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_OPMODE, + FIELD_PREP(SPI_NFI_OPMODE, 3)); + if (err) + return err; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE); + if (err) + return err; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80); + if (err) + return err; + + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) + return err; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) + return err; + + err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR, + val, (val & SPI_NFI_AHB_DONE), 0, + 1 * USEC_PER_SEC); + if (err) + return err; + + err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_STA_CTL1, val, + (val & SPI_NFI_LOAD_TO_CACHE_DONE), + 0, 1 * USEC_PER_SEC); + if (err) + return err; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, + SPI_NFI_LOAD_TO_CACHE_DONE); + if (err) + return err; + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + if (err < 0) + return err; + + return len; +} + +static int airoha_snand_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct airoha_snand_dev *as_dev = spi_get_ctldata(mem->spi); + u8 data[8], cmd, opcode = op->cmd.opcode; + struct airoha_snand_ctrl *as_ctrl; + int i, err; + + as_ctrl = spi_controller_get_devdata(mem->spi->controller); + if (opcode == SPI_NAND_OP_PROGRAM_EXECUTE && + op->addr.val == as_dev->cur_page_num) { + as_dev->data_need_update = true; + } else if (opcode == SPI_NAND_OP_PAGE_READ) { + if (!as_dev->data_need_update && + op->addr.val == as_dev->cur_page_num) + return 0; + + as_dev->data_need_update = true; + as_dev->cur_page_num = op->addr.val; + } + + /* switch to manual mode */ + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + if (err < 0) + return err; + + err = airoha_snand_set_cs(as_ctrl, SPI_CHIP_SEL_LOW); + if (err < 0) + return err; + + /* opcode */ + err = airoha_snand_write_data(as_ctrl, 0x8, &opcode, sizeof(opcode)); + if (err) + return err; + + /* addr part */ + cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8; + put_unaligned_be64(op->addr.val, data); + + for (i = ARRAY_SIZE(data) - op->addr.nbytes; + i < ARRAY_SIZE(data); i++) { + err = airoha_snand_write_data(as_ctrl, cmd, &data[i], + sizeof(data[0])); + if (err) + return err; + } + + /* dummy */ + data[0] = 0xff; + for (i = 0; i < op->dummy.nbytes; i++) { + err = airoha_snand_write_data(as_ctrl, 0x8, &data[0], + sizeof(data[0])); + if (err) + return err; + } + + /* data */ + if (op->data.dir == SPI_MEM_DATA_IN) { + err = airoha_snand_read_data(as_ctrl, op->data.buf.in, + op->data.nbytes); + if (err) + return err; + } else { + err = airoha_snand_write_data(as_ctrl, 0x8, op->data.buf.out, + op->data.nbytes); + if (err) + return err; + } + + return airoha_snand_set_cs(as_ctrl, SPI_CHIP_SEL_HIGH); +} + +static const struct spi_controller_mem_ops airoha_snand_mem_ops = { + .adjust_op_size = airoha_snand_adjust_op_size, + .supports_op = airoha_snand_supports_op, + .exec_op = airoha_snand_exec_op, + .dirmap_create = airoha_snand_dirmap_create, + .dirmap_read = airoha_snand_dirmap_read, + .dirmap_write = airoha_snand_dirmap_write, +}; + +static int airoha_snand_setup(struct spi_device *spi) +{ + struct airoha_snand_ctrl *as_ctrl; + struct airoha_snand_dev *as_dev; + + as_ctrl = spi_controller_get_devdata(spi->controller); + + as_dev = devm_kzalloc(as_ctrl->dev, sizeof(*as_dev), GFP_KERNEL); + if (!as_dev) + return -ENOMEM; + + /* prepare device buffer */ + as_dev->buf_len = SPI_NAND_CACHE_SIZE; + as_dev->txrx_buf = devm_kzalloc(as_ctrl->dev, as_dev->buf_len, + GFP_KERNEL); + if (!as_dev->txrx_buf) + return -ENOMEM; + + as_dev->dma_addr = dma_map_single(as_ctrl->dev, as_dev->txrx_buf, + as_dev->buf_len, DMA_BIDIRECTIONAL); + if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr)) + return -ENOMEM; + + as_dev->data_need_update = true; + spi_set_ctldata(spi, as_dev); + + return 0; +} + +static void airoha_snand_cleanup(struct spi_device *spi) +{ + struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); + struct airoha_snand_ctrl *as_ctrl; + + as_ctrl = spi_controller_get_devdata(spi->controller); + dma_unmap_single(as_ctrl->dev, as_dev->dma_addr, + as_dev->buf_len, DMA_BIDIRECTIONAL); + spi_set_ctldata(spi, NULL); +} + +static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) +{ + u32 val, sec_size, sec_num; + int err; + + err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, &val); + if (err) + return err; + + sec_num = FIELD_GET(SPI_NFI_SEC_NUM, val); + + err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, &val); + if (err) + return err; + + sec_size = FIELD_GET(SPI_NFI_CUS_SEC_SIZE, val); + + /* init default value */ + as_ctrl->nfi_cfg.sec_size = sec_size; + as_ctrl->nfi_cfg.sec_num = sec_num; + as_ctrl->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); + as_ctrl->nfi_cfg.spare_size = 16; + + err = airoha_snand_nfi_init(as_ctrl); + if (err) + return err; + + return airoha_snand_nfi_config(as_ctrl); +} + +static const struct regmap_config spi_ctrl_regmap_config = { + .name = "ctrl", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = REG_SPI_CTRL_NFI2SPI_EN, +}; + +static const struct regmap_config spi_nfi_regmap_config = { + .name = "nfi", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = REG_SPI_NFI_SNF_NFI_CNFG, +}; + +static const struct of_device_id airoha_snand_ids[] = { + { .compatible = "airoha,en7581-snand" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, airoha_snand_ids); + +static int airoha_snand_probe(struct platform_device *pdev) +{ + struct airoha_snand_ctrl *as_ctrl; + struct device *dev = &pdev->dev; + struct spi_controller *ctrl; + void __iomem *base; + int err; + + ctrl = devm_spi_alloc_host(dev, sizeof(*as_ctrl)); + if (!ctrl) + return -ENOMEM; + + as_ctrl = spi_controller_get_devdata(ctrl); + as_ctrl->dev = dev; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + as_ctrl->regmap_ctrl = devm_regmap_init_mmio(dev, base, + &spi_ctrl_regmap_config); + if (IS_ERR(as_ctrl->regmap_ctrl)) + return dev_err_probe(dev, PTR_ERR(as_ctrl->regmap_ctrl), + "failed to init spi ctrl regmap\n"); + + base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(base)) + return PTR_ERR(base); + + as_ctrl->regmap_nfi = devm_regmap_init_mmio(dev, base, + &spi_nfi_regmap_config); + if (IS_ERR(as_ctrl->regmap_nfi)) + return dev_err_probe(dev, PTR_ERR(as_ctrl->regmap_nfi), + "failed to init spi nfi regmap\n"); + + as_ctrl->spi_clk = devm_clk_get_enabled(dev, "spi"); + if (IS_ERR(as_ctrl->spi_clk)) + return dev_err_probe(dev, PTR_ERR(as_ctrl->spi_clk), + "unable to get spi clk\n"); + + err = dma_set_mask(as_ctrl->dev, DMA_BIT_MASK(32)); + if (err) + return err; + + ctrl->num_chipselect = 2; + ctrl->mem_ops = &airoha_snand_mem_ops; + ctrl->bits_per_word_mask = SPI_BPW_MASK(8); + ctrl->mode_bits = SPI_RX_DUAL; + ctrl->setup = airoha_snand_setup; + ctrl->cleanup = airoha_snand_cleanup; + device_set_node(&ctrl->dev, dev_fwnode(dev)); + + err = airoha_snand_nfi_setup(as_ctrl); + if (err) + return err; + + return devm_spi_register_controller(dev, ctrl); +} + +static struct platform_driver airoha_snand_driver = { + .driver = { + .name = "airoha-spi", + .of_match_table = airoha_snand_ids, + }, + .probe = airoha_snand_probe, +}; +module_platform_driver(airoha_snand_driver); + +MODULE_DESCRIPTION("Airoha SPI-NAND Flash Controller Driver"); +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_AUTHOR("Ray Liu "); +MODULE_LICENSE("GPL"); From 8bd0d557aa8394b75f6983b2334aaf1a633e1ce5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 29 Apr 2024 10:13:08 +0200 Subject: [PATCH 58/89] spi: dt-bindings: airoha: Add YAML schema for SNFI controller Introduce Airoha EN7581 SPI NAND controller binding Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Conor Dooley Tested-by: Rajeev Kumar Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/f3377b323f00589e6b7ed7950c4840d18129238b.1714377864.git.lorenzo@kernel.org Signed-off-by: Mark Brown --- .../bindings/spi/airoha,en7581-snand.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml diff --git a/Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml b/Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml new file mode 100644 index 000000000000..b820c5613dcc --- /dev/null +++ b/Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/airoha,en7581-snand.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SPI-NAND flash controller for Airoha ARM SoCs + +maintainers: + - Lorenzo Bianconi + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + const: airoha,en7581-snand + + reg: + items: + - description: spi base address + - description: nfi2spi base address + + clocks: + maxItems: 1 + + clock-names: + items: + - const: spi + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + spi@1fa10000 { + compatible = "airoha,en7581-snand"; + reg = <0x0 0x1fa10000 0x0 0x140>, + <0x0 0x1fa11000 0x0 0x160>; + + clocks = <&scuclk EN7523_CLK_SPI>; + clock-names = "spi"; + + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <2>; + }; + }; + }; From 7dbbbb1206dd0b695b9a76d3b758c8a689f1aa52 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:33 +0200 Subject: [PATCH 59/89] spi: armada-3700: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'unsigned long' while here. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240430114142.28551-2-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 3c9ed412932f..02c1e625742d 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -339,7 +339,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id) static bool a3700_spi_wait_completion(struct spi_device *spi) { struct a3700_spi *a3700_spi; - unsigned int timeout; + unsigned long time_left; unsigned int ctrl_reg; unsigned long timeout_jiffies; @@ -361,12 +361,12 @@ static bool a3700_spi_wait_completion(struct spi_device *spi) a3700_spi->wait_mask); timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT); - timeout = wait_for_completion_timeout(&a3700_spi->done, - timeout_jiffies); + time_left = wait_for_completion_timeout(&a3700_spi->done, + timeout_jiffies); a3700_spi->wait_mask = 0; - if (timeout) + if (time_left) return true; /* there might be the case that right after we checked the From eef51e99f7b9ecc903a3a9ad9e7ca84dc35c3f52 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:34 +0200 Subject: [PATCH 60/89] spi: fsl-lpspi: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240430114142.28551-3-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 92a662d1b55c..aa5ed254be46 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -553,7 +553,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, { struct dma_async_tx_descriptor *desc_tx, *desc_rx; unsigned long transfer_timeout; - unsigned long timeout; + unsigned long time_left; struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; int ret; @@ -594,9 +594,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, transfer->len); /* Wait eDMA to finish the data transfer.*/ - timeout = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion, - transfer_timeout); - if (!timeout) { + time_left = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion, + transfer_timeout); + if (!time_left) { dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n"); dmaengine_terminate_all(controller->dma_tx); dmaengine_terminate_all(controller->dma_rx); @@ -604,9 +604,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, return -ETIMEDOUT; } - timeout = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion, - transfer_timeout); - if (!timeout) { + time_left = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion, + transfer_timeout); + if (!time_left) { dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n"); dmaengine_terminate_all(controller->dma_tx); dmaengine_terminate_all(controller->dma_rx); From eaeac043ab842d2e84616ff0412eec0121c1758c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:35 +0200 Subject: [PATCH 61/89] spi: imx: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20240430114142.28551-4-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index c3e5cee18bea..f4006c82f867 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1405,7 +1405,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, { struct dma_async_tx_descriptor *desc_tx, *desc_rx; unsigned long transfer_timeout; - unsigned long timeout; + unsigned long time_left; struct spi_controller *controller = spi_imx->controller; struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents); @@ -1471,18 +1471,18 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); /* Wait SDMA to finish the data transfer.*/ - timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion, + time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion, transfer_timeout); - if (!timeout) { + if (!time_left) { dev_err(spi_imx->dev, "I/O Error in DMA TX\n"); dmaengine_terminate_all(controller->dma_tx); dmaengine_terminate_all(controller->dma_rx); return -ETIMEDOUT; } - timeout = wait_for_completion_timeout(&spi_imx->dma_rx_completion, - transfer_timeout); - if (!timeout) { + time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion, + transfer_timeout); + if (!time_left) { dev_err(&controller->dev, "I/O Error in DMA RX\n"); spi_imx->devtype_data->reset(spi_imx); dmaengine_terminate_all(controller->dma_rx); @@ -1501,7 +1501,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi, { struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); unsigned long transfer_timeout; - unsigned long timeout; + unsigned long time_left; spi_imx->tx_buf = transfer->tx_buf; spi_imx->rx_buf = transfer->rx_buf; @@ -1517,9 +1517,9 @@ static int spi_imx_pio_transfer(struct spi_device *spi, transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); - timeout = wait_for_completion_timeout(&spi_imx->xfer_done, - transfer_timeout); - if (!timeout) { + time_left = wait_for_completion_timeout(&spi_imx->xfer_done, + transfer_timeout); + if (!time_left) { dev_err(&spi->dev, "I/O Error in PIO\n"); spi_imx->devtype_data->reset(spi_imx); return -ETIMEDOUT; From a7c79e50a26cb619400ccc6294dbd7d8c24a0341 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:36 +0200 Subject: [PATCH 62/89] spi: pic32-sqi: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240430114142.28551-5-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-pic32-sqi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index 3f1e5b27776b..0031063a7e25 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -344,7 +344,7 @@ static int pic32_sqi_one_message(struct spi_controller *host, struct spi_transfer *xfer; struct pic32_sqi *sqi; int ret = 0, mode; - unsigned long timeout; + unsigned long time_left; u32 val; sqi = spi_controller_get_devdata(host); @@ -410,8 +410,8 @@ static int pic32_sqi_one_message(struct spi_controller *host, writel(val, sqi->regs + PESQI_BD_CTRL_REG); /* wait for xfer completion */ - timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ); + if (time_left == 0) { dev_err(&sqi->host->dev, "wait timedout/interrupted\n"); ret = -ETIMEDOUT; msg->status = ret; From e66480aed4a194f278da1e46ec45221b3983216f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:37 +0200 Subject: [PATCH 63/89] spi: pic32: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240430114142.28551-6-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-pic32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index 709edb70ad7d..b8bcc220e96d 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -498,7 +498,7 @@ static int pic32_spi_one_transfer(struct spi_controller *host, { struct pic32_spi *pic32s; bool dma_issued = false; - unsigned long timeout; + unsigned long time_left; int ret; pic32s = spi_controller_get_devdata(host); @@ -545,8 +545,8 @@ static int pic32_spi_one_transfer(struct spi_controller *host, } /* wait for completion */ - timeout = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ); + if (time_left == 0) { dev_err(&spi->dev, "wait error/timedout\n"); if (dma_issued) { dmaengine_terminate_all(host->dma_rx); From 34bed8a33f3a4f69b0ef584ef49f04a671a4a5c2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:38 +0200 Subject: [PATCH 64/89] spi: sun4i: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'unsigned long' while here. Signed-off-by: Wolfram Sang Acked-by: Jernej Skrabec Reviewed-by: Andre Przywara Link: https://lore.kernel.org/r/20240430114142.28551-7-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-sun4i.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 11d8bd27b3e9..2ee6755b43f5 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -206,7 +206,8 @@ static int sun4i_spi_transfer_one(struct spi_controller *host, struct spi_transfer *tfr) { struct sun4i_spi *sspi = spi_controller_get_devdata(host); - unsigned int mclk_rate, div, timeout; + unsigned int mclk_rate, div; + unsigned long time_left; unsigned int start, end, tx_time; unsigned int tx_len = 0; int ret = 0; @@ -327,10 +328,10 @@ static int sun4i_spi_transfer_one(struct spi_controller *host, tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U); start = jiffies; - timeout = wait_for_completion_timeout(&sspi->done, - msecs_to_jiffies(tx_time)); + time_left = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(tx_time)); end = jiffies; - if (!timeout) { + if (!time_left) { dev_warn(&host->dev, "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", dev_name(&spi->dev), tfr->len, tfr->speed_hz, From 83a3f1ba60d6e2f73c9dd2627a8ce41867dbc46b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:39 +0200 Subject: [PATCH 65/89] spi: sun6i: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'unsigned long' while here. Signed-off-by: Wolfram Sang Acked-by: Jernej Skrabec Reviewed-by: Andre Przywara Link: https://lore.kernel.org/r/20240430114142.28551-8-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index cd018ea1abf1..5c26bf056293 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -277,7 +277,8 @@ static int sun6i_spi_transfer_one(struct spi_controller *host, struct spi_transfer *tfr) { struct sun6i_spi *sspi = spi_controller_get_devdata(host); - unsigned int div, div_cdr1, div_cdr2, timeout; + unsigned int div, div_cdr1, div_cdr2; + unsigned long time_left; unsigned int start, end, tx_time; unsigned int trig_level; unsigned int tx_len = 0, rx_len = 0, nbits = 0; @@ -488,26 +489,26 @@ static int sun6i_spi_transfer_one(struct spi_controller *host, tx_time = spi_controller_xfer_timeout(host, tfr); start = jiffies; - timeout = wait_for_completion_timeout(&sspi->done, - msecs_to_jiffies(tx_time)); + time_left = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(tx_time)); if (!use_dma) { sun6i_spi_drain_fifo(sspi); } else { - if (timeout && rx_len) { + if (time_left && rx_len) { /* * Even though RX on the peripheral side has finished * RX DMA might still be in flight */ - timeout = wait_for_completion_timeout(&sspi->dma_rx_done, - timeout); - if (!timeout) + time_left = wait_for_completion_timeout(&sspi->dma_rx_done, + time_left); + if (!time_left) dev_warn(&host->dev, "RX DMA timeout\n"); } } end = jiffies; - if (!timeout) { + if (!time_left) { dev_warn(&host->dev, "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", dev_name(&spi->dev), tfr->len, tfr->speed_hz, From 594aa75d6bdda85b5fd027a5056d8cd1345c1db3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Apr 2024 13:41:40 +0200 Subject: [PATCH 66/89] spi: xlp: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'unsigned long' while here. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240430114142.28551-9-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-xlp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index 49302364b7bd..2fec18b68449 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -270,7 +270,7 @@ static int xlp_spi_xfer_block(struct xlp_spi_priv *xs, const unsigned char *tx_buf, unsigned char *rx_buf, int xfer_len, int cmd_cont) { - int timeout; + unsigned long time_left; u32 intr_mask = 0; xs->tx_buf = tx_buf; @@ -299,11 +299,11 @@ static int xlp_spi_xfer_block(struct xlp_spi_priv *xs, intr_mask |= XLP_SPI_INTR_DONE; xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, intr_mask); - timeout = wait_for_completion_timeout(&xs->done, - msecs_to_jiffies(1000)); + time_left = wait_for_completion_timeout(&xs->done, + msecs_to_jiffies(1000)); /* Disable interrupts */ xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0); - if (!timeout) { + if (!time_left) { dev_err(&xs->dev, "xfer timedout!\n"); goto out; } From 52267fe8456a2a05f70b29d68292eec789c960b9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 30 Apr 2024 15:15:27 -0500 Subject: [PATCH 67/89] spi: use spi_valid_{tx,rx}buf() in stats function There are macros spi_valid_txbuf() and spi_valid_rxbuf() for determining if an xfer actually intended to send or receive data. These checks were hard-coded in spi_statistics_add_transfer_stats(). We can make use of the macros instead to make the code more readable and more robust against potential future changes in case the definition of what valid means changes. The macro takes the spi_message as an argument, so we need to change spi_statistics_add_transfer_stats() to take the spi_message as an argument instead of the controller. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240430201530.2138095-3-dlechner@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 34fca94b2b5b..a500a4137a78 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -312,7 +312,7 @@ static const struct attribute_group *spi_master_groups[] = { static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats, struct spi_transfer *xfer, - struct spi_controller *ctlr) + struct spi_message *msg) { int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1; struct spi_statistics *stats; @@ -328,11 +328,9 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pc u64_stats_inc(&stats->transfer_bytes_histo[l2len]); u64_stats_add(&stats->bytes, xfer->len); - if ((xfer->tx_buf) && - (xfer->tx_buf != ctlr->dummy_tx)) + if (spi_valid_txbuf(msg, xfer)) u64_stats_add(&stats->bytes_tx, xfer->len); - if ((xfer->rx_buf) && - (xfer->rx_buf != ctlr->dummy_rx)) + if (spi_valid_rxbuf(msg, xfer)) u64_stats_add(&stats->bytes_rx, xfer->len); u64_stats_update_end(&stats->syncp); @@ -1618,8 +1616,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, list_for_each_entry(xfer, &msg->transfers, transfer_list) { trace_spi_transfer_start(msg, xfer); - spi_statistics_add_transfer_stats(statm, xfer, ctlr); - spi_statistics_add_transfer_stats(stats, xfer, ctlr); + spi_statistics_add_transfer_stats(statm, xfer, msg); + spi_statistics_add_transfer_stats(stats, xfer, msg); if (!ctlr->ptp_sts_supported) { xfer->ptp_sts_word_pre = 0; From 11ae2e63b2a517742d233c4e5b67b898c797973e Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2024 18:06:42 +0300 Subject: [PATCH 68/89] spi: dw: Convert to using BITS_TO_BYTES() macro Since commit dd3e7cba1627 ("ocfs2/dlm: move BITS_TO_BYTES() to bitops.h for wider use") there is a generic helper available to calculate a number of bytes needed to accommodate the specified number of bits. Let's use it instead of the hard-coded DIV_ROUND_UP() macro function. Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240424150657.9678-2-fancer.lancer@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 0274c9295514..722b5eb1f709 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -421,10 +422,7 @@ static int dw_spi_transfer_one(struct spi_controller *host, int ret; dws->dma_mapped = 0; - dws->n_bytes = - roundup_pow_of_two(DIV_ROUND_UP(transfer->bits_per_word, - BITS_PER_BYTE)); - + dws->n_bytes = roundup_pow_of_two(BITS_TO_BYTES(transfer->bits_per_word)); dws->tx = (void *)transfer->tx_buf; dws->tx_len = transfer->len / dws->n_bytes; dws->rx = transfer->rx_buf; From e164be7e1e9373bd10e6b79924b0a6374752775e Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2024 18:06:43 +0300 Subject: [PATCH 69/89] spi: dw: Add a number of native CS auto-detection Aside with the FIFO depth and DFS field size it's possible to auto-detect a number of native chip-select synthesized in the DW APB/AHB SSI IP-core. It can be done just by writing ones to the SER register. The number of writable flags in the register is limited by the SSI_NUM_SLAVES IP-core synthesize parameter. All the upper flags are read-only and wired to zero. Based on that let's add the number of native CS auto-detection procedure so the low-level platform drivers wouldn't need to manually set it up unless it's required to set a constraint due to platform-specific reasons (for instance, due to a hardware bug). Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240424150657.9678-3-fancer.lancer@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 722b5eb1f709..ddfdb903047a 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -834,6 +834,20 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) DW_SPI_GET_BYTE(dws->ver, 1)); } + /* + * Try to detect the number of native chip-selects if the platform + * driver didn't set it up. There can be up to 16 lines configured. + */ + if (!dws->num_cs) { + u32 ser; + + dw_writel(dws, DW_SPI_SER, 0xffff); + ser = dw_readl(dws, DW_SPI_SER); + dw_writel(dws, DW_SPI_SER, 0); + + dws->num_cs = hweight16(ser); + } + /* * Try to detect the FIFO depth if not set by interface driver, * the depth could be from 2 to 256 from HW spec From 33c85972d1e4952a8c93ec260be2e6ff4470e619 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2024 18:06:44 +0300 Subject: [PATCH 70/89] spi: dw: Convert dw_spi::num_cs to u32 Number of native chip-select lines is either retrieved from the "num-cs" DT-property or auto-detected in the generic DW APB/AHB SSI probe method. In the former case the property is supposed to be of the "u32" size. Convert the field type to being u32 then to be able to drop the temporary variable afterwards. Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240424150657.9678-4-fancer.lancer@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 6cafeee8ee2a..fc267c6437ae 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -164,8 +164,8 @@ struct dw_spi { u32 max_freq; /* max bus freq supported */ u32 reg_io_width; /* DR I/O width in bytes */ + u32 num_cs; /* chip select lines */ u16 bus_num; - u16 num_cs; /* supported slave numbers */ void (*set_cs)(struct spi_device *spi, bool enable); /* Current message transfer state info */ From 98d75b9ef282f6b9bfa1ea06d8a0824e0edaea97 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2024 18:06:45 +0300 Subject: [PATCH 71/89] spi: dw: Drop default number of CS setting DW APB/AHB SSI core now supports the procedure automatically detecting the number of native chip-select lines. Thus there is no longer point in defaulting to four CS if the platform doesn't specify the real number especially seeing the default number didn't correspond to any original DW APB/AHB databook. Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240424150657.9678-5-fancer.lancer@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index cc74cbe03431..c56de35eca98 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -320,7 +320,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) struct resource *mem; struct dw_spi *dws; int ret; - int num_cs; dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio), GFP_KERNEL); @@ -364,11 +363,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) &dws->reg_io_width)) dws->reg_io_width = 4; - num_cs = 4; - - device_property_read_u32(&pdev->dev, "num-cs", &num_cs); - - dws->num_cs = num_cs; + /* Rely on the auto-detection if no property specified */ + device_property_read_u32(&pdev->dev, "num-cs", &dws->num_cs); init_func = device_get_match_data(&pdev->dev); if (init_func) { From 645094b41157cce4ec41dc31298646c82f6998e0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 May 2024 18:48:25 +0300 Subject: [PATCH 72/89] spi: bitbang: Use NSEC_PER_*SEC rather than hard coding Use NSEC_PER_*SEC rather than the hard coded value of 1000s. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240502154825.2752464-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a0e2204fc039..c11af39c9842 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -168,8 +169,8 @@ int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (!hz) hz = spi->max_speed_hz; if (hz) { - cs->nsecs = (1000000000/2) / hz; - if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000)) + cs->nsecs = (NSEC_PER_SEC / 2) / hz; + if (cs->nsecs > (MAX_UDELAY_MS * NSEC_PER_MSEC)) return -EINVAL; } From 8ee46db14169fe1b028078767fda904d2fcbc04e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 May 2024 20:15:18 +0300 Subject: [PATCH 73/89] spi: bitbang: Add missing MODULE_DESCRIPTION() The modpost script is not happy WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spi/spi-bitbang.o because there is a missing module description. Add it to the module. While at it, update the terminology in Kconfig section to be in align with added description along with the code comments. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240502171518.2792895-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 4 ++-- drivers/spi/spi-bitbang.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 86f6115f417c..993526308c4b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -226,11 +226,11 @@ config SPI_BCMBCA_HSSPI explicitly. config SPI_BITBANG - tristate "Utilities for Bitbanging SPI masters" + tristate "Utilities for Bitbanging SPI host controllers" help With a few GPIO pins, your system can bitbang the SPI protocol. Select this to get SPI support through I/O pins (GPIO, parallel - port, etc). Or, some systems' SPI master controller drivers use + port, etc). Or, some systems' SPI host controller drivers use this code to manage the per-word or per-transfer accesses to the hardware shift registers. diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index c11af39c9842..ca5cc67555c5 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * polling/bitbanging SPI master controller driver utilities + * Polling/bitbanging SPI host controller controller driver utilities */ #include @@ -394,12 +394,12 @@ int spi_bitbang_init(struct spi_bitbang *bitbang) EXPORT_SYMBOL_GPL(spi_bitbang_init); /** - * spi_bitbang_start - start up a polled/bitbanging SPI master driver + * spi_bitbang_start - start up a polled/bitbanging SPI host controller driver * @bitbang: driver handle * * Caller should have zero-initialized all parts of the structure, and then - * provided callbacks for chip selection and I/O loops. If the master has - * a transfer method, its final step should call spi_bitbang_transfer; or, + * provided callbacks for chip selection and I/O loops. If the host controller has + * a transfer method, its final step should call spi_bitbang_transfer(); or, * that's the default if the transfer routine is not initialized. It should * also set up the bus number and number of chipselects. * @@ -407,9 +407,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init); * hardware that basically exposes a shift register) or per-spi_transfer * (which takes better advantage of hardware like fifos or DMA engines). * - * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup, - * spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi - * master methods. Those methods are the defaults if the bitbang->txrx_bufs + * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup(), + * spi_bitbang_cleanup() and spi_bitbang_setup_transfer() to handle those SPI + * host controller methods. Those methods are the defaults if the bitbang->txrx_bufs * routine isn't initialized. * * This routine registers the spi_controller, which will process requests in a @@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init); * * On success, this routine will take a reference to the controller. The caller * is responsible for calling spi_bitbang_stop() to decrement the reference and - * spi_controller_put() as counterpart of spi_alloc_master() to prevent a memory + * spi_controller_put() as counterpart of spi_alloc_host() to prevent a memory * leak. */ int spi_bitbang_start(struct spi_bitbang *bitbang) @@ -451,4 +451,4 @@ void spi_bitbang_stop(struct spi_bitbang *bitbang) EXPORT_SYMBOL_GPL(spi_bitbang_stop); MODULE_LICENSE("GPL"); - +MODULE_DESCRIPTION("Utilities for Bitbanging SPI host controllers"); From c24d340598ed535d3bb6f5e64c544cad4ab2b67b Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Wed, 1 May 2024 22:18:53 +0530 Subject: [PATCH 74/89] spi: dt-bindings: ti,qspi: convert to dtschema Convert txt binding of TI's qspi controller (found on their omap SoCs) to dtschema to allow for validation. The changes, w.r.t. the original txt binding, are: - Introduce "clocks" and "clock-names" which was never mentioned. - Reflect that "ti,hwmods" is deprecated and is not a "required" property anymore. - Introduce "num-cs" which allows for setting the number of chip selects. - Drop "qspi_ctrlmod". Signed-off-by: Kousik Sanagavarapu Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240501165203.13763-1-five231003@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/ti,qspi.yaml | 96 +++++++++++++++++++ .../devicetree/bindings/spi/ti_qspi.txt | 53 ---------- 2 files changed, 96 insertions(+), 53 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/ti,qspi.yaml delete mode 100644 Documentation/devicetree/bindings/spi/ti_qspi.txt diff --git a/Documentation/devicetree/bindings/spi/ti,qspi.yaml b/Documentation/devicetree/bindings/spi/ti,qspi.yaml new file mode 100644 index 000000000000..626a915b3d77 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/ti,qspi.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/ti,qspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI QSPI controller + +maintainers: + - Kousik Sanagavarapu + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + enum: + - ti,am4372-qspi + - ti,dra7xxx-qspi + + reg: + items: + - description: base registers + - description: mapped memory + + reg-names: + items: + - const: qspi_base + - const: qspi_mmap + + clocks: + maxItems: 1 + + clock-names: + items: + - const: fck + + interrupts: + maxItems: 1 + + num-cs: + minimum: 1 + maximum: 4 + default: 1 + + ti,hwmods: + description: + Name of the hwmod associated to the QSPI. This is for legacy + platforms only. + $ref: /schemas/types.yaml#/definitions/string + deprecated: true + + syscon-chipselects: + description: + Handle to system control region containing QSPI chipselect register + and offset of that register. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to system control register + - description: register offset + + spi-max-frequency: + description: Maximum SPI clocking speed of the controller in Hz. + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi@4b300000 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b300000 0x100>, + <0x5c000000 0x4000000>; + reg-names = "qspi_base", "qspi_mmap"; + syscon-chipselects = <&scm_conf 0x558>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&l4per2_clkctrl DRA7_L4PER2_QSPI_CLKCTRL 25>; + clock-names = "fck"; + num-cs = <4>; + spi-max-frequency = <48000000>; + interrupts = ; + }; +... diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt deleted file mode 100644 index 47b184bce414..000000000000 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ /dev/null @@ -1,53 +0,0 @@ -TI QSPI controller. - -Required properties: -- compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi". -- reg: Should contain QSPI registers location and length. -- reg-names: Should contain the resource reg names. - - qspi_base: Qspi configuration register Address space - - qspi_mmap: Memory mapped Address space - - (optional) qspi_ctrlmod: Control module Address space -- interrupts: should contain the qspi interrupt number. -- #address-cells, #size-cells : Must be present if the device has sub-nodes -- ti,hwmods: Name of the hwmod associated to the QSPI - -Recommended properties: -- spi-max-frequency: Definition as per - Documentation/devicetree/bindings/spi/spi-bus.txt - -Optional properties: -- syscon-chipselects: Handle to system control region contains QSPI - chipselect register and offset of that register. - -NOTE: TI QSPI controller requires different pinmux and IODelay -parameters for Mode-0 and Mode-3 operations, which needs to be set up by -the bootloader (U-Boot). Default configuration only supports Mode-0 -operation. Hence, "spi-cpol" and "spi-cpha" DT properties cannot be -specified in the slave nodes of TI QSPI controller without appropriate -modification to bootloader. - -Example: - -For am4372: -qspi: qspi@47900000 { - compatible = "ti,am4372-qspi"; - reg = <0x47900000 0x100>, <0x30000000 0x4000000>; - reg-names = "qspi_base", "qspi_mmap"; - #address-cells = <1>; - #size-cells = <0>; - spi-max-frequency = <25000000>; - ti,hwmods = "qspi"; -}; - -For dra7xx: -qspi: qspi@4b300000 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4b300000 0x100>, - <0x5c000000 0x4000000>, - reg-names = "qspi_base", "qspi_mmap"; - syscon-chipselects = <&scm_conf 0x558>; - #address-cells = <1>; - #size-cells = <0>; - spi-max-frequency = <48000000>; - ti,hwmods = "qspi"; -}; From 2c547549ac69380bb03b495c5ef3dbc03c9c7a48 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:28 +0300 Subject: [PATCH 75/89] spi: pxa2xx: Allow number of chip select pins to be read from property In some cases the number of the chip select pins might come from the device property. Allow driver to use it. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 2f60b2fde8d5..ab6fd55237cd 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1357,6 +1357,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) struct ssp_device *ssp = NULL; const void *match; bool is_lpss_priv; + u32 num_cs = 1; int status; is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); @@ -1395,8 +1396,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) pdata->dma_filter = pxa2xx_spi_idma_filter; } + /* Read number of chip select pins, if provided */ + device_property_read_u32(dev, "num-cs", &num_cs); + + pdata->num_chipselect = num_cs; pdata->is_target = device_property_read_bool(dev, "spi-slave"); - pdata->num_chipselect = 1; pdata->enable_dma = true; pdata->dma_burst_size = 1; From 11346db50616698b04da44a62d4fac17d9227a62 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:29 +0300 Subject: [PATCH 76/89] spi: pxa2xx: Provide num-cs for Sharp PDAs via device properties Since driver can parse num-cs device property, replace platform data with this new approach. This pursues the following objectives: - getting rid of the public header that barely used outside of the SPI subsystem (more specifically the SPI PXA2xx drivers) - making a trampoline for the driver to support non-default number of the chip select pins in case the original code is going to be converted to Device Tree model It's not expected to have more users in board files except this one. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- arch/arm/mach-pxa/spitz.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 318402ad685e..3c5f5a3cb480 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -18,10 +18,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -569,10 +569,6 @@ static struct spi_board_info spitz_spi_devices[] = { }, }; -static struct pxa2xx_spi_controller spitz_spi_info = { - .num_chipselect = 3, -}; - static struct gpiod_lookup_table spitz_spi_gpio_table = { .dev_id = "spi2", .table = { @@ -583,10 +579,20 @@ static struct gpiod_lookup_table spitz_spi_gpio_table = { }, }; +static const struct property_entry spitz_spi_properties[] = { + PROPERTY_ENTRY_U32("num-cs", 3), + { } +}; + +static const struct software_node spitz_spi_node = { + .properties = spitz_spi_properties, +}; + static void __init spitz_spi_init(void) { struct platform_device *pd; int id = 2; + int err; if (machine_is_akita()) gpiod_add_lookup_table(&akita_lcdcon_gpio_table); @@ -601,8 +607,13 @@ static void __init spitz_spi_init(void) if (pd == NULL) { pr_err("pxa2xx-spi: failed to allocate device id %d\n", id); } else { - pd->dev.platform_data = &spitz_spi_info; - platform_device_add(pd); + err = device_add_software_node(&pd->dev, &spitz_spi_node); + if (err) { + platform_device_put(pd); + pr_err("pxa2xx-spi: failed to add software node\n"); + } else { + platform_device_add(pd); + } } spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices)); From 2a45166938f145294b73445b0af997b3100f02b4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:30 +0300 Subject: [PATCH 77/89] spi: pxa2xx: Move contents of linux/spi/pxa2xx_spi.h to a local one There is no user of the linux/spi/pxa2xx_spi.h. Move its contents to the drivers/spi/spi-pxa2xx.h. Suggested-by: Arnd Bergmann Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 1 - drivers/spi/spi-pxa2xx-pci.c | 4 +-- drivers/spi/spi-pxa2xx.c | 1 - drivers/spi/spi-pxa2xx.h | 36 ++++++++++++++++++++++++- include/linux/spi/pxa2xx_spi.h | 48 ---------------------------------- 5 files changed, 37 insertions(+), 53 deletions(-) delete mode 100644 include/linux/spi/pxa2xx_spi.h diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index be563f0dd03a..26416ced6505 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -12,7 +12,6 @@ #include #include -#include #include #include "spi-pxa2xx.h" diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 861b21c63504..e11a613bc340 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -10,11 +10,11 @@ #include #include -#include - #include #include +#include "spi-pxa2xx.h" + #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0935 #define PCI_DEVICE_ID_INTEL_BYT 0x0f0e #define PCI_DEVICE_ID_INTEL_MRFLD 0x1194 diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index ab6fd55237cd..82633682b581 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "spi-pxa2xx.h" diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 45cdbbc71c4b..08296729ea80 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -7,6 +7,7 @@ #ifndef SPI_PXA2XX_H #define SPI_PXA2XX_H +#include #include #include #include @@ -15,7 +16,40 @@ #include struct gpio_desc; -struct pxa2xx_spi_controller; + +/* + * The platform data for SSP controller devices + * (resides in device.platform_data). + */ +struct pxa2xx_spi_controller { + u8 num_chipselect; + u8 enable_dma; + u8 dma_burst_size; + bool is_target; + + /* DMA engine specific config */ + dma_filter_fn dma_filter; + void *tx_param; + void *rx_param; + + /* For non-PXA arches */ + struct ssp_device ssp; +}; + +/* + * The controller specific data for SPI target devices + * (resides in spi_board_info.controller_data), + * copied to spi_device.platform_data ... mostly for + * DMA tuning. + */ +struct pxa2xx_spi_chip { + u8 tx_threshold; + u8 tx_hi_threshold; + u8 rx_threshold; + u8 dma_burst_size; + u32 timeout; +}; + struct spi_controller; struct spi_device; struct spi_transfer; diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h deleted file mode 100644 index e5a4a045fb67..000000000000 --- a/include/linux/spi/pxa2xx_spi.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - */ -#ifndef __LINUX_SPI_PXA2XX_SPI_H -#define __LINUX_SPI_PXA2XX_SPI_H - -#include -#include - -#include - -struct dma_chan; - -/* - * The platform data for SSP controller devices - * (resides in device.platform_data). - */ -struct pxa2xx_spi_controller { - u8 num_chipselect; - u8 enable_dma; - u8 dma_burst_size; - bool is_target; - - /* DMA engine specific config */ - dma_filter_fn dma_filter; - void *tx_param; - void *rx_param; - - /* For non-PXA arches */ - struct ssp_device ssp; -}; - -/* - * The controller specific data for SPI target devices - * (resides in spi_board_info.controller_data), - * copied to spi_device.platform_data ... mostly for - * DMA tuning. - */ -struct pxa2xx_spi_chip { - u8 tx_threshold; - u8 tx_hi_threshold; - u8 rx_threshold; - u8 dma_burst_size; - u32 timeout; -}; - -#endif /* __LINUX_SPI_PXA2XX_SPI_H */ From 2d069c11e8229e9f380af0c3bffe4b95cd2cf9ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:31 +0300 Subject: [PATCH 78/89] spi: pxa2xx: Remove outdated documentation The documentation is referring to the legacy enumeration of the SPI host controllers and target devices. It has nothing to do with the modern way, which is the only supported in kernel right now. Hence, remove outdated documentation file. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 208 ----------------------------------- drivers/spi/Kconfig | 3 +- 2 files changed, 1 insertion(+), 210 deletions(-) delete mode 100644 Documentation/spi/pxa2xx.rst diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst deleted file mode 100644 index 33d2ad95901e..000000000000 --- a/Documentation/spi/pxa2xx.rst +++ /dev/null @@ -1,208 +0,0 @@ -============================== -PXA2xx SPI on SSP driver HOWTO -============================== - -This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx -synchronous serial port into an SPI host controller -(see Documentation/spi/spi-summary.rst). The driver has the following features - -- Support for any PXA2xx and compatible SSP. -- SSP PIO and SSP DMA data transfers. -- External and Internal (SSPFRM) chip selects. -- Per peripheral device (chip) configuration. -- Full suspend, freeze, resume support. - -The driver is built around a &struct spi_message FIFO serviced by kernel -thread. The kernel thread, spi_pump_messages(), drives message FIFO and -is responsible for queuing SPI transactions and setting up and launching -the DMA or interrupt driven transfers. - -Declaring PXA2xx host controllers ---------------------------------- -Typically, for a legacy platform, an SPI host controller is defined in the -arch/.../mach-*/board-*.c as a "platform device". The host controller configuration -is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h:: - - struct pxa2xx_spi_controller { - u8 num_chipselect; - u8 enable_dma; - ... - }; - -The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of -peripheral devices (chips) attached to this SPI host controller. - -The "pxa2xx_spi_controller.enable_dma" field informs the driver that SSP DMA should -be used. This caused the driver to acquire two DMA channels: Rx channel and -Tx channel. The Rx channel has a higher DMA service priority than the Tx channel. -See the "PXA2xx Developer Manual" section "DMA Controller". - -For the new platforms the description of the controller and peripheral devices -comes from Device Tree or ACPI. - -NSSP HOST SAMPLE ----------------- -Below is a sample configuration using the PXA255 NSSP for a legacy platform:: - - static struct resource pxa_spi_nssp_resources[] = { - [0] = { - .start = __PREG(SSCR0_P(2)), /* Start address of NSSP */ - .end = __PREG(SSCR0_P(2)) + 0x2c, /* Range of registers */ - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_NSSP, /* NSSP IRQ */ - .end = IRQ_NSSP, - .flags = IORESOURCE_IRQ, - }, - }; - - static struct pxa2xx_spi_controller pxa_nssp_controller_info = { - .num_chipselect = 1, /* Matches the number of chips attached to NSSP */ - .enable_dma = 1, /* Enables NSSP DMA */ - }; - - static struct platform_device pxa_spi_nssp = { - .name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */ - .id = 2, /* Bus number, MUST MATCH SSP number 1..n */ - .resource = pxa_spi_nssp_resources, - .num_resources = ARRAY_SIZE(pxa_spi_nssp_resources), - .dev = { - .platform_data = &pxa_nssp_controller_info, /* Passed to driver */ - }, - }; - - static struct platform_device *devices[] __initdata = { - &pxa_spi_nssp, - }; - - static void __init board_init(void) - { - (void)platform_add_device(devices, ARRAY_SIZE(devices)); - } - -Declaring peripheral devices ----------------------------- -Typically, for a legacy platform, each SPI peripheral device (chip) is defined in the -arch/.../mach-*/board-*.c using the "spi_board_info" structure found in -"linux/spi/spi.h". See "Documentation/spi/spi-summary.rst" for additional -information. - -Each peripheral device (chip) attached to the PXA2xx must provide specific chip configuration -information via the structure "pxa2xx_spi_chip" found in -"include/linux/spi/pxa2xx_spi.h". The PXA2xx host controller driver will use -the configuration whenever the driver communicates with the peripheral -device. All fields are optional. - -:: - - struct pxa2xx_spi_chip { - u8 tx_threshold; - u8 rx_threshold; - u8 dma_burst_size; - u32 timeout; - }; - -The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are -used to configure the SSP hardware FIFO. These fields are critical to the -performance of pxa2xx_spi driver and misconfiguration will result in rx -FIFO overruns (especially in PIO mode transfers). Good default values are:: - - .tx_threshold = 8, - .rx_threshold = 8, - -The range is 1 to 16 where zero indicates "use default". - -The "pxa2xx_spi_chip.dma_burst_size" field is used to configure PXA2xx DMA -engine and is related the "spi_device.bits_per_word" field. Read and understand -the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers -to determine the correct value. An SSP configured for byte-wide transfers would -use a value of 8. The driver will determine a reasonable default if -dma_burst_size == 0. - -The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle -trailing bytes in the SSP receiver FIFO. The correct value for this field is -dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific -peripheral device. Please note that the PXA2xx SSP 1 does not support trailing byte -timeouts and must busy-wait any trailing bytes. - -NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the -chipselect is dropped after each spi_transfer. Most devices need chip select -asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor) -to accommodate these chips. - - -NSSP PERIPHERAL SAMPLE ----------------------- -For a legacy platform or in some other cases, the pxa2xx_spi_chip structure -is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data" -field. Below is a sample configuration using the PXA255 NSSP. - -:: - - static struct pxa2xx_spi_chip cs8415a_chip_info = { - .tx_threshold = 8, /* SSP hardware FIFO threshold */ - .rx_threshold = 8, /* SSP hardware FIFO threshold */ - .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ - .timeout = 235, /* See Intel documentation */ - }; - - static struct pxa2xx_spi_chip cs8405a_chip_info = { - .tx_threshold = 8, /* SSP hardware FIFO threshold */ - .rx_threshold = 8, /* SSP hardware FIFO threshold */ - .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ - .timeout = 235, /* See Intel documentation */ - }; - - static struct spi_board_info streetracer_spi_board_info[] __initdata = { - { - .modalias = "cs8415a", /* Name of spi_driver for this device */ - .max_speed_hz = 3686400, /* Run SSP as fast a possible */ - .bus_num = 2, /* Framework bus number */ - .chip_select = 0, /* Framework chip select */ - .platform_data = NULL; /* No spi_driver specific config */ - .controller_data = &cs8415a_chip_info, /* Host controller config */ - .irq = STREETRACER_APCI_IRQ, /* Peripheral device interrupt */ - }, - { - .modalias = "cs8405a", /* Name of spi_driver for this device */ - .max_speed_hz = 3686400, /* Run SSP as fast a possible */ - .bus_num = 2, /* Framework bus number */ - .chip_select = 1, /* Framework chip select */ - .controller_data = &cs8405a_chip_info, /* Host controller config */ - .irq = STREETRACER_APCI_IRQ, /* Peripheral device interrupt */ - }, - }; - - static void __init streetracer_init(void) - { - spi_register_board_info(streetracer_spi_board_info, - ARRAY_SIZE(streetracer_spi_board_info)); - } - - -DMA and PIO I/O Support ------------------------ -The pxa2xx_spi driver supports both DMA and interrupt driven PIO message -transfers. The driver defaults to PIO mode and DMA transfers must be enabled -by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. -For the newer platforms, that are known to support DMA, the driver will enable -it automatically and try it first with a possible fallback to PIO. The DMA -mode supports both coherent and stream based DMA mappings. - -The following logic is used to determine the type of I/O to be used on -a per "spi_transfer" basis:: - - if spi_message.len > 65536 then - print "rate limited" warning - use PIO transfers - - if enable_dma and the size is in the range [DMA burst size..65536] then - use streaming DMA mode - - otherwise - use PIO transfer - -THANKS TO ---------- -David Brownell and others for mentoring the development of this driver. diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 86f6115f417c..e2d2f011f973 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -832,8 +832,7 @@ config SPI_PXA2XX select PXA_SSP if ARCH_PXA || ARCH_MMP help This enables using a PXA2xx or Sodaville SSP port as a SPI master - controller. The driver can be configured to use any SSP port and - additional documentation can be found a Documentation/spi/pxa2xx.rst. + controller. The driver can be configured to use any SSP port. config SPI_PXA2XX_PCI def_tristate SPI_PXA2XX && PCI && COMMON_CLK From 4091770969bffba9dcb071b81d4010331d4dbee7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:32 +0300 Subject: [PATCH 79/89] spi: pxa2xx: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-6-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 10 ++++++++-- drivers/spi/spi-pxa2xx-pci.c | 6 ++++++ drivers/spi/spi-pxa2xx.c | 10 +++++++--- drivers/spi/spi-pxa2xx.h | 3 +-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 26416ced6505..751cb0f77b62 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -6,16 +6,22 @@ * Author: Mika Westerberg */ -#include +#include +#include #include #include +#include +#include #include -#include +#include +#include #include #include "spi-pxa2xx.h" +struct device; + static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, bool error) { diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index e11a613bc340..6d2efdb0e95f 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -6,9 +6,15 @@ * Copyright (C) 2016, 2021 Intel Corporation */ #include +#include +#include #include #include #include +#include +#include +#include +#include #include #include diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 82633682b581..cc0e54f8d2c3 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -5,24 +5,28 @@ */ #include +#include #include +#include #include #include #include #include #include -#include #include #include #include +#include #include -#include -#include +#include +#include #include +#include #include #include #include #include +#include #include diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 08296729ea80..f1097c96c50f 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -8,8 +8,7 @@ #define SPI_PXA2XX_H #include -#include -#include +#include #include #include From 513525e99898a722b365ceda6c5a2e4c83adda89 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:33 +0300 Subject: [PATCH 80/89] spi: pxa2xx: Drop struct pxa2xx_spi_chip No more users. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-7-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 9 ++------- drivers/spi/spi-pxa2xx.c | 25 ------------------------- drivers/spi/spi-pxa2xx.h | 14 -------------- 3 files changed, 2 insertions(+), 46 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 751cb0f77b62..d77279c3acd8 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -231,16 +231,11 @@ int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, u8 bits_per_word, u32 *burst_code, u32 *threshold) { - struct pxa2xx_spi_chip *chip_info = spi->controller_data; struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); u32 dma_burst_size = drv_data->controller_info->dma_burst_size; - /* - * If the DMA burst size is given in chip_info we use that, - * otherwise we use the default. Also we use the default FIFO - * thresholds for now. - */ - *burst_code = chip_info ? chip_info->dma_burst_size : dma_burst_size; + /* We use the default the DMA burst size and FIFO thresholds for now */ + *burst_code = dma_burst_size; *threshold = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index cc0e54f8d2c3..00aa33c937bf 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1154,7 +1154,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller) static int setup(struct spi_device *spi) { - struct pxa2xx_spi_chip *chip_info; struct chip_data *chip; const struct lpss_config *config; struct driver_data *drv_data = @@ -1218,25 +1217,6 @@ static int setup(struct spi_device *spi) chip->timeout = TIMOUT_DFLT; } - /* - * Protocol drivers may change the chip settings, so... - * if chip_info exists, use it. - */ - chip_info = spi->controller_data; - - /* chip_info isn't always needed */ - if (chip_info) { - if (chip_info->timeout) - chip->timeout = chip_info->timeout; - if (chip_info->tx_threshold) - tx_thres = chip_info->tx_threshold; - if (chip_info->tx_hi_threshold) - tx_hi_thres = chip_info->tx_hi_threshold; - if (chip_info->rx_threshold) - rx_thres = chip_info->rx_threshold; - chip->dma_threshold = 0; - } - chip->cr1 = 0; if (spi_controller_is_target(drv_data->controller)) { chip->cr1 |= SSCR1_SCFR; @@ -1256,11 +1236,6 @@ static int setup(struct spi_device *spi) chip->lpss_tx_threshold = tx_thres; } - /* - * Set DMA burst and threshold outside of chip_info path so that if - * chip_info goes away after setting chip->enable_dma, the burst and - * threshold can still respond to changes in bits_per_word. - */ if (chip->enable_dma) { /* Set up legal burst and threshold for DMA */ if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi, diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index f1097c96c50f..ae9c99bc9f6c 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -35,20 +35,6 @@ struct pxa2xx_spi_controller { struct ssp_device ssp; }; -/* - * The controller specific data for SPI target devices - * (resides in spi_board_info.controller_data), - * copied to spi_device.platform_data ... mostly for - * DMA tuning. - */ -struct pxa2xx_spi_chip { - u8 tx_threshold; - u8 tx_hi_threshold; - u8 rx_threshold; - u8 dma_burst_size; - u32 timeout; -}; - struct spi_controller; struct spi_device; struct spi_transfer; From 5c5de36d04cd848587f21c0c872682476d5df8e5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:34 +0300 Subject: [PATCH 81/89] spi: pxa2xx: Remove DMA parameters from struct chip_data The DMA related fields are set once and never modified. It effectively repeats the content of the same fields in struct pxa2xx_spi_controller. With that, remove DMA parameters from struct chip_data. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-8-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 22 ++------------------ drivers/spi/spi-pxa2xx.c | 40 +++++++----------------------------- drivers/spi/spi-pxa2xx.h | 8 -------- 3 files changed, 9 insertions(+), 61 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index d77279c3acd8..08cb6e96ac94 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -68,8 +68,6 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, enum dma_transfer_direction dir, struct spi_transfer *xfer) { - struct chip_data *chip = - spi_get_ctldata(drv_data->controller->cur_msg->spi); enum dma_slave_buswidth width; struct dma_slave_config cfg; struct dma_chan *chan; @@ -94,14 +92,14 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, if (dir == DMA_MEM_TO_DEV) { cfg.dst_addr = drv_data->ssp->phys_base + SSDR; cfg.dst_addr_width = width; - cfg.dst_maxburst = chip->dma_burst_size; + cfg.dst_maxburst = drv_data->controller_info->dma_burst_size; sgt = &xfer->tx_sg; chan = drv_data->controller->dma_tx; } else { cfg.src_addr = drv_data->ssp->phys_base + SSDR; cfg.src_addr_width = width; - cfg.src_maxburst = chip->dma_burst_size; + cfg.src_maxburst = drv_data->controller_info->dma_burst_size; sgt = &xfer->rx_sg; chan = drv_data->controller->dma_rx; @@ -225,19 +223,3 @@ void pxa2xx_spi_dma_release(struct driver_data *drv_data) controller->dma_tx = NULL; } } - -int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, - struct spi_device *spi, - u8 bits_per_word, u32 *burst_code, - u32 *threshold) -{ - struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); - u32 dma_burst_size = drv_data->controller_info->dma_burst_size; - - /* We use the default the DMA burst size and FIFO thresholds for now */ - *burst_code = dma_burst_size; - *threshold = SSCR1_RxTresh(RX_THRESH_DFLT) - | SSCR1_TxTresh(TX_THRESH_DFLT); - - return 0; -} diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 00aa33c937bf..3ba0f5816f7f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -934,11 +934,11 @@ static bool pxa2xx_spi_can_dma(struct spi_controller *controller, struct spi_device *spi, struct spi_transfer *xfer) { - struct chip_data *chip = spi_get_ctldata(spi); + struct driver_data *drv_data = spi_controller_get_devdata(controller); - return chip->enable_dma && + return drv_data->controller_info->enable_dma && xfer->len <= MAX_DMA_LEN && - xfer->len >= chip->dma_burst_size; + xfer->len >= drv_data->controller_info->dma_burst_size; } static int pxa2xx_spi_transfer_one(struct spi_controller *controller, @@ -947,9 +947,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, { struct driver_data *drv_data = spi_controller_get_devdata(controller); struct chip_data *chip = spi_get_ctldata(spi); - u32 dma_thresh = chip->dma_threshold; - u32 dma_burst = chip->dma_burst_size; u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); + u32 dma_thresh; u32 clk_div; u8 bits; u32 speed; @@ -959,7 +958,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, int dma_mapped; /* Check if we can DMA this transfer */ - if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { + if (transfer->len > MAX_DMA_LEN && drv_data->controller_info->enable_dma) { /* Warn ... we force this to PIO mode */ dev_warn_ratelimited(&spi->dev, "DMA disabled for transfer length %u greater than %d\n", @@ -995,19 +994,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, drv_data->read = drv_data->rx ? u32_reader : null_reader; drv_data->write = drv_data->tx ? u32_writer : null_writer; } - /* - * If bits per word is changed in DMA mode, then must check - * the thresholds and burst also. - */ - if (chip->enable_dma) { - if (pxa2xx_spi_set_dma_burst_and_threshold(chip, - spi, - bits, &dma_burst, - &dma_thresh)) - dev_warn_ratelimited(&spi->dev, - "DMA burst size reduced to match bits_per_word\n"); - } + dma_thresh = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT); dma_mapped = controller->can_dma && controller->can_dma(controller, spi, transfer) && controller->cur_msg_mapped; @@ -1213,7 +1201,6 @@ static int setup(struct spi_device *spi) if (!chip) return -ENOMEM; - chip->enable_dma = drv_data->controller_info->enable_dma; chip->timeout = TIMOUT_DFLT; } @@ -1236,20 +1223,6 @@ static int setup(struct spi_device *spi) chip->lpss_tx_threshold = tx_thres; } - if (chip->enable_dma) { - /* Set up legal burst and threshold for DMA */ - if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi, - spi->bits_per_word, - &chip->dma_burst_size, - &chip->dma_threshold)) { - dev_warn(&spi->dev, - "in setup: DMA burst size reduced to match bits_per_word\n"); - } - dev_dbg(&spi->dev, - "in setup: DMA burst size set to %u\n", - chip->dma_burst_size); - } - switch (drv_data->ssp_type) { case QUARK_X1000_SSP: chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres) @@ -1439,6 +1412,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) if (IS_ERR(platform_info)) return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n"); } + dev_dbg(dev, "DMA burst size set to %u\n", platform_info->dma_burst_size); ssp = pxa_ssp_request(pdev->id, pdev->name); if (!ssp) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index ae9c99bc9f6c..10294ef209d9 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -79,9 +79,6 @@ struct chip_data { u32 cr1; u32 dds_rate; u32 timeout; - u8 enable_dma; - u32 dma_burst_size; - u32 dma_threshold; u32 threshold; u16 lpss_rx_threshold; u16 lpss_tx_threshold; @@ -142,10 +139,5 @@ extern void pxa2xx_spi_dma_start(struct driver_data *drv_data); extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data); extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data); extern void pxa2xx_spi_dma_release(struct driver_data *drv_data); -extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, - struct spi_device *spi, - u8 bits_per_word, - u32 *burst_code, - u32 *threshold); #endif /* SPI_PXA2XX_H */ From 35bf074b1d4b252d04540acc7256e4ebee5b2dd5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:35 +0300 Subject: [PATCH 82/89] spi: pxa2xx: Remove timeout field from struct chip_data The timeout field is used only once and assigned to a predefined constant. Replace all that by using the constant directly. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-9-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 +--- drivers/spi/spi-pxa2xx.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 3ba0f5816f7f..030afb17e606 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1058,7 +1058,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, pxa_ssp_disable(drv_data->ssp); if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, chip->timeout); + pxa2xx_spi_write(drv_data, SSTO, TIMOUT_DFLT); /* First set CR1 without interrupt and service enables */ pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1); @@ -1200,8 +1200,6 @@ static int setup(struct spi_device *spi) chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); if (!chip) return -ENOMEM; - - chip->timeout = TIMOUT_DFLT; } chip->cr1 = 0; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 10294ef209d9..5f741bb30240 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -78,7 +78,6 @@ struct driver_data { struct chip_data { u32 cr1; u32 dds_rate; - u32 timeout; u32 threshold; u16 lpss_rx_threshold; u16 lpss_tx_threshold; From b5ec3986da5d928e4fd9ed24b5d367c4b420f1d4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Apr 2024 13:54:36 +0300 Subject: [PATCH 83/89] spi: pxa2xx: Don't provide struct chip_data for others Now the struct chip_data is local to spi-pxa2xx.c, move its definition to the C file. This will slightly speed up a build and also hide badly named data type (too generic). Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240417110334.2671228-10-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 8 ++++++++ drivers/spi/spi-pxa2xx.h | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 030afb17e606..efe76d0c21bb 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -66,6 +66,14 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) +struct chip_data { + u32 cr1; + u32 dds_rate; + u32 threshold; + u16 lpss_rx_threshold; + u16 lpss_tx_threshold; +}; + #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define LPSS_CS_CONTROL_SW_MODE BIT(0) #define LPSS_CS_CONTROL_CS_HIGH BIT(1) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 5f741bb30240..93e1e471e1c6 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -75,14 +75,6 @@ struct driver_data { struct gpio_desc *gpiod_ready; }; -struct chip_data { - u32 cr1; - u32 dds_rate; - u32 threshold; - u16 lpss_rx_threshold; - u16 lpss_tx_threshold; -}; - static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg) { return pxa_ssp_read_reg(drv_data->ssp, reg); From b62b9c90450a0789a55287a56d6930276dbae0e1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 7 May 2024 16:20:02 +0300 Subject: [PATCH 84/89] spi: pxa2xx: Drop the stale entry in documentation TOC The documentation had been removed, so should TOC entry. Reported-by: Stephen Rothwell Fixes: 2d069c11e822 ("spi: pxa2xx: Remove outdated documentation") Signed-off-by: Andy Shevchenko Closes: https://lore.kernel.org/r/20240507163131.183813ee@canb.auug.org.au Link: https://lore.kernel.org/r/20240507132002.71938-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/spi/index.rst b/Documentation/spi/index.rst index 06c34ea11bcf..824ce42ed4f0 100644 --- a/Documentation/spi/index.rst +++ b/Documentation/spi/index.rst @@ -10,7 +10,6 @@ Serial Peripheral Interface (SPI) spi-summary spidev butterfly - pxa2xx spi-lm70llp spi-sc18is602 From eab80a2ee46bb362e2c4434cf0da96d3a6bda544 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 7 May 2024 16:14:49 +0200 Subject: [PATCH 85/89] MAINTAINERS: repair file entry in AIROHA SPI SNFI DRIVER Commit a403997c1201 ("spi: airoha: add SPI-NAND Flash controller driver") adds a new section AIROHA SPI SNFI DRIVER referring to the file spi-airoha.c. The commit however adds the file spi-airoha-snfi.c. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Repair this file entry in the AIROHA SPI SNFI DRIVER section. Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20240507141449.177538-1-lukas.bulwahn@redhat.com Signed-off-by: Mark Brown --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index dde7dd956156..893ca3d7a623 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -660,7 +660,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-spi@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml -F: drivers/spi/spi-airoha.c +F: drivers/spi/spi-airoha-snfi.c AIRSPY MEDIA DRIVER L: linux-media@vger.kernel.org From 8cc3bad9d9d6a4735a8c8998c6daa1ef31cbf708 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 7 May 2024 23:10:27 +0300 Subject: [PATCH 86/89] spi: Remove unneded check for orig_nents Both dma_unmap_sgtable() and sg_free_table() in spi_unmap_buf_attrs() have checks for orig_nents against 0. No need to duplicate this. All the same applies to other DMA mapping API calls. Also note, there is no other user in the kernel that does this kind of checks. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240507201028.564630-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a500a4137a78..a8966caed841 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1208,12 +1208,10 @@ static void spi_unmap_buf_attrs(struct spi_controller *ctlr, enum dma_data_direction dir, unsigned long attrs) { - if (sgt->orig_nents) { - dma_unmap_sgtable(dev, sgt, dir, attrs); - sg_free_table(sgt); - sgt->orig_nents = 0; - sgt->nents = 0; - } + dma_unmap_sgtable(dev, sgt, dir, attrs); + sg_free_table(sgt); + sgt->orig_nents = 0; + sgt->nents = 0; } void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, @@ -1318,10 +1316,8 @@ static void spi_dma_sync_for_device(struct spi_controller *ctlr, if (!ctlr->cur_msg_mapped) return; - if (xfer->tx_sg.orig_nents) - dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); - if (xfer->rx_sg.orig_nents) - dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); } static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, @@ -1333,10 +1329,8 @@ static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, if (!ctlr->cur_msg_mapped) return; - if (xfer->rx_sg.orig_nents) - dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); - if (xfer->tx_sg.orig_nents) - dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } #else /* !CONFIG_HAS_DMA */ static inline int __spi_map_msg(struct spi_controller *ctlr, From d6e7ffd4820f8894eb865890c96852085d3640e1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 8 May 2024 12:20:27 +0200 Subject: [PATCH 87/89] spi: dw: Bail out early on unsupported target mode Currently, the DesignWare SPI controller driver supports only host mode. However, spi2 on the Kendryte K210 SoC supports only target mode, triggering an error message on e.g. SiPEED MAiXBiT since commit 98d75b9ef282f6b9 ("spi: dw: Drop default number of CS setting"): dw_spi_mmio 50240000.spi: error -22: problem registering spi host dw_spi_mmio 50240000.spi: probe with driver dw_spi_mmio failed with error -22 As spi2 rightfully has no "num-cs" property, num_chipselect is now zero, causing spi_alloc_host() to fail to register the controller. Before, the driver silently registered an SPI host controller with 4 chip selects. Reject target mode early on and warn the user, getting rid of the error message. Signed-off-by: Geert Uytterhoeven Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/7ae28d83bff7351f34782658ae1bb69cc731693e.1715163113.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index c56de35eca98..819907e332c4 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -321,6 +321,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) struct dw_spi *dws; int ret; + if (device_property_read_bool(&pdev->dev, "spi-slave")) { + dev_warn(&pdev->dev, "spi-slave is not yet supported\n"); + return -ENODEV; + } + dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio), GFP_KERNEL); if (!dwsmmio) From 9f788ba457b45b0ce422943fcec9fa35c4587764 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 May 2024 20:09:49 +0300 Subject: [PATCH 88/89] spi: Don't mark message DMA mapped when no transfer in it is There is no need to set the DMA mapped flag of the message if it has no mapped transfers. Moreover, it may give the code a chance to take the wrong paths, i.e. to exercise DMA related APIs on unmapped data. Make __spi_map_msg() to bail earlier on the above mentioned cases. Fixes: 99adef310f68 ("spi: Provide core support for DMA mapping transfers") Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240522171018.3362521-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a8966caed841..d40ce0fdb1a8 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1243,6 +1243,7 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) else rx_dev = ctlr->dev.parent; + ret = -ENOMSG; list_for_each_entry(xfer, &msg->transfers, transfer_list) { /* The sync is done before each transfer. */ unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; @@ -1272,6 +1273,9 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) } } } + /* No transfer has been mapped, bail out with success */ + if (ret) + return 0; ctlr->cur_rx_dma_dev = rx_dev; ctlr->cur_tx_dma_dev = tx_dev; From da560097c05612f8d360f86528f6213629b9c395 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 May 2024 20:09:50 +0300 Subject: [PATCH 89/89] spi: Check if transfer is mapped before calling DMA sync APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The resent update to remove the orig_nents checks revealed that not all DMA sync backends can cope with the unallocated SG list, while supplying orig_nents == 0 (the commit 861370f49ce4 ("iommu/dma: force bouncing if the size is not cacheline-aligned"), for example, makes that happen for the IOMMU case). It means we have to check if the buffers are DMA mapped before trying to sync them. Re-introduce that check in a form of calling ->can_dma() in the same way as it's done in the DMA mapping loop for the SPI transfers. Reported-by: Nícolas F. R. A. Prado Reported-by: Neil Armstrong Closes: https://lore.kernel.org/r/8ae675b5-fcf9-4c9b-b06a-4462f70e1322@linaro.org Closes: https://lore.kernel.org/all/d3679496-2e4e-4a7c-97ed-f193bd53af1d@notapiano Fixes: 8cc3bad9d9d6 ("spi: Remove unneded check for orig_nents") Suggested-by: Nícolas F. R. A. Prado Tested-by: Nícolas F. R. A. Prado Signed-off-by: Andy Shevchenko Link: https://msgid.link/r/20240522171018.3362521-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d40ce0fdb1a8..b18a4c871e21 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1311,7 +1311,7 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) return 0; } -static void spi_dma_sync_for_device(struct spi_controller *ctlr, +static void spi_dma_sync_for_device(struct spi_controller *ctlr, struct spi_message *msg, struct spi_transfer *xfer) { struct device *rx_dev = ctlr->cur_rx_dma_dev; @@ -1320,11 +1320,14 @@ static void spi_dma_sync_for_device(struct spi_controller *ctlr, if (!ctlr->cur_msg_mapped) return; + if (!ctlr->can_dma(ctlr, msg->spi, xfer)) + return; + dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); } -static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, +static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, struct spi_message *msg, struct spi_transfer *xfer) { struct device *rx_dev = ctlr->cur_rx_dma_dev; @@ -1333,6 +1336,9 @@ static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, if (!ctlr->cur_msg_mapped) return; + if (!ctlr->can_dma(ctlr, msg->spi, xfer)) + return; + dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } @@ -1350,11 +1356,13 @@ static inline int __spi_unmap_msg(struct spi_controller *ctlr, } static void spi_dma_sync_for_device(struct spi_controller *ctrl, + struct spi_message *msg, struct spi_transfer *xfer) { } static void spi_dma_sync_for_cpu(struct spi_controller *ctrl, + struct spi_message *msg, struct spi_transfer *xfer) { } @@ -1626,10 +1634,10 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, reinit_completion(&ctlr->xfer_completion); fallback_pio: - spi_dma_sync_for_device(ctlr, xfer); + spi_dma_sync_for_device(ctlr, msg, xfer); ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { - spi_dma_sync_for_cpu(ctlr, xfer); + spi_dma_sync_for_cpu(ctlr, msg, xfer); if (ctlr->cur_msg_mapped && (xfer->error & SPI_TRANS_FAIL_NO_START)) { @@ -1654,7 +1662,7 @@ fallback_pio: msg->status = ret; } - spi_dma_sync_for_cpu(ctlr, xfer); + spi_dma_sync_for_cpu(ctlr, msg, xfer); } else { if (xfer->len) dev_err(&msg->spi->dev,