* [PATCH 1/5] spi-geni-qcom: remove manual CS control
@ 2025-11-20 21:11 Jonathan Marek
2025-11-20 21:11 ` [PATCH 2/5] spi-geni-qcom: don't set max clock in setup_fifo_params Jonathan Marek
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Jonathan Marek @ 2025-11-20 21:11 UTC (permalink / raw)
To: linux-arm-msm; +Cc: Mark Brown, open list:SPI SUBSYSTEM, open list
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 <jonathan@marek.ca>
---
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.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] spi-geni-qcom: don't set max clock in setup_fifo_params
2025-11-20 21:11 [PATCH 1/5] spi-geni-qcom: remove manual CS control Jonathan Marek
@ 2025-11-20 21:11 ` Jonathan Marek
2025-11-20 21:12 ` [PATCH 3/5] spi-geni-qcom: use xfer->bits_per_word for can_dma() Jonathan Marek
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Marek @ 2025-11-20 21:11 UTC (permalink / raw)
To: linux-arm-msm; +Cc: Mark Brown, open list:SPI SUBSYSTEM, open list
setup_se_xfer() already sets the correct clock (xfer->speed_hz). Setting
the clock to max_speed_hz here makes the driver change the clock rate
between speed_hz and max_speed_hz for every message (if not equal),
slowing it down significantly.
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
drivers/spi/spi-geni-qcom.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index ed80f49c7b2f3..c33d79d9afaf8 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -379,7 +379,7 @@ static int setup_fifo_params(struct spi_device *spi_slv,
mas->last_mode = spi_slv->mode;
}
- return geni_spi_set_clock_and_bw(mas, spi_slv->max_speed_hz);
+ return 0;
}
static void
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/5] spi-geni-qcom: use xfer->bits_per_word for can_dma()
2025-11-20 21:11 [PATCH 1/5] spi-geni-qcom: remove manual CS control Jonathan Marek
2025-11-20 21:11 ` [PATCH 2/5] spi-geni-qcom: don't set max clock in setup_fifo_params Jonathan Marek
@ 2025-11-20 21:12 ` Jonathan Marek
2025-11-20 21:12 ` [PATCH 4/5] spi-geni-qcom: initialize mode related registers to 0 Jonathan Marek
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Marek @ 2025-11-20 21:12 UTC (permalink / raw)
To: linux-arm-msm; +Cc: Mark Brown, open list:SPI SUBSYSTEM, open list
mas->cur_bits_per_word may not reflect the value of xfer->bits_per_word
when can_dma() is called. Use the right value instead.
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
drivers/spi/spi-geni-qcom.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index c33d79d9afaf8..575b112d4acb1 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -499,10 +499,10 @@ static u32 get_xfer_len_in_words(struct spi_transfer *xfer,
{
u32 len;
- if (!(mas->cur_bits_per_word % MIN_WORD_LEN))
- len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word;
+ if (!(xfer->bits_per_word % MIN_WORD_LEN))
+ len = xfer->len * BITS_PER_BYTE / xfer->bits_per_word;
else
- len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1);
+ len = xfer->len / (xfer->bits_per_word / BITS_PER_BYTE + 1);
len &= TRANS_LEN_MSK;
return len;
@@ -522,7 +522,7 @@ static bool geni_can_dma(struct spi_controller *ctlr,
return true;
len = get_xfer_len_in_words(xfer, mas);
- fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
+ fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / xfer->bits_per_word;
if (len > fifo_size)
return true;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/5] spi-geni-qcom: initialize mode related registers to 0
2025-11-20 21:11 [PATCH 1/5] spi-geni-qcom: remove manual CS control Jonathan Marek
2025-11-20 21:11 ` [PATCH 2/5] spi-geni-qcom: don't set max clock in setup_fifo_params Jonathan Marek
2025-11-20 21:12 ` [PATCH 3/5] spi-geni-qcom: use xfer->bits_per_word for can_dma() Jonathan Marek
@ 2025-11-20 21:12 ` Jonathan Marek
2025-11-20 21:12 ` [PATCH 5/5] spi-geni-qcom: rework setup_fifo_params Jonathan Marek
2025-12-15 13:59 ` [PATCH 1/5] spi-geni-qcom: remove manual CS control Mark Brown
4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Marek @ 2025-11-20 21:12 UTC (permalink / raw)
To: linux-arm-msm; +Cc: Mark Brown, open list:SPI SUBSYSTEM, open list
setup_fifo_params assumes these will be zero, it won't write these
registers if the initial mode is zero.
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
drivers/spi/spi-geni-qcom.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 575b112d4acb1..53229150b86b5 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -675,6 +675,12 @@ static int spi_geni_init(struct spi_geni_master *mas)
case 0:
mas->cur_xfer_mode = GENI_SE_FIFO;
geni_se_select_mode(se, GENI_SE_FIFO);
+ /* setup_fifo_params assumes that these registers start with a zero value */
+ writel(0, se->base + SE_SPI_LOOPBACK);
+ writel(0, se->base + SE_SPI_DEMUX_SEL);
+ writel(0, se->base + SE_SPI_CPHA);
+ writel(0, se->base + SE_SPI_CPOL);
+ writel(0, se->base + SE_SPI_DEMUX_OUTPUT_INV);
ret = 0;
break;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/5] spi-geni-qcom: rework setup_fifo_params
2025-11-20 21:11 [PATCH 1/5] spi-geni-qcom: remove manual CS control Jonathan Marek
` (2 preceding siblings ...)
2025-11-20 21:12 ` [PATCH 4/5] spi-geni-qcom: initialize mode related registers to 0 Jonathan Marek
@ 2025-11-20 21:12 ` Jonathan Marek
2025-12-15 13:59 ` [PATCH 1/5] spi-geni-qcom: remove manual CS control Mark Brown
4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Marek @ 2025-11-20 21:12 UTC (permalink / raw)
To: linux-arm-msm; +Cc: Mark Brown, open list:SPI SUBSYSTEM, open list
Update each register only if it changes.
This also fixes the chipselect related registers not being changed when
chipselect changes but not the mode.
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
---
drivers/spi/spi-geni-qcom.c | 48 ++++++++++++++++---------------------
1 file changed, 20 insertions(+), 28 deletions(-)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 53229150b86b5..5cca356cb673a 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -82,6 +82,7 @@ struct spi_geni_master {
u32 fifo_width_bits;
u32 tx_wm;
u32 last_mode;
+ u8 last_cs;
unsigned long cur_speed_hz;
unsigned long cur_sclk_hz;
unsigned int cur_bits_per_word;
@@ -350,34 +351,25 @@ static int setup_fifo_params(struct spi_device *spi_slv,
{
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
struct geni_se *se = &mas->se;
- u32 loopback_cfg = 0, cpol = 0, cpha = 0, demux_output_inv = 0;
- u32 demux_sel;
-
- if (mas->last_mode != spi_slv->mode) {
- if (spi_slv->mode & SPI_LOOP)
- loopback_cfg = LOOPBACK_ENABLE;
-
- if (spi_slv->mode & SPI_CPOL)
- cpol = CPOL;
-
- if (spi_slv->mode & SPI_CPHA)
- cpha = CPHA;
-
- if (spi_slv->mode & SPI_CS_HIGH)
- demux_output_inv = BIT(spi_get_chipselect(spi_slv, 0));
-
- demux_sel = spi_get_chipselect(spi_slv, 0);
- mas->cur_bits_per_word = spi_slv->bits_per_word;
-
- spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
- writel(loopback_cfg, se->base + SE_SPI_LOOPBACK);
- writel(demux_sel, se->base + SE_SPI_DEMUX_SEL);
- writel(cpha, se->base + SE_SPI_CPHA);
- writel(cpol, se->base + SE_SPI_CPOL);
- writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV);
-
- mas->last_mode = spi_slv->mode;
- }
+ u8 chipselect = spi_get_chipselect(spi_slv, 0);
+ bool cs_changed = (mas->last_cs != chipselect);
+ u32 mode_changed = mas->last_mode ^ spi_slv->mode;
+
+ mas->last_cs = chipselect;
+ mas->last_mode = spi_slv->mode;
+
+ if (mode_changed & SPI_LSB_FIRST)
+ mas->cur_bits_per_word = 0; /* force next setup_se_xfer to call spi_setup_word_len */
+ if (mode_changed & SPI_LOOP)
+ writel((spi_slv->mode & SPI_LOOP) ? LOOPBACK_ENABLE : 0, se->base + SE_SPI_LOOPBACK);
+ if (cs_changed)
+ writel(chipselect, se->base + SE_SPI_DEMUX_SEL);
+ if (mode_changed & SE_SPI_CPHA)
+ writel((spi_slv->mode & SPI_CPHA) ? CPHA : 0, se->base + SE_SPI_CPHA);
+ if (mode_changed & SE_SPI_CPOL)
+ writel((spi_slv->mode & SPI_CPOL) ? CPOL : 0, se->base + SE_SPI_CPOL);
+ if ((mode_changed & SPI_CS_HIGH) || (cs_changed && (spi_slv->mode & SPI_CS_HIGH)))
+ writel((spi_slv->mode & SPI_CS_HIGH) ? BIT(chipselect) : 0, se->base + SE_SPI_DEMUX_OUTPUT_INV);
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/5] spi-geni-qcom: remove manual CS control
2025-11-20 21:11 [PATCH 1/5] spi-geni-qcom: remove manual CS control Jonathan Marek
` (3 preceding siblings ...)
2025-11-20 21:12 ` [PATCH 5/5] spi-geni-qcom: rework setup_fifo_params Jonathan Marek
@ 2025-12-15 13:59 ` Mark Brown
4 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2025-12-15 13:59 UTC (permalink / raw)
To: linux-arm-msm, Jonathan Marek; +Cc: linux-spi, linux-kernel
On Thu, 20 Nov 2025 16:11:58 -0500, Jonathan Marek wrote:
> 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.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
Thanks!
[1/5] spi-geni-qcom: remove manual CS control
commit: b99181cdf9fa0247dda3ba1228b4578286ab7ecd
[2/5] spi-geni-qcom: don't set max clock in setup_fifo_params
commit: 7ba2e0edb18b3ccee7339315be47080832a3c355
[3/5] spi-geni-qcom: use xfer->bits_per_word for can_dma()
commit: fb2bbe3838728f572485706677590e4fc41eec5c
[4/5] spi-geni-qcom: initialize mode related registers to 0
commit: 739062a9f1e9a77a9687c8fd30f8e5dd12ec70be
[5/5] spi-geni-qcom: rework setup_fifo_params
commit: 781c3e71c94c80e1b33a7d84b970907dd32abc10
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-12-15 13:59 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-20 21:11 [PATCH 1/5] spi-geni-qcom: remove manual CS control Jonathan Marek
2025-11-20 21:11 ` [PATCH 2/5] spi-geni-qcom: don't set max clock in setup_fifo_params Jonathan Marek
2025-11-20 21:12 ` [PATCH 3/5] spi-geni-qcom: use xfer->bits_per_word for can_dma() Jonathan Marek
2025-11-20 21:12 ` [PATCH 4/5] spi-geni-qcom: initialize mode related registers to 0 Jonathan Marek
2025-11-20 21:12 ` [PATCH 5/5] spi-geni-qcom: rework setup_fifo_params Jonathan Marek
2025-12-15 13:59 ` [PATCH 1/5] spi-geni-qcom: remove manual CS control Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox