imx8mm: Wake Linux from M4 core

cancel
Showing results for 
Search instead for 
Did you mean: 

imx8mm: Wake Linux from M4 core

136 Views
DavidC1
Contributor II

We are developing a product that has an i.MX8 mini SoC in it (imx8mm).

There is an IMU (MEMS motion sensor) connected to it, which we are reading using code running the M4 core.  We use RPMSG to communicate with the product's main application, running on Linux on the A53 cores.

We already know from experience that the flow of data from the M4 to Linux via RPMSG prevent Linux from going to sleep.  So we have code where we tell the M4 code to stop sending messages before we attempt to enter sleep.  We then send it a command to resume sending messages after waking from sleep.  This code works.  We can wake it from sleep using the same button/interrupt we use to power our device on and off.

The next step, however, is to enter/leave sleep based on lack of motion, as determined by the IMU chip.  I have already written the code so we can tell the M4 to stop sending messages until significant motion is detected, and then resume.  This works great for temporarily suspending the data flow from the M4 to Linux, but the resumption of data flow does not cause Linux to wake from sleep.

It seems that the RPMSG activity is sufficient to prevent Linux from going to sleep, but they are not sufficient to wake it from sleep.

I don't yet know the reason why, but I assume the interrupt used to signal RPMSG data to Linux isn't able to wake the A53 cores from sleep.  I assume I need to configure something in order to tell the IMX that its interrupt should be treated as a wakeup event, but I don't know what it is that I need to configure.

I already looked at application note AN12195 (low power audio) which talks about doing something very similar (for audio), but it doesn't include any code fragments.  It only has a high-level description and links to Git repositories for massive components (like the Linux kernel), without specifying where the relevant bits of code or patch files may be found.

Update:

We've recently done some more testing, connecting to the M4's debug console and adding trace messages and it seems that the M4 core is being put to sleep along with the A53 cores.

If we start our application immediately after Linux boots, and it goes to sleep soon afterward (we've been using a 10s timeout for testing), and then move the device very soon afterward, then it will wake from sleep.

If, however, we allow the device to be running long enough for Linux to finish its startup sequences (including starting a few kernel device drivers that don't seem to start until after 60 seconds), then no luck.  The device can not be awakened.  Messages on the M4 console and GPIO activity from the M4 application both stop as well.  It appears that the M4 has been put to sleep.  So only an external interrupt (e.g. our power button) can wake it.

Similarly, if our device goes to sleep before Linux completes its startup, but remains asleep until after the kernel drivers all start themselves, kernel messages indicate that part of the sleep process waits for the kernel drivers to start, and then it goes completely to sleep.  At which point, M4 activity also stops.

So the question is no longer how to get the M4 to generate an interrupt that will wake up Linux.  That seems to be working fine.  The question now is how to put the Linux cores (the A53) to sleep without putting the M4 to sleep.

Labels (1)
0 Kudos
7 Replies

85 Views
jimmychan
NXP TechSupport
NXP TechSupport
0 Kudos

65 Views
DavidC1
Contributor II

No luck with the 5.10.52 ("Hardknott") BSP distribution.

The person who posted the help to that thread shared code for the 4.14.98 ("Sumo") kernel, which works great, but his patch for the 5.4 kernel did not work when I tried to apply it to a 5.10 kernel.

It appears that I can no longer reply to that thread (it must be too old).  Can you help out?  Or can @terry_lv possibly help out here as he did in the original thread?  I am interested in getting this to work on 5.10.52 (right now) and later for 5.15 ("Kirkstone"), which we are evaluating for use in the future.

Attached are the patch files I (unsuccessfully) tried to use on my 5.10.52 kernel.  The "enable-a53-fast-wakeup..." patch file is for the imx-atf component.  The "imx8mm-gir-wakeup" patch is for the linux-imx component.

When I used these patches, not only could the M4 not wake the device, but it seems that my other method of waking it (the interrupt from our power-on button) also didn't work.  I was forced to use our device's force-power-off in order to recover.

0 Kudos

56 Views
terry_lv
NXP Employee
NXP Employee

Hi,

  Please refer to the AN13400:
https://www.nxp.com.cn/docs/en/application-note/AN13400.pdf

  The implementation mentioned in Chapter 5.3 might help you.

  Thanks!

Regards

Terry

0 Kudos

12 Views
DavidC1
Contributor II

I think I've finally got it working for real (again, for the Linux 5.10.52 "Hardknott" kernel).

Since the last patch files I uploaded, I made the following changes:

  • Get rid of the functions in mx8_mu.c.  As you suggested, I wrote (new and better) versions in imx-mailbox.c
  • Set the GIE flag to enable the GP interrupt.  Do it in imx_mu_probe
  • In imx_mu_isr, if we receive an interrupt that isn't being handled by other code (that is, not for messaging), check to see if there's an unhandled GIR interrupt.  If so, clear the flag and let Linux know that it has been handled.  (The patch file has a warning message in there for debugging, which I'll remove once I'm a bit more confident that the code works.)

@terry_lv: Please review the two patch files and let me know if I'm doing anything wrong that I should change.  It seems to work, but I'm still very new to Linux kernel development so I might have missed something important.

To everybody else reading this, I hope it helps you with your problems.

0 Kudos

16 Views
DavidC1
Contributor II

After a lot of study, I am starting to understand more.

It appears that the imx-mailbox.c file already loads the DeviceTree object when the driver starts up (via the .of_match_table field in the imx_mu_driver struct).  So the imx_mu_probe function already has it, included in the paltform_device pointer it is given.

The existing call to devm_platform_ioremap_resource appears to fetch the correct address, and maps it onto virtual address space (hence the reason why dumping the pointer doesn't show 0x30aa0000, but a different address).

I added this line just before the call to pm_runtime_enable():

MU_EnableGIRInt(priv->base, 0x8);

 

With this, I can wake from sleep once, but not again, because I'm not clearing the interrupt.  So my next step is to figure out where to add the call to MU_ClearGIRInt().

Attached are the two patches I've got so far.  Patch 0001 is for ATF.  Patch 0002 is for Linux.

Please take a look and let me know if I'm doing this right.

0 Kudos

25 Views
DavidC1
Contributor II

Hi, Terry,

I'm re-posting my reply because my previous one got deleted for some reason.

AN13400 explains what needs to be done at a register level, but it doesn't talk about how to patch the Linux kernel in order to implement the changes, which is where I need help.

I did find AN13340 (code here: https://source.codeaurora.org/external/imxsupport/cortex-M4_Cortex-A53_low_power_use_cases/tree/), which is designed for use with the 5.10 Linux kernel.  It was able to help me with half the solution.  Based on it, I was able to create a patch for the ATF code (attached).  With this, the M4 keeps running while the A53 sleeps, but additional work is needed to enable the interrupt that the M4 generates in order to wake the A53.

In another discussion thread (https://community.nxp.com/t5/i-MX-Processors-Knowledge-Base/M4-Low-Power-Demo-on-i-MX8MM/ta-p/110110...), you provided working patches for the 4.14 Linux kernel.  They work great for me, Thanks.

You discuss patches to the imx_mailbox.c source file in order to enable the wakeup interrupt, but the kernel 5.4 patches you provide do not work on my 5.10 kernel (and I'm not sure how they would work on 5.4 either).

In following your advice, however, I have ported the two MU_ClearGIRInt and MU_EnableGIRInt functions.  I have two questions, however, which I'm hoping you can answer:

  • When calling MU_EnableGIRInt from the imx_mu_probe() function, where do I get the base address?  Should I hard-code the constant 0x30aa0000?  Should I read it from the DeviceTree?  Is it already available somewhere?
  • I see (from the 4.14 kernel patches), that I need to call MU_ClearGIRInt in the MU interrupt handler, in order to clear the GIR bit.  Should I do this from imx_mu_isr()?  If not, where?  And where should I insert the call?

Finally, the MU base address is in the DeviceTree, but I don't know how to read it correctly.  I tried the following code:

struct device_node *np_mu;
void __iomem *mu_base;
...
np_mu = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-mu");
mu_base = of_iomap(np_mu);
pr_info("MU base is 0x%px\n", mu_base);

 

but it did not print the expected value (0x30aa0000).  Instead, it printed 0xffff80001b1b0000.

So am I reading the value incorrectly?  If so, how should I read it?

Thank in advance,

-- David

0 Kudos

73 Views
DavidC1
Contributor II

Thanks much.  The solution presented there works great with the 4.14 (Sumo) kernel.

I will now try and apply it to the 5.10 (Hardknott) kernel.  The solution doesn't mention this version, but it does provide alternative code for 5.4.  Hopefully those changes will work.  If not, I may have to ask for additional help.

0 Kudos