From 762a6f1256b52df4b343300edc03e0e846c9670a Mon Sep 17 00:00:00 2001 From: sago35 Date: Fri, 15 Jul 2022 00:54:13 +0900 Subject: [PATCH] rp2040: fix usb device enumeration (RP2040-E5) --- src/machine/machine_rp2040_usb.go | 1 + ...e_rp2040_usb_fix_usb_device_enumeration.go | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/machine/machine_rp2040_usb_fix_usb_device_enumeration.go diff --git a/src/machine/machine_rp2040_usb.go b/src/machine/machine_rp2040_usb.go index eecf9d63..372080ee 100644 --- a/src/machine/machine_rp2040_usb.go +++ b/src/machine/machine_rp2040_usb.go @@ -130,6 +130,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { rp.USBCTRL_REGS.ADDR_ENDP.Set(0) initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL) + fixRP2040UsbDeviceEnumeration() } } diff --git a/src/machine/machine_rp2040_usb_fix_usb_device_enumeration.go b/src/machine/machine_rp2040_usb_fix_usb_device_enumeration.go new file mode 100644 index 00000000..dd7e0c42 --- /dev/null +++ b/src/machine/machine_rp2040_usb_fix_usb_device_enumeration.go @@ -0,0 +1,101 @@ +//go:build rp2040 +// +build rp2040 + +package machine + +import ( + "device/rp" +) + +// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c +func fixRP2040UsbDeviceEnumeration() { + + // Wait SE0 phase will call force ls_j phase which will call finish phase + hw_enumeration_fix_wait_se0() +} + +func hw_enumeration_fix_wait_se0() { + // Wait for SE0 to end (i.e. the host to stop resetting). This reset can last quite long. + // 10-15ms so we are going to set a timer callback. + + // if timer pool disabled, or no timer available, have to busy wait. + hw_enumeration_fix_busy_wait_se0() +} + +const ( + LS_SE0 = 0b00 + LS_J = 0b01 + LS_K = 0b10 + LS_SE1 = 0b11 +) + +const ( + dp = 15 +) + +var ( + gpioCtrlPrev uint32 + padCtrlPrev uint32 +) + +func hw_enumeration_fix_busy_wait_se0() { + for ((rp.USBCTRL_REGS.SIE_STATUS.Get() & rp.USBCTRL_REGS_SIE_STATUS_LINE_STATE_Msk) >> rp.USBCTRL_REGS_SIE_STATUS_LINE_STATE_Pos) == LS_SE0 { + } + + // Now force LS_J (next stage of fix) + hw_enumeration_fix_force_ls_j() +} + +func hw_enumeration_fix_force_ls_j() { + // DM must be 0 for this to work. This is true if it is selected + // to any other function. fn 8 on this pin is only for debug so shouldn't + // be selected + + // Before changing any pin state, take a copy of the current gpio control register + gpioCtrlPrev = ioBank0.io[dp].ctrl.Get() + // Also take a copy of the pads register + padCtrlPrev = padsBank0.io[dp].Get() + + // Enable bus keep and force pin to tristate, so USB DP muxing doesn't affect + // pin state + padsBank0.io[dp].SetBits(rp.PADS_BANK0_GPIO0_PUE | rp.PADS_BANK0_GPIO0_PDE) + ioBank0.io[dp].ctrl.ReplaceBits(rp.IO_BANK0_GPIO0_CTRL_OEOVER_DISABLE, rp.IO_BANK0_GPIO0_CTRL_OEOVER_Msk>>rp.IO_BANK0_GPIO0_CTRL_OEOVER_Pos, rp.IO_BANK0_GPIO0_CTRL_OEOVER_Pos) + + // Select function 8 (USB debug muxing) without disturbing other controls + ioBank0.io[dp].ctrl.ReplaceBits(8, rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Msk>>rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Pos, rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Pos) + + // J state is a differential 1 for a full speed device so + // DP = 1 and DM = 0. Don't actually need to set DM low as it + // is already gated assuming it isn't funcseld. + ioBank0.io[dp].ctrl.ReplaceBits(rp.IO_BANK0_GPIO1_CTRL_INOVER_HIGH, rp.IO_BANK0_GPIO1_CTRL_INOVER_Msk>>rp.IO_BANK0_GPIO1_CTRL_INOVER_Pos, rp.IO_BANK0_GPIO1_CTRL_INOVER_Pos) + + // Force PHY pull up to stay before switching away from the phy + rp.USBCTRL_REGS.USBPHY_DIRECT.SetBits(rp.USBCTRL_REGS_USBPHY_DIRECT_DP_PULLUP_EN) + rp.USBCTRL_REGS.USBPHY_DIRECT_OVERRIDE.SetBits(rp.USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN) + + // Switch to GPIO phy with LS_J forced + rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_DIGITAL_PAD | rp.USBCTRL_REGS_USB_MUXING_SOFTCON) + + // LS_J is now forced but while loop here just to check + + // if timer pool disabled, or no timer available, have to busy wait. + hw_enumeration_fix_finish() + +} + +func hw_enumeration_fix_finish() { + // Should think we are connected now + for (rp.USBCTRL_REGS.SIE_STATUS.Get() & rp.USBCTRL_REGS_SIE_STATUS_CONNECTED) != rp.USBCTRL_REGS_SIE_STATUS_CONNECTED { + } + + // Switch back to USB phy + rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_PHY | rp.USBCTRL_REGS_USB_MUXING_SOFTCON) + + // Get rid of DP pullup override + rp.USBCTRL_REGS.USBPHY_DIRECT_OVERRIDE.ClearBits(rp.USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN) + + // Finally, restore the gpio ctrl value back to GPIO15 + ioBank0.io[dp].ctrl.Set(gpioCtrlPrev) + // Restore the pad ctrl value + padsBank0.io[dp].Set(padCtrlPrev) +}