AnsweredAssumed Answered

i.MX53 eCSPI Stops Sending when CPU Idles

Question asked by TomE on Nov 10, 2015
Latest reply on Nov 12, 2015 by igorpadykov

We've got an i.MX53 board with chips connected to an eCSPI port that implement a 576-bit shift register. There are 16 three-colour multi-level LEDs connected to it.

 

So we need to send 72 bytes, or (way preferable) 18 32-bit words out the eCSPI port every 20ms or so.

 

When it works properly the burst of data looks like this:

 

TEK00025.PNG

That capture has the wrong labels on it. The Blue is the Chip Select. The Pink is the clock (all 576 of them) and the Yellow the the Data. The clock is about 1 MHz.

 

But most of the time it does things like this:

 

TEK00026.PNG

What happens in the above is that the eCSPI sends three words, waits for about a millisecond, sends 10 more, waits for about 2ms (in the above) and then sends the rest.

 

This happens with Freescale's "mxc_spi.c" driver in 2.6.35_maintain and in the the mainline "spi-mxc.c" driver in Linux 3.4.

 

I've got diagnostic code all over the driver and it is definitely pushing all 18 32-bit words into the transmit FIFO and telling it to start. The hardware is "all on its own", but it stops sending from the FIFO.

 

It completes the individual 32-bit transfers, stopping cleanly at the end of them.

 

I can get it to work properly by typing this in at a command prompt:  "while true; do true; done". That makes the CPU 100% busy and it never drops into its idle loop.

 

I can also get it to work properly by making the following single-line change to this file:

 

http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/arch/arm/mach-mx5/system.c?h=imx_2.6.35_maintain

 

diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c
index 2070341..336bf78 100644
--- a/arch/arm/mach-mx5/system.c
+++ b/arch/arm/mach-mx5/system.c
@@ -171,7 +171,8 @@ EXPORT_SYMBOL(mxc_pg_disable);
  * power mode as in enum mxc_cpu_pwr_mode.
  * May allow dynamically changing the idle mode.
  */
-static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF;
+// static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF;
+static int arch_idle_mode = WAIT_CLOCKED;
 /*!
  * This function puts the CPU into idle mode. It is called by default_idle()
  * in process.c file.


(Edit: the formatting messed up the first time I tried to paste the above in).

 

The above changes the CPU Idle mode from WAIT_UNCLOCKED_POWER_OFF to WAIT_CLOCKED.

 

Then the eCSPI completes the transfer properly. So it really does look to be related to whatever "WAIT_UNCLOCKED" means to the CPU.

 

And "WAIT_UNCLOCKED" is the default setting with no way to change it apart from editing the above file. I'd prefer something in /proc or in the .config file somewhere to editing code.

 

So it seems to me that when the CPU drops into its idle loop it stops the eCSPI from sending. It doesn't stop the "baud rate clock" which is set to 54MHz in this setup (I've also tried the default 12MHz clock in the normal config, but it does the same thing), but it must stop some other clock that prevents it from working its way through the FIFO. It looks like it has stopped a "control clock".

 

So does anyone know what the "system clock" or "control clock" is to to eCSPI and how to keep it running when the CPU idles?

 

Or any guesses on what is wrong if you don't think it is what I think it is?

 

I don't think anyone has pushed the eCSPI much due to the poor state of the 2.6.35 mxc_spi.c driver as detailed here:

 

https://community.freescale.com/message/585208#585208

 

Tom

Outcomes