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

Implement pico_bootsel_via_double_reset with the POWMAN DOUBLE_TAP flag on RP2350. #2083

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
#include "pico/bootrom.h"
#include "pico/binary_info.h"

#if !PICO_RP2040
#include "hardware/structs/powman.h"
#endif

// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS, Window of opportunity for a second press of a reset button to enter BOOTSEL mode (milliseconds), type=int, default=200, group=pico_bootsel_via_double_reset
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS 200
Expand Down Expand Up @@ -41,12 +45,62 @@
bi_decl(bi_program_feature("double reset -> BOOTSEL"));
#endif

#if PICO_RP2040

// RP2040 stores a token in RAM, which is retained over assertion of the RUN pin.

static const uint32_t magic_token[] = {
0xf01681de, 0xbd729b29, 0xd359be7a,
};

static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];

static inline bool double_tap_flag_is_set(void) {
for (uint i = 0; i < count_of(magic_token); i++) {
if (magic_location[i] != magic_token[i]) {
return false;
}
}
return true;
}

static inline void set_double_tap_flag(void) {
for (uint i = 0; i < count_of(magic_token); i++) {
magic_location[i] = magic_token[i];
}
}

static inline void clear_double_tap_flag(void) {
magic_location[0] = 0;
}

#else

// Newer microcontrollers have a purpose-made register which is retained over
// RUN events, for detecting double-tap events. The ROM has built-in support
// for this, but this library can also use the same hardware feature.
// (Also, RAM is powered down when the RUN pin is asserted, so it's a bad
// place to put the token!)
//
// Note if ROM support is also enabled (via DOUBLE_TAP in OTP BOOT_FLAGS) then
// we never reach this point with the double tap flag still set. The window
// is the sum of the delay added by this library and the delay added by the
// ROM. It's not recommended to enable both, but it works.

static inline bool double_tap_flag_is_set(void) {
return powman_hw->chip_reset & POWMAN_CHIP_RESET_DOUBLE_TAP_BITS;
}

static inline void set_double_tap_flag(void) {
hw_set_bits(&powman_hw->chip_reset, POWMAN_CHIP_RESET_DOUBLE_TAP_BITS);
}

static inline void clear_double_tap_flag(void) {
hw_clear_bits(&powman_hw->chip_reset, POWMAN_CHIP_RESET_DOUBLE_TAP_BITS);
}

#endif

/* Check for double reset and enter BOOTSEL mode if detected
*
* This function is registered to run automatically before main(). The
Expand All @@ -62,19 +116,16 @@ static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];
* in place so that the second boot will go to the bootloader.
*/
static void __attribute__((constructor)) boot_double_tap_check(void) {
for (uint i = 0; i < count_of(magic_token); i++) {
if (magic_location[i] != magic_token[i]) {
// Arm, wait, then disarm and continue booting
for (i = 0; i < count_of(magic_token); i++) {
magic_location[i] = magic_token[i];
}
busy_wait_us(PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000);
magic_location[0] = 0;
return;
}
if (!double_tap_flag_is_set()) {
// Arm, wait, then disarm and continue booting
set_double_tap_flag();
busy_wait_us(PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000);
clear_double_tap_flag();
return;
}

// Detected a double reset, so enter USB bootloader
magic_location[0] = 0;
clear_double_tap_flag();
#ifdef PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED
const uint32_t led_mask = 1u << PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED;
#else
Expand Down
Loading