Compiling Custom Linux Kernel for Beaglebone Black Industrial 6.18.16-bone23

Some history, I decided to use the Beaglebone Black Industrial (BBBI) for a new project due to the outstanding temperature specifications. For the project I needed an ADC, i2c, and plenty of gpio inputs and outputs which the BBBI had. I’d been using the Raspberry PI but had failures due to temperature. So time will tell if the BBBI industrial can stand up to the heat.

After purchasing the BBBI, which came with Kernel 6.18.16-bone23, I started getting the foundational basic code written mapping the gpio. That’s when I noticed that some of the GPIO was internally pulled up and some was internally pull down or floating. That’s when the fun started. I spent many hours learning libgpiod starting with version 1 and then porting to version 2. That’s another topic for discussion. libgpiod has functions built in to set the internal gpio mux to pull up or pull down. I needed all of the gpio inputs to pull up for ease of just ground the pins in the field wiring. Reading the pin = high, switch open, reading the pin = low, switch closed.

I worked with libgpiod for a while and it failed to change the pin mux settings. I could read the input pins and write to the output pins. But no luck changing the mux values.

I then tried writing a device tree overlay for pin P8_11 and while it loaded, the overlay failed to change the pin mux register value to 0x37. After these failures and some hints from Daniel I decided to compile a custom kernel just so I could internally pull up four pins. P8_11, P8_12, P8_15 and P8_18. A bit of a challenge I guess, considering I could just use external 10K ohm pull up resistors.

I’m going to try to list the steps to document this effort. Please comment to clarify.

The first step was to download the kernel
git clone -b 6.18.16-bone23 https://github.com/RobertCNelson/linux-stable-rcn-ee --depth=100

Then I installed the cross compiler for the BBBI arm system and some other utilities
sudo apt-get update
sudo apt install build-essential crossbuild-essential-armhf
sudo apt install bison flex lzop u-boot-tools libncurses5-dev bc device-tree-compiler libssl-dev
I might be missing a few things here

The next few steps to compile the kernel
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make omap2pluslplc_defconfig, i modified this to enable the heartbeat LED=y
make menuconfig, nothing to change here. probably can skip this step
make

The compile took a few minutes and the zImage was created in
linux-stable-rcn-ee/arch/arm/boot
It also looks like the modules and the device tree overlays compiled also.

Now what? More to come soon

git clone -b am33x-v6.18 https://github.com/RobertCNelson/bb-kernel
cd ./bb-kernel/
./build_deb.sh

Regards,

1 Like

After the first compile with no custom modifications, linux-stable-rcn-ee/arch/arm/boot/zImage was moved to the BBBI in /boot to make sure the image would load. The old kernel, /boot/vmlinuz-6.18.16-bone23 was moved to a safe location and the new zImage was renamed to vmlinuz-6.18.16-bone23. Modules and device tree overlay files were left as is with no changes. In the future I am going to learn about placing the module and device tree files in the correct spot with the kernel naming convention matching the uEnv.txt variables. I need help in this area.

The system booted just fine with no errors.

Now for the modifications,

With a little research I was able to find the spot in the kernel just before user space where processes took over.

This entry point location is in init/main.c located here just before rest_init();

#ifdef CONFIG_SOC_AM33XX
	bgpioSetPinMux();
#endif
	/* Do the rest non-__init'ed, we're now alive */
	rest_init();```

and for the code to change the mux registers,

#ifdef CONFIG_SOC_AM33XX
#define P8_11_PINMUX_ADDR 0x44e10834
#define P8_12_PINMUX_ADDR 0x44e10830
#define P8_15_PINMUX_ADDR 0x44e1083c
#define P8_18_PINMUX_ADDR 0x44e1088c

void bgpioSetPinMux(void);

void bgpioSetPinMux(void) {

    void __iomem *addr;


    pr_info("bgpioSetPimMux Version 1.0\n");
    /* Map the physical 4 byte address */
    addr = ioremap(P8_11_PINMUX_ADDR, 0x4);
    if (!addr) {
        pr_err("Failed to map pinmux register P8_11\n");
        return;
    }

    /* Write value 0x37 */
    writel(0x37, addr);

    /* Ensure write completes */
    wmb();

    /* Unmap */
    iounmap(addr);

    pr_info("Pinmux P8_11 BBB set\n");

    /* Map the physical 4 byte address */
    addr = ioremap(P8_12_PINMUX_ADDR, 0x4);
    if (!addr) {
        pr_err("Failed to map pinmux register P8_12\n");
        return;
    }

    /* Write value 0x37 */
    writel(0x37, addr);

    /* Ensure write completes */
    wmb();

    /* Unmap */
    iounmap(addr);

    pr_info("Pinmux P8_12 BBB set\n");


    /* Map the physical 4 byte address */
    addr = ioremap(P8_15_PINMUX_ADDR, 0x4);
    if (!addr) {
        pr_err("Failed to map pinmux register P8_15\n");
        return;
    }

    /* Write value 0x37 */
    writel(0x37, addr);

    /* Ensure write completes */
    wmb();

    /* Unmap */
    iounmap(addr);

    pr_info("Pinmux P8_15 BBB set\n");


    /* Map the physical 4 byte address */
    addr = ioremap(P8_18_PINMUX_ADDR, 0x4);
    if (!addr) {
        pr_err("Failed to map pinmux register P8_18\n");
        return;
    }

    /* Write value 0x37 */
    writel(0x37, addr);

    /* Ensure write completes */
    wmb();

    /* Unmap */
    iounmap(addr);

    pr_info("Pinmux P8_18 BBB set\n");

}

#endif```

I placed the above code at the top of main.c. I suppose a separate file would have been better but I spent enough time on this and I need to move on to other priorities. Then I repeated the compile process and successfully changed the pins to pull up. Did I break something? we will see :slight_smile:

For future builds I would like to better understand the naming convention of the kernel and how uboot finds the kernel. Also to better understand the module naming and location and the device tree naming and location, all these things have to be named exactly correct and be placed in the correct locations or they don’t work. I my case here I just compiled the same kernel, renamed the kernel with the same name and used the old modules and old device tree files already there.

There’s a post install kernel script pre installed, if you build the deb package, everything gets dropped in the correct location on install…

Thanks, I will check it out

Are you going to push changes to personal propper? To my mind it’s fair clear what should be done, that is set the pull on gpio pins in the device tree. Now of course it would only apply to gpio pins, so pins with other functionality in the device tree could have other pulls. E.g. Really want there to be a consistent way of doing this in the root kernel.

This change is kind of a hack work around to the kernel. I was hoping that a proper permanent fix to the user space libgpiod gpio mux functions would be officially completed. If Robert could provide some guidance here I would be willing to take a look.

I still don’t have a clear understanding of why the pin mux settings were disabled from user space and/or the device tree overlays. Or maybe there is just a bug that needs fixing, Don’t know.

This kernel hack pin mux config shown above is static on boot, so like some applications, easy dynamic run time changes are needed by the user.

If you can’t get a device-tree or libgpiod to set the exact value you require,
you’ve stumbled on a bug. Device-tree and libgpiod exists to avoid
having to poke around in the kernel directly!

I tried the deb method but ran into problems.

instead I did this summary

  1. Clone set environment
    git clone -b 6.19.11-bone14 https://github.com/RobertCNelson/linux-stable-rcn-ee --depth=100
    cross compile on fast machine
    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabihf-
    export DTC_FLAGS=“-@”

  2. Configure and compile
    cp omap2pluslplc_defconfig omap2pluslplc_defconfig
    nano omap2pluslplc_defconfig, CONFIG_LEDS_TRIGGER_HEARTBEAT=y

src/linux-stable-rcn-ee make omap2pluslplc_defconfig

make menuconfig
→ Device Drivers │
│ → Network device support (NETDEVICES [=y]) │
│ → Wireless LAN (WLAN [=y]) │
│ → Realtek devices (WLAN_VENDOR_REALTEK [=y]) │
│ (1) → Realtek 802.11ac wireless chips support (RTW88 [=n]) │
│ → Realtek 8821CU USB wireless network adapter (RTW88_8821CU [=n]) │
│ Selects: RTW88_CORE [=n] && RTW88_USB [=n] && RTW88_8821C [=n]

set the USB drivers ON

make

  1. Move to BBB
    move compiled kernel directory to BBB
    sudo make dtbs_install
    sudo make modules_install
    rename zImage to vmlinuz-6.19.11-00008-g8d6ded334af0-dirty
    sudo cp vmlinuz-6.19.11-00008-g8d6ded334af0-dirty /boot
    edit /boot/uEnv.txt , uname_r=6.19.11-00008-g8d6ded334af0-dirty

sudo reboot

  1. Get wireless LAN to work
    had to do this in /etc/rc.local to get the wireless to work
    #! /bin/bash

sleep 10
depmod -a
modprobe rtw88_8821cu
sleep 50
wpa_supplicant -B -c /etc/wpa_supplicant/wpa_supplicant-wlan0.conf -i wlan0
exit 0

for some reason the usb rtw88_8821cu driver module will not load on boot. Any thoughts on this?
Seems there are timing issues with the driver?

sudo beagle-version
eeprom:[A335BNLTEID02547SBI04226]
model:[TI_AM335x_BeagleBone_Black]
dogtag:[BeagleBoard.org Debian Trixie Base Image 2026-03-17]
bootloader:[microSD-(push-button)]:[/dev/mmcblk0]:[U-Boot SPL 2022.04-g5509547b (Jan 22 2026 - 19:56:08 +0000)]:[location: dd MBR]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot SPL 2022.04-gc6f4cf7d (Apr 24 2025 - 03:22:59 +0000)]:[location: dd MBR]
UBOOT: Booted Device-Tree:[am335x-boneblack-uboot.dts]
UBOOT: Loaded Overlay:[BB-ADC-00A0.kernel]
UBOOT: Loaded Overlay:[BB-BONE-eMMC1-01-00A0.kernel]
kernel:[6.19.11-00008-g8d6ded334af0-dirty]
/boot/uEnv.txt Settings:
uboot_overlay_options:[enable_uboot_overlays=1]
uboot_overlay_options:[disable_uboot_overlay_video=1]
uboot_overlay_options:[disable_uboot_overlay_audio=1]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade <pkg>]
pkg:[bb-customizations]:[1.20250808.0-0~trixie+20250808]
pkg:[bb-usb-gadgets]:[1.20250523.1-0~trixie+20250527]
pkg:[bb-wl18xx-firmware]:[1.20230703.0-0~trixie+20240703]
pkg:[kmod]:[34.2-2bbbio1~trixie+20250522]
groups:[debian : debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal input render netdev i2c bluetooth gpio admin tisdk weston-launch]
cmdline:[console=ttyS0,115200n8 root=/dev/mmcblk0p3 ro rootfstype=ext4 rootwait fsck.repair=yes earlycon coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100]
dmesg | grep remote
[    6.152062] systemd[1]: Reached target remote-fs.target - Remote File Systems.
[   20.008365] remoteproc remoteproc0: wkup_m3 is available
[   21.881838] remoteproc remoteproc0: powering up wkup_m3
[   21.962549] remoteproc remoteproc0: Direct firmware load for am335x-pm-firmware.elf failed with error -2
[   21.972340] remoteproc remoteproc0: request_firmware failed: -2
dmesg | grep pru
dmesg | grep pinctrl-single
[    0.329847] pinctrl-single 44e10800.pinmux: 142 pins, size 568
dmesg | grep gpio-of-helper
dmesg | grep wlcore
lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0bda:c811 Realtek Semiconductor Corp. 802.11ac NIC
END

Could you please start enclosing text dumps in tripple-backticks?

That will make reading what you’re sending so much easier

1 Like

the kernel has a nice scripts enabling different configs for this stuff..

./scripts/config --enable CONFIG_EXT4_FS

pleas share your amazon/etc link to the device, these are fun to deal with:

sudo dmesg | grep -E "rtw8|irmware"

and can you dump dmesg rtw88 and Firmware

Regards,

[    7.632713] systemd[1]: systemd-hibernate-clear.service - Clear Stale Hibernate Storage Info was skipped because of an unmet condition check (ConditionPathExists=/sys/firmware/efi/efivars/HibernateLocation-8cf2644b-4b0b-428f-9387-6d876050dc67).
[   21.962549] remoteproc remoteproc0: Direct firmware load for am335x-pm-firmware.elf failed with error -2
[   21.972340] remoteproc remoteproc0: request_firmware failed: -2
[   32.565748] faux_driver regulatory: Direct firmware load for regulatory.db failed with error -2
[   52.467904] rtw88_8821cu 1-1:1.0: Firmware version 24.11.0, H2C version 12
[   52.678670] usbcore: registered new interface driver rtw88_8821cu
./etc/ssl/certs/Amazon_Root_CA_2.pem
./etc/ssl/certs/Amazon_Root_CA_3.pem
./etc/ssl/certs/Amazon_Root_CA_4.pem
./etc/ssl/certs/Amazon_Root_CA_1.pem
./mnt/linux-stable-rcn-ee/Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.yaml
./mnt/linux-stable-rcn-ee/Documentation/devicetree/bindings/arm/amazon,al.yaml
./mnt/linux-stable-rcn-ee/Documentation/devicetree/bindings/edac/amazon,al-mc-edac.yaml
./mnt/linux-stable-rcn-ee/Documentation/devicetree/bindings/pci/amazon,al-alpine-v3-pcie.yaml
./mnt/linux-stable-rcn-ee/Documentation/devicetree/bindings/thermal/amazon,al-thermal.yaml
./mnt/linux-stable-rcn-ee/Documentation/networking/device_drivers/ethernet/amazon
./mnt/linux-stable-rcn-ee/drivers/net/ethernet/amazon
./mnt/linux-stable-rcn-ee/arch/arm64/boot/dts/amazon
./mnt/linux-stable-rcn-ee/arch/arm/boot/dts/amazon
./usr/share/mime/application/vnd.amazon.mobi8-ebook.xml
./usr/share/ca-certificates/mozilla/Amazon_Root_CA_1.crt
./usr/share/ca-certificates/mozilla/Amazon_Root_CA_2.crt
./usr/share/ca-certificates/mozilla/Amazon_Root_CA_4.crt
./usr/share/ca-certificates/mozilla/Amazon_Root_CA_3.crt

not sure what amazon is

okay so you have the rtw88_8821cu firwmare..

I ship that firmware in the git tree you cloned..

./scripts/config --set-str CONFIG_EXTRA_FIRMWARE "regulatory.db regulatory.db.p7s"

Regards,

1 Like
./scripts/config --enable CONFIG_OF_OVERLAY
./scripts/config --enable CONFIG_LEDS_TRIGGER_HEARTBEAT