Skip to content

Commit b7b6781

Browse files
committed
RP2040: backport rp2040_usb_device_enumeration fix
1 parent c19d206 commit b7b6781

File tree

1 file changed

+33
-9
lines changed

1 file changed

+33
-9
lines changed

Diff for: targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c

+33-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "pico/time.h"
99
#include "hardware/structs/usb.h"
1010
#include "hardware/gpio.h"
11+
#include "hardware/structs/iobank0.h"
12+
#include "hardware/structs/padsbank0.h"
1113
#include "pico/fix/rp2040_usb_device_enumeration.h"
1214

1315
#define LS_SE0 0b00
@@ -36,7 +38,7 @@ static inline uint8_t hw_line_state(void) {
3638
return (usb_hw->sie_status & USB_SIE_STATUS_LINE_STATE_BITS) >> USB_SIE_STATUS_LINE_STATE_LSB;
3739
}
3840

39-
int64_t hw_enumeration_fix_wait_se0_callback(alarm_id_t id, void *user_data) {
41+
int64_t hw_enumeration_fix_wait_se0_callback(__unused alarm_id_t id, __unused void *user_data) {
4042
if (hw_line_state() == LS_SE0) {
4143
// Come back in 1ms and check again
4244
return 1000;
@@ -69,25 +71,42 @@ static void hw_enumeration_fix_wait_se0(void) {
6971
hw_enumeration_fix_busy_wait_se0();
7072
}
7173

72-
int64_t hw_enumeration_fix_force_ls_j_done(alarm_id_t id, void *user_data) {
74+
int64_t hw_enumeration_fix_force_ls_j_done(__unused alarm_id_t id, __unused void *user_data) {
7375
hw_enumeration_fix_finish();
7476
return 0;
7577
}
7678

79+
static uint32_t gpio_ctrl_prev = 0;
80+
static uint32_t pad_ctrl_prev = 0;
81+
static const uint dp = 15;
82+
static const uint dm = 16;
83+
7784
static void hw_enumeration_fix_force_ls_j(void) {
78-
// Force LS_J
79-
const uint dp = 15;
80-
//const uint dm = 16;
81-
gpio_set_function(dp, 8);
82-
// TODO: assert dm is not funcseld to usb
85+
// DM must be 0 for this to work. This is true if it is selected
86+
// to any other function. fn 8 on this pin is only for debug so shouldn't
87+
// be selected
88+
if (gpio_get_function(dm) == 8) {
89+
panic("Not expecting DM to be function 8");
90+
}
91+
92+
// Before changing any pin state, take a copy of the current gpio control register
93+
gpio_ctrl_prev = iobank0_hw->io[dp].ctrl;
94+
// Also take a copy of the pads register
95+
pad_ctrl_prev = padsbank0_hw->io[dp];
96+
97+
// Enable bus keep and force pin to tristate, so USB DP muxing doesn't affect
98+
// pin state
99+
gpio_set_pulls(dp, true, true);
100+
gpio_set_oeover(dp, GPIO_OVERRIDE_LOW);
101+
// Select function 8 (USB debug muxing) without disturbing other controls
102+
hw_write_masked(&iobank0_hw->io[dp].ctrl,
103+
8 << IO_BANK0_GPIO15_CTRL_FUNCSEL_LSB, IO_BANK0_GPIO15_CTRL_FUNCSEL_BITS);
83104

84105
// J state is a differential 1 for a full speed device so
85106
// DP = 1 and DM = 0. Don't actually need to set DM low as it
86107
// is already gated assuming it isn't funcseld.
87108
gpio_set_inover(dp, GPIO_OVERRIDE_HIGH);
88109

89-
// TODO: What to do about existing DP state here?
90-
91110
// Force PHY pull up to stay before switching away from the phy
92111
hw_set_alias(usb_hw)->phy_direct = USB_USBPHY_DIRECT_DP_PULLUP_EN_BITS;
93112
hw_set_alias(usb_hw)->phy_direct_override = USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS;
@@ -118,4 +137,9 @@ static void hw_enumeration_fix_finish(void) {
118137

119138
// Get rid of DP pullup override
120139
hw_clear_alias(usb_hw)->phy_direct_override = USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS;
140+
141+
// Finally, restore the gpio ctrl value back to GPIO15
142+
iobank0_hw->io[dp].ctrl = gpio_ctrl_prev;
143+
// Restore the pad ctrl value
144+
padsbank0_hw->io[dp] = pad_ctrl_prev;
121145
}

0 commit comments

Comments
 (0)