wip: duet (2)
This commit is contained in:
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
ChromeOS
|
||||
rootfs
|
||||
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ml-auto mr-auto mt-2 mb-2 p-2 rounded-xl bg-slate-100 sm:max-w-[85%] max-w-[95%] overflow-x-auto slot">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="ml-auto mr-auto mt-2 w-fit max-w-[80%] slot-desc">
|
||||
<slot name="description" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.slot :deep(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 18px;
|
||||
}
|
||||
.slot :deep(th),
|
||||
.slot :deep(td) {
|
||||
border: 1px solid #cbd5e1;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
.slot :deep(th) {
|
||||
background-color: #e2e8f0;
|
||||
font-weight: 600;
|
||||
}
|
||||
.slot :deep(tr:nth-child(even) td) {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.slot-desc > * {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
+238
-74
@@ -8,7 +8,7 @@ tags:
|
||||
- chromebook
|
||||
---
|
||||
|
||||
I own a Lenovo IdeaPad Duet Chromebook, a ChromeOS tablet-laptop.
|
||||
I own a Lenovo IdeaPad Duet Chromebook, a ChromeOS 2-in-1 ARM64 tablet.
|
||||
I had been running ChromeOS, then postmarketOS, which suddenly broke.
|
||||
Time for some firmware hacking to try and get Ubuntu to run there!
|
||||
|
||||
@@ -17,36 +17,36 @@ Time for some firmware hacking to try and get Ubuntu to run there!
|
||||
## Lenovo IdeaPad Duet
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/lenovo-ideapad-duet.jpg"}
|
||||
*The Lenovo Ideapad Duet, 10.1" tablet, with a plug-and-play attachable keyboard, 1920x1200 screen, Mediatek MT8183 SoC, 4GiB RAM*
|
||||
*The Lenovo IdeaPad Duet: a 10.1" tablet with a plug-and-play detachable keyboard, a 1920x1200 screen, an ARM64 MediaTek MT8183 SoC and 4 GiB of RAM*
|
||||
(Image credits: [Lenovo](https://www.lenovo.com/fr/fr/p/laptops/lenovo/chromebooks/lenovo-ct-x636/zziczctct1x))
|
||||
::
|
||||
|
||||
I bought the device a while ago, during my first year at ENS Rennes.
|
||||
It was cheap (~100€), used but in really nice condition. I love 10" laptops for their portability, and this one could even work with a stylus for note-taking, a workflow I wanted to try (turns out it wasn't really for me).
|
||||
|
||||
I also had never used ChromeOS, and was really curious.
|
||||
At the time I was developing Android applications, and being able to natively code and run the app on-device sounded exciting.
|
||||
It turned out disappointing because the performance in ChromeOS was not really there, and I had to run everything through a container which felt awkward. I silently stopped using the device.
|
||||
I had also never used ChromeOS, and was really curious.
|
||||
At the time I was developing Android apps, and being able to code natively and run the app on-device sounded exciting.
|
||||
It turned out to be disappointing because the performance in ChromeOS was not really there, and I had to run everything Linux through a container, which felt awkward. I quietly stopped using the device.
|
||||
|
||||
A while later, I realized that [postmarketOS](https://postmarketos.org/) was compatible. This meant a real Linux distribution, based on [Alpine Linux](https://alpinelinux.org/), with any DE (GNOME, KDE, etc) and proper Linux tooling and performance. I had to try.
|
||||
A while later, I realized that [postmarketOS](https://postmarketos.org/) supported it. That meant a real Linux distribution, based on [Alpine Linux](https://alpinelinux.org/), with any DE (GNOME, KDE, etc) and proper Linux tooling and performance. I had to try.
|
||||
|
||||
Installing postmarketOS was really easy, thanks to the effort they put into the [wiki](https://wiki.postmarketos.org/wiki/Lenovo_IdeaPad_Duet_Chromebook_(google-krane)) and [installation guide](https://wiki.postmarketos.org/wiki/Category:ChromeOS). Basically: put the device in developer mode, download an image, write it to a USB stick, and boot from it using the developer-mode menu. You then land in a live postmarketOS image you can use to install to the eMMC.
|
||||
Installing postmarketOS was really easy, thanks to the effort they put into the [wiki](https://wiki.postmarketos.org/wiki/Lenovo_IdeaPad_Duet_Chromebook_(google-krane)) and the [installation guide](https://wiki.postmarketos.org/wiki/Category:ChromeOS). Basically: put the device in 'developer mode', download an image, write it to a USB stick and boot from it using the 'developer mode' menu. You then land in a live postmarketOS image you can use to install to the eMMC.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/duet-depthcharge.jpg"}
|
||||
*The ChromeOS firmware 'developer mode' menu, which allows you to select boot media, USB or internal storage. Mine is in French. 'Start legacy BIOS' does not do anything here; I suspect this only works on x86 Chromebooks, and they just reused the same firmware.*
|
||||
*The ChromeOS firmware 'developer mode' menu, which allows you to select boot media, USB or internal storage. Mine is in French. 'Start legacy BIOS' does nothing here; I suspect this only works on x86 Chromebooks, and they just reused the same firmware.*
|
||||
::
|
||||
|
||||
So far, so good; and they even have images with preinstalled DEs like GNOME. I'm a heavy GNOME user on my main computer, so I went with that one. Unfortunately, this turned out to be a mistake.
|
||||
GNOME can be quite resource-hungry, which didn't suit the device's weak CPU and only 4 GiB of RAM. It was a bit slow, and there was too much friction to make it really usable.
|
||||
I also find GNOME ill-suited for a "minimalist" workflow - it tends to go all out. Thinking about it now, a tiling window manager with a terminal-centric workflow would have surely been better for the device.
|
||||
So far, so good: they even have images with preinstalled DEs like GNOME. I'm a heavy GNOME user on my main computer, so I went with that one. Unfortunately, it turned out to be a mistake.
|
||||
GNOME can be quite resource-hungry, which didn't suit the device's weak CPU and 4 GiB of RAM. It was a bit slow, and there was too much friction for it to be really usable.
|
||||
I also find GNOME ill-suited to a "minimalist" workflow - it tends to go all out. Thinking about it now, a tiling window manager with a terminal-centric workflow would have surely been better for the device.
|
||||
|
||||
I kept using it anyway from time to time. Eventually I updated to postmarketOS 26.06 - and then the device refused to reboot.
|
||||
I kept using it from time to time anyway. Eventually I updated to postmarketOS 26.06, and then the device refused to reboot.
|
||||
|
||||
I managed to reboot from the old 25.12 version, but even writing 26.06 on a USB key and booting from it does not seem to work. Something must have changed between the two versions that silently breaks booting on the Duet. While investigating that, I realized that all the necessary drivers were now present in the mainline kernel. I also now [work at Canonical on Ubuntu development, doing bring-up of RISC-V devices](https://vhaudiquet.fr/blog/joining-canonical-riscv/). Given the state of the Duet, an Ubuntu bring-up seemed really possible. So... I have a weekend. Let's do it!
|
||||
I managed to boot the old 25.12 version, but even writing 26.06 to a USB stick and booting it does not seem to work. Something must have changed between the two versions that silently breaks boot on the Duet. While investigating, I realized that all the necessary drivers were now in the mainline kernel. I also now [work at Canonical on Ubuntu development, doing bring-up of RISC-V devices](https://vhaudiquet.fr/blog/joining-canonical-riscv/). Given the state of the Duet, an Ubuntu bring-up seemed genuinely feasible. So... I have a weekend. Let's do it!
|
||||
|
||||
## Installing Ubuntu?
|
||||
|
||||
At this point, I have almost no idea how postmarketOS boots on the device, what the boot flow looks like, and if anything will work with Ubuntu. One of the easiest ways to get 'something that looks like Ubuntu' is to replace the postmarketOS 26.06 rootfs with an Ubuntu rootfs. So that's what I did.
|
||||
At this point, I have almost no idea how postmarketOS boots on the device, what the boot flow looks like, and whether anything will work with Ubuntu. One of the easiest ways to get 'something that looks like Ubuntu' is to replace the postmarketOS 26.06 rootfs with an Ubuntu rootfs. So that's what I did.
|
||||
|
||||
I booted into my postmarketOS 25.12 USB stick. First, I inspected the state of the internal eMMC storage:
|
||||
|
||||
@@ -65,7 +65,7 @@ An easy way to then install the Ubuntu rootfs is to just replace that one. Which
|
||||
# rm -rf /mnt/*
|
||||
Removing all files on the old postmarketOS rootfs
|
||||
# curl -L -O https://cdimage.ubuntu.com/.../ubuntu-base-26.04-base-arm64.tar.gz
|
||||
Downloading the Ubuntu 'base' image, minimal Ubuntu rootfs
|
||||
Downloading the Ubuntu 'base' image, a minimal Ubuntu rootfs
|
||||
# tar -C /mnt -xzf ubuntu-base-26.04-base-arm64.tar.gz
|
||||
Extracting that base Ubuntu rootfs at /dev/mmcblk0p3
|
||||
```
|
||||
@@ -74,53 +74,53 @@ An easy way to then install the Ubuntu rootfs is to just replace that one. Which
|
||||
With that, I was ready to `chroot` into `/mnt` to enjoy my new Ubuntu system.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/ubuntu-chroot.jpg"}
|
||||
*Chrooted from postmarketOS 25.12 USB stick, into /dev/mmcblk0p3 with the new Ubuntu rootfs. I even installed some packages, like fastfetch! Notice the 6.12.87-mt81 kernel: it is the postmarketOS kernel from the USB stick.*
|
||||
*Chrooted from the postmarketOS 25.12 USB stick into /dev/mmcblk0p3 with the new Ubuntu rootfs. I even installed some packages, like fastfetch! Notice the 6.12.87-mt81 kernel: that's the postmarketOS kernel from the USB stick.*
|
||||
::
|
||||
|
||||
Ok, this is all very nice, but living my life inside a chroot forever and having to boot from USB just to mount the internal storage doesn't feel great at all. Time to see if we can boot into this new rootfs! I expected this to fail, as I assumed something was wrong with the new postmarketOS 26.06 kernel; but to my surprise it worked flawlessly (which means the 26.06 issue must have been in the rootfs startup programs, silently crashing something).
|
||||
Ok, this is all very nice, but living inside a chroot forever and having to boot from USB just to mount the internal storage doesn't feel great at all. Time to see if we can boot into this new rootfs! I expected this to fail, since I assumed something was wrong with the new postmarketOS 26.06 kernel, but to my surprise it worked flawlessly. Which means the 26.06 issue must have been in the rootfs startup programs, silently crashing something.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/ubuntu-rootfs-booted.jpg"}
|
||||
*Booted from internal storage into the Ubuntu rootfs on /dev/mmcblk0p3. Notice the new 6.18.44-mt81 kernel: it is the postmarketOS kernel from the 26.06 installation, on the /dev/mmcblk0p1 or p2 boot partitions.*
|
||||
*Booted from internal storage into the Ubuntu rootfs on /dev/mmcblk0p3. Notice the new 6.18.44-mt81 kernel: that's the postmarketOS kernel from the 26.06 installation, on the /dev/mmcblk0p1 or p2 boot partitions.*
|
||||
::
|
||||
|
||||
As you can see, the device now calls itself `localhost`, so I'd have to do some setup to finish configuration; but I already had created my user account in the chroot before. Another issue: the new rootfs lacks the firmware for the postmarketOS kernel, so Wi-Fi no longer works. A simple fix is to take the 26.06 image, extract the `/lib/firmware/6.18.../*` tree, and copy it into the rootfs, which would restore Wi-Fi.
|
||||
As you can see, the device now calls itself `localhost`, so I'd have to do some setup to finish configuration; but I had already created my user account in the chroot before. Another issue: the new rootfs lacks the firmware for the postmarketOS kernel, so Wi-Fi no longer works. A simple fix is to take the 26.06 image, extract the `/lib/firmware/6.18.../*` tree and copy it into the rootfs, which would restore Wi-Fi.
|
||||
|
||||
But that means staying with the postmarketOS kernel, unable to update. I did not want that, I want full Ubuntu running, including the kernel.
|
||||
|
||||
So I did the simplest thing: I installed the `linux-generic` package from the archive. It copied `vmlinuz` and `initrd` into `/dev/mmcblk0p2`, the `/boot` partition. I also copied the upstream dtb for the device into the `/boot` partition, so I could hardcode it in the kernel command line if needed. I expected everything to crash, nothing to work, as I did not know the bootloader, and thought the kernel would not get the correct DTB. I rebooted.
|
||||
So I did the simplest thing: I installed the `linux-generic` package from the archive. It copied `vmlinuz` and `initrd` into `/dev/mmcblk0p2`, the `/boot` partition. I also copied the upstream DTB for the device into the `/boot` partition, so I could hardcode it on the kernel command line if needed. I expected everything to crash, nothing to work, since I didn't know the bootloader and assumed the kernel wouldn't get the right DTB. I rebooted.
|
||||
|
||||
To my surprise, the machine booted normally. Even more so: I ran `fastfetch` again, **everything** was identical. **Including the kernel version.**
|
||||
To my surprise, the machine booted normally. Better yet: I ran `fastfetch` again and **everything** was identical, **including the kernel version.**
|
||||
|
||||
Wait, what? I overwrote that kernel in the `/boot` partition. Is that partition not used at all?
|
||||
Wait, what? I had just overwritten that kernel in the `/boot` partition. Is that partition not used at all?
|
||||
|
||||
## Using Ubuntu Kernel
|
||||
## Using the Ubuntu kernel
|
||||
|
||||
### Understanding the boot flow
|
||||
|
||||
Clearly, I needed to take a step back and start learning/understanding how the machine boots, as trying random stuff was not going to work anymore. So I read some resources, talked with Claude, giving him the URLs and asking for a boot flow explanation.
|
||||
Clearly, I needed to take a step back and actually understand how the machine boots, as trying random stuff was not going to work anymore. So I read some resources and talked with Claude, giving him (it?) the URLs and asking for a boot flow explanation.
|
||||
|
||||
Turns out the boot flow is a bit complicated for Chromebooks. Here are schematics that Claude generated when explaining the chain for me. I find them quite clear.
|
||||
Turns out the boot flow is a bit complicated on Chromebooks. Here are the schematics that Claude generated when explaining the chain to me. I find them quite clear.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/duet_firmware_chain.svg"}
|
||||
Firmware boot chain for Chromebooks. The boot ROM contains the FSBL, that loads Coreboot, which has [upstream support for the Duet](https://github.com/coreboot/coreboot/blob/main/src/mainboard/google/kukui/panel_krane.c). Then, Coreboot loads the Arm Trusted Firmware (not relevant to this analysis), which then loads [Depthcharge](https://chromium.googlesource.com/chromiumos/platform/depthcharge/), the bootloader for ChromeOS devices.
|
||||
Firmware boot chain for Chromebooks. The boot ROM contains the FSBL, which loads Coreboot, which has [upstream support for the Duet](https://github.com/coreboot/coreboot/blob/main/src/mainboard/google/kukui/panel_krane.c). Then, Coreboot loads the Arm Trusted Firmware (not relevant to this analysis), which then loads [Depthcharge](https://chromium.googlesource.com/chromiumos/platform/depthcharge/), the bootloader for ChromeOS devices.
|
||||
::
|
||||
|
||||
So the ChromeOS bootloader, Depthcharge, is also the one responsible for the 'Developer Mode' menu allowing me to select booting from USB or internal storage. This is really interesting. Now, what is the next step? What does Depthcharge actually load?
|
||||
So Depthcharge, the ChromeOS bootloader, is also what shows the 'Developer Mode' menu that lets me pick between USB and internal storage at boot. This is really interesting. Now, what is the next step? What does Depthcharge actually load?
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/duet_emmc_layout_today.svg"}
|
||||
Depthcharge booting internal storage. It only cares about the first, mysterious "ChromeOS kernel" partition. This actually contains a [FIT image](https://fitspec.osfw.foundation/), which is basically a bundle of kernel, initrd and device tree here.
|
||||
Depthcharge booting internal storage. It only cares about the first, mysterious "ChromeOS kernel" partition. That actually contains a [FIT image](https://fitspec.osfw.foundation/), which here is basically a bundle of kernel, initrd and device tree.
|
||||
::
|
||||
|
||||
That clears up the mistery! The `/boot` partition was never *actually* used at boot, only by postmarketOS to prepare the Depthcharge FIT image (using the `mkdepthcharge` tool). So installing my new kernel there was not enough. I would also have to re-generate the Depthcharge image.
|
||||
That clears up the mystery! The `/boot` partition was never *actually* used at boot, only by postmarketOS to prepare the Depthcharge FIT image (using the `mkdepthcharge` tool). So installing my new kernel there was not enough. I would also have to re-generate the Depthcharge image.
|
||||
|
||||
### EFI environment needed
|
||||
|
||||
Although this would be very easy, it would unfortunately not work. See, in this bootflow, there was never an EFI-capable firmware present. Neither EDK2 nor U-Boot are used, Depthcharge directly loads and boots the kernel via the FIT image. That works fine for the postmarketOS kernel, but not for the Ubuntu kernel, which is an EFI executable and expects an EFI environment. **[Ubuntu only boots via UEFI](https://ubuntu.com/hardware/docs/image-cookbook/explanation/bootflow/)**.
|
||||
Although this would be very easy, it would unfortunately not work. See, in this bootflow, there was never EFI-capable firmware involved. Neither EDK2 nor U-Boot is used: Depthcharge loads and boots the kernel directly from the FIT image. That works fine for the postmarketOS kernel, but not for the Ubuntu kernel, which is an EFI executable and expects an EFI environment. **[Ubuntu only boots via UEFI](https://ubuntu.com/hardware/docs/image-cookbook/explanation/bootflow/)**.
|
||||
|
||||
So, we need a UEFI-capable firmware. The easiest to get working would be U-Boot: EDK2 can be harder to work with, and U-Boot already has support for the `mt8183` SoC. That support is only present as a config for the 'Pumpkin' reference development board of the SoC, so we will need to do some work into U-Boot to be able to boot it. Our goal is to get to chainload U-Boot via Depthcharge, to get a UEFI environment, that will be able to boot Grub which will then boot our Ubuntu kernel:
|
||||
So, we need a UEFI-capable firmware. The easiest to get working would be U-Boot: EDK2 can be harder to work with, and U-Boot already has support for the `mt8183` SoC. That support is only present as a config for the 'Pumpkin' reference development board of the SoC, so we will need to do some work into U-Boot to be able to boot it. Our goal is to chainload U-Boot via Depthcharge, in order to get a UEFI environment, that will be able to boot Grub which will then boot our Ubuntu kernel:
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/duet_planned_efi_path.svg"}
|
||||
*Target boot flow after DepthCharge.*
|
||||
*Target boot flow after Depthcharge.*
|
||||
::
|
||||
|
||||
Let's get started hacking U-Boot! Wait, but do we even know how to print something to the screen? How are we going to debug this? We can't expect U-Boot with no drivers at all for the board to work right away printing debug logs... and bringing up a screen is not easy. Let's think this through.
|
||||
@@ -131,19 +131,19 @@ Let's get started hacking U-Boot! Wait, but do we even know how to print somethi
|
||||
|
||||
Our goal is to have U-Boot chainloaded as a Depthcharge payload, for it to then be able to access the eMMC and load Grub that is there. Grub will then use the UEFI storage drivers, i.e. U-Boot drivers exposed over the EFI API, to load the kernel and initrd.
|
||||
|
||||
U-Boot already has support for the `mt8183`, so we won't need to write the drivers, which makes this work possible. Unfortunately, we will still-need board-specific adaptations for the Lenovo IdeaPad Duet, which I will also refer to by its codename `kukui-krane` (`kukui` being codename for the `mt8183`-based chromebooks, `krane` for the specific Lenovo IdeaPad Duet).
|
||||
U-Boot already has support for the `mt8183`, so we won't need to write the drivers, which makes this work possible. Unfortunately, we will still need board-specific adaptations for the Lenovo IdeaPad Duet. I'll also refer to it by its codename `kukui-krane` (`kukui` being the codename for the `mt8183`-based chromebooks, `krane` for the specific Lenovo IdeaPad Duet).
|
||||
|
||||
Realistically, we will need some form of logging to debug our U-Boot build. There are two options for that:
|
||||
- Using a serial output on the board. This is actually possible, with what is called a [SuzyQable](https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/main/docs/ccd.md#suzyq-suzyqable) which allows to do 'CCD', Closed-Case Debug, and get an UART interface on Chromebooks. Unfortunately, I don't have such a cable (I've ordered one).
|
||||
- Using the screen directly. This is harder, because we would need to write a driver for that specific panel, or the specific framebuffer as initialized by Coreboot. It is also something that we ultimately want: proper U-Boot support for the device. So let's go!
|
||||
Realistically, we will need some form of logging to debug our U-Boot build. Two options:
|
||||
- Using a serial output on the board. This is actually possible, with what is called a [SuzyQable](https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/main/docs/ccd.md#suzyq-suzyqable) which enables 'CCD', Closed-Case Debug, and gives you a UART interface on Chromebooks. Unfortunately, I don't have such a cable (I've ordered one).
|
||||
- Using the screen directly. Harder, because we would need to write a driver for that specific panel, or the specific framebuffer as initialized by Coreboot. It is also something that we ultimately want: proper U-Boot support for the device. So let's go!
|
||||
|
||||
Coreboot source tree shows a `krane_panel.c` file which contains some of the panel initialization code. I was not so sure what to do with that, but I figured that either we could use Coreboot/Depthcharge code to rewrite a panel driver, or directly use the framebuffer that Coreboot did set up. So I gave that suggestion to Claude.
|
||||
The Coreboot source tree has a `krane_panel.c` file with some of the panel initialization code. I was not so sure what to do with that, but I figured that either we could use Coreboot/Depthcharge code to rewrite a panel driver, or directly use the framebuffer that Coreboot had already set up. So I gave Claude that suggestion.
|
||||
|
||||
Immediately, it started with a wonderful idea: instead of directly trying to make that work into U-Boot, just write an assembly stub that would show colors on the screen. It also figured out how to read Coreboot's "LBIO" table to get the framebuffer details. I asked it for a detailed prompt for an agent to implement that, and it gave me one.
|
||||
Immediately, it started with a wonderful idea: instead of trying to make that work inside U-Boot directly, just write an assembly stub that shows colors on the screen. It also figured out how to read Coreboot's "LBIO" table to get the framebuffer details. I asked it for a detailed prompt for an agent to implement that, and it wrote one.
|
||||
|
||||
### krane-fb-stub
|
||||
|
||||
Now, I rebooted on the Duet, installed [OhMyPi](https://omp.sh/) and connected it to [GLM-5.3-Flash](https://z.ai/blog/glm-5.3-flash). I then gave it the prompt prepared by Claude, and it started implementing the stub and investigating all available kernel/firmware logs on-device.
|
||||
I rebooted the Duet, installed [OhMyPi](https://omp.sh/) and connected it to [GLM-5.3-Flash](https://z.ai/blog/glm-5.3-flash). I then gave it the prompt Claude had prepared, and it started implementing the stub and investigating all available kernel/firmware logs on-device.
|
||||
|
||||
::BlogQuote
|
||||
> # Task: Build and test a minimal ARM64 "hello framebuffer" stub for a Lenovo
|
||||
@@ -160,24 +160,24 @@ Now, I rebooted on the Duet, installed [OhMyPi](https://omp.sh/) and connected i
|
||||
> freestanding binary, as small and dependency-free as possible.
|
||||
|
||||
#description
|
||||
*Extract of Claude prompt fed to my local OhMyPi+GLM-5.3-Flash agent*
|
||||
*Extract of the prompt fed to my local OhMyPi + GLM-5.3-Flash agent*
|
||||
::
|
||||
|
||||
The agent happily started writing ARM assembly code as entry point, then C code for the mail "color display" thing, i.e. parsing Coreboot tables and device tree, finding the framebuffer, and utility code for showing colors.
|
||||
The agent happily started writing ARM assembly as the entry point, then C code for the actual "color display" thing, i.e. parsing Coreboot tables and device tree, finding the framebuffer, and utility code for showing colors.
|
||||
|
||||
The flow went like this: the agent would make a build, then bundle it into a Depthcharge image and flash it to the internal storage. Then I would reboot into it, see what happens, and report back to the agent. It took a total of 10 tries for us to get a fully working stub.
|
||||
The flow went like this: the agent would make a build, then bundle it into a Depthcharge image and flash it to internal storage. Then I would reboot into it, see what happened, and report back to the agent. It took a total of 10 tries for us to get a fully working stub.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/omp-stub.jpg"}
|
||||
*OhMyPi testing the framebuffer stub in QEMU, mid-implementation (**not** part of the prompt, by the way)*
|
||||
::
|
||||
|
||||
There were small issues, like register layouts being wrong and needing re-inspection comparing Coreboot and Depthcharge trees. Debugging was a bit hard in the beginning, as "black screen, no backlight" could mean anything: from no payload to any part of the display driver being wrong.
|
||||
There were small issues, like wrong register layouts, which required going back and comparing the Coreboot and Depthcharge trees. Debugging was hard at first, because "black screen, no backlight" could mean anything, from no payload at all, to any part of the display driver being wrong.
|
||||
|
||||
Eventually, it figured out the real issue. Depthcharge was actually blanking the screen, killing the backlight, and disabling the display. That is a real problem, that the agent chose to circumvent by adding a *revival* step: exactly undoing what Depthcharge did, right after handoff.
|
||||
|
||||
Afterwards, debugging became easier: I became to see backlight patterns (blinks) that I could describe to the agent as feedback. Soon enough, there were colors on the screen.
|
||||
Afterwards, debugging got easier: I started seeing backlight patterns (blinks) that I could describe to the agent as feedback. Soon enough, there were colors on the screen.
|
||||
|
||||
Finally, the stub was complete, and showed the color sequence imagined by Claude: red (early init), yellow (DTB parsed), green (LBIO parsed), blue (all good). This was actually completely faked by the agent, as early init, DTB and LBIO are all necessary for detecting framebuffer, so it just parsed all and showed all colors in a sequence. In any case, using the framebuffer now works!
|
||||
Finally, the stub was complete, and showed the color sequence imagined by Claude: red (early init), yellow (DTB parsed), green (LBIO parsed), blue (all good). This was actually completely faked by the agent, as early init, DTB and LBIO are all required to find the framebuffer, so it just parsed all and showed all colors in a sequence. In any case, drawing to the framebuffer now works!
|
||||
|
||||
::BlogVideo{video="/img/duet-ubuntu/duet-stub.mp4"}
|
||||
*The final stub booted on the Duet*
|
||||
@@ -185,9 +185,9 @@ Finally, the stub was complete, and showed the color sequence imagined by Claude
|
||||
|
||||
### U-Boot using the framebuffer
|
||||
|
||||
So, this framebuffer revival hack is a bit ugly; but I still do not have a serial cable and I would really like to be able to see U-Boot logs on the screen, and now we have a way to print to the screen, so let's go with that.
|
||||
So, this framebuffer revival hack is a bit ugly; but I still do not have a serial cable and I would really like to be able to see U-Boot logs on the screen, and now we have a way to print to the screen, so let's go with that.
|
||||
|
||||
With the stub over, I asked the agent to prepare a prompt for a new session to make U-Boot work on the board, including graphical output using our work on the previous stub.
|
||||
With the stub done, I asked the agent to prepare a prompt for a new session to get U-Boot working on the board, including graphical output reusing our work from the stub.
|
||||
|
||||
::BlogQuote
|
||||
> # Task: bring up mainline U-Boot on the Lenovo IdeaPad Duet (google,krane sku176, MT8183)
|
||||
@@ -198,30 +198,28 @@ With the stub over, I asked the agent to prepare a prompt for a new session to m
|
||||
> U-Boot shallow clone: /home/vhaudiquet/u-boot (mainline main, ~2026-08). SoC support exists: arch/arm/mach-mediatek/mt8183/. Reference target: configs/mt8183_pumpkin_defconfig (CONFIG_POSITION_INDEPENDENT=y, MTK serial, mtk-sd MMC, WDT, USB). dts/upstream/src/arm64/mediatek/mt8183-kukui-krane-sku176.dts exists; there is NO krane/kukui defconfig or board dir yet — that is your starting point.
|
||||
|
||||
#description
|
||||
*Extract of the agent prompt for the new session, for U-Boot bringup*
|
||||
*Extract of the agent prompt for the new session, for U-Boot bring-up*
|
||||
::
|
||||
|
||||
This was unexpectedly a **lot** harder then the framebuffer stub. It took 27 tries before U-Boot ran properly on the device.
|
||||
This was unexpectedly a **lot** harder than the framebuffer stub. It took 27 tries before U-Boot ran properly on the device.
|
||||
|
||||
The first flash went in the worst possible way, i.e. the screen was pitch black again. This is really bad, as I cannot know anything about what is wrong from the observation.
|
||||
|
||||
I suggested the agent to use the same kind of debugging we did before: show me colored bands on the screen for every step. One in the stub (which was necessary for the revival step), one as first step in U-Boot, etc. This helped a lot to pinpoint the issues to the specific lines of code involved.
|
||||
I suggested the agent to use the same kind of debugging we did before: show colored bands on the screen for every step. One in the stub (which was kept at first for the revival step), one as first step in U-Boot, etc. This helped a lot to pinpoint the issues to the specific lines of code involved.
|
||||
|
||||
It turned out that the issue was very early in U-Boot (the agent added something like 13 checkpoints, and I only saw the second one). Actually, the steps were a bit more embarrassing, with errors made by the agent thinking something was already in U-Boot when it was in the stub, and other issues, but we ended up finding the big issue: an alignment problem.
|
||||
It turned out that the issue was very early in U-Boot (the agent added something like 13 checkpoints, and I only saw the second one). Actually, the steps were a bit more embarrassing, with errors made by the agent thinking something was already in U-Boot when it was in the stub, and other issues, but we ended up finding the big one: an alignment problem.
|
||||
|
||||
There are two separate alignment requirements in play here, and they can't both be satisfied at the same address:
|
||||
|
||||
- depthcharge's boot protocol hands control to a fixed offset: `0x40` bytes into the payload. No matter what. On this device that offset is not a multiple of 4096.
|
||||
- U-Boot, being built as position-independent code, requires its own entry point to be on a 4096-byte boundary. Its startup code literally checks this and spins forever if it doesn't hold, because the relocation math it does immediately afterward assumes it.
|
||||
- U-Boot, built as position-independent code, requires its entry point to be on a 4096-byte boundary. Its startup code literally checks this and spins forever if it doesn't hold, because the relocation math it does immediately afterward assumes it.
|
||||
|
||||
TODO finish alignment and shim
|
||||
The only way to fix that seems to be keeping a shim loader, that can have its entry point at the address that Depthcharge wants, and that will jump to U-Boot afterwards, which can be anywhere in the payload. So this is what we did.
|
||||
|
||||
<!-- ```
|
||||
Everything after that was a faster, more conventional slog: the video console turning out to need an environment variable it wasn't getting (inherited from a board config this one was forked from), a mysterious sub-second reset that turned out to be a panic handler quietly rebooting the board instead of showing an error, and a final crash traced to the video driver's memory mappings simply running U-Boot out of page-table space. None of those were especially deep bugs — mostly a matter of getting visibility into a device with no serial console and no way to leave a trace behind a reset.
|
||||
``` -->
|
||||
Everything after that was faster, and the issues that were left were all small (missing environment variable in defconfig for the board, reset that turned out to be a panic and a crash in the video driver's memory mapping, as U-Boot was running out of page-table space). Eventually, we got rid of all those issues, and U-Boot finally showed up on the display.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/first-uboot-prompt.jpg"}
|
||||
*U-Boot finally appearing on the Duet. Appears in portrait instead of landscape, with all the diagnostic color bands from earlier.*
|
||||
*U-Boot finally appearing on the Duet. It shows up in portrait instead of landscape, with all the diagnostic color bands from earlier.*
|
||||
::
|
||||
|
||||
### Console and USB keyboard
|
||||
@@ -233,19 +231,18 @@ The console appears in portrait, and given that the device has an attached keybo
|
||||
Once we have this, we also need to rebuild U-Boot enabling all UEFI-support related configurations. Then, time to try and boot!
|
||||
Wait, I can't type anything?
|
||||
|
||||
Right, so we first need to make the keyboard work in the U-Boot console, that will be helpful for debugging.
|
||||
All we need is to enable a pre-init sequence that will run the USB set-up (even though the keyboard is attached via pogo pins, those pogo pins actually carry USB data lines).
|
||||
Right, so we first need to make the keyboard work in the U-Boot console, which will help with debugging.
|
||||
All we need is to enable a pre-init sequence that will run the USB set-up (even though the keyboard attaches via pogo pins, those pogo pins actually carry USB data lines).
|
||||
|
||||
Then we can start typing. Let me type 'help' to look at the commands and... weird, the console does not scroll. The text overwrites itself in a weird way? That was really puzzling. I re-opened the agent and explained the problem, as that did
|
||||
not seem like a straightforward issue.
|
||||
Then we can start typing. Let me type 'help' to look at the commands and... weird, the console does not scroll. The text overwrites itself in a weird way? That was really puzzling. I reopened the agent and explained the problem, since it didn't look like a straightforward issue.
|
||||
|
||||
It turns out that it was not a straightforward issue at all, as it was actually an upstream bug. I prepared an [upstream patch that fixes scrolling on a weirdly rotated screen](https://lore.kernel.org/u-boot/20260831163056.3854693-1-valentin.haudiquet@canonical.com/T/#u) (i.e. screens were `rot=1` or `rot=3`). This is litterally a one-character fix, that the agent pointed out. Nice to be able to encounter that and fix it!
|
||||
It turns out that it was not a straightforward issue at all, as it was actually an upstream bug. I prepared an [upstream patch that fixes scrolling on a weirdly rotated screen](https://lore.kernel.org/u-boot/20260831163056.3854693-1-valentin.haudiquet@canonical.com/T/#u) (i.e. screens where `rot=1` or `rot=3`). This is literally a one-character fix, that the agent pointed out. Nice to run into that and fix it!
|
||||
|
||||
Now, we can finally try booting.
|
||||
Now we can finally try booting.
|
||||
|
||||
### Booting the eMMC
|
||||
|
||||
Let's go! `bootefi bootmgr` is the magic command to start the EFI boot manager and try to boot the EFI entries. Typing that, and... nothing. Right, we don't have any EFI bootable executable yet on the EFI partition... the Ubuntu chroot does not contain grub and it was never installed properly. So let's reboot into the chroot from the postmarketOS USB and install Grub:
|
||||
Let's go! `bootefi bootmgr` is the magic command that starts the EFI boot manager and tries to boot the EFI entries. Typing that, and... nothing. Right, we don't have any EFI bootable executable yet on the EFI partition... the Ubuntu chroot does not contain grub and it was never installed properly. So let's reboot into the chroot from the postmarketOS USB stick and install Grub:
|
||||
|
||||
::BlogCode
|
||||
```
|
||||
@@ -257,35 +254,202 @@ $ sudo grub-install --target=arm64-efi --efi-directory=/boot/efi \
|
||||
```
|
||||
::
|
||||
|
||||
Now, we can try booting again. This time, `bootefi bootmgr` takes us to Grub!
|
||||
Now let's try booting again. This time, `bootefi bootmgr` takes us to Grub!
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/first-grub-console.jpg"}
|
||||
*The Grub prompt appearing for the first time on the Duet. Sadly, that is not a Grub menu... something went wrong when grub tried to load its configuration.*
|
||||
*The Grub prompt appearing for the first time on the Duet. Sadly, that's not a Grub menu... something went wrong when Grub tried to load its configuration.*
|
||||
::
|
||||
|
||||
After investigating in Grub console, I can manually make it load `grub.cfg`; something seems wrong at handoff time, and Grub cannot access the eMMC. Maybe it is because U-Boot is still using it, so Grub cannot directly access it, and then Grub fully loads without it's config, U-Boot lets go of the eMMC, and Grub can now access it, but too late. In any case, we can manually progress to a menu.
|
||||
After investigating in Grub console, I can manually make it load `grub.cfg`; something seems wrong at handoff time, and Grub cannot access the eMMC. Maybe it is because U-Boot is still using it, so Grub cannot directly access it, and then Grub fully loads without its config, U-Boot lets go of the eMMC, and Grub can now access it, but too late. In any case, we can manually progress to a menu.
|
||||
|
||||
The only issue is that this menu was portrait. After changing Grub config, we can finally get to a clean landscape Grub menu!
|
||||
The only issue is that the menu was in portrait. After changing Grub config, we can finally get to a clean landscape Grub menu!
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/first-grub-menu-landscape.jpg"}
|
||||
*The Grub menu, finally working for the first time on the Duet.*
|
||||
::
|
||||
|
||||
Finally, let's boot into Ubuntu! I see some kernel logs, of course in portrait, and... what is happening? Why is the display suddendly corrupting itself? Oh. Right. Our display framebuffer is a hack.
|
||||
Finally, let's boot into Ubuntu! I see some kernel logs, in portrait of course, and... what's happening? Why is the display suddenly corrupting itself? Oh. Right. Our display framebuffer is a hack.
|
||||
|
||||
Remember the "revival" hack to reuse the framebuffer from coreboot for U-Boot and Grub?
|
||||
Remember the "revival" hack to reuse the framebuffer from Coreboot for U-Boot and Grub?
|
||||
Well, it seems that the kernel did not like it. After the end of the earlycon which uses that same EFI-provided framebuffer,
|
||||
the kernel tries to set up the display for itself, finding it in this weird hacked state. At least that is my theory.
|
||||
In any case, this makes the display show weird things, blinking bands and logs that are disappearing, with lines showing here and there. Something is wrong.
|
||||
the kernel tries to set up the display for itself, finding it in this weird hacked state. At least that's my theory.
|
||||
In any case, the display shows weird things: blinking bands, logs disappearing, lines appearing here and there. Something is wrong.
|
||||
|
||||
Given the display hack, and the fact that there was no way I was gonna see kernel logs on there, it felt only natural to try and implement a *real* panel driver for U-Boot and drop the hack once and for all. So that is what I (or rather, the agent) did.
|
||||
Given the display hack and the fact that there was no way I was gonna see kernel logs on there, it felt only natural to try and implement a *real* panel driver for U-Boot and drop the hack once and for all. So that is what I (or rather, the agent) did.
|
||||
|
||||
## U-Boot panel driver
|
||||
|
||||
So.... we have to write a real panel driver. How do we do that? This was also the end of the weekend and I was starting to feel tired. But I was set on starting the real panel driver work when convenient for me.
|
||||
So.... we have to write a real panel driver. How do we do that? This was also the end of the weekend, and I was starting to feel tired. But I was set on starting the real panel driver work when convenient for me.
|
||||
|
||||
I had some time on weekday evenings and the next weekend, but not enough of course to try and write a driver myself. So I started another agent with that mission:
|
||||
|
||||
::BlogQuote
|
||||
> # Task: proper MT8183 display pipeline bring-up (MIPI DSI host + PHY + BOE TV101WUM-NL6 panel driver) for U-Boot on the Lenovo IdeaPad Duet (google,krane sku176)
|
||||
> You are taking over an in-progress U-Boot port on this machine. U-Boot already boots on the device with a working rotated vidconsole. Today's display path is a "scanout" driver that revives the display pipeline left running by the boot firmware (coreboot + depthcharge) instead of bringing it up itself. Your job is to add a real display pipeline: a MediaTek MT8183 MIPI DSI host driver, the MIPI TX PHY, and a proper driver for the panel (BOE TV101WUM-NL6), so U-Boot brings the panel up from scratch and no longer depends on firmware handoff.
|
||||
|
||||
::
|
||||
|
||||
This also meant going back into the dark: no screen output at all if something failed. Back to blinking screens and dark panels. After 3 flashes like that, it was clear this wasn't going to work. Debugging a real display driver with blinking lights alone is just not realistic.
|
||||
|
||||
Remember the SuzyQable I ordered? Well, it fortunately arrived around that time. It's not a cable per se, but rather a small SuzyQ adapter that you plug any regular USB-C cable into for the host connection.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/suzyq-adapter-2.jpg"}
|
||||
*The SuzyQ adapter. It plugs into the device's USB-C port and connects to a host computer with a USB-C cable, giving serial access.*
|
||||
::
|
||||
|
||||
This required a small amount of work to bring up serial support in U-Boot: just changing the baudrate in the defconfig to 115200. Not obvious at first, but `pumpkin`, the reference `mt8183` board in the U-Boot tree, sets the baudrate to `921600`, and that setting had been carried over to `kukui_krane`.
|
||||
|
||||
After that, serial helped spot the issue with the panel driver: the agent had forgotten to set a property that gets read during initialization, leading to a NULL pointer dereference. An easy fix. Once that was done, the panel driver worked.
|
||||
I would have expected this to be much harder, but with serial the issues were easy to spot, and the agent mostly adapted work from the existing Coreboot panel driver (and the kernel one), which made the task easy for it (him?).
|
||||
|
||||
Technical details on the panel driver and the whole U-Boot saga are available in the "Cleaning up, technical details" section below. Before that, let's boot the kernel.
|
||||
|
||||
## Kernel
|
||||
|
||||
### Fixing with an agent
|
||||
|
||||
Finally, we can try booting our Ubuntu 7.0 kernel!
|
||||
Booting it with Grub went fine, but the kernel output on screen got stuck once the boot console went down.
|
||||
It seems that the U-Boot display driver keeps control of the screen, so when the kernel wants to take over and bring the display up itself, it can't. That is ok, it is also something we can fix directly. We still have the rest of the logs over serial now (with the SuzyQ), so let's follow... wait... why did it stop there?
|
||||
|
||||
So it turns out that the kernel 'hangs' in the middle of initrd, sometimes before, sometimes after pivoting root and showing the login prompt. I've had a true nightmare debugging this. I was pretty sure it was a U-Boot issue (something going wrong in the handoff), but the agents were convinced that there were upstream kernel bugs everywhere. We tried many things in random order, including a lot of changes that weren't necessary.
|
||||
|
||||
This ate a lot of my evenings and got nowhere.
|
||||
|
||||
In the end I had the new OpenAI model, GPT-6 Astra, take a look, and maybe because it was new (so its knowledge cutoff was later), it found a real issue: [an upstream kernel patch not present in the 7.0 kernel, "pmdomain: mediatek: Fix mt8183 hang on boot"](https://lkml.org/lkml/2026/7/29/1310). At that moment I thought Astra was magic and everything was solved. I was about to find out that I was wrong.
|
||||
|
||||
To try it, I tasked an agent with rebuilding the 7.0 kernel for me with that patch on top and the Ubuntu default configs. Somehow, that didn't work at all: the kernel didn't boot to initrd properly. Kernel builds were also very slow on the device, and I had to rebuild all the modules, which was even slower. That was not fun at all.
|
||||
|
||||
I decided to switch to the development release, Ubuntu 26.10 Stonking Stingray. It has a 7.2 kernel packaged, which is more recent, contains that patch, and maybe other fixes introduced along the way. Upgraded the kernel package, rebooted... and... it's just like the 7.0 kernel. Same hang. Astra was wrong.
|
||||
|
||||
So, this patch might be useful, but the hang that it fixes seems very specific and might not be the one I was experiencing. It still allowed me to switch to a more recent kernel, and to consider the fact that there might be multiple bugs involved causing multiple different kinds of hang. That might be a reason why the agent went in all kinds of random directions and each fix did not seem to change anything.
|
||||
|
||||
### Getting (a bit more) involved
|
||||
|
||||
I decided to change my approach and get a bit more involved in the fixing process.
|
||||
I started reading a full boot log from a hang, looking for every error or weird stuff in **chronological order**.
|
||||
|
||||
The first weird thing was in the U-Boot startup log over serial:
|
||||
|
||||
::BlogCode
|
||||
```
|
||||
U-Boot 2026.10-rc2-00071-g7670f264dc3a (Sep 10 2026 - 21:09:40 +0200)
|
||||
|
||||
CPU: MediaTek MT8183
|
||||
DRAM: 2 GiB
|
||||
Core: 47 devices, 14 uclasses, devicetree: separate
|
||||
MMC: mmc@11230000: 0, mmc@11240000: 1
|
||||
Loading Environment from nowhere...
|
||||
Loading Environment from nowhere... OK
|
||||
In: serial,usbkbd
|
||||
Out: serial,vidconsole
|
||||
Err: serial,vidconsole
|
||||
Net: No ethernet found.
|
||||
```
|
||||
#description
|
||||
*U-Boot banner and initial logs. Do you see something weird?*
|
||||
::
|
||||
|
||||
U-Boot only reports 2 GiB of DRAM! We had some issues around memory reservation tables and the EFI memory map before, so this might be real. Could be harmless, but might be a problem, so let's fix it. That one was easy to hand to an agent. In parallel I had other agents working on fixing the slow display bring-up, and the slow serial console.
|
||||
|
||||
The agent fixed this the right way (reading Coreboot tables to find the actual amount of memory on the board), and also the wrong way (adding a config override to 4 GiB in defconfig for `kukui-krane`). Given that `kukui-krane` only exists in 4 GiB variants (to my knowledge), I decided to still keep the defconfig entry, but verified (with logs) that the Coreboot read worked:
|
||||
|
||||
::BlogCode
|
||||
```
|
||||
DRAM: DRAM: coreboot tables at 0xffed9000 report 4096 MiB of usable RAM
|
||||
4 GiB
|
||||
```
|
||||
#description
|
||||
*U-Boot reporting 4 GiB RAM after reading the Coreboot tables*
|
||||
::
|
||||
|
||||
I spotted other small issues in the logs and tasked the agent with fixing them one by one, each in a new session.
|
||||
That took a bit more time and involvement, since I was analyzing everything and verifying the work each time.
|
||||
|
||||
### Ubuntu works (?)
|
||||
|
||||
Afterwards, I rebooted, wanting to retry a full chain, capture a new log, and address the remaining errors.
|
||||
To my surprise, after rebooting once, twice, and multiple times: boot worked flawlessly every time, and I could actually use the system. Finally.
|
||||
|
||||
::BlogImage{image="/img/duet-ubuntu/ubuntu-stonking.jpg"}
|
||||
*Ubuntu 26.10 development release, with the Ubuntu 7.2 generic kernel, actually running on the Duet. Finally. All of this for a single 'Kernel' line change... :)*
|
||||
::
|
||||
|
||||
I started using the system, connected to Wi-Fi (which worked fine!), cleaned up patches, ran an update and... oh. Stuck again. During `apt upgrade`. I rebooted, ran the `dpkg` command to fix up the upgrade, and... stuck again. Always while `dracut` was generating the initramfs. That's a problem.
|
||||
|
||||
I tried multiple things, but it turns out that the machine still seemingly hangs in some CPU-heavy tasks, or long-running tasks.
|
||||
At this point, it's a bit hard to reproduce: you have to use the machine for 20+ minutes before it shows up. Specific operations like `apt upgrade` seem to trigger it every time, though. I tried looking online, and it seems that the LKML has recent patches for that SoC.
|
||||
|
||||
Particularly, ["ASoC: mediatek: mt8183: Fix clock error handling"](https://lkml.org/lkml/2026/8/28/313) seems to aim at fixing some clock errors, most likely the ones that I see in red in the kernel boot log every time. This patch was sent only 2 weeks ago (!!) at the time of writing of this article, so it is definitely not in 7.2. Maybe this will improve things?
|
||||
|
||||
For now, I don't want to try rebuilding another kernel. I want to try and cleanup everything in the U-Boot code, which I first did with agents again. Adversarial reviewers found style issues, stale comments, etc. They also addressed some display performance issues. I made sure to clean up stale configs and build caches, then to rebuild with the `kukui-krane` defconfig. Below is a video of the final boot flow for Ubuntu on the device.
|
||||
|
||||
::BlogVideo{video="/img/duet-ubuntu/full-boot.mp4"}
|
||||
*Full boot chain on the display. Depthcharge kills the display, U-Boot brings it back up, Grub is loaded, EFI `exitBootServices` kills the display again, to allow the kernel to bring it back up again. Could be optimized, but working.*
|
||||
::
|
||||
|
||||
## Cleaning up, technical details
|
||||
|
||||
After all of those debugging steps, the U-Boot tree was a bit of a mess: 43 commits on top of main. **43**.
|
||||
|
||||
That is a lot, so I started refactoring, squashing, dropping, and cleaning up all of this. After a heavy pass, that also caught issues (performance-wise, potential bugs in the driver, or stylistic errors, all through this 'static analysis'), I ended up with **20** commits. Still a lot, but more manageable. Here they are:
|
||||
|
||||
::BlogTable
|
||||
| # | Commit |
|
||||
| --- | --- |
|
||||
| 1 | arm: mediatek: add MT8183 kukui krane board support |
|
||||
| 2 | scripts: Makefile.lib: prefer upstream DT includes with OF_UPSTREAM |
|
||||
| 3 | serial: mtk: leave the sample count alone in low-speed mode |
|
||||
| 4 | video: console: fix scrolling and cursor position on rotated consoles |
|
||||
| 5 | video: console: report damage when showing the cursor |
|
||||
| 6 | efi: console: re-sync the vidconsole cursor and accept stdout lists |
|
||||
| 7 | boot: image-fdt: treat duplicate region reservation as a no-op |
|
||||
| 8 | clk: mediatek: mt8183: add MMSYS display clock gates |
|
||||
| 9 | gpio: add MediaTek MT8183 GPIO driver |
|
||||
| 10 | phy: add MediaTek MT8183 MIPI TX D-PHY driver |
|
||||
| 11 | video: add MediaTek MT8183 MIPI DSI host driver |
|
||||
| 12 | video: add MT8183 cold display bring-up for krane with BOE panel |
|
||||
| 13 | video: mt8183: quiesce the display pipeline at ExitBootServices |
|
||||
| 14 | arm: mediatek: mt8183: enlarge the page-table budget for dynamic display mappings |
|
||||
| 15 | arm: mediatek: mt8183: determine the real DRAM size from the previous bootloader |
|
||||
| 16 | mmc: mtk-sd: bounce DMA above 4 GiB and keep U-Boot inside the 32-bit window |
|
||||
| 17 | usb: xhci: bound the interrupt-in event wait to unblock the console |
|
||||
| 18 | usb: xhci-mtk: shut the T-PHY down on remove |
|
||||
| 19 | arm64: dts: mt8183: krane: describe the SSUSB block for U-Boot's xhci driver |
|
||||
| 20 | board: mediatek: mt8183: finish the krane configuration for EFI boot |
|
||||
|
||||
#description
|
||||
*Full commit series added to U-Boot at the end of the experimentation, after a cleanup phase.*
|
||||
::
|
||||
|
||||
This is all the changes that the agents added, grouped together when that made sense (for example, there were 8 commits for the DSI driver, with fix-up stuff and performance improvements, so they all got squashed together to make a final commit for the DSI driver). As you can see, there are also changes that are there not directly for the board itself, but to fix a more generic bug, like ["video: console: fix scrolling and cursor position on rotated consoles", sent upstream already](https://lore.kernel.org/u-boot/20260831163056.3854693-1-valentin.haudiquet@canonical.com/T/#u). Some of those changes might not be useful at all though, or even break other boards, so this will need a manual review. Let's do that.
|
||||
|
||||
First, we need to walk through the generic upstream bug candidates, that have virtually nothing to do with MT8183:
|
||||
|
||||
- #2: a real bug in the U-Boot machinery for `OF_UPSTREAM` devicetree usage (which is used to sync the DTS of the board with the one in the upstream kernel) Specific case of the SoC having both a legacy and an upstream dt-bindings header. Really looks like a genuine bug, will be sent as PATCH RFC upstream after verifications.
|
||||
- #4: already sent upstream to fix scrolling on weirdly rotated screens
|
||||
- #5: reporting video "damage" when the cursor is set visible. Damage was missing for this specific function, so when having the video console in "only refresh damaged parts" mode, showing the cursor would not work until the next update. Will be sent upstream as PATCH after verification.
|
||||
- #6: another simple bug fix, related to EFI console output string. This is just a re-sync of the cursor in the EFI console with the one in the U-Boot video console. This will also need evaluation to see if it is really needed, but another candidate for a standalone upstream patch.
|
||||
- #7: seems like a wrong patch. It is a change to treat a second reservation of the same region for the same purpose as a no-op. That seems like shadowing a real issue that the reservation function was called twice, and will need further investigation why (and maybe a patch). Moving on, dropping it.
|
||||
- #17: also seems a bit weird. This was added by the agent when investigating serial typing slowness when video was on, and it somehow seems to address a USB keyboard typing slowness which never existed, by creating a new, smaller USB driver timeout kind for waiting over an interrupt. Dropping it seems fine.
|
||||
|
||||
Then, we can tackle the MediaTek fixes (not specific to MT8183 SoC):
|
||||
- #3:
|
||||
- #18: a simple one-line change to call `xhci_mtk_phy_shutdown()` on driver removal, so that the kernel can bring up the driver on its own later. Simple fix to verify and send upstream.
|
||||
|
||||
Now, we are left with the board enablement patches:
|
||||
|
||||
|
||||
|
||||
|
||||
## A bootable Ubuntu image
|
||||
|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
### Using AI for hardware bring-up/debugging
|
||||
|
||||
### Next steps
|
||||
|
||||
coreboot, fix errors, upstreaming
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 552 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
Reference in New Issue
Block a user