GPIO poweroff in Linux?

I’m building a retro gaming handheld around the Radxa Zero. It has an external battery and power controller and a physical power switch. To make sure I have safe shutdown, it is necessary for the Zero to change the state of a given GPIO pin once the system shutdown is complete, so the external power controller will know that it’s safe to remove power from the Zero.

The Linux kernel supports this through the gpio-poweroff driver and device tree. The Raspberry Pi has a device tree overlay that does exactly this. I’ve been trying to implement something similar on the Radxa Zero but so far without success.

I’ve made a thread on the EmuELEC forum detailing my efforts. As things currently stand, I’ve been able to compille and boot a kernel that has the gpio_poweroff driver enabled and I’ve tried to enable it in the device tree, but at boot I get an error in dmesg saying:
[ 0.674882@1]- poweroff-gpio gpio-poweroff: gpio_poweroff_probe: pm_power_off function already registered
[ 0.674935@1]- poweroff-gpio: probe of gpio-poweroff failed with error -16
I’m not sure but my suspicion is that there is something in the Amlogic vendor kernel that implements platform-specific power management stuff that is registering a pm_power_off handler, which blocks gpio-poweroff. I’m hoping someone here either knows how to accomplish what I am trying to do, or is willing to help me get over this hump and get it working. Thanks in advance for any suggestions!

I got this working. For whatever it’s worth, this is on the 4.9 kernel. The pm_power_off() handler is in /drivers/firmware/psci.c, around line 561. I commented out this line:
pm_power_off = psci_sys_poweroff;
After recompiling the kernel, gpio-poweroff is working as expected. Obviously though, this is a hack and not the proper way to do what I’m trying to do. I found another thread discussing this issue on the ST platform, and a discussion on the ARM kernel listserv, indicating that hardware with PSCI should handle poweroff functions at the firmware level.

This is way outside the scope of anything I’ve ever dealt with before so I really have no idea what I’m talking about. I couldn’t find anything like documentation on the Amlogic firmware for S905Y2 or whether it implements something like gpio poweroff. But I did find that TrustedFirmware-A has been ported to the Meson G12A platform. The docs mention the S905X2 chip, but from my understanding, the S905Y2 is very similar. The docs also indicate there is support for basic PSCI functions including SYSTEM_OFF. So it seems like this should make it possible to implement a gpio-based power off at the firmware level like I’m trying to do. Has anyone tried TF-A on the Radxa Zero? Or does anyone know if the Amlogic firmware supports this?

1 Like

We will take a look at this. However, you can also try using upstream kernel instead of amlogic’s kernel. I think every hardware features is supported over there.

Thanks, I am going to experiment with that. I have been assuming that the proprietary gpu drivers will perform better than the panfrost driver, but I could be wrong.

I’m currently playing around with DietPi, which is based on Debian Bullseye and uses the mainline kernel build from Armbian (5.10.123). dmesg output tells me this, which is encouraging:

[ 0.000000] psci: probing for conduit method from DT.
[ 0.000000] psci: PSCIv1.0 detected in firmware.
[ 0.000000] psci: Using standard PSCI v0.2 function IDs
[ 0.000000] psci: MIGRATE_INFO_TYPE not supported.
[ 0.000000] psci: SMC Calling Convention v1.1

But I just don’t know enough about this subject to know what, if anything, I can do to have the firmware pull a specified GPIO pin low on SYSTEM_OFF through PSCI.

1 Like

You can use this as an example, and fill gpio-poweroff part in the similar looking section. You will need to keep the GPIO pin definition in the same style as meson-g12a-w1-gpioao-3.dts.
Then you need to compile this dts file into dtbo object, and the easier way is to compile it in the kernel source tree.

I am also interested in gpio-poweroff for a safe shutdown. I am using the Ubuntu 20.04 image. Much less experience than either of you. I notice when running “gpioinfo” that line 82 already seems to functioning as a shutdown pin. Is this accessible anywhere on the board? Can this also be mapped to a pin on the header?

I’ve had a chance to read through all your posts and try out everything you’ve done. I can get the shutdown signal by commenting out the psci.c line like you did.

The way I see it there are two ways to solve this problem. A custom one-time solution or trying to make something that everyone in the community can use.

In terms on custom one-time solutions, what you have shared works. It takes a little time but it works and I consider it to be valid. As long as you can guarantee the GPIO will cut power as PSCI won’t be there to do it.

If this were to be solved perfectly for the community, there probably should be some code in the TF-A to assert the GPIO pin but still use PSCI if the power is not cut. The problem with this is that we would need to define some way to disable the GPIO so that this product can still be used by everybody.

The other community solution would be to find some way to get gpio-poweroff and psci to work together, but I feel this is out of scope considering the widespread use of both of these drivers.

Either way this solution works for now. Only way we could help the community more is by sharing our repos with the modified kernel and building dt overlays to make it configurable.

What do you think?

I agree. I think I found how Hardkernel implements this in this series of patches:



Maybe this could be adapted.

1 Like

I’m also (super slowly) trying to make one of these, and wanna do similar.

If it helps I made some power discoveries on the pins here. Plus you can push ethernet through the OTG at about 500MB I think.

I think I asked some questions on the MEGAPI github page about their on/off switch (which is what I was using to power this) or maybe I didn’t … either way, I had a really nice little box there which could make a great cheap TV box, if I could do safe shut-down and control that horrific fan.

Also, have you tried anyuthing with libmraa, @theophile?

At the moment, I have a functioning battery powered setup using the RetroPSU board, a 5000mAh battery, and a simple-but-effective safe shutdown circuit consisting of two resistors, three diodes, and a SPDT slide switch. The hardware was repurposed from my original build that used the Raspberry Pi Zero W.

The SBC connections are made directly to the GPIO pins. I’ve tested a 4-port USB2 hub connected to the “middle” port and it has had no trouble powering a 5" LCD display, a USB gamepad, a keyboard, and USB flash drive.

I haven’t done anything with libmraa yet. I played around with Armbian at first but I prefer the “just works” approach (and QOL enhancements) of Batocera. That system uses squashfs for the root filesystem. While it can be modified, it’s more involved than with a normal Linux distro, so I’m trying to do as much as possible through the the device tree.

1 Like

You see, you say:

But I see:

:sweat_smile:

((( thanks, though, I will try to learn french so that I can catch up with all this :wink: )))

No, I would definitely not use jangablards in a circuit like this. Too much potential for quantum displacement, which could result in accidental interdimensional travel.

You can buy a safe shutdown module here: https://www.humblebazooka.com/product/raspberry-pi-safe-shutdown-board-for-helders-retropsu/
If you go this route, you should probably get the version for the Adafruit PowerBoost 1000c because I think some resellers still have the Adafruit board in inventory. The RetroPSU appears to be out of stock for the foreseeable future.

I have patches that make the safe shutdown work on the Radxa Zero but I haven’t published them anywhere yet because they’re very hacky.

1 Like

BTW where did you get the 4.9 kernel for Zero? I’m actually trying to get Amlogic 4.9 kernel working on Zero 2 (mainline is missing CSI/DSI/NPU support) and currently can’t get it to boot.

It was the EmuELEC kernel. I’ve since got these patches working on mainline.

I gave TF-A bl31 a try today and I could boot into U-Boot’s hush shell. No further Linux boot was tested. I’m not sure if there is any practical benefit though.

Thanks, that’s good to know. Incidentally, from my further adventures with U-Boot, it appears that PSCI is supported in the standard vendor firmware packages, it’s just a matter of Linux driver implementation. From what I can gather, the Linux kernel only allows one pm_power_off handler to be registered. The PSCI driver and the gpio-poweroff driver both try to register a pm_power_off handler, but PSCI usually registers it first, causing gpio-poweroff driver loading to fail.

My hacky solution that is working for me is to manually edit psci.c to remove the line that registers the pm_power_off handler so that the gpio-poweroff driver can register it. The better solution is to either patch gpio-poweroff or write an alternate driver that does not attempt to register the pm_power_off handler at all, but instead initiates a system off command via PSCI.

Per the patches above, I think Hardkernel has implemented the latter via a new driver called odroid-reboot. It adds a Kconfig entry that suggests it should work on meson g12a SoCs, but I haven’t yet experimented with it on the Radxa Zero. If/when I do, I’ll report my experiences in this thread. In the meantime, if anyone else has any comments on the subject, they’d be much appreciated.

Also of possible interest, it looks like Raspberry Pi’s solution to this problem was to modify the gpio-poweroff driver to force registration of the pm_power_off handler overriding the PSCI registration, but in such a way that the PSCI handler will be restored if the gpio-poweroff module is unloaded or if the gpio device doesn’t remove power after a specified timeout:

This is probably not the perfect solution, but it’s way better than my “comment it out” approach. I’ll give this a shot and report back.

The RPi patches apply cleanly to 5.10 and work perfectly. The gpio-poweroff driver works as expected without having to disable the PSCI pm_power_off() handler. Normal shutdown and poweroff procedure appears to work normally as well so there does not appear to be a downside. I’ll plan to submit a PR for this so others can take advantage of it.

2 Likes

The change is merged. @Stephen will upload prebuilt kernel shortly.