Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bootloader/retention boot mode support #2683

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

petejohanson
Copy link
Contributor

Ok, expanding our support for entering the bootloader on more targets!

Overview

This PR works to expand our bootloader support beyond the Adafruit nRF bootloader by moving to new (relatively) new Zephyr retention boot mode support. The scope of this change includes:

  • Updates to the reset behavior to use the retention boot mode API if the Kconfig symbol is enabled.
  • Add a new "boot mode to magic value" retained mem driver that maps from the basic BOOT_MODE_TYPE_BOOTLOADER to storing the 32-bit "magic value" to the real underlying retention location.
  • Switches to a Zephyr branch of our v3.5+zmk-fixes branch that includes a new STM32 bootloader support, to jump automatically to the ROM bootloader when startup determines the bootmode was set to bootloader before the restart. This piece is tested on stm32f072 only so far, my testing on F4 is complicated by all my devices having tinyuf2 flashed to them as a second stage bootloader.

Bootloaders Supported

Adafruit nRF52

The nRF52 bootloader should be supported, will be testing this more tomorrow, by the following:

&gpregret1 {
    magic_retention: retention@0 {
        compatible = "zephyr,retention";
        status = "okay";
        reg = <0x0 0x4>;
    };
};

/ {
	magic_mapper {
		compatible = "zmk,bootmode-to-magic-mapper";
		status = "okay";
		bootloader-magic-value = <0xf01669ef>;

		#address-cells = <1>;
		#size-cells = <1>;

		boot_retention: retention@0 {
			compatible = "zephyr,retention";
			status = "okay";
			reg = <0x0 0x1>;
		};
	};

        chosen {
                zephyr,boot-mode = &boot_retention;
		zmk,magic-boot-mode = &magic_retention;
        };
};

And enabling:

CONFIG_RETAINED_MEM=y
CONFIG_RETENTION=y
CONFIG_RETENTION_BOOT_MODE=y
CONFIG_ZMK_BOOTMODE_MAGIC_VALUE_BOOTLOADER_TYPE_ADAFRUIT_NRF52=y

Adafruit bossa/samd21 and tinyuf2 UF2 Bootloaders

The adafruit tinyuf2 and samd21 bootloaders both use the same magic value stored in the last 4 bytes of RAM to trigger bootloader mode, so the setup for these two bootloaders is effectively the same:

Here is an example for samd21e18 (which has 32K of RAM)

Devicetree:

/ {
        sram@20007FFC {
                compatible = "zephyr,memory-region", "mmio-sram";
                reg = <0x20007FFC 0x4>;
                zephyr,memory-region = "RetainedMem";
                status = "okay";

                retainedmem {
                        compatible = "zephyr,retained-ram";
                        status = "okay";
                        #address-cells = <1>;
                        #size-cells = <1>;

                        magic_retention: retention@0 {
                                compatible = "zephyr,retention";
                                status = "okay";
                                reg = <0x0 0x4>;
                        };
                };
        };

        magic_mapper {
                compatible = "zmk,bootmode-to-magic-mapper";
                status = "okay";

                #address-cells = <1>;
                #size-cells = <1>;

                boot_retention: retention@0 {
                        compatible = "zephyr,retention";
                        status = "okay";
                        reg = <0x0 0x1>;
                };
        };

        chosen {
                zephyr,boot-mode = &boot_retention;
		zmk,magic-boot-mode = &magic_retention;
        };
};

/* Reduce SRAM0 usage by 4 bytes to account for non-init area */
&sram0 {
        reg = <0x20000000 0x7FFC>;
};

Kconfig settings:

CONFIG_RETAINED_MEM=y
CONFIG_RETENTION=y
CONFIG_RETENTION_BOOT_MODE=y
CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y

Similar mechanism forks on stm32f4 with tinyuf2 as long as you use the correct reg/offsets for the RAM on the given device.

STM32 ROM Bootloader

The STM32 ROM bootloader is handled a bit differently, using an early init callback that checks the bootmode in RAM, and if finding BOOT_MODE_TYPE_BOOTLOADER, uses a small bit of code to de-init and jump to the bootloader directly. That means no magic value mapping has to occur.

The following works on stm32f072.

Devicetree:

/ {
        sram@20003FFF {
                compatible = "zephyr,memory-region", "mmio-sram";
                reg = <0x20003FFF 0x1>;
                zephyr,memory-region = "RetainedMem";
                status = "okay";

                retainedmem {
                        compatible = "zephyr,retained-ram";
                        status = "okay";
                        #address-cells = <1>;
                        #size-cells = <1>;

                        retention0: retention@0 {
                                compatible = "zephyr,retention";
                                status = "okay";
                                reg = <0x0 0x1>;
                        };
                };
        };

        chosen {
                zephyr,boot-mode = &retention0;
        };
};

/* Reduce SRAM0 usage by 1 byte to account for non-init area */
&sram0 {
        reg = <0x20000000 0x3FFF>;
};

This also requires the ROM bootloader details (found in AN2606 from ST) has been added to the SoC .dtsi file, e.g. from https://github.com/zmkfirmware/zephyr/pull/39/files#diff-c3c466b9a87ae3801f4ebf6b99797e29304b66407ef9393c203b92896eafd229

		bootloader: bootloader@0x1FFF0000 {
			compatible = "st,stm32-bootloader";
			reg = <0x1FFF0000 DT_SIZE_K(29)>;
			status = "reserved";
		};

Kconfig:

CONFIG_RETAINED_MEM=y
CONFIG_RETENTION=y
CONFIG_RETENTION_BOOT_MODE=y

Testing

I've specifically tested so far:

  • SAMD21 running https://github.com/adafruit/uf2-samdx1 with my samd21pad
  • f072 on my Le Chiffre stm32 from sporkus
  • stm32f401 with tinyuf2 as a secondary bootloader on a prototype PCB I was sent.

Still needs testing:

  • stm32f4 and jumping to ROM bootloader. I encountered issues here I believe thanks to tinyuf2 running before the early init code.
  • nRF52 changes.

@petejohanson petejohanson added enhancement New feature or request board PRs and issues related to boards. core Core functionality/behavior of ZMK behaviors labels Dec 2, 2024
@petejohanson petejohanson self-assigned this Dec 2, 2024
@petejohanson petejohanson requested a review from a team as a code owner December 2, 2024 08:03
@petejohanson
Copy link
Contributor Author

If this passes all the various testing, we'd probably want to add some either .dtsi files, snippets, or both, to allow for consistent setup of the devicetree/Kconfig bits.

@petejohanson petejohanson force-pushed the bootloader/retention-boot-mode-support branch from 0393958 to 96c6d03 Compare December 2, 2024 17:29
To trigger bootloaders that use a magic value in RAM to trigger
bootloader mode, add a mapping retained memory driver that maps
write/read of boot mode values to a special magic value stored
in the actually backing RAM.
Support new generic Zephyr retention boot mode API in the reset
behavior.
@petejohanson petejohanson force-pushed the bootloader/retention-boot-mode-support branch from 96c6d03 to 6976913 Compare December 3, 2024 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
behaviors board PRs and issues related to boards. core Core functionality/behavior of ZMK enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant