Wherein I update my Turing Pi 2 boards to a new firmware.

During the migration of my Homelab to a fleet of Raspberry Pi 4, I bought two Turing Pi 2 boards and put eight Raspberry Pi CM4 8GB into them. You can read more about my setup here.

The board has a nice Board Management Controller (BMC). It is an Allwinner SoC with 128 MB of RAM and 128 MB of flash for the OS. It’s running an embedded Linux distribution. This BMC implements a few interesting features:

  • Turning power on/off for each individual node
  • Connecting to the serial console of each of the nodes
  • Flashing each of the nodes if it has internal storage, like Pi CM4 with eMMC

There is also an internal Ethernet switch chip, which connects the four nodes and two external 1GbE ports for external connectivity. Sadly, that chip is not really controllable yet, even with the newest firmware. So it’s still only usable as a dumb switch.

As originally delivered, the firmware was perfectly workable, I’ve been running my boards with it for two years. But it was also a bit problematic, as it provided a web UI without any authentication at all. And you could flash nodes via it and turn them on and off.

The v2 firmware I’m installing in this blog post has proper authentication, and adds support for a CLI tool which can be used to control the board remotely, in addition to the web UI.

The new version also adds support for the Turing Pi RK1. That’s an SBC based on the RK3588 SoC, developed by the same people who designed the Turing Pi 2 board. And I’ve got one of those laying around. But more on that later.

Firmware update

I was still on the original v1 firmware and needed to update to the most recent v2.1. One note: For some reason, their docs point to this part of their website from the docs, but the newer firmware versions are only available in their GitHub repo.

For the update, I followed these docs. While the new version of the firmware supports flashing via the web UI, this update from v1 to v2 needs to be done via the SD card.

But before I could get started, I had to solve the Homelab uptime problem. As I’m running a very serious operation here, I could of course not tolerate any downtime for any services. But at the same time, this update couldn’t be done online, so I would have to take down four of my CM4. Meaning 16 cores and 32 GB of RAM would be temporarily unavailable. And while my Homelab is intentionally designed with some slack, I didn’t have quite that much slack left. So I went to my Ceph hosts, specifically the largest, which has 32 GB of RAM. Which it currently does definitely not need. Here is what my three Ceph hosts look like under normal operation:

ceph1:
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests       Limits
  --------           --------       ------
  cpu                3 (75%)        0 (0%)
  memory             11412Mi (72%)  14624Mi (92%)
ceph2:
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests       Limits
  --------           --------       ------
  cpu                3400m (85%)    0 (0%)
  memory             11824Mi (77%)  15648Mi (102%)
ceph3:
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests       Limits
  --------           --------       ------
  cpu                3150m (39%)    0 (0%)
  memory             10276Mi (32%)  14012Mi (44%)

So at least going by the limits, two of them were almost full already. But ceph3 still had enough unused resources to hold a few Pods during the downtime.

So I removed the NoSchedule taint from it like this:

kubectl taint nodes ceph3 homelab/taint.role=ceph:NoSchedule-

With that, it would be allowed to run non-Ceph Pods.

I then drained the four CM4 on the first board:

kubectl drain --delete-emptydir-data --force --ignore-daemonsets worker1 worker2 worker3 worker4

And finally shut them all down:

ansible "worker1:worker2:worker3:worker4" -a "systemctl poweroff"

I will describe the effects and show some metrics about the shutdown’s impact on my cluster later in this post.

To prepare the update, I needed to put the firmware on an SD card. Here are the commands to do that:

wget https://github.com/turing-machines/BMC-Firmware/releases/download/v2.1.0/tp2-firmware-sdcard-v2.1.0.img
dd if=tp2-firmware-sdcard-v2.1.0.img of=/non-existant-path bs=1M status=progress

The of parameter should then point to the SD card. Point it to the device, e.g. /dev/sde, not /dev/sde1.

With that done, I opened the board’s schematics to hunt for the SD card slot:

A schematic of the top side of the Turing Pi 2 board. The important part is that there's no SD card slot anywhere on it. What follows is a more detailed description, but I only provide it for completeness' sake, it is not relevant for the rest of the post and you can safely skip it. In the center of the board are the four slots for the compute modules. Each of them has a fan header next to it. They're connected to different peripherals on the board. The top slot is connected an mPCIe slot. The second node is connected to another mPCIe slot. Node 3 has connections to two SATA3 ports. Node 4 is connected to two USB 3.0 ports. In addition, there is a GPIO 40-pin connector and a slot for a CR2032 battery. Power is supplied via a standard 24-pin ATX connector in the bottom left corner. Along the lower right edge are several external ports, from top to bottom: 1x CM4 USB connector. 1x HDMI display connector. 2x 1GbE RJ45 jacks. 2x USB 3.0 connectors. On the upper edge are some internal connectors for UART to the nodes and the BMC. Along the left edge are some more internal connectors, namely 2x SATA 3 ports, 2x internal USB 3.0 ports, the front panel IO header and a DSI header.

No SD card slot on the top of the boards. From https://docs.turingpi.com/docs/turing-pi2-specs-and-io-ports

Sadly, the SD card slot is not on the top, but instead it’s on the bottom:
A schematic of the bottom side of the Turing Pi 2 board. There's a lot less to see here. Along the left side are for M.2 NVMe slots for storage. And to the right of them, quite a bit away from the edge of the board, is a lone SD card slot.

There is the SD card slot. From https://docs.turingpi.com/docs/turing-pi2-specs-and-io-ports

The slot is entirely inaccessible while the board is mounted in a case.

So I had to do the one thing about Homelabbing I actually don’t enjoy that much: Touching hardware. I’m still thinking that at some point, I should click myself something roughly equivalent to my Homelab at a large cloud provider and see how expensive it really is.

Here is the board still in the case:

A picture of the TP2 board sitting in a 3U rack case. It has four Raspberry Pi CM4 modules in it. It's connected with a 24-pin ATX connector to a normal ATX power supply. Also connected is part of the front panel header and the internal USB connector. In addition, there's a Noctua fan controller sitting there, connected to two 120mm Noctua fans and powered by one of the SATA rails from the power supply. It is all extremely dusty. As in: You couldn't just write your name in it. You could write the entirety of The Prince in it, with multiple layers.

One of the boards in its 3U rack case. Dust left in for realism.

Dusted after taking the picture, so you all know its real. 😅

I was a bit apprehensive about taking the case out of the rack, to be honest. This particular case was mounted before I figured out how rack rails work. And I was pretty brutal with the ones for this case. I didn’t see any problem with taking it out. But I was a bit worried whether I would be able to put it back in again. Luckily, it all worked out at the end.

With the board removed from the case, I was finally able to access the SD card slot:

A picture of the backside of the board. It shows exactly what the schematics above showed: Four M.2 slots for NVMe SSDs and a single lone SD card slot, definitely too far away from the edge of the board to be accessible while the board is mounted in a case.

There’s the SD card slot.

I’ve finally found the place to put the SD card. This was already a lot more work than I had initially thought. But from hereon out, everything went quite smoothly. I connected the board’s UART to my trusty USB-to-Serial adapter and launched minicom:

minicom -b 115200 -D /dev/ttyUSB0

After starting the board, I was greeted with this text on said console:

 _____ _   _ ____  ___ _   _  ____
|_   _| | | |  _ \|_ _| \ | |/ ___|
  | | | | | | |_) || ||  \| | |  _
  | | | |_| |  _ < | || |\  | |_| |
  |_|  \___/|_| \_\___|_| \_|\____|

This utility will perform a fresh installation of the Turing Pi 2 BMC firmware.

Note that this will ERASE ALL USER DATA stored on the Turing Pi 2 BMC, thus
restoring back to factory defaults. Do NOT proceed unless you have first backed
up any files that you care about!

If you wish to confirm the operation and proceed, either:
1) Type 'CONFIRM' at the below prompt
2) Press one of the front panel buttons (POWER or RESET), or the KEY1 button on
   the Turing Pi 2 board itself, three times in a row

If you are here in error, please remove the microSD card from the Turing Pi 2
board and reset the BMC.

Type "CONFIRM" to continue:

I typed CONFIRM here as instructed, but the flashing could also be started by pressing a button on the board itself 3x in quick succession. So a serial connection is not strictly necessary. The flashing went pretty quickly, in under a minute, with relatively little output:

INFO: Legacy Allwinner boot code has been found and erased
INFO: Legacy Allwinner boot code has been found and erased
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: AWNAND SIMULATE_MULTIPLANE layout detected, performing migration
INFO: Legacy Allwinner boot code has been found and erased
INFO: Legacy Allwinner boot code has been found and erased
[+] DONE: Please remove the microSD card and reset the BMC.

As instructed, I removed the SD card and rebooted the board. I was immediately greeted by some Linux boot output and then a login prompt. Everything had worked nicely.

I needed to do a few little adaptions to the configuration though. First, the MAC had changed, so I needed to update it in my DHCP static leases. At least the MAC is now static by default, instead of being generated anew every time the board boots, as with the previous firmware. Then I set the hostname in /etc/hosts and /etc/hostname and updated the root password. Finally, I created a non-root user:

  • mkdir -p /home/myuser
  • adduser -s /bin/bash -D myuser
  • Then I went into /etc/shadow and replaced the ! with a * in the password field. No idea why I had run with the -D option initially.

Then I could switch to the user and enter a few SSH keys. Finally, I also had to change the SSHD configuration. Because by default, it allows password logins and logins of root. I added/changed the following configs:

  • PubkeyAuthentication yes
  • PermitRootLogin no
  • PasswordAuthentication no
  • AllowUsers myuser

The restart of SSHD was a bit tricky. There’s a script they tell you to use:

/etc/init.d/S50sshd restart

The problem is that that’s a shell script which first stops SSHD and then starts it again. As you might imagine, that doesn’t go too well when executed via SSH. While the stop action is still run, the terminal is disconnected after that, because SSH is gone. So the start command is never run.

But that’s it already. After those steps I was able to put the board back into the case and start with the next one.

With that done too, the only thing left was to add back the taint to my Ceph node so it’s no longer used for non-Ceph stuff:

kubectl taint nodes ceph3 homelab/taint.role=ceph:NoSchedule

Same command as removing the taint, just without the - at the end.

Results

Well, first of all: Most things still worked. Emphasis on most. The one thing which no longer seems to work is connecting to the node’s serial consoles. It just outputs garbage. And it seems that’s because the new BCMd opens the serial console devices as well. So you now can’t open them anymore when SSH’d into the board. Which really isn’t ideal.

But onto the good things. First, there’s been a rework of the UI. Here’s an example of the old UI:

A screenshot of the old Turing Pi 2 web UI's power tab. It shows four selector switches for turning power on and off for each node and a Submit button at the bottom.

The old Turing Pi 2 v1 web UI

And here’s the equivalent page on the new UI:
Another screenshot of a similar page. the theme is now dark. Each node has two additional fields the user can set, one for the node name and one for the node module type. In addition to the previously present power toggle, there's now also a restart button. Also in contrast to the previous version, the UI is now labeled in German.

The new Turing Pi 2 web UI

I like the new style and the fact that there’s now a dark theme. Plus, the restart buttons are nice. Previously, when I needed to do a hard reset of one of the nodes, I had to first switch it off and then switch it back on again. In the future, that will be one click. In addition, this UI now has proper authentication, where the previous version had exactly none. It uses the accounts of the BMC system, there’s not separate user management for the web UI.

In addition to this update of the UI, there’s now an HTTP API and a CLI tool for using it, the tpi tool. It can do all of the things the web UI can, and then some. For example, this command will show the serial console output of node 2:

tpi uart --host my.turingpi --user root --node 2 get

This functionality is the reason that the serial consoles are useless when you’re actually logged into the BMC, see this issue.

Finally: The new firmware has support for flashing and using the Turing RK1. An RK3588-based SBC that can be plugged into the Turing Pi 2 boards. I should be excited about it. I bought one of them a while ago, with 32 GB of RAM. It would be really cool to use these as an upgrade path for my Homelab. The RK3588 is a good chip and makes a nice Homelab host with 8 cores. But there’s exactly zero broad support for the chip in Linux. There is an Ubuntu that’s supposed to work, ubuntu-rockchip. But the maintainer stepped back from it about a year ago. So what am I supposed to do? Run a chip with an outdated kernel, running services accessible from the Internet? I don’t think so.

So very likely, I will keep it as a high-tech paperweight. What do you mean I sound miffed with my past self for dropping money on a piece of hardware with shaky software support? Naaah, not at all. 😒

How the Homelab reacted

Before ending this post, I’d like to do a quick section about what the Homelab looked like during the periods where I took one of the Turing Pi boards out of the cluster. Those Pi CM4 8GB modules in the two Turing Pi 2 boards are my main worker nodes. I’ve also got one more node, an older x86 SBC I keep around for apps which don’t support aarch64. So with taking out one of the boards, I lose 16 cores and 32 GB of RAM. And my Homelab didn’t really bat an eye at that. I’ve already got a bit of slack in the resources. The idea being that I can take out a few nodes for maintenance, e.g. reboots during the regular host updates, without having to take down the entire Homelab.

So there wasn’t much of a change in the k8s cluster and my apps. Temporarily allowing Pods onto my largest Ceph node took care of that. But there was a reduction in the overall power consumption of the Homelab.

A screenshot of a Grafana time series chart with one plot. It shows the power consumption of my Homelab over the time period from 2025-12-12 to 2025-12-18. The plot shows an average power consumption between 155 and 165 W. Some high spikes go up to over 200 W, but those are only very short spikes. The only exception is the period between the 21:00 on the 15th and 17:30 on the 16th. In that period, the power consumption goes down to about 140 - 150 W, before going aback to the previous values.

Power consumption of my entire Homelab

This plot shows that one full board with 16 cores and 32 GB worth of Pi 4 consume somewhere around 20 - 25 W under normal conditions. But there was one effect I will have to think about a bit more:

A screenshot of the same chart, but now zoomed into the time when I first disconnected the board from power entirely, pulling the power plug. It goes from 19:10 to 23:00. At the beginning, the consumption hovers around 155 to 160 W. Then, at 21:04, it drops a bit to 146 W. Another drop happens around 21:16, down to 136 W. After that drop, the power consumption mostly stays around that value.

Power consumption of my Homelab, zoomed in.

In the plot, I switched off the four Pi CM4 on the board around 21:04, resulting in the initial drop from 156 W to about 146 W. Then, at about 21:16, I pulled the power plug from the PSU, resulting in another drop to 138 W. Which honestly looks a bit weird? By that time, the only thing powered on were two 120mm fans on pretty low revolutions and the BMC itself, which is a piddly Allwinner SoC and really shouldn’t eat almost 10 W. The only thing I can come up with is: Could this be the fact that the power supply is a 550 W unit? And it’s running at very low power draw and is terribly inefficient at that point?

Might warrant some more investigations.

And just in case I don’t find time for another post before it: Happy Christmas to all of you who celebrate. I hope you find at least a modicum of peace and quiet.