summaryrefslogtreecommitdiff
path: root/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2018-06-29 16:09:28 -0400
committerSolomon Peachy <pizza@shaftnet.org>2019-01-02 08:10:01 -0500
commitd4942cc74c82c465ea395637c77ed06565b8b497 (patch)
tree8c1fa737c93f8a2ade5a1566857dc4dc8f578bd6 /firmware/target/arm/rk27xx/usb-drv-rk27xx.c
parentaf9459a7992596e932c6d8cc0a6366ff0f0b0fca (diff)
downloadrockbox-d4942cc74c82c465ea395637c77ed06565b8b497.tar.gz
rockbox-d4942cc74c82c465ea395637c77ed06565b8b497.zip
Add Xuelin iHIFI 770/770C/800 support
Taken from the xvortex fork (Roman Stolyarov) Ported, rebased, and cleaned up by myself. Change-Id: I7b2bca2d29502f2e4544e42f3d122786dd4b7978
Diffstat (limited to 'firmware/target/arm/rk27xx/usb-drv-rk27xx.c')
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c787
1 files changed, 293 insertions, 494 deletions
diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
index badc3ab5ed..057ecf6ebc 100644
--- a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
+++ b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
@@ -28,37 +28,16 @@
28#include "kernel.h" 28#include "kernel.h"
29#include "panic.h" 29#include "panic.h"
30 30
31//#include "usb-s3c6400x.h"
32
33#include "usb_ch9.h" 31#include "usb_ch9.h"
34#include "usb_core.h" 32#include "usb_core.h"
35#include <inttypes.h> 33#include <inttypes.h>
36#include "power.h" 34#include "power.h"
37 35
36#define LOGF_ENABLE
38#include "logf.h" 37#include "logf.h"
39 38
40typedef volatile uint32_t reg32; 39typedef volatile uint32_t reg32;
41 40
42/* Bulk OUT: ep1, ep4, ep7, ep10, ep13 */
43#define BOUT_RXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x54+0x38*(ep_num/3)))
44#define BOUT_RXCON(ep_num) (*(reg32*)(AHB0_UDC+0x58+0x38*(ep_num/3)))
45#define BOUT_DMAOUTCTL(ep_num) (*(reg32*)(AHB0_UDC+0x5C+0x38*(ep_num/3)))
46#define BOUT_DMAOUTLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x60+0x38*(ep_num/3)))
47
48/* Bulk IN: ep2, ep5, ep8, ep11, ep4 */
49#define BIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x64+0x38*(ep_num/3)))
50#define BIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x68+0x38*(ep_num/3)))
51#define BIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x6C+0x38*(ep_num/3)))
52#define BIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x70+0x38*(ep_num/3)))
53#define BIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x74+0x38*(ep_num/3)))
54
55/* INTERRUPT IN: ep3, ep6, ep9, ep12, ep15 */
56#define IIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x78+0x38*((ep_num/3)-1)))
57#define IIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x7C+0x38*((ep_num/3)-1)))
58#define IIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x80+0x38*((ep_num/3)-1)))
59#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1)))
60#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1)))
61
62#ifdef LOGF_ENABLE 41#ifdef LOGF_ENABLE
63#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT") 42#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
64#define XFER_TYPE_STR(type) \ 43#define XFER_TYPE_STR(type) \
@@ -68,9 +47,12 @@ typedef volatile uint32_t reg32;
68 ((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL")))) 47 ((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
69#endif 48#endif
70 49
71struct endpoint_t { 50struct endpoint_t
51{
52 const int ep_num; /* EP number */
72 const int type; /* EP type */ 53 const int type; /* EP type */
73 const int dir; /* DIR_IN/DIR_OUT */ 54 const int dir; /* DIR_IN/DIR_OUT */
55 volatile unsigned long *stat; /* RXSTAT/TXSTAT register */
74 bool allocated; /* flag to mark EPs taken */ 56 bool allocated; /* flag to mark EPs taken */
75 volatile void *buf; /* tx/rx buffer address */ 57 volatile void *buf; /* tx/rx buffer address */
76 volatile int len; /* size of the transfer (bytes) */ 58 volatile int len; /* size of the transfer (bytes) */
@@ -79,110 +61,91 @@ struct endpoint_t {
79 struct semaphore complete; /* semaphore for blocking transfers */ 61 struct semaphore complete; /* semaphore for blocking transfers */
80}; 62};
81 63
82#define EP_INIT(_type, _dir, _alloced, _buf, _len, _cnt, _block) \ 64/* compute RXCON address from RXSTAT, and so on */
83 { .type = (_type), .dir = (_dir), .allocated = (_alloced), .buf = (_buf), \ 65#define RXSTAT(endp) *((endp)->stat)
84 .len = (_len), .cnt = (_cnt), .block = (_block) } 66#define RXCON(endp) *(1 + (endp)->stat)
85 67#define DMAOUTCTL(endp) *(2 + (endp)->stat)
86static struct endpoint_t ctrlep[2] = { 68#define DMAOUTLMADDR(endp) *(3 + (endp)->stat)
87 EP_INIT(USB_ENDPOINT_XFER_CONTROL, DIR_OUT, true, NULL, 0, 0, true), 69/* compute TXCON address from TXSTAT, and so on */
88 EP_INIT(USB_ENDPOINT_XFER_CONTROL, DIR_IN, true, NULL, 0, 0, true), 70#define TXSTAT(endp) *((endp)->stat)
71#define TXCON(endp) *(1 + (endp)->stat)
72#define TXBUF(endp) *(2 + (endp)->stat)
73#define DMAINCTL(endp) *(3 + (endp)->stat)
74#define DMAINLMADDR(endp) *(4 + (endp)->stat)
75
76#define ENDPOINT(num, type, dir, reg) \
77 {num, USB_ENDPOINT_XFER_##type, USB_DIR_##dir, reg, false, NULL, 0, 0, true, {{0, 0}, 0, 0}}
78
79static struct endpoint_t ctrlep[2] =
80{
81 ENDPOINT(0, CONTROL, OUT, &RX0STAT),
82 ENDPOINT(0, CONTROL, IN, &TX0STAT),
89}; 83};
90 84
91static struct endpoint_t endpoints[16] = { 85static struct endpoint_t endpoints[16] =
92 EP_INIT(USB_ENDPOINT_XFER_CONTROL, 3, true, NULL, 0, 0, true ), /* stub */ 86{
93 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT1 */ 87 ENDPOINT(0, CONTROL, OUT, NULL), /* stub */
94 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN2 */ 88 ENDPOINT(1, BULK, OUT, &RX1STAT), /* BOUT1 */
95 EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN3 */ 89 ENDPOINT(2, BULK, IN, &TX2STAT), /* BIN2 */
96 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT4 */ 90 ENDPOINT(3, INT, IN, &TX3STAT), /* IIN3 */
97 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN5 */ 91 ENDPOINT(4, BULK, OUT, &RX4STAT), /* BOUT4 */
98 EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN6 */ 92 ENDPOINT(5, BULK, IN, &TX5STAT), /* BIN5 */
99 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT7 */ 93 ENDPOINT(6, INT, IN, &TX6STAT), /* IIN6 */
100 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN8 */ 94 ENDPOINT(7, BULK, OUT, &RX7STAT), /* BOUT7 */
101 EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN9 */ 95 ENDPOINT(8, BULK, IN, &TX8STAT), /* BIN8 */
102 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT10 */ 96 ENDPOINT(9, INT, IN, &TX9STAT), /* IIN9 */
103 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN11 */ 97 ENDPOINT(10, BULK, OUT, &RX10STAT), /* BOUT10 */
104 EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN12 */ 98 ENDPOINT(11, BULK, IN, &TX11STAT), /* BIN11 */
105 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT13 */ 99 ENDPOINT(12, INT, IN, &TX12STAT), /* IIN12 */
106 EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN14 */ 100 ENDPOINT(13, BULK, OUT, &RX13STAT), /* BOUT13 */
107 EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN15 */ 101 ENDPOINT(14, BULK, IN, &TX14STAT), /* BIN14 */
102 ENDPOINT(15, INT, IN, &TX15STAT), /* IIN15 */
108}; 103};
109 104
105static volatile bool set_address = false;
106static volatile bool set_configuration = false;
107
108#undef ENDPOINT
109
110static void setup_received(void) 110static void setup_received(void)
111{ 111{
112 static uint32_t setup_data[2]; 112 static uint32_t setup_data[2];
113 113 logf("udc: setup");
114
114 /* copy setup data from packet */ 115 /* copy setup data from packet */
115 setup_data[0] = SETUP1; 116 setup_data[0] = SETUP1;
116 setup_data[1] = SETUP2; 117 setup_data[1] = SETUP2;
117 118
118 /* clear all pending control transfers
119 * do we need this here?
120 */
121
122 /* pass setup data to the upper layer */ 119 /* pass setup data to the upper layer */
123 usb_core_control_request((struct usb_ctrlrequest*)setup_data); 120 usb_core_control_request((struct usb_ctrlrequest*)setup_data);
124} 121}
125 122
126/* service ep0 IN transaction */ 123static int max_pkt_size(struct endpoint_t *endp)
127static void ctr_write(void)
128{ 124{
129 int xfer_size = (ctrlep[DIR_IN].cnt > 64) ? 64 : ctrlep[DIR_IN].cnt; 125 switch(endp->type)
130 unsigned int timeout = current_tick + HZ/10;
131
132 while (TX0BUF & TXFULL) /* TX0FULL flag */
133 { 126 {
134 if(TIME_AFTER(current_tick, timeout)) 127 case USB_ENDPOINT_XFER_CONTROL: return 64;
135 break; 128 case USB_ENDPOINT_XFER_BULK: return usb_drv_port_speed() ? 512 : 64;
129 case USB_ENDPOINT_XFER_INT: return usb_drv_port_speed() ? 1024 : 64;
130 default: panicf("die"); return 0;
136 } 131 }
137
138 TX0STAT = xfer_size; /* size of the transfer */
139 TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */
140 TX0DMAINCTL = DMA_START; /* start DMA */
141 TX0CON &= ~TXNAK; /* clear NAK */
142
143 /* Decrement by max packet size is intentional.
144 * This way if we have final packet short one we will get negative len
145 * after transfer, which in turn indicates we *don't* need to send
146 * zero length packet. If the final packet is max sized packet we will
147 * get zero len after transfer which indicates we need to send
148 * zero length packet to signal host end of the transfer.
149 */
150 ctrlep[DIR_IN].cnt -= 64;
151 ctrlep[DIR_IN].buf += xfer_size;
152}
153
154static void ctr_read(void)
155{
156 int xfer_size = RX0STAT & 0xffff;
157
158 /* clear NAK bit */
159 RX0CON &= ~RXNAK;
160
161 ctrlep[DIR_OUT].cnt -= xfer_size;
162 ctrlep[DIR_OUT].buf += xfer_size;
163
164 RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */
165 RX0DMACTLO = DMA_START; /* start DMA */
166} 132}
167 133
168static void blk_write(int ep) 134static void ep_write(struct endpoint_t *endp)
169{ 135{
170 int ep_num = EP_NUM(ep); 136 int xfer_size = MIN(max_pkt_size(endp), endp->cnt);
171 int max = usb_drv_port_speed() ? 512 : 64;
172 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
173 unsigned int timeout = current_tick + HZ/10; 137 unsigned int timeout = current_tick + HZ/10;
174 138
175 while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */ 139 while(TXBUF(endp) & TXFULL) /* TXFULL flag */
176 { 140 {
177 if(TIME_AFTER(current_tick, timeout)) 141 if(TIME_AFTER(current_tick, timeout))
178 break; 142 break;
179 } 143 }
180 144
181 BIN_TXSTAT(ep_num) = xfer_size; /* size */ 145 /* setup transfer size and DMA */
182 BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */ 146 TXSTAT(endp) = xfer_size;
183 BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */ 147 DMAINLMADDR(endp) = (uint32_t)endp->buf; /* local buffer address */
184 BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */ 148 DMAINCTL(endp) = DMA_START;
185
186 /* Decrement by max packet size is intentional. 149 /* Decrement by max packet size is intentional.
187 * This way if we have final packet short one we will get negative len 150 * This way if we have final packet short one we will get negative len
188 * after transfer, which in turn indicates we *don't* need to send 151 * after transfer, which in turn indicates we *don't* need to send
@@ -190,247 +153,141 @@ static void blk_write(int ep)
190 * get zero len after transfer which indicates we need to send 153 * get zero len after transfer which indicates we need to send
191 * zero length packet to signal host end of the transfer. 154 * zero length packet to signal host end of the transfer.
192 */ 155 */
193 endpoints[ep_num].cnt -= max; 156 endp->cnt -= max_pkt_size(endp);
194 endpoints[ep_num].buf += xfer_size; 157 endp->buf += xfer_size;
158 /* clear NAK */
159 TXCON(endp) &= ~TXNAK;
195} 160}
196 161
197static void blk_read(int ep) 162static void ep_read(struct endpoint_t *endp)
198{ 163{
199 int ep_num = EP_NUM(ep); 164 /* setup DMA */
200 int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff; 165 DMAOUTLMADDR(endp) = (uint32_t)endp->buf; /* local buffer address */
201 166 DMAOUTCTL(endp) = DMA_START;
202 /* clear NAK bit */ 167 /* clear NAK */
203 BOUT_RXCON(ep_num) &= ~RXNAK; 168 RXCON(endp) &= ~RXNAK;
204
205 endpoints[ep_num].cnt -= xfer_size;
206 endpoints[ep_num].buf += xfer_size;
207
208 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf;
209 BOUT_DMAOUTCTL(ep_num) = DMA_START;
210}
211
212static void int_write(int ep)
213{
214 int ep_num = EP_NUM(ep);
215 int max = usb_drv_port_speed() ? 1024 : 64;
216 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
217 unsigned int timeout = current_tick + HZ/10;
218
219 while (IIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
220 {
221 if(TIME_AFTER(current_tick, timeout))
222 break;
223 }
224
225 IIN_TXSTAT(ep_num) = xfer_size; /* size */
226 IIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
227 IIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
228 IIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
229
230 /* Decrement by max packet size is intentional.
231 * This way if we have final packet short one we will get negative len
232 * after transfer, which in turn indicates we *don't* need to send
233 * zero length packet. If the final packet is max sized packet we will
234 * get zero len after transfer which indicates we need to send
235 * zero length packet to signal host end of the transfer.
236 */
237 endpoints[ep_num].cnt -= max;
238 endpoints[ep_num].buf += xfer_size;
239} 169}
240 170
241/* UDC ISR function */ 171static void in_intr(struct endpoint_t *endp)
242void INT_UDC(void)
243{ 172{
244 uint32_t txstat, rxstat; 173 uint32_t txstat = TXSTAT(endp);
245 int tmp, ep_num; 174 /* check if clear feature was sent by host */
246 175 if(txstat & TXCFINT)
247 /* read what caused UDC irq */
248 uint32_t intsrc = INT2FLAG & 0x7fffff;
249
250 if (intsrc & SETUP_INTR) /* setup interrupt */
251 { 176 {
252 setup_received(); 177 logf("clear_stall: %d", endp->ep_num);
178 usb_drv_stall(endp->ep_num, false, true);
253 } 179 }
254 else if (intsrc & IN0_INTR) /* ep0 in interrupt */ 180 /* check if a transfer has finished */
181 if(txstat & TXACK)
255 { 182 {
256 txstat = TX0STAT; /* read clears flags */ 183 logf("udc: ack(%d)", endp->ep_num);
257 184 /* finished ? */
258 /* TODO handle errors */ 185 if(endp->cnt <= 0)
259 if (txstat & TXACK) /* check TxACK flag */
260 { 186 {
261 if (ctrlep[DIR_IN].cnt >= 0) 187 usb_core_transfer_complete(endp->ep_num, endp->dir, 0, endp->len);
262 { 188 /* release semaphore for blocking transfer */
263 /* we still have data to send (or ZLP) */ 189 if(endp->block)
264 ctr_write(); 190 semaphore_release(&endp->complete);
265 }
266 else
267 {
268 /* final ack received */
269 usb_core_transfer_complete(0, /* ep */
270 USB_DIR_IN, /* dir */
271 0, /* status */
272 ctrlep[DIR_IN].len); /* length */
273
274 /* release semaphore for blocking transfer */
275 if (ctrlep[DIR_IN].block)
276 semaphore_release(&ctrlep[DIR_IN].complete);
277 }
278 } 191 }
192 else /* more data to send */
193 ep_write(endp);
279 } 194 }
280 else if (intsrc & OUT0_INTR) /* ep0 out interrupt */ 195}
281 {
282 rxstat = RX0STAT;
283 196
284 /* TODO handle errors */ 197static void out_intr(struct endpoint_t *endp)
285 if (rxstat & RXACK) /* RxACK */ 198{
286 { 199 uint32_t rxstat = RXSTAT(endp);
287 if (ctrlep[DIR_OUT].cnt > 0) 200 logf("udc: out intr(%d)", endp->ep_num);
288 ctr_read(); 201 /* check if clear feature was sent by host */
289 else 202 if(rxstat & RXCFINT)
290 usb_core_transfer_complete(0, /* ep */
291 USB_DIR_OUT, /* dir */
292 0, /* status */
293 ctrlep[DIR_OUT].len); /* length */
294 }
295 }
296 else if (intsrc & USBRST_INTR) /* usb reset */
297 {
298 usb_drv_init();
299 }
300 else if (intsrc & RESUME_INTR) /* usb resume */
301 {
302 TX0CON |= TXCLR; /* TxClr */
303 TX0CON &= ~TXCLR;
304 RX0CON |= RXCLR; /* RxClr */
305 RX0CON &= ~RXCLR;
306 }
307 else if (intsrc & SUSP_INTR) /* usb suspend */
308 { 203 {
204 logf("clear_stall: %d", endp->ep_num);
205 usb_drv_stall(endp->ep_num, false, false);
309 } 206 }
310 else if (intsrc & CONN_INTR) /* usb connect */ 207 /* check if a transfer has finished */
208 if(rxstat & RXACK)
311 { 209 {
210 int xfer_size = rxstat & 0xffff;
211 endp->cnt -= xfer_size;
212 endp->buf += xfer_size;
213 logf("udc: ack(%d) -> %d/%d", endp->ep_num, xfer_size, endp->cnt);
214 /* finished ? */
215 if(endp->cnt <= 0 || xfer_size < max_pkt_size(endp))
216 usb_core_transfer_complete(endp->ep_num, endp->dir, 0, endp->len);
217 else
218 ep_read(endp);
312 } 219 }
313 else 220}
314 { 221
315 /* lets figure out which ep generated irq */ 222static void udc_phy_reset(void)
316 tmp = intsrc >> 7; 223{
317 for (ep_num=1; ep_num < 15; ep_num++) 224 DEV_CTL |= SOFT_POR;
318 { 225 udelay(10000); /* min 10ms */
319 tmp >>= ep_num; 226 DEV_CTL &= ~SOFT_POR;
320 if (tmp & 0x01) 227}
321 break; 228
322 } 229static void udc_soft_connect(void)
323 230{
324 if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20))) 231 DEV_CTL |= CSR_DONE |
325 { 232 DEV_SOFT_CN |
326 /* bulk out */ 233 DEV_SELF_PWR;
327 rxstat = BOUT_RXSTAT(ep_num); 234}
328 235
329 /* TODO handle errors */ 236static void udc_helper(void)
330 if (rxstat & (1<<18)) /* RxACK */ 237{
331 { 238 uint32_t dev_info = DEV_INFO;
332 if (endpoints[ep_num].cnt > 0) 239
333 blk_read(ep_num); 240 /* This polls for DEV_EN bit set in DEV_INFO register
334 else 241 * as well as tracks current requested configuration
335 usb_core_transfer_complete(ep_num, /* ep */ 242 * (DEV_INFO [11:8]). On state change it notifies usb stack
336 USB_DIR_OUT, /* dir */ 243 * about it.
337 0, /* status */ 244 */
338 endpoints[ep_num].len); /* length */ 245
339 } 246 /* SET ADDRESS request */
340 } 247 if(!set_address)
341 else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21))) 248 if(dev_info & 0x7f)
342 { 249 {
343 /* bulk in */ 250 set_address = true;
344 txstat = BIN_TXSTAT(ep_num); 251 usb_core_notify_set_address(dev_info & 0x7f);
345
346 /* TODO handle errors */
347 if (txstat & (1<<18)) /* check TxACK flag */
348 {
349 if (endpoints[ep_num].cnt >= 0)
350 {
351 /* we still have data to send (or ZLP) */
352 blk_write(ep_num);
353 }
354 else
355 {
356 /* final ack received */
357 usb_core_transfer_complete(ep_num, /* ep */
358 USB_DIR_IN, /* dir */
359 0, /* status */
360 endpoints[ep_num].len); /* length */
361
362 /* release semaphore for blocking transfer */
363 if (endpoints[ep_num].block)
364 semaphore_release(&endpoints[ep_num].complete);
365 }
366 }
367 } 252 }
368 else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22))) 253
254 /* SET CONFIGURATION request */
255 if(!set_configuration)
256 if(dev_info & DEV_EN)
369 { 257 {
370 /* int in */ 258 set_configuration = true;
371 txstat = IIN_TXSTAT(ep_num); 259 usb_core_notify_set_config(((dev_info >> 7) & 0xf) + 1);
372
373 /* TODO handle errors */
374 if (txstat & TXACK) /* check TxACK flag */
375 {
376 if (endpoints[ep_num].cnt >= 0)
377 {
378 /* we still have data to send (or ZLP) */
379 int_write(ep_num);
380 }
381 else
382 {
383 /* final ack received */
384 usb_core_transfer_complete(ep_num, /* ep */
385 USB_DIR_IN, /* dir */
386 0, /* status */
387 endpoints[ep_num].len); /* length */
388
389 /* release semaphore for blocking transfer */
390 if (endpoints[ep_num].block)
391 semaphore_release(&endpoints[ep_num].complete);
392 }
393 }
394 } 260 }
395 }
396} 261}
397 262
398/* return port speed FS=0, HS=1 */ 263/* return port speed FS=0, HS=1 */
399int usb_drv_port_speed(void) 264int usb_drv_port_speed(void)
400{ 265{
401 return ((DEV_INFO & DEV_SPEED) == 0) ? 0 : 1; 266 return (DEV_INFO & DEV_SPEED) ? 0 : 1;
402} 267}
403 268
404/* Reserve endpoint */ 269/* Reserve endpoint */
405int usb_drv_request_endpoint(int type, int dir) 270int usb_drv_request_endpoint(int type, int dir)
406{ 271{
407 int ep_num, ep_dir; 272 logf("req: %s %s", XFER_DIR_STR(dir), XFER_TYPE_STR(type));
408 int ep_type;
409
410 /* Safety */
411 ep_dir = EP_DIR(dir);
412 ep_type = type & USB_ENDPOINT_XFERTYPE_MASK;
413 273
414 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
415
416 /* Find an available ep/dir pair */ 274 /* Find an available ep/dir pair */
417 for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) 275 for(int ep_num = 1; ep_num<USB_NUM_ENDPOINTS;ep_num++)
418 { 276 {
419 struct endpoint_t* endpoint = &endpoints[ep_num]; 277 struct endpoint_t *endp = &endpoints[ep_num];
420 278
421 if (endpoint->type == ep_type && 279 if(endp->allocated || endp->type != type || endp->dir != dir)
422 endpoint->dir == ep_dir && 280 continue;
423 !endpoint->allocated) 281 /* allocate endpoint and enable interrupt */
424 { 282 endp->allocated = true;
425 /* mark endpoint as taken */ 283 if(dir == USB_DIR_IN)
426 endpoint->allocated = true; 284 TXCON(endp) = (ep_num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
427 285 else
428 /* enable interrupt from this endpoint */ 286 RXCON(endp) = (ep_num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
429 EN_INT |= (1<<(ep_num+7)); 287 EN_INT |= 1 << (ep_num + 7);
430 288
431 logf("add: ep%d %s", ep_num, XFER_DIR_STR(ep_dir)); 289 logf("add: ep%d %s", ep_num, XFER_DIR_STR(dir));
432 return (ep_num | (dir & USB_ENDPOINT_DIR_MASK)); 290 return ep_num | dir;
433 }
434 } 291 }
435 return -1; 292 return -1;
436} 293}
@@ -439,14 +296,12 @@ int usb_drv_request_endpoint(int type, int dir)
439void usb_drv_release_endpoint(int ep) 296void usb_drv_release_endpoint(int ep)
440{ 297{
441 int ep_num = EP_NUM(ep); 298 int ep_num = EP_NUM(ep);
442 int ep_dir = EP_DIR(ep);
443 (void) ep_dir;
444 299
445 logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir)); 300 logf("rel: ep%d", ep_num);
446 endpoints[ep_num].allocated = false; 301 endpoints[ep_num].allocated = false;
447 302
448 /* disable interrupt from this endpoint */ 303 /* disable interrupt from this endpoint */
449 EN_INT &= ~(1<<(ep_num+7)); 304 EN_INT &= ~(1 << (ep_num + 7));
450} 305}
451 306
452/* Set the address (usually it's in a register). 307/* Set the address (usually it's in a register).
@@ -463,39 +318,25 @@ void usb_drv_set_address(int address)
463 318
464static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) 319static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
465{ 320{
321 logf("udc: send(%x)", endpoint);
466 struct endpoint_t *ep; 322 struct endpoint_t *ep;
467 int ep_num = EP_NUM(endpoint); 323 int ep_num = EP_NUM(endpoint);
468 324
469 if (ep_num == 0) 325 if (ep_num == 0)
470 ep = &ctrlep[DIR_IN]; 326 ep = &ctrlep[DIR_IN];
471 else 327 else
472 ep = &endpoints[ep_num]; 328 ep = &endpoints[ep_num];
473 329
330 /* for send transfers, make sure the data is committed */
331 commit_discard_dcache_range(ptr, length);
474 ep->buf = ptr; 332 ep->buf = ptr;
475 ep->len = ep->cnt = length; 333 ep->len = ep->cnt = length;
476 334 ep->block = block;
477 if (block) 335
478 ep->block = true; 336 ep_write(ep);
479 else 337
480 ep->block = false; 338 /* wait for transfer to end */
481 339 if(block)
482 switch (ep->type)
483 {
484 case USB_ENDPOINT_XFER_CONTROL:
485 ctr_write();
486 break;
487
488 case USB_ENDPOINT_XFER_BULK:
489 blk_write(ep_num);
490 break;
491
492 case USB_ENDPOINT_XFER_INT:
493 int_write(ep_num);
494 break;
495 }
496
497 if (block)
498 /* wait for transfer to end */
499 semaphore_wait(&ep->complete, TIMEOUT_BLOCK); 340 semaphore_wait(&ep->complete, TIMEOUT_BLOCK);
500 341
501 return 0; 342 return 0;
@@ -516,28 +357,20 @@ int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
516/* Setup a receive transfer. (non blocking) */ 357/* Setup a receive transfer. (non blocking) */
517int usb_drv_recv(int endpoint, void* ptr, int length) 358int usb_drv_recv(int endpoint, void* ptr, int length)
518{ 359{
360 logf("udc: recv(%x)", endpoint);
519 struct endpoint_t *ep; 361 struct endpoint_t *ep;
520 int ep_num = EP_NUM(endpoint); 362 int ep_num = EP_NUM(endpoint);
521 363
522 if (ep_num == 0) 364 if(ep_num == 0)
523 {
524 ep = &ctrlep[DIR_OUT]; 365 ep = &ctrlep[DIR_OUT];
525
526 ctr_read();
527 }
528 else 366 else
529 {
530 ep = &endpoints[ep_num]; 367 ep = &endpoints[ep_num];
531 368
532 /* clear NAK bit */ 369 /* for recv, discard the cache lines related to the buffer */
533 BOUT_RXCON(ep_num) &= ~RXNAK; 370 commit_discard_dcache_range(ptr, length);
534 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr;
535 BOUT_DMAOUTCTL(ep_num) = DMA_START;
536 }
537
538 ep->buf = ptr; 371 ep->buf = ptr;
539 ep->len = ep->cnt = length; 372 ep->len = ep->cnt = length;
540 373 ep_read(ep);
541 return 0; 374 return 0;
542} 375}
543 376
@@ -560,173 +393,54 @@ void usb_drv_set_test_mode(int mode)
560/* Check if endpoint is in stall state */ 393/* Check if endpoint is in stall state */
561bool usb_drv_stalled(int endpoint, bool in) 394bool usb_drv_stalled(int endpoint, bool in)
562{ 395{
563 int ep_num = EP_NUM(endpoint); 396 struct endpoint_t *endp = &endpoints[EP_NUM(endpoint)];
564
565 switch (endpoints[ep_num].type)
566 {
567 case USB_ENDPOINT_XFER_CONTROL:
568 if (in)
569 return (TX0CON & TXSTALL) ? true : false;
570 else
571 return (RX0CON & RXSTALL) ? true : false;
572
573 break;
574 397
575 case USB_ENDPOINT_XFER_BULK: 398 if(in)
576 if (in) 399 return !!(TXCON(endp) & TXSTALL);
577 return (BIN_TXCON(ep_num) & TXSTALL) ? true : false; 400 else
578 else 401 return !!(RXCON(endp) & RXSTALL);
579 return (BOUT_RXCON(ep_num) & RXSTALL) ? true : false;
580
581 break;
582
583 case USB_ENDPOINT_XFER_INT:
584 if (in)
585 return (IIN_TXCON(ep_num) & TXSTALL) ? true : false;
586 else
587 return false; /* we don't have such endpoint anyway */
588
589 break;
590 }
591
592 return false;
593} 402}
594 403
595/* Stall the endpoint. Usually set a flag in the controller */ 404/* Stall the endpoint. Usually set a flag in the controller */
596void usb_drv_stall(int endpoint, bool stall, bool in) 405void usb_drv_stall(int endpoint, bool stall, bool in)
597{ 406{
598 int ep_num = EP_NUM(endpoint); 407 struct endpoint_t *endp = &endpoints[EP_NUM(endpoint)];
599 408 if(in)
600 switch (endpoints[ep_num].type)
601 { 409 {
602 case USB_ENDPOINT_XFER_CONTROL: 410 if(stall)
603 if (in) 411 TXCON(endp) |= TXSTALL;
604 { 412 else
605 if (stall) 413 TXCON(endp) &= ~TXSTALL;
606 TX0CON |= TXSTALL; 414 }
607 else 415 else
608 TX0CON &= ~TXSTALL; 416 {
609 } 417 if(stall)
610 else 418 RXCON(endp) |= RXSTALL;
611 { 419 else
612 if (stall) 420 RXCON(endp) &= ~RXSTALL;
613 RX0CON |= RXSTALL;
614 else
615 RX0CON &= ~RXSTALL; /* doc says Auto clear by UDC 2.0 */
616 }
617 break;
618
619 case USB_ENDPOINT_XFER_BULK:
620 if (in)
621 {
622 if (stall)
623 BIN_TXCON(ep_num) |= TXSTALL;
624 else
625 BIN_TXCON(ep_num) &= ~TXSTALL;
626 }
627 else
628 {
629 if (stall)
630 BOUT_RXCON(ep_num) |= RXSTALL;
631 else
632 BOUT_RXCON(ep_num) &= ~RXSTALL;
633 }
634 break;
635
636 case USB_ENDPOINT_XFER_INT:
637 if (in)
638 {
639 if (stall)
640 IIN_TXCON(ep_num) |= TXSTALL;
641 else
642 IIN_TXCON(ep_num) &= ~TXSTALL;
643 }
644 break;
645 } 421 }
646} 422}
647 423
648/* one time init (once per connection) - basicaly enable usb core */ 424/* one time init (once per connection) - basicaly enable usb core */
649void usb_drv_init(void) 425void usb_drv_init(void)
650{ 426{
651 int ep_num;
652
653 /* enable USB clock */
654 SCU_CLKCFG &= ~CLKCFG_UDC;
655
656 /* 1. do soft disconnect */
657 DEV_CTL = DEV_SELF_PWR;
658
659 /* 2. do power on reset to PHY */
660 DEV_CTL = DEV_SELF_PWR |
661 SOFT_POR;
662
663 /* 3. wait more than 10ms */
664 udelay(20000);
665
666 /* 4. clear SOFT_POR bit */
667 DEV_CTL &= ~SOFT_POR;
668
669 /* 5. configure minimal EN_INT */
670 EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
671 EN_RESUME_INTR | /* Enable Resume Interrupt */
672 EN_USBRST_INTR | /* Enable USB Reset Interrupt */
673 EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
674 EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
675 EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
676
677 /* 6. configure INTCON */
678 INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
679 UDC_INTEN; /* enable EP0 interrupts */
680
681 /* 7. configure EP0 control registers */
682 TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
683 TXNAK; /* Set as one to response NAK handshake */
684
685 RX0CON = RXACKINTEN |
686 RXEPEN | /* Endpoint 0 Enable. When cleared the endpoint does
687 * not respond to an SETUP or OUT token
688 */
689
690 RXNAK; /* Set as one to response NAK handshake */
691
692 /* 8. write final bits to DEV_CTL */
693 DEV_CTL = CSR_DONE | /* Configure CSR done */
694 DEV_PHY16BIT | /* 16-bit data path enabled. udc_clk = 30MHz */
695 DEV_SOFT_CN | /* Device soft connect */
696 DEV_SELF_PWR; /* Device self power */
697
698 /* init semaphore of ep0 */ 427 /* init semaphore of ep0 */
699 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0); 428 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0);
700 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0); 429 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0);
701 430
702 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++) 431 for(int ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
703 {
704 semaphore_init(&endpoints[ep_num].complete, 1, 0); 432 semaphore_init(&endpoints[ep_num].complete, 1, 0);
705
706 if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */
707 {
708 IIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
709 }
710 else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */
711 {
712 BOUT_RXCON(ep_num) |= (ep_num<<8)|RXEPEN|RXNAK; /* ep_num, NAK, enable */
713 }
714 else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */
715 {
716 BIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
717 }
718 }
719} 433}
720 434
721/* turn off usb core */ 435/* turn off usb core */
722void usb_drv_exit(void) 436void usb_drv_exit(void)
723{ 437{
724 DEV_CTL = DEV_SELF_PWR; 438 DEV_CTL = DEV_SELF_PWR;
725 439
726 /* disable USB interrupts in interrupt controller */ 440 /* disable USB interrupts in interrupt controller */
727 INTC_IMR &= ~IRQ_ARM_UDC; 441 INTC_IMR &= ~IRQ_ARM_UDC;
728 INTC_IECR &= ~IRQ_ARM_UDC; 442 INTC_IECR &= ~IRQ_ARM_UDC;
729 443
730 /* we cannot disable UDC clock since this causes data abort 444 /* we cannot disable UDC clock since this causes data abort
731 * when reading DEV_INFO in order to check usb connect event 445 * when reading DEV_INFO in order to check usb connect event
732 */ 446 */
@@ -734,9 +448,94 @@ void usb_drv_exit(void)
734 448
735int usb_detect(void) 449int usb_detect(void)
736{ 450{
737 if (DEV_INFO & VBUS_STS) 451 if(DEV_INFO & VBUS_STS)
738 return USB_INSERTED; 452 return USB_INSERTED;
739 else 453 else
740 return USB_EXTRACTED; 454 return USB_EXTRACTED;
741} 455}
742 456
457/* UDC ISR function */
458void INT_UDC(void)
459{
460 /* read what caused UDC irq */
461 uint32_t intsrc = INT2FLAG & 0x7fffff;
462
463 if(intsrc & USBRST_INTR) /* usb reset */
464 {
465 logf("udc_int: reset, %ld", current_tick);
466
467 EN_INT = EN_SUSP_INTR | /* Enable Suspend Irq */
468 EN_RESUME_INTR | /* Enable Resume Irq */
469 EN_USBRST_INTR | /* Enable USB Reset Irq */
470 EN_OUT0_INTR | /* Enable OUT Token receive Irq EP0 */
471 EN_IN0_INTR | /* Enable IN Token transmit Irq EP0 */
472 EN_SETUP_INTR; /* Enable SETUP Packet Receive Irq */
473
474 INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
475 UDC_INTEN; /* enable EP0 irqs */
476
477 TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
478 TXNAK; /* Set as one to response NAK handshake */
479
480 RX0CON = RXACKINTEN |
481 RXEPEN | /* Endpoint 0 Enable. When cleared the
482 * endpoint does not respond to an SETUP
483 * or OUT token */
484 RXNAK; /* Set as one to response NAK handshake */
485
486 set_address = false;
487 set_configuration = false;
488 }
489 /* This needs to be processed AFTER usb reset */
490 udc_helper();
491
492 if(intsrc & SETUP_INTR) /* setup interrupt */
493 {
494 setup_received();
495 }
496 if(intsrc & IN0_INTR)
497 {
498 /* EP0 IN done */
499 in_intr(&ctrlep[DIR_IN]);
500 }
501 if(intsrc & OUT0_INTR)
502 {
503 /* EP0 OUT done */
504 out_intr(&ctrlep[DIR_OUT]);
505 }
506 if(intsrc & USBRST_INTR)
507 {
508 /* usb reset */
509 usb_drv_init();
510 }
511 if(intsrc & RESUME_INTR)
512 {
513 /* usb resume */
514 TX0CON |= TXCLR; /* TxClr */
515 TX0CON &= ~TXCLR;
516 RX0CON |= RXCLR; /* RxClr */
517 RX0CON &= ~RXCLR;
518 }
519 if(intsrc & SUSP_INTR)
520 {
521 /* usb suspend */
522 }
523 if(intsrc & CONN_INTR)
524 {
525 /* usb connect */
526 udc_phy_reset();
527 udelay(10000); /* wait at least 10ms */
528 udc_soft_connect();
529 }
530 /* other endpoints */
531 for(int ep_num = 1; ep_num < 16; ep_num++)
532 {
533 if(!(intsrc & (1 << (ep_num + 7))))
534 continue;
535 struct endpoint_t *endp = &endpoints[ep_num];
536 if(endp->dir == USB_DIR_IN)
537 in_intr(endp);
538 else
539 out_intr(endp);
540 }
541}