Skip to content

Commit 31ee9b2

Browse files
committed
pbio/drv/usb/usb_ev3: Perform PHY reset interrupt setup
1 parent 50beb6c commit 31ee9b2

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

lib/pbio/drv/usb/usb_ev3.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdint.h>
1212

1313
#include <pbdrv/usb.h>
14+
#include <pbio/os.h>
1415
#include <pbio/util.h>
1516

1617
#include <tiam1808/armv5/am1808/interrupt.h>
@@ -22,11 +23,99 @@
2223
#include <tiam1808/hw/soc_AM1808.h>
2324
#include <tiam1808/hw/hw_psc_AM1808.h>
2425
#include <tiam1808/psc.h>
26+
#include <tiam1808/usb.h>
2527

2628
#include <pbdrv/clock.h>
2729

30+
#define INTR_BIT_USB_RESET (1 << 18)
31+
#define INTR_BIT_EP1_OUT (1 << 9)
32+
#define INTR_BIT_EP1_IN (1 << 1)
33+
#define INTR_BIT_EP0 (1 << 0)
34+
35+
static void usb_device_intr(void) {
36+
IntSystemStatusClear(SYS_INT_USB0);
37+
}
38+
39+
static pbio_os_process_t pbdrv_usb_ev3_process;
40+
41+
static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *context) {
42+
PBIO_OS_ASYNC_BEGIN(state);
43+
44+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
45+
}
2846

2947
void pbdrv_usb_init(void) {
48+
// This reset sequence is from Example 34-1 in the AM1808 TRM (spruh82c.pdf)
49+
// Because PHYs and clocking are... as they tend to be, use the precise sequence
50+
// of operations specified.
51+
52+
// Power on and reset the controller
53+
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_USB0, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
54+
USBReset(USB0_BASE);
55+
56+
// Reset the PHY
57+
HWREG(CFGCHIP2_USBPHYCTRL) |= CFGCHIP2_RESET;
58+
for (int i = 0; i < 50; i++) {
59+
// Empty delay loop which should not be optimized out.
60+
// This is the delay amount in the TI datasheet example.
61+
__asm__ volatile ("");
62+
}
63+
HWREG(CFGCHIP2_USBPHYCTRL) &= ~CFGCHIP2_RESET;
64+
65+
// Set up the PHY and force it into device mode
66+
HWREG(CFGCHIP2_USBPHYCTRL) =
67+
(HWREG(CFGCHIP2_USBPHYCTRL) &
68+
~CFGCHIP2_OTGMODE &
69+
~CFGCHIP2_PHYPWRDN & // Make sure PHY is on
70+
~CFGCHIP2_OTGPWRDN) | // Make sure OTG subsystem is on
71+
CFGCHIP2_FORCE_DEVICE | // We only ever want device operation
72+
CFGCHIP2_DATPOL | // Data lines are *not* inverted
73+
CFGCHIP2_SESENDEN | // Enable various analog comparators
74+
CFGCHIP2_VBDTCTEN;
75+
76+
HWREG(CFGCHIP2_USBPHYCTRL) =
77+
(HWREG(CFGCHIP2_USBPHYCTRL) & ~CFGCHIP2_REFFREQ) |
78+
CFGCHIP2_REFFREQ_24MHZ | // Clock is 24 MHz
79+
CFGCHIP2_USB2PHYCLKMUX; // Clock comes from PLL
80+
81+
// Wait for PHY clocks to be ready
82+
while (!(HWREG(CFGCHIP2_USBPHYCTRL) & CFGCHIP2_PHYCLKGD)) {
83+
}
84+
85+
// Enable "PDR" mode for handling interrupts
86+
//
87+
// The datasheet doesn't clearly explain what this means,
88+
// but what it appears TI has done is to wrap some custom interrupt and DMA
89+
// logic around the Mentor Graphics core. The standard core registers
90+
// thus now live at offset +0x400, and addresses below that pertain to the wrapper.
91+
// This leaves some redundancy with how interrupts are set up, and this bit
92+
// seems to enable accessing everything the TI way (more convenient) rather than
93+
// the standard Mentor Graphics way (interrupt flags spread across more registers).
94+
HWREG(USB_0_OTGBASE + USB_0_CTRL) &= ~(1 << 3);
95+
HWREGH(USB0_BASE + USB_O_TXIE) = 0x1f;
96+
HWREGH(USB0_BASE + USB_O_RXIE) = 0x1e;
97+
HWREGB(USB0_BASE + USB_O_IE) = 0xff;
98+
99+
// Enable the interrupts we actually care about
100+
HWREG(USB_0_OTGBASE + USB_0_INTR_MASK_SET) =
101+
INTR_BIT_USB_RESET |
102+
INTR_BIT_EP1_OUT |
103+
INTR_BIT_EP1_IN |
104+
INTR_BIT_EP0;
105+
106+
// Clear all the interrupts once
107+
HWREG(USB_0_OTGBASE + USB_0_INTR_SRC_CLEAR) = HWREG(USB_0_OTGBASE + USB_0_INTR_SRC);
108+
109+
// Hook up interrupt handler
110+
IntRegister(SYS_INT_USB0, usb_device_intr);
111+
IntChannelSet(SYS_INT_USB0, 2);
112+
IntSystemEnable(SYS_INT_USB0);
113+
114+
// Finally signal a connection
115+
USBDevConnect(USB0_BASE);
116+
117+
// We are basically done. USB is event-driven, and so we don't have to block boot.
118+
pbio_os_process_start(&pbdrv_usb_ev3_process, pbdrv_usb_ev3_process_thread, NULL);
30119
}
31120

32121
pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) {

0 commit comments

Comments
 (0)