From b99181cdf9fa0247dda3ba1228b4578286ab7ecd Mon Sep 17 00:00:00 2001 From: Jonathan Marek Date: Thu, 20 Nov 2025 16:11:58 -0500 Subject: [PATCH] spi-geni-qcom: remove manual CS control The GPI_DMA mode already uses automatic CS control, to use automatic CS control for non-GPI case all that's needed is to set the FRAGMENTATION flag using the same logic as setup_gsi_xfer(). (note clearing SPI_TRANS_CFG's CS_TOGGLE bit enables automatic CS control, the comment was wrong) spi_geni_set_cs() is slow, so this is a big performance improvement. Signed-off-by: Jonathan Marek Link: https://patch.msgid.link/20251120211204.24078-1-jonathan@marek.ca Signed-off-by: Mark Brown --- drivers/spi/spi-geni-qcom.c | 67 +++++-------------------------------- 1 file changed, 8 insertions(+), 59 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index a0d8d3425c6c6..ed80f49c7b2f3 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -284,55 +284,6 @@ static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas) return false; } -static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) -{ - struct spi_geni_master *mas = spi_controller_get_devdata(slv->controller); - struct spi_controller *spi = dev_get_drvdata(mas->dev); - struct geni_se *se = &mas->se; - unsigned long time_left; - - if (!(slv->mode & SPI_CS_HIGH)) - set_flag = !set_flag; - - if (set_flag == mas->cs_flag) - return; - - pm_runtime_get_sync(mas->dev); - - if (spi_geni_is_abort_still_pending(mas)) { - dev_err(mas->dev, "Can't set chip select\n"); - goto exit; - } - - spin_lock_irq(&mas->lock); - if (mas->cur_xfer) { - dev_err(mas->dev, "Can't set CS when prev xfer running\n"); - spin_unlock_irq(&mas->lock); - goto exit; - } - - mas->cs_flag = set_flag; - /* set xfer_mode to FIFO to complete cs_done in isr */ - mas->cur_xfer_mode = GENI_SE_FIFO; - geni_se_select_mode(se, mas->cur_xfer_mode); - - reinit_completion(&mas->cs_done); - if (set_flag) - geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); - else - geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); - spin_unlock_irq(&mas->lock); - - time_left = wait_for_completion_timeout(&mas->cs_done, HZ); - if (!time_left) { - dev_warn(mas->dev, "Timeout setting chip select\n"); - handle_se_timeout(spi, NULL); - } - -exit: - pm_runtime_put(mas->dev); -} - static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, unsigned int bits_per_word) { @@ -728,7 +679,7 @@ static int spi_geni_init(struct spi_geni_master *mas) break; } - /* We always control CS manually */ + /* We never control CS manually */ if (!spi->target) { spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); spi_tx_cfg &= ~CS_TOGGLE; @@ -841,6 +792,7 @@ static int setup_se_xfer(struct spi_transfer *xfer, u16 mode, struct spi_controller *spi) { u32 m_cmd = 0; + u32 m_params = 0; u32 len; struct geni_se *se = &mas->se; int ret; @@ -904,12 +856,17 @@ static int setup_se_xfer(struct spi_transfer *xfer, mas->cur_xfer_mode = GENI_SE_DMA; geni_se_select_mode(se, mas->cur_xfer_mode); + if (!xfer->cs_change) { + if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers)) + m_params = FRAGMENTATION; + } + /* * Lock around right before we start the transfer since our * interrupt could come in at any time now. */ spin_lock_irq(&mas->lock); - geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); + geni_se_setup_m_cmd(se, m_cmd, m_params); if (mas->cur_xfer_mode == GENI_SE_DMA) { if (m_cmd & SPI_RX_ONLY) @@ -1148,14 +1105,6 @@ static int spi_geni_probe(struct platform_device *pdev) if (ret) return ret; - /* - * check the mode supported and set_cs for fifo mode only - * for dma (gsi) mode, the gsi will set cs based on params passed in - * TRE - */ - if (!spi->target && mas->cur_xfer_mode == GENI_SE_FIFO) - spi->set_cs = spi_geni_set_cs; - /* * TX is required per GSI spec, see setup_gsi_xfer(). */ -- 2.47.3