Skip to content

Commit e9874f4

Browse files
ArcaneNibbledlech
authored andcommitted
pbio/drv/usb/usb_ev3: Perform PHY reset and interrupt setup
These are the most basic steps needed for a USB peripheral to be detected. After this commit, hosts will notice a USB device, but the device will not function because none of the required USB requests are handled.
1 parent 4871f41 commit e9874f4

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

lib/pbio/drv/usb/usb_ev3.c

Lines changed: 84 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,94 @@
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+
static void usb_device_intr(void) {
31+
IntSystemStatusClear(SYS_INT_USB0);
32+
}
33+
34+
static pbio_os_process_t pbdrv_usb_ev3_process;
35+
36+
static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *context) {
37+
PBIO_OS_ASYNC_BEGIN(state);
38+
39+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
40+
}
2841

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

32116
pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) {

lib/tiam1808/tiam1808/hw/hw_usb.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,8 @@
777777
#define USB_TXIE_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt
778778
// Enable
779779

780+
#define USB_TXIE_ALL_AM1808 0x0000001F // EP0, EP1-4
781+
780782
//*****************************************************************************
781783
//
782784
// The following are defines for the bit fields in the USB_O_RXIE register.
@@ -798,6 +800,8 @@
798800
#define USB_RXIE_EP2 0x00000004 // RX Endpoint 2 Interrupt Enable
799801
#define USB_RXIE_EP1 0x00000002 // RX Endpoint 1 Interrupt Enable
800802

803+
#define USB_RXIE_ALL_AM1808 0x0000001E // EP1-4
804+
801805
//*****************************************************************************
802806
//
803807
// The following are defines for the bit fields in the USB_O_IS register.
@@ -828,6 +832,8 @@
828832
#define USB_IE_RESUME 0x00000002 // Enable RESUME Interrupt
829833
#define USB_IE_SUSPND 0x00000001 // Enable SUSPEND Interrupt
830834

835+
#define USB_IE_ALL 0x000000FF
836+
831837
//*****************************************************************************
832838
//
833839
// The following are defines for the bit fields in the USB_O_FRAME register.

lib/tiam1808/tiam1808/hw/hw_usbOtg_AM1808.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,33 @@ extern "C"
7979
#define USB_0_GEN_RNDIS_SIZE_EP4 0x5C
8080
#define USB_0_GENR_INTR 0x22
8181

82+
// Bits for CTRL
83+
#define USBOTG_CTRL_RESET 0x01
84+
#define USBOTG_CTRL_CLKFACK 0x02
85+
#define USBOTG_CTRL_UINT 0x08
86+
#define USBOTG_CTRL_RNDIS 0x10
87+
88+
// The following are interrupt bits as found in the OTG wrapper
89+
#define USBOTG_INTR_EP0 0x00000001
90+
#define USBOTG_INTR_EP1_IN 0x00000002
91+
#define USBOTG_INTR_EP2_IN 0x00000004
92+
#define USBOTG_INTR_EP3_IN 0x00000008
93+
#define USBOTG_INTR_EP4_IN 0x00000010
94+
#define USBOTG_INTR_EP1_OUT 0x00000200
95+
#define USBOTG_INTR_EP2_OUT 0x00000400
96+
#define USBOTG_INTR_EP3_OUT 0x00000800
97+
#define USBOTG_INTR_EP4_OUT 0x00001000
98+
#define USBOTG_INTR_DRVVBUS 0x01000000 // DRVVBUS level change
99+
#define USBOTG_INTR_VBUSERR 0x00800000 // VBUS Error
100+
#define USBOTG_INTR_SESREQ 0x00400000 // SESSION REQUEST
101+
#define USBOTG_INTR_DISCON 0x00200000 // Session Disconnect
102+
#define USBOTG_INTR_CONN 0x00100000 // Session Connect
103+
#define USBOTG_INTR_SOF 0x00080000 // Start of Frame
104+
#define USBOTG_INTR_BABBLE 0x00040000 // Babble Detected
105+
#define USBOTG_INTR_RESET 0x00040000 // RESET Signaling Detected
106+
#define USBOTG_INTR_RESUME 0x00020000 // RESUME Signaling Detected
107+
#define USBOTG_INTR_SUSPEND 0x00010000 // SUSPEND Signaling Detected
108+
82109
#ifdef __cplusplus
83110
}
84111
#endif

0 commit comments

Comments
 (0)