diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index ff6e82bb4..f897da34e 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -63,6 +63,26 @@ void __attribute__((noreturn)) rom_reset_usb_boot(uint32_t usb_activity_gpio_pin #endif } +void __attribute__((noreturn)) rom_reset_usb_boot_extra(int usb_activity_gpio_pin, uint32_t disable_interface_mask, bool usb_activity_gpio_pin_active_low) { +#ifdef ROM_FUNC_RESET_USB_BOOT + (void)usb_activity_gpio_pin_active_low; + rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT); + func(usb_activity_gpio_pin < 0 ? 0 : (1u << usb_activity_gpio_pin), disable_interface_mask); +#elif defined(ROM_FUNC_REBOOT) + uint32_t flags = disable_interface_mask; + if (usb_activity_gpio_pin >= 0) { + flags |= BOOTSEL_FLAG_GPIO_PIN_SPECIFIED; + if (usb_activity_gpio_pin_active_low) { + flags |= BOOTSEL_FLAG_GPIO_PIN_ACTIVE_LOW; + } + } + rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL | REBOOT2_FLAG_NO_RETURN_ON_SUCCESS, 10, flags, usb_activity_gpio_pin); + __builtin_unreachable(); +#else + panic_unsupported(); +#endif +} + #if !PICO_RP2040 bool rom_get_boot_random(uint32_t out[4]) { uint32_t result[5]; diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index ffd2a8b94..498d4f724 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -237,6 +237,25 @@ static inline void __attribute__((noreturn)) reset_usb_boot(uint32_t usb_activit rom_reset_usb_boot(usb_activity_gpio_pin_mask, disable_interface_mask); } +/*! + * \brief Reboot the device into BOOTSEL mode + * \ingroup pico_bootrom + * + * This function reboots the device into the BOOTSEL mode ('usb boot"). + * + * Facilities are provided to enable an "activity light" via GPIO attached LED for the USB Mass Storage Device, + * and to limit the USB interfaces exposed. + * + * \param usb_activity_gpio_pin GPIO pin to be used as an activitiy pin, or -1 for none + * from the host. + * \param disable_interface_mask value to control exposed interfaces + * - 0 To enable both interfaces (as per a cold boot) + * - 1 To disable the USB Mass Storage Interface + * - 2 To disable the USB PICOBOOT Interface + * \param usb_activity_gpio_pin_active_low Activity GPIO is active low (ignored on RP2040) + */ +void __attribute__((noreturn)) rom_reset_usb_boot_extra(int usb_activity_gpio_pin, uint32_t disable_interface_mask, bool usb_activity_gpio_pin_active_low); + /*! * \brief Connect the SSI/QMI to the QSPI pads * \ingroup pico_bootrom diff --git a/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c b/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c index 1c1947eac..8028936e2 100644 --- a/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c +++ b/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c @@ -24,6 +24,11 @@ // PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED, Optionally define a pin to use as bootloader activity LED when BOOTSEL mode is entered via reset double tap, type=int, min=0, max=47 on RP2350B, 29 otherwise, group=pico_bootsel_via_double_reset +// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED_ACTIVE_LOW, Whether pin used as bootloader activity LED when BOOTSEL mode is entered via reset double tap is active low. Not supported on RP2040, type=bool, default=0, group=pico_bootsel_via_double_reset +#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED_ACTIVE_LOW +#define PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED_ACTIVE_LOW 0 +#endif + // PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK, Optionally disable either the mass storage interface (bit 0) or the PICOBOOT interface (bit 1) when entering BOOTSEL mode via double reset, type=int, min=0, max=3, default=0, group=pico_bootsel_via_double_reset #ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK #define PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK 0u @@ -127,13 +132,14 @@ static void __attribute__((constructor)) boot_double_tap_check(void) { // Detected a double reset, so enter USB bootloader 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; + const int led = PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED; #else - const uint32_t led_mask = 0u; + const int led = -1; #endif - reset_usb_boot( - led_mask, - PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK + rom_reset_usb_boot_extra( + led, + PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK, + PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED_ACTIVE_LOW ); } diff --git a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h index 472e078e1..b572998d8 100644 --- a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h +++ b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h @@ -73,6 +73,11 @@ // PICO_CONFIG: PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED, Optionally define a pin to use as bootloader activity LED when BOOTSEL mode is entered via USB (either VIA_BAUD_RATE or VIA_VENDOR_INTERFACE), type=int, min=0, max=47 on RP2350B, 29 otherwise, group=pico_stdio_usb +// PICO_CONFIG: PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED_ACTIVE_LOW, Whether pin to use as bootloader activity LED when BOOTSEL mode is entered via USB (either VIA_BAUD_RATE or VIA_VENDOR_INTERFACE) is active low, type=bool, default=0, group=pico_stdio_usb +#ifndef PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED_ACTIVE_LOW +#define PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED_ACTIVE_LOW 0 +#endif + // PICO_CONFIG: PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED, Whether the pin specified by PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED is fixed or can be modified by picotool over the VENDOR USB interface, type=bool, default=0, group=pico_stdio_usb #ifndef PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED #define PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED 0 diff --git a/src/rp2_common/pico_stdio_usb/reset_interface.c b/src/rp2_common/pico_stdio_usb/reset_interface.c index 4d52689a1..26afa3de1 100644 --- a/src/rp2_common/pico_stdio_usb/reset_interface.c +++ b/src/rp2_common/pico_stdio_usb/reset_interface.c @@ -119,16 +119,19 @@ static bool resetd_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_ #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL if (request->bRequest == RESET_REQUEST_BOOTSEL) { #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED - uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; + int gpio = PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; + bool active_low = PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED_ACTIVE_LOW; #else - uint gpio_mask = 0u; + int gpio = -1; + bool active_low = false; #endif #if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED if (request->wValue & 0x100) { - gpio_mask = 1u << (request->wValue >> 9u); + gpio = request->wValue >> 9u; } + active_low = request->wValue & 0x200; #endif - reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); + rom_reset_usb_boot_extra(gpio, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK, active_low); // does not return, otherwise we'd return true } #endif @@ -173,11 +176,13 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { void tud_cdc_line_coding_cb(__unused uint8_t itf, cdc_line_coding_t const* p_line_coding) { if (p_line_coding->bit_rate == PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE) { #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED - const uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; + int gpio = PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; + bool active_low = PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED_ACTIVE_LOW; #else - const uint gpio_mask = 0u; + int gpio = -1; + bool active_low = false; #endif - reset_usb_boot(gpio_mask, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); + rom_reset_usb_boot_extra(gpio, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK, active_low); } } #endif