diff mbox series

[2/2] spi: omap2-mcspi: Add support for MULTI-mode

Message ID 20240126-spi-omap2-mcspi-multi-mode-v1-2-d143d33f0fe0@bootlin.com
State Superseded
Headers show
Series [1/2] Revert "spi: spi-omap2-mcspi.c: Toggle CS after each word" | expand

Commit Message

Louis Chauvet Feb. 6, 2024, 10 a.m. UTC
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 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 <louis.chauvet@bootlin.com>
---
 drivers/spi/spi-omap2-mcspi.c | 57 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 51 insertions(+), 6 deletions(-)

Comments

kernel test robot Feb. 7, 2024, 9:19 a.m. UTC | #1
Hi Louis,

kernel test robot noticed the following build errors:

[auto build test ERROR on 41bccc98fb7931d63d03f326a746ac4d429c1dd3]

url:    https://github.com/intel-lab-lkp/linux/commits/Louis-Chauvet/Revert-spi-spi-omap2-mcspi-c-Toggle-CS-after-each-word/20240206-180243
base:   41bccc98fb7931d63d03f326a746ac4d429c1dd3
patch link:    https://lore.kernel.org/r/20240126-spi-omap2-mcspi-multi-mode-v1-2-d143d33f0fe0%40bootlin.com
patch subject: [PATCH 2/2] spi: omap2-mcspi: Add support for MULTI-mode
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20240207/202402071719.e1p4tUge-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240207/202402071719.e1p4tUge-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402071719.e1p4tUge-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   drivers/spi/spi-omap2-mcspi.c: In function 'omap2_mcspi_prepare_message':
>> drivers/spi/spi-omap2-mcspi.c:1415:30: error: 'master' undeclared (first use in this function)
    1415 |         omap2_mcspi_set_mode(master);
         |                              ^~~~~~
   drivers/spi/spi-omap2-mcspi.c:1415:30: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/spi/spi-omap2-mcspi.c:1388:13: warning: unused variable 'speed_hz' [-Wunused-variable]
    1388 |         u32 speed_hz;
         |             ^~~~~~~~


vim +/master +1415 drivers/spi/spi-omap2-mcspi.c

  1379	
  1380	static int omap2_mcspi_prepare_message(struct spi_controller *ctlr,
  1381					       struct spi_message *msg)
  1382	{
  1383		struct omap2_mcspi	*mcspi = spi_controller_get_devdata(ctlr);
  1384		struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
  1385		struct omap2_mcspi_cs	*cs;
  1386		struct spi_transfer	*tr;
  1387		u8 bits_per_word;
> 1388		u32 speed_hz;
  1389	
  1390		/*
  1391		 * The conditions are strict, it is mandatory to check each transfer of the list to see if
  1392		 * multi-mode is applicable.
  1393		 */
  1394		mcspi->use_multi_mode = true;
  1395		list_for_each_entry(tr, &msg->transfers, transfer_list) {
  1396			if (!tr->bits_per_word)
  1397				bits_per_word = msg->spi->bits_per_word;
  1398			else
  1399				bits_per_word = tr->bits_per_word;
  1400	
  1401			/* Check if the transfer content is only one word */
  1402			if ((bits_per_word < 8 && tr->len > 1) ||
  1403			    (bits_per_word >= 8 && tr->len > bits_per_word / 8))
  1404				mcspi->use_multi_mode = false;
  1405	
  1406			/* Check if transfer asks to change the CS status after the transfer */
  1407			if (!tr->cs_change)
  1408				mcspi->use_multi_mode = false;
  1409	
  1410			/* If at least one message is not compatible, switch back to single mode */
  1411			if (!mcspi->use_multi_mode)
  1412				break;
  1413		}
  1414	
> 1415		omap2_mcspi_set_mode(master);
  1416	
  1417		/* In single mode only a single channel can have the FORCE bit enabled
  1418		 * in its chconf0 register.
  1419		 * Scan all channels and disable them except the current one.
  1420		 * A FORCE can remain from a last transfer having cs_change enabled
  1421		 *
  1422		 * In multi mode all FORCE bits must be disabled.
  1423		 */
  1424		list_for_each_entry(cs, &ctx->cs, node) {
  1425			if (msg->spi->controller_state == cs && !mcspi->use_multi_mode) {
  1426				continue;
  1427			}
  1428	
  1429			if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
  1430				cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
  1431				writel_relaxed(cs->chconf0,
  1432						cs->base + OMAP2_MCSPI_CHCONF0);
  1433				readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0);
  1434			}
  1435		}
  1436	
  1437		return 0;
  1438	}
  1439
Mark Brown Feb. 7, 2024, 3:46 p.m. UTC | #2
On Wed, Feb 07, 2024 at 04:25:16PM +0100, Louis Chauvet wrote:
> Le 06/02/24 - 10:56, Mark Brown a écrit :

> this addition following the above paragraph, would it be clearer?
> 
>   [...] 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 [...]

Yes.

> > Note that you may not have to tell the hardware the same word length as
> > the transfer specifies, so long as the wire result is the same it
> > doesn't matter.

> If I understand correclty what you want is: given a message, containing 2
> transfers of 4 bits, with cs_change disabled, use the multi mode and send 
> only one 8 bits transfer instead of two 4 bits transfer?

> This seems very complex to implement, and will only benefit in very 
> niche cases.

I was hoping that the hardware supports more than 8 bit words, in that
case then it gets useful for common operations like 8 bit register 8 bit
data register writes (and more for larger word sizes) which are
relatively simple.  If it's just 8 bit words then yes, totally not worth
the effort.

> If I have to add this, I have to:
> - detect the very particular pattern "message of multiple transfer and 
> those transfer can be packed in bigger transfer"

Or just a single transfer with two words, it's trivial cases that don't
involve rewriting anything beyond lying about the word lengths that I
was thinking of.  Anything more involved should go in the core.
diff mbox series

Patch

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index fc7f69973334..ab22b1b062f3 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -133,6 +133,8 @@  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 {
@@ -258,10 +260,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);
 
@@ -285,7 +292,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);
 
@@ -1371,15 +1383,48 @@  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;
+	u32 speed_hz;
 
-	/* 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 the transfer content is only one word */
+		if ((bits_per_word < 8 && tr->len > 1) ||
+		    (bits_per_word >= 8 && tr->len > bits_per_word / 8))
+			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 */
+		if (!mcspi->use_multi_mode)
+			break;
+	}
+
+	omap2_mcspi_set_mode(master);
+
+	/* 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;