aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2022-06-07 11:43:19 -0400
committerKevin O'Connor <kevin@koconnor.net>2022-06-12 11:25:57 -0400
commitea4f6d6a77567e9277f775cdb50375fd3e6a25d4 (patch)
tree0e4ff0b0dd03d3de11b5244d6243258accac8ad2
parentc30e5f847cb1c1f30376a3282cd03c77da364cff (diff)
downloadkutter-ea4f6d6a77567e9277f775cdb50375fd3e6a25d4.tar.gz
kutter-ea4f6d6a77567e9277f775cdb50375fd3e6a25d4.tar.xz
kutter-ea4f6d6a77567e9277f775cdb50375fd3e6a25d4.zip
rp2040: Implement workaround for USB errata "rp2040-e5"
The rp2040 USB may not connect after a reset. Implementation the recommended workaround. Signed-off-by: Lasse Dalegaard <dalegaard@gmail.com> Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r--docs/Config_Changes.md6
-rw-r--r--src/rp2040/usbserial.c102
2 files changed, 105 insertions, 3 deletions
diff --git a/docs/Config_Changes.md b/docs/Config_Changes.md
index ca97a6cc..6961cbde 100644
--- a/docs/Config_Changes.md
+++ b/docs/Config_Changes.md
@@ -8,6 +8,12 @@ All dates in this document are approximate.
## Changes
+20220612: The rp2040 micro-controller now has a workaround for the
+"rp2040-e5" USB errata. This should make initial USB connections more
+reliable. However, it may result in a change in behavior for the
+gpio15 pin. It is unlikely the gpio15 behavior change will be
+noticeable.
+
20220407: The temperature_fan `pid_integral_max` config option has
been removed (it was deprecated on 20210612).
diff --git a/src/rp2040/usbserial.c b/src/rp2040/usbserial.c
index 3a6736ef..83838d2d 100644
--- a/src/rp2040/usbserial.c
+++ b/src/rp2040/usbserial.c
@@ -7,9 +7,13 @@
#include <string.h> // memcpy
#include "board/armcm_boot.h" // armcm_enable_irq
#include "board/io.h" // writeb
+#include "board/misc.h" // timer_read_time
#include "board/usb_cdc.h" // usb_notify_ep0
#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN
#include "board/usbstd.h" // USB_ENDPOINT_XFER_INT
+#include "hardware/regs/sysinfo.h" // SYSINFO_CHIP_ID_OFFSET
+#include "hardware/structs/iobank0.h" // iobank0_hw
+#include "hardware/structs/padsbank0.h" // padsbank0_hw
#include "hardware/structs/resets.h" // RESETS_RESET_USBCTRL_BITS
#include "hardware/structs/usb.h" // usb_hw
#include "internal.h" // enable_pclock
@@ -165,6 +169,89 @@ usb_request_bootloader(void)
/****************************************************************
+ * USB Errata workaround
+ ****************************************************************/
+
+// The rp2040 USB has an errata causing it to sometimes not connect
+// after a reset. The following code has extracts from the PICO SDK.
+
+static struct task_wake usb_errata_wake;
+
+// Workaround for rp2040-e5 errata
+void
+usb_errata_task(void)
+{
+ if (!sched_check_wake(&usb_errata_wake))
+ return;
+
+ if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS)
+ // Already connected - workaround not needed
+ return;
+
+ // Wait for not in SE0 state
+ if (!(usb_hw->sie_status & USB_SIE_STATUS_LINE_STATE_BITS)) {
+ sched_wake_task(&usb_errata_wake);
+ return;
+ }
+
+ // Backup GPIO15 pad state
+ uint32_t dp = 15;
+ uint32_t gpio_ctrl_prev = iobank0_hw->io[dp].ctrl;
+ uint32_t pad_ctrl_prev = padsbank0_hw->io[dp];
+
+ // Enable bus keep
+ hw_write_masked(&padsbank0_hw->io[dp],
+ PADS_BANK0_GPIO15_PUE_BITS | PADS_BANK0_GPIO15_PDE_BITS,
+ PADS_BANK0_GPIO15_PUE_BITS | PADS_BANK0_GPIO15_PDE_BITS);
+ // Disable pad output
+ hw_write_masked(&iobank0_hw->io[dp].ctrl,
+ 0x2 << IO_BANK0_GPIO15_CTRL_OEOVER_LSB,
+ IO_BANK0_GPIO15_CTRL_OEOVER_BITS);
+ // Enable USB debug muxing function
+ hw_write_masked(&iobank0_hw->io[dp].ctrl,
+ 8 << IO_BANK0_GPIO15_CTRL_FUNCSEL_LSB,
+ IO_BANK0_GPIO15_CTRL_FUNCSEL_BITS);
+ // Set input override
+ hw_write_masked(&iobank0_hw->io[dp].ctrl,
+ 0x3 << IO_BANK0_GPIO15_CTRL_INOVER_LSB,
+ IO_BANK0_GPIO15_CTRL_INOVER_BITS);
+ // PHY pullups need to stay on
+ hw_set_alias(usb_hw)->phy_direct = USB_USBPHY_DIRECT_DP_PULLUP_EN_BITS;
+ hw_set_alias(usb_hw)->phy_direct_override =
+ USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS;
+ // Switch from USB PHY to GPIO PHY, now with J forced
+ usb_hw->muxing = (USB_USB_MUXING_TO_DIGITAL_PAD_BITS
+ | USB_USB_MUXING_SOFTCON_BITS);
+
+ // Wait 1ms
+ uint32_t endtime = timer_read_time() + timer_from_us(1000);
+ while (timer_is_before(timer_read_time(), endtime))
+ ;
+
+ // Verify in connected state
+ endtime += timer_from_us(1000);
+ for (;;) {
+ if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS)
+ break;
+ if (timer_is_before(endtime, timer_read_time()))
+ // Something went wrong - restore state and continue anyway
+ break;
+ }
+
+ // Switch back to USB phy
+ usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
+ // Unset PHY pullup overrides
+ hw_clear_alias(usb_hw)->phy_direct_override =
+ USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS;
+
+ // Restore GPIO control states
+ iobank0_hw->io[dp].ctrl = gpio_ctrl_prev;
+ padsbank0_hw->io[dp] = pad_ctrl_prev;
+}
+DECL_TASK(usb_errata_task);
+
+
+/****************************************************************
* Setup and interrupts
****************************************************************/
@@ -191,6 +278,10 @@ USB_Handler(void)
}
}
}
+ if (ints & USB_INTS_BUS_RESET_BITS) {
+ usb_hw->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
+ sched_wake_task(&usb_errata_wake);
+ }
}
static void
@@ -228,15 +319,20 @@ usbserial_init(void)
| USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS);
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
+ // Check if usb errata workaround needed
+ enable_pclock(RESETS_RESET_SYSINFO_BITS);
+ uint32_t chip_id = *((io_ro_32*)(SYSINFO_BASE + SYSINFO_CHIP_ID_OFFSET));
+ uint32_t version = ((chip_id & SYSINFO_CHIP_ID_REVISION_BITS)
+ >> SYSINFO_CHIP_ID_REVISION_LSB);
+
// Enable irqs
usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
- usb_hw->inte = USB_INTE_BUFF_STATUS_BITS | USB_INTE_SETUP_REQ_BITS;
+ usb_hw->inte = (USB_INTE_BUFF_STATUS_BITS | USB_INTE_SETUP_REQ_BITS
+ | (version == 1 ? USB_INTE_BUS_RESET_BITS: 0));
armcm_enable_irq(USB_Handler, USBCTRL_IRQ_IRQn, 1);
// Enable USB pullup
usb_hw->sie_ctrl = (USB_SIE_CTRL_EP0_INT_1BUF_BITS
| USB_SIE_CTRL_PULLUP_EN_BITS);
-
- // XXX - errata reset workaround??
}
DECL_INIT(usbserial_init);