Skip to main content

SAMD21 UF2 Bootloader

The SAMD21 UF2 Bootloader is a magic value type bootloader, with some extra setup used to integrate with it.

Kconfig Symbol Enablement

Three Kconfig symbols need to be enabled for this feature to work, namely RETAINED_MEM, RETENTION, and RETENTION_BOOT_MODE. Typically, this is done by implying the symbols for the board symbol in the Kconfig.<board>, file, e.g.:

config BOARD_TOFU65
select SOC_RP2040
imply RETAINED_MEM
imply RETENTION
imply RETENTION_BOOT_MODE

By using imply at the board level, users of the board can choose to override the setting and disable the feature if they so choose.

Adjust The Existing RAM node

We'll first adjust the SRAM to ensure Zephyr does not overwrite the memory location the bootloader inspect to determine if it should enter bootloader mode:

&sram0 {
reg = <0x20000000 0x7FFC>;
};

Note:

  • The 0x20000000 address is the address of the RAM for the target. This is nearly always 0x20000000.
  • The exact value of 0x7FFC will depend on the total RAM on the target. The value should be the total RAM, minus 4-bytes, in hex.

Add a new memory region node with retainer RAM

/ {
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>;
};
};
};
};

Note:

  • The node sram@20007FFC and the corresponding reg property values are obtained by adding the base RAM address (.e.g. 0x20000000) to the shrunk RAM size (e.g. 0x7FFC) to get the new start address for the area of reserved RAM.
  • The magic values are 32-bits (4 bytes), so the second reg size value is 0x4.

Magic Mapper node

Next, we'll set up our mapping retained mem driver, which will map from the Zephyr boot mode values to the values the bootloader is looking for:

/ {
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>;
};
};
};

Assign Chosen Properties

Finally, we'll assign two chosen properties for the two nodes that have been defined:

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

Magic Value Type Kconfig

Lastly, one Kconfig choice needs to be set, e.g. in Kconfig.defaults for the board:

choice ZMK_BOOTMODE_MAGIC_VALUE_BOOTLOADER_TYPE
default ZMK_BOOTMODE_MAGIC_VALUE_BOOTLOADER_TYPE_ADAFRUIT_BOSSA

endchoice