Some stuff arrived; Sunxi-linux power management woes.

Some cool stuff arrived in the post! First off, after a long wait, my NTC CHIP 9$ computer:

It's a neat little device which I preordered 2 of last year. It's fast enough, has integrated Wifi, and also Bluetooth 4.0. It also has 1 USB port, which I figure will be perfect for this 3G/4G dongle:

As written previously, I've been wanting a computer to live in my car and send some interesting telemetry to the internet from my OBD scanner; things like RPM, engine temperature and fuel consumption.
This will be a bit more convenient than the A20-OLinuXino-LIME I have been playing around with, due to the integrated radios and smaller size.

It would be good for the device to be always ready to go with no startup delay, so rather than just wiring the power into the ignition circuit of the car, I'd like it to take power directly from the battery, but go into a very low power mode when ignition is off. Perhaps powering itself up fully now and again to transmit interesting environmental information.

To achieve this, I need to make some use of Linux's power management facilities. I'm hoping the hardware in the Allwinner R8 SoC will support everything that's necessary.

The device comes with Debian preinstalled, and helpfully has its USB Slave port already configured as a serial console. So you can literally just plug this thing into a computer and go:

lee@terra:~$ sudo screen /dev/ttyACM0 115200
...
chip login: root
Password: 
...
root@chip:~# 

Power management is probably going to be one of the trickier things for me to get working, as I have relatively little experience with it. It looks like /sys/power/state contains a list of supported states. On my laptop, for example:

lee@terra:~$ cat /sys/power/state 
freeze mem disk
lee@terra:~$

Now lets try this on the CHIP:

root@chip:~# cat /sys/power/state 
root@chip:~#

Ok, not good. Lets check the kernel config:

root@chip:~# grep SUSPEND /boot/config-4.3.0-ntc 
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_SUSPEND_SKIP_SYNC is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARM_CPU_SUSPEND=y
root@chip:~#

That looks like I'd expect it to; how strange.
What's more, the Linux documentation claims that "freeze" should always be supported. Why is there nothing here?

Time for google. Looks like this was talked about in January and again in May on the CHIP forums. It doesn't work at the moment. Damn, not good!

I'll have a look at the kernel tree anyway, and try to get an idea about how this is all supposed to work.
Grepping around a bit teaches that the list from /sys/power/state is based on the contents of the pm_states array. This is initialized by suspend_set_ops, which is called from a number of places:

lee@terra:~/CHIP-SDK/CHIP-buildroot/output/build/linux-debian_4.4.11-ntc-1$ rgrep -I suspend_set_ops
...
arch/x86/platform/olpc/olpc-xo1-pm.c:		suspend_set_ops(&xo1_suspend_ops);
arch/arm/mach-davinci/pm.c:	suspend_set_ops(&davinci_pm_ops);
...
arch/arm/mach-omap2/pm.c:	suspend_set_ops(&omap_pm_ops);
arch/sh/kernel/cpu/shmobile/pm.c:	suspend_set_ops(&sh_pm_ops);
...
arch/blackfin/mach-common/pm.c:	suspend_set_ops(&bfin_pm_ops);
arch/unicore32/kernel/pm.c:	suspend_set_ops(&puv3_pm_ops);
arch/avr32/mach-at32ap/pm.c:	suspend_set_ops(&avr32_pm_ops);
...
drivers/firmware/psci.c:		suspend_set_ops(&psci_suspend_ops);
drivers/acpi/sleep.c:	suspend_set_ops(old_suspend_ordering ?
drivers/macintosh/via-pmu.c:	suspend_set_ops(&pmu_pm_ops);
...

There are a lot of lines from arch/arm/mach-XXX directories, showing how this array is initialized on boot for various different platforms, though none for the relevant one here - sunxi. The OLinuXino board I have is also sunxi and has this list populated, so there must be some other way that it works.
I grab the linux-sunxi source which I know is capable of building a kernel for the OLinuXino and look for answers.
Lo and behold, there's a file which calls this function: arch/arm/plat-sunxi/pm/pm.c.

This plat-sunxi directory doesn't seem to be present in mainline Linux (or the CHIP kernel, which derives from it), and after chatting with some people on IRC it becomes clear what the situation is; the sunxi-linux kernel's features are currently in the process of being brought into mainline Linux, and PM is something which hasn't yet been done. Simple as that.

It doesn't look too tricky, though there are a few peripherals which are touched as part of a standby sequence to actually make it happen, such as the DRAM controller and clock/PLL. These things would perhaps look different in mainline, and the whole thing is probably a pain in the neck to debug.

So my options are:

  • Stick with the OLinuXino for the project
  • Wait for someone who knows their stuff to mainline it
  • Try to do it myself
  • Try to use CHIP with the sunxi-linux kernel
  • Don't bother with the power saving thing, run from ignition circuit and put up with the startup delay and unexpected shutdowns.
  • Don't bother with the power saving thing, run from ignition circuit and add a LiPo battery to avoid problems.

I'll carry on looking through the sunxi-linux code as it's quite interesting, but I almost certainly won't get around to porting it myself.