1 /*
2  * Copyright (c) 2013 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <lk/err.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <lk/trace.h>
12 #include <lk/debug.h>
13 #include <platform.h>
14 #include <lk/reg.h>
15 #include <dev/usb.h>
16 #include <dev/usbc.h>
17 #include <arch/arm/cm.h>
18 
19 #include "ti_driverlib.h"
20 #include "inc/hw_usb.h"
21 
22 #define LOCAL_TRACE 0
23 
24 static bool pending_addr_change = false;
25 static uint8_t addr;
26 
usbc_dump_regs(void)27 static void usbc_dump_regs(void) {
28     printf("USB0 reg dump:\n");
29 #define DUMPREG8(r) printf("\t" #r ": 0x%hhx\n", *REG8(USB0_BASE + (r)));
30 #define DUMPREG16(r) printf("\t" #r ": 0x%hx\n", *REG16(USB0_BASE + (r)));
31 #define DUMPREG32(r) printf("\t" #r ": 0x%x\n",  *REG32(USB0_BASE + (r)));
32 
33     DUMPREG8(USB_O_FADDR);
34     DUMPREG8(USB_O_POWER);
35     DUMPREG16(USB_O_TXIS);
36     DUMPREG16(USB_O_RXIS);
37     DUMPREG16(USB_O_TXIE);
38     DUMPREG16(USB_O_RXIE);
39     DUMPREG8(USB_O_IS);
40     DUMPREG8(USB_O_IE);
41     DUMPREG16(USB_O_FRAME);
42     DUMPREG8(USB_O_EPIDX);
43     DUMPREG8(USB_O_TEST);
44     DUMPREG32(USB_O_FIFO0);
45     DUMPREG32(USB_O_FIFO1);
46     DUMPREG32(USB_O_FIFO2);
47     DUMPREG32(USB_O_FIFO3);
48     DUMPREG32(USB_O_FIFO4);
49     DUMPREG32(USB_O_FIFO5);
50     DUMPREG32(USB_O_FIFO6);
51     DUMPREG32(USB_O_FIFO7);
52     DUMPREG32(USB_O_FIFO8);
53     DUMPREG32(USB_O_FIFO9);
54     DUMPREG32(USB_O_FIFO10);
55     DUMPREG32(USB_O_FIFO11);
56     DUMPREG32(USB_O_FIFO12);
57     DUMPREG32(USB_O_FIFO13);
58     DUMPREG32(USB_O_FIFO14);
59     DUMPREG32(USB_O_FIFO15);
60     DUMPREG16(USB_O_DEVCTL);
61     DUMPREG8(USB_O_TXFIFOSZ);
62     DUMPREG8(USB_O_RXFIFOSZ);
63     DUMPREG16(USB_O_TXFIFOADD);
64     DUMPREG16(USB_O_RXFIFOADD);
65     DUMPREG32(USB_O_PP);
66 
67 #undef DUMPREG8
68 #undef DUMPREG16
69 #undef DUMPREG32
70 }
71 
stellaris_usbc_early_init(void)72 void stellaris_usbc_early_init(void) {
73     LTRACE_ENTRY;
74     LTRACE_EXIT;
75 }
76 
stellaris_usbc_init(void)77 void stellaris_usbc_init(void) {
78     LTRACE_ENTRY;
79 
80     SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
81     SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
82 
83     SysCtlUSBPLLEnable();
84 
85     GPIOPinTypeUSBAnalog(GPIO_PORTD_AHB_BASE, GPIO_PIN_4 | GPIO_PIN_5);
86 
87     USBDevMode(USB0_BASE);
88     USBPHYPowerOn(USB0_BASE);
89 
90 #if LOCAL_TRACE
91     usbc_dump_regs();
92 
93     printf("addr %lu\n", USBDevAddrGet(USB0_BASE));
94     printf("ep0 status 0x%lx\n", USBEndpointStatus(USB0_BASE, USB_EP_0));
95 #endif
96 
97     NVIC_EnableIRQ(INT_USB0 - 16);
98     USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
99 
100     LTRACE_EXIT;
101 }
102 
ep0_irq(void)103 static void ep0_irq(void) {
104     uint status = USBEndpointStatus(USB0_BASE, USB_EP_0);
105 
106     LTRACEF("ep0 status 0x%x\n", status);
107 
108     /* delay setting the address until the ack as completed */
109     if (pending_addr_change) {
110         LTRACEF("pending addr change\n");
111         USBDevAddrSet(USB0_BASE, addr);
112         pending_addr_change = false;
113     }
114 
115     if (status & USB_DEV_EP0_OUT_PKTRDY) {
116         LTRACEF("pktrdy\n");
117 
118         uchar buf[sizeof(struct usb_setup)];
119         ulong avail = sizeof(buf);
120 
121         if (USBEndpointDataGet(USB0_BASE, USB_EP_0, buf, &avail) < 0 || avail != sizeof(buf)) {
122             LTRACEF("short setup packet, size %lu\n", avail);
123         } else {
124             union usb_callback_args args;
125             args.setup = (void *)buf;
126             usbc_callback(USB_CB_SETUP_MSG, &args);
127         }
128     }
129     if (status & USB_DEV_EP0_SENT_STALL) {
130         LTRACEF("stall complete\n");
131         USBDevEndpointStallClear(USB0_BASE, USB_EP_0, 0);
132     }
133 }
134 
stellaris_usb0_irq(void)135 void stellaris_usb0_irq(void) {
136     arm_cm_irq_entry();
137 
138     uint status = USBIntStatusControl(USB0_BASE);
139 
140     //LTRACEF("usb irq, status 0x%x\n", status);
141 
142     if (status & USB_INTCTRL_RESET) {
143         // reset
144         LTRACEF("reset\n");
145         pending_addr_change = false;
146         usbc_callback(USB_CB_RESET, NULL);
147     }
148     if (status & USB_INTCTRL_CONNECT) {
149         // reset
150         LTRACEF("connect\n");
151     }
152 
153     status = USBIntStatusEndpoint(USB0_BASE);
154 
155     if (status & USB_INTEP_0) {
156         // ep0
157         //LTRACEF("ep0\n");
158         ep0_irq();
159     }
160 
161     arm_cm_irq_exit(true);
162 }
163 
usbc_ep0_ack(void)164 void usbc_ep0_ack(void) {
165     LTRACE_ENTRY;
166 
167     USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
168 }
169 
usbc_ep0_stall(void)170 void usbc_ep0_stall(void) {
171     LTRACE_ENTRY;
172 
173     USBDevEndpointStall(USB0_BASE, USB_EP_0, 0);
174 }
175 
usbc_ep0_send(const void * buf,size_t len,size_t maxlen)176 void usbc_ep0_send(const void *buf, size_t len, size_t maxlen) {
177     LTRACEF("buf %p, len %zu, maxlen %zu\n", buf, len, maxlen);
178 
179     USBEndpointDataPut(USB0_BASE, USB_EP_0, (void *)buf, MIN(len, maxlen));
180 
181     USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_SETUP);
182 }
183 
usbc_set_address(uint8_t address)184 void usbc_set_address(uint8_t address) {
185     LTRACEF("address 0x%hhx\n", address);
186 
187     addr = address;
188     pending_addr_change = true;
189 }
190 
usbc_ep0_recv(void * buf,size_t len,ep_callback cb)191 void usbc_ep0_recv(void *buf, size_t len, ep_callback cb) {
192     PANIC_UNIMPLEMENTED;
193 }
194 
usbc_is_highspeed(void)195 bool usbc_is_highspeed(void) {
196     return false;
197 }
198 
usbc_set_active(bool active)199 status_t usbc_set_active(bool active) {
200     LTRACEF("active %d\n", active);
201     if (active) {
202         USBIntEnableControl(USB0_BASE, USB_INTCTRL_CONNECT | USB_INTCTRL_RESET);
203         USBIntEnableEndpoint(USB0_BASE, USB_INTEP_0);
204         USBDevConnect(USB0_BASE);
205     } else {
206         USBDevDisconnect(USB0_BASE);
207     }
208 
209     return NO_ERROR;
210 }
211 
usbc_setup_endpoint(ep_t ep,ep_dir_t dir,uint width,ep_type_t type)212 status_t usbc_setup_endpoint(ep_t ep, ep_dir_t dir, uint width, ep_type_t type) {
213     PANIC_UNIMPLEMENTED;
214 }
215 
usbc_queue_rx(ep_t ep,usbc_transfer_t * transfer)216 status_t usbc_queue_rx(ep_t ep, usbc_transfer_t *transfer) {
217     PANIC_UNIMPLEMENTED;
218 }
219 
usbc_queue_tx(ep_t ep,usbc_transfer_t * transfer)220 status_t usbc_queue_tx(ep_t ep, usbc_transfer_t *transfer) {
221     PANIC_UNIMPLEMENTED;
222 }
223 
usbc_flush_ep(ep_t ep)224 status_t usbc_flush_ep(ep_t ep) {
225     PANIC_UNIMPLEMENTED;
226 }