mps depends on endpoint, I wonder why gcc didn't warn about i being used uninitialized...
[kugel-rb.git] / firmware / target / arm / as3525 / usb-drv-as3525.c
blobd41acc7f8129351f3280bc659e1e35415a19fca4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright © 2010 Tobias Diedrich
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "system.h"
23 #include "usb.h"
24 #include "usb_drv.h"
25 #include "as3525.h"
26 #include "clock-target.h"
27 #include "ascodec.h"
28 #include "as3514.h"
29 #include <stdbool.h>
30 #include "panic.h"
31 /*#define LOGF_ENABLE*/
32 #include "logf.h"
33 #include "usb_ch9.h"
34 #include "usb_core.h"
35 #include "string.h"
37 #if defined(USE_ROCKBOX_USB)
39 #include "usb-drv-as3525.h"
41 static struct usb_endpoint endpoints[USB_NUM_EPS][2];
44 * dma/setup descriptors and buffers should avoid sharing
45 * a cacheline with other data.
46 * dmadescs may share with each other, since we only access them uncached.
48 static struct usb_dev_dma_desc dmadescs[USB_NUM_EPS][2] __attribute__((aligned(32)));
49 /* reuse unused EP2 OUT descriptor here */
50 static struct usb_dev_setup_buf *setup_desc = (void*)&dmadescs[2][1];
52 #if AS3525_MCLK_SEL != AS3525_CLK_PLLB
53 static inline void usb_enable_pll(void)
55 CGU_COUNTB = CGU_LOCK_CNT;
56 CGU_PLLB = AS3525_PLLB_SETTING;
57 CGU_PLLBSUP = 0; /* enable PLLB */
58 while(!(CGU_INTCTRL & CGU_PLLB_LOCK)); /* wait until PLLB is locked */
61 static inline void usb_disable_pll(void)
63 CGU_PLLBSUP = CGU_PLL_POWERDOWN;
65 #else
66 static inline void usb_enable_pll(void)
70 static inline void usb_disable_pll(void)
73 #endif /* AS3525_MCLK_SEL != AS3525_CLK_PLLB */
75 void usb_attach(void)
77 usb_enable(true);
80 static void usb_phy_on(void)
82 /* PHY clock */
83 CGU_USB = 1<<5 /* enable */
84 | (CLK_DIV(AS3525_PLLB_FREQ, 48000000) / 2) << 2
85 | 2; /* source = PLLB */
87 /* UVDD on */
88 ascodec_write(AS3515_USB_UTIL, ascodec_read(AS3515_USB_UTIL) | (1<<4));
89 mdelay(100);
91 /* reset */
92 CCU_SRC = CCU_SRC_USB_AHB_EN|CCU_SRC_USB_PHY_EN;
93 CCU_SRL = CCU_SRL_MAGIC_NUMBER;
94 mdelay(1);
95 CCU_SRC = CCU_SRC_USB_AHB_EN;
96 mdelay(1);
97 CCU_SRC = CCU_SRL = 0;
99 USB_GPIO_CSR = USB_GPIO_TX_ENABLE_N
100 | USB_GPIO_TX_BIT_STUFF_EN
101 | USB_GPIO_XO_ON
102 | USB_GPIO_CLK_SEL10; /* 0x06180000; */
105 static void usb_phy_suspend(void)
107 USB_GPIO_CSR |= USB_GPIO_ASESSVLD_EXT |
108 USB_GPIO_BSESSVLD_EXT |
109 USB_GPIO_VBUS_VLD_EXT;
110 mdelay(3);
111 USB_GPIO_CSR |= USB_GPIO_VBUS_VLD_EXT_SEL;
112 mdelay(10);
115 static void usb_phy_resume(void)
117 USB_GPIO_CSR &= ~(USB_GPIO_ASESSVLD_EXT |
118 USB_GPIO_BSESSVLD_EXT |
119 USB_GPIO_VBUS_VLD_EXT);
120 mdelay(3);
121 USB_GPIO_CSR &= ~USB_GPIO_VBUS_VLD_EXT_SEL;
122 mdelay(10);
125 static void setup_desc_init(struct usb_dev_setup_buf *desc)
127 struct usb_dev_setup_buf *uc_desc = AS3525_UNCACHED_ADDR(desc);
129 uc_desc->status = USB_DMA_DESC_BS_HST_RDY;
130 uc_desc->resv = 0xffffffff;
131 uc_desc->data1 = 0xffffffff;
132 uc_desc->data2 = 0xffffffff;
135 static void dma_desc_init(int ep, int dir)
137 struct usb_dev_dma_desc *desc = &dmadescs[ep][dir];
138 struct usb_dev_dma_desc *uc_desc = AS3525_UNCACHED_ADDR(desc);
140 endpoints[ep][dir].uc_desc = uc_desc;
142 uc_desc->status = USB_DMA_DESC_BS_DMA_DONE | \
143 USB_DMA_DESC_LAST | \
144 USB_DMA_DESC_ZERO_LEN;
145 uc_desc->resv = 0xffffffff;
146 uc_desc->data_ptr = 0;
147 uc_desc->next_desc = 0;
150 static void reset_endpoints(int init)
152 int i;
155 * OUT EP 2 is an alias for OUT EP 0 on this HW!
157 * Resonates with "3 bidirectional- plus 1 in-endpoints in device mode"
158 * from the datasheet, but why ep2 and not ep3?
160 * Reserve it here so we will skip over it in request_endpoint().
162 endpoints[2][1].state |= EP_STATE_ALLOCATED;
164 for(i = 0; i < USB_NUM_EPS; i++) {
166 * MPS sizes depending on speed:
167 * LS: 8 (control), no bulk available
168 * FS: 64 (control), 64 (bulk)
169 * HS: 64 (control), 512 (bulk)
171 * We don't need to handle LS since there is no low-speed only
172 * host AFAIK.
174 int mps = i == 0 ? 64 : (usb_drv_port_speed() ? 512 : 64);
176 if (init) {
177 endpoints[i][0].state = 0;
178 wakeup_init(&endpoints[i][0].complete);
180 if (i != 2) { /* Skip the OUT EP0 alias */
181 endpoints[i][1].state = 0;
182 wakeup_init(&endpoints[i][1].complete);
183 USB_OEP_SUP_PTR(i) = 0;
187 dma_desc_init(i, 0);
188 USB_IEP_CTRL (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK;
189 USB_IEP_MPS (i) = mps; /* in bytes */
190 /* We don't care about the 'IN token received' event */
191 USB_IEP_STS_MASK(i) = USB_EP_STAT_IN; /* OF: 0x840 */
192 USB_IEP_TXFSIZE (i) = mps/2; /* in dwords => mps*2 bytes */
193 USB_IEP_STS (i) = 0xffffffff; /* clear status */
194 USB_IEP_DESC_PTR(i) = 0;
196 if (i != 2) { /* Skip the OUT EP0 alias */
197 dma_desc_init(i, 1);
198 USB_OEP_CTRL (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK;
199 USB_OEP_MPS (i) = (mps/2 << 23) | mps;
200 USB_OEP_STS_MASK(i) = 0x0000; /* OF: 0x1800 */
201 USB_OEP_RXFR (i) = 0; /* Always 0 in OF trace? */
202 USB_OEP_STS (i) = 0xffffffff; /* clear status */
203 USB_OEP_DESC_PTR(i) = 0;
207 setup_desc_init(setup_desc);
208 USB_OEP_SUP_PTR(0) = (int)setup_desc;
211 void usb_drv_init(void)
213 logf("usb_drv_init() !!!!\n");
215 usb_enable_pll();
217 /* length regulator: normal operation */
218 ascodec_write(AS3514_CVDD_DCDC3, ascodec_read(AS3514_CVDD_DCDC3) | 1<<2);
220 /* AHB part */
221 CGU_PERI |= CGU_USB_CLOCK_ENABLE;
223 /* reset AHB */
224 CCU_SRC = CCU_SRC_USB_AHB_EN;
225 CCU_SRL = CCU_SRL_MAGIC_NUMBER;
226 mdelay(1);
227 CCU_SRC = CCU_SRL = 0;
229 USB_GPIO_CSR = USB_GPIO_TX_ENABLE_N
230 | USB_GPIO_TX_BIT_STUFF_EN
231 | USB_GPIO_XO_ON
232 | USB_GPIO_CLK_SEL10; /* 0x06180000; */
234 /* bug workaround according to linux patch */
235 USB_DEV_CFG = (USB_DEV_CFG & ~3) | 1; /* full speed */
237 /* enable soft disconnect */
238 USB_DEV_CTRL |= USB_DEV_CTRL_SOFT_DISCONN;
240 usb_phy_on();
241 usb_phy_suspend();
242 USB_DEV_CTRL |= USB_DEV_CTRL_SOFT_DISCONN;
244 /* We don't care about SVC or SOF events */
245 /* Right now we don't handle suspend, so mask those too */
246 USB_DEV_INTR_MASK = USB_DEV_INTR_SVC |
247 USB_DEV_INTR_SOF |
248 USB_DEV_INTR_USB_SUSPEND |
249 USB_DEV_INTR_EARLY_SUSPEND;
251 USB_DEV_CFG = USB_DEV_CFG_STAT_ACK |
252 USB_DEV_CFG_UNI_DIR |
253 USB_DEV_CFG_PI_16BIT |
254 USB_DEV_CFG_HS |
255 USB_DEV_CFG_SELF_POWERED |
256 USB_DEV_CFG_CSR_PRG |
257 USB_DEV_CFG_PHY_ERR_DETECT;
259 USB_DEV_CTRL = USB_DEV_CTRL_BLEN_1DWORD |
260 USB_DEV_CTRL_DESC_UPDATE |
261 USB_DEV_CTRL_THRES_ENABLE |
262 USB_DEV_CTRL_RDE |
263 0x04000000;
265 USB_DEV_EP_INTR_MASK &= ~((1<<0) | (1<<16)); /* ep 0 */
267 reset_endpoints(1);
269 /* clear pending interrupts */
270 USB_DEV_EP_INTR = 0xffffffff;
271 USB_DEV_INTR = 0xffffffff;
273 VIC_INT_ENABLE = INTERRUPT_USB;
275 usb_phy_resume();
276 USB_DEV_CTRL &= ~USB_DEV_CTRL_SOFT_DISCONN;
278 USB_GPIO_CSR = USB_GPIO_TX_ENABLE_N
279 | USB_GPIO_TX_BIT_STUFF_EN
280 | USB_GPIO_XO_ON
281 | USB_GPIO_HS_INTR
282 | USB_GPIO_CLK_SEL10; /* 0x06180000; */
286 void usb_drv_exit(void)
288 USB_DEV_CTRL |= (1<<10); /* soft disconnect */
290 * mask all interrupts _before_ writing to VIC_INT_EN_CLEAR,
291 * or else the core might latch the interrupt while
292 * the write ot VIC_INT_EN_CLEAR is in the pipeline and
293 * so cause a fake spurious interrupt.
295 USB_DEV_EP_INTR_MASK = 0xffffffff;
296 USB_DEV_INTR_MASK = 0xffffffff;
297 VIC_INT_EN_CLEAR = INTERRUPT_USB;
298 CGU_USB &= ~(1<<5);
299 CGU_PERI &= ~CGU_USB_CLOCK_ENABLE;
300 /* Disable UVDD generating LDO */
301 ascodec_write(AS3515_USB_UTIL, ascodec_read(AS3515_USB_UTIL) & ~(1<<4));
302 usb_disable_pll();
303 logf("usb_drv_exit() !!!!\n");
306 int usb_drv_port_speed(void)
308 return (USB_DEV_STS & USB_DEV_STS_MASK_SPD) ? 0 : 1;
311 int usb_drv_request_endpoint(int type, int dir)
313 int d = dir == USB_DIR_IN ? 0 : 1;
314 int i = 1; /* skip the control EP */
316 for(; i < USB_NUM_EPS; i++) {
317 if (endpoints[i][d].state & EP_STATE_ALLOCATED)
318 continue;
320 endpoints[i][d].state |= EP_STATE_ALLOCATED;
322 if (dir == USB_DIR_IN) {
323 USB_IEP_CTRL(i) = USB_EP_CTRL_FLUSH |
324 USB_EP_CTRL_SNAK |
325 USB_EP_CTRL_ACT |
326 (type << 4);
327 USB_DEV_EP_INTR_MASK &= ~(1<<i);
328 } else {
329 USB_OEP_CTRL(i) = USB_EP_CTRL_FLUSH |
330 USB_EP_CTRL_SNAK |
331 USB_EP_CTRL_ACT |
332 (type << 4);
333 USB_DEV_EP_INTR_MASK &= ~(1<<(16+i));
335 /* logf("usb_drv_request_endpoint(%d, %d): returning %02x\n", type, dir, i | dir); */
336 return i | dir;
339 logf("usb_drv_request_endpoint(%d, %d): no free endpoint found\n", type, dir);
340 return -1;
343 void usb_drv_release_endpoint(int ep)
345 int i = ep & 0x7f;
346 int d = ep & USB_DIR_IN ? 0 : 1;
348 if (i >= USB_NUM_EPS)
349 return;
351 * Check for control EP and ignore it.
352 * Unfortunately the usb core calls
353 * usb_drv_release_endpoint() for ep=0..(USB_NUM_ENDPOINTS-1),
354 * but doesn't request a new control EP after that...
356 if (i == 0 || /* Don't mask control EP */
357 (i == 2 && d == 1)) /* See reset_endpoints(), EP2_OUT == EP0_OUT */
358 return;
360 if (!(endpoints[i][d].state & EP_STATE_ALLOCATED))
361 return;
363 /* logf("usb_drv_release_endpoint(%d, %d)\n", i, d); */
364 endpoints[i][d].state = 0;
365 USB_DEV_EP_INTR_MASK |= (1<<(16*d+i));
366 USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK;
369 void usb_drv_cancel_all_transfers(void)
371 logf("usb_drv_cancel_all_transfers()\n");
372 return;
374 int flags = disable_irq_save();
375 reset_endpoints(0);
376 restore_irq(flags);
379 int usb_drv_recv(int ep, void *ptr, int len)
381 struct usb_dev_dma_desc *uc_desc = endpoints[ep][1].uc_desc;
383 ep &= 0x7f;
384 logf("usb_drv_recv(%d,%x,%d)\n", ep, (int)ptr, len);
386 if ((int)ptr & 31) {
387 logf("addr %08x not aligned!\n", (int)ptr);
390 endpoints[ep][1].state |= EP_STATE_BUSY;
391 endpoints[ep][1].len = len;
392 endpoints[ep][1].rc = -1;
394 /* remove data buffer from cache */
395 dump_dcache_range(ptr, len);
397 /* DMA setup */
398 uc_desc->status = USB_DMA_DESC_BS_HST_RDY |
399 USB_DMA_DESC_LAST |
400 len;
401 if (len == 0) {
402 uc_desc->status |= USB_DMA_DESC_ZERO_LEN;
403 uc_desc->data_ptr = 0;
404 } else {
405 uc_desc->data_ptr = ptr;
407 USB_OEP_DESC_PTR(ep) = (int)&dmadescs[ep][1];
408 USB_OEP_STS(ep) = USB_EP_STAT_OUT_RCVD; /* clear status */
409 USB_OEP_CTRL(ep) |= USB_EP_CTRL_CNAK;
411 return 0;
414 #if defined(LOGF_ENABLE)
415 static char hexbuf[1025];
416 static char hextab[16] = "0123456789abcdef";
418 char *make_hex(char *data, int len)
420 int i;
421 if (!((int)data & 0x40000000))
422 data = AS3525_UNCACHED_ADDR(data); /* don't pollute the cache */
424 if (len > 512)
425 len = 512;
427 for (i=0; i<len; i++) {
428 hexbuf[2*i ] = hextab[(unsigned char)data[i] >> 4 ];
429 hexbuf[2*i+1] = hextab[(unsigned char)data[i] & 0xf];
431 hexbuf[2*i] = 0;
433 return hexbuf;
435 #endif
437 void ep_send(int ep, void *ptr, int len)
439 struct usb_dev_dma_desc *uc_desc = endpoints[ep][0].uc_desc;
441 endpoints[ep][0].state |= EP_STATE_BUSY;
442 endpoints[ep][0].len = len;
443 endpoints[ep][0].rc = -1;
445 /* Make sure data is committed to memory */
446 clean_dcache_range(ptr, len);
448 logf("xx%s\n", make_hex(ptr, len));
450 uc_desc->status = USB_DMA_DESC_BS_HST_RDY |
451 USB_DMA_DESC_LAST |
452 len;
453 if (len == 0)
454 uc_desc->status |= USB_DMA_DESC_ZERO_LEN;
456 uc_desc->data_ptr = ptr;
458 USB_IEP_DESC_PTR(ep) = (int)&dmadescs[ep][0];
459 USB_IEP_STS(ep) = 0xffffffff; /* clear status */
460 /* start transfer */
461 USB_IEP_CTRL(ep) |= USB_EP_CTRL_CNAK | USB_EP_CTRL_PD;
462 /* HW automatically sets NAK bit later */
465 int usb_drv_send(int ep, void *ptr, int len)
467 logf("usb_drv_send(%d,%x,%d): ", ep, (int)ptr, len);
469 ep &= 0x7f;
470 ep_send(ep, ptr, len);
471 while (endpoints[ep][0].state & EP_STATE_BUSY)
472 wakeup_wait(&endpoints[ep][0].complete, TIMEOUT_BLOCK);
474 return endpoints[ep][0].rc;
477 int usb_drv_send_nonblocking(int ep, void *ptr, int len)
479 logf("usb_drv_send_nonblocking(%d,%x,%d): ", ep, (int)ptr, len);
480 ep &= 0x7f;
481 endpoints[ep][0].state |= EP_STATE_ASYNC;
482 ep_send(ep, ptr, len);
483 return 0;
486 static void handle_in_ep(int ep)
488 int ep_sts = USB_IEP_STS(ep) & ~USB_IEP_STS_MASK(ep);
490 if (ep > 3)
491 panicf("in_ep > 3?!");
493 USB_IEP_STS(ep) = ep_sts; /* ack */
495 if (ep_sts & USB_EP_STAT_BNA) { /* Buffer was not set up */
496 logf("ep%d IN, status %x (BNA)\n", ep, ep_sts);
497 panicf("ep%d IN 0x%x (BNA)", ep, ep_sts);
500 if (ep_sts & USB_EP_STAT_TDC) {
501 endpoints[ep][0].state &= ~EP_STATE_BUSY;
502 endpoints[ep][0].rc = 0;
503 logf("EP%d %x %stx done len %x stat %08x\n",
504 ep, ep_sts, endpoints[ep][0].state & EP_STATE_ASYNC ? "async " :"",
505 endpoints[ep][0].len,
506 endpoints[ep][0].uc_desc->status);
507 if (endpoints[ep][0].state & EP_STATE_ASYNC) {
508 endpoints[ep][0].state &= ~EP_STATE_ASYNC;
509 usb_core_transfer_complete(ep, USB_DIR_IN, 0, endpoints[ep][0].len);
510 } else {
511 wakeup_signal(&endpoints[ep][0].complete);
513 ep_sts &= ~USB_EP_STAT_TDC;
516 if (ep_sts) {
517 logf("ep%d IN, hwstat %lx, epstat %x\n", ep, USB_IEP_STS(ep), endpoints[ep][0].state);
518 panicf("ep%d IN 0x%x", ep, ep_sts);
521 /* HW automatically disables RDE, re-enable it */
522 /* But this an IN ep, I wonder... */
523 USB_DEV_CTRL |= USB_DEV_CTRL_RDE;
526 static void handle_out_ep(int ep)
528 struct usb_ctrlrequest *req = (void*)AS3525_UNCACHED_ADDR(&setup_desc->data1);
529 int ep_sts = USB_OEP_STS(ep) & ~USB_OEP_STS_MASK(ep);
530 struct usb_dev_dma_desc *uc_desc = endpoints[ep][1].uc_desc;
532 if (ep > 3)
533 panicf("out_ep > 3!?");
535 USB_OEP_STS(ep) = ep_sts; /* ACK */
537 if (ep_sts & USB_EP_STAT_BNA) { /* Buffer was not set up */
538 logf("ep%d OUT, status %x (BNA)\n", ep, ep_sts);
539 panicf("ep%d OUT 0x%x (BNA)", ep, ep_sts);
542 if (ep_sts & USB_EP_STAT_OUT_RCVD) {
543 int dma_sts = uc_desc->status;
544 int dma_len = dma_sts & 0xffff;
546 if (!(dma_sts & USB_DMA_DESC_ZERO_LEN)) {
547 logf("EP%d OUT token, st:%08x len:%d frm:%x data=%s epstate=%d\n",
548 ep, dma_sts & 0xf8000000, dma_len, (dma_sts >> 16) & 0x7ff,
549 make_hex(uc_desc->data_ptr, dma_len), endpoints[ep][1].state);
551 * If parts of the just dmaed range are in cache, dump them now.
553 dump_dcache_range(uc_desc->data_ptr, dma_len);
554 } else{
555 logf("EP%d OUT token, st:%08x frm:%x (no data)\n", ep,
556 dma_mst, dma_frm);
559 if (endpoints[ep][1].state & EP_STATE_BUSY) {
560 endpoints[ep][1].state &= ~EP_STATE_BUSY;
561 endpoints[ep][1].rc = 0;
562 usb_core_transfer_complete(ep, USB_DIR_OUT, 0, dma_len);
563 } else {
564 logf("EP%d OUT, but no one was listening?\n", ep);
567 USB_OEP_CTRL(ep) |= USB_EP_CTRL_SNAK; /* make sure NAK is set */
569 ep_sts &= ~USB_EP_STAT_OUT_RCVD;
572 if (ep_sts & USB_EP_STAT_SETUP_RCVD) {
573 static struct usb_ctrlrequest req_copy;
575 req_copy = *req;
576 logf("t%ld:got SETUP packet: type=%d req=%d val=%d ind=%d len=%d\n",
577 current_tick,
578 req->bRequestType,
579 req->bRequest,
580 req->wValue,
581 req->wIndex,
582 req->wLength);
584 usb_core_control_request(&req_copy);
585 setup_desc_init(setup_desc);
587 ep_sts &= ~USB_EP_STAT_SETUP_RCVD;
590 if (ep_sts) {
591 logf("ep%d OUT, status %x\n", ep, ep_sts);
592 panicf("ep%d OUT 0x%x", ep, ep_sts);
595 /* HW automatically disables RDE, re-enable it */
596 /* THEORY: Because we only set up one DMA buffer... */
597 USB_DEV_CTRL |= USB_DEV_CTRL_RDE;
600 /* interrupt service routine */
601 void INT_USB(void)
603 int ep = USB_DEV_EP_INTR & ~USB_DEV_EP_INTR_MASK;
604 int intr = USB_DEV_INTR & ~USB_DEV_INTR_MASK;
606 /* ACK interrupt sources */
607 USB_DEV_EP_INTR = ep;
608 USB_DEV_INTR = intr;
610 /* Handle endpoint interrupts */
611 while (ep) {
612 int onebit = 31-__builtin_clz(ep);
614 if (onebit < 16) handle_in_ep(onebit);
615 else handle_out_ep(onebit-16);
617 ep &= ~(1 << onebit);
620 /* Handle general device interrupts */
621 if (intr) {
622 if (intr & USB_DEV_INTR_SET_INTERFACE) {/* SET_INTERFACE received */
623 logf("set interface\n");
624 panicf("set interface");
625 intr &= ~USB_DEV_INTR_SET_INTERFACE;
627 if (intr & USB_DEV_INTR_SET_CONFIG) {/* SET_CONFIGURATION received */
629 * This is handled in HW, we have to fake a request here
630 * for usb_core.
632 static struct usb_ctrlrequest set_config = {
633 bRequestType: USB_TYPE_STANDARD | USB_RECIP_DEVICE,
634 bRequest: USB_REQ_SET_CONFIGURATION,
635 wValue: 0,
636 wIndex: 0,
637 wLength: 0,
640 logf("set config\n");
642 set_config.wValue = USB_DEV_STS & USB_DEV_STS_MASK_CFG;
643 usb_core_control_request(&set_config);
645 /* Tell the HW we handled the request */
646 USB_DEV_CTRL |= USB_DEV_CTRL_APCSR_DONE;
647 intr &= ~USB_DEV_INTR_SET_CONFIG;
649 if (intr & USB_DEV_INTR_EARLY_SUSPEND) {/* idle >3ms detected */
650 logf("usb idle\n");
651 intr &= ~USB_DEV_INTR_EARLY_SUSPEND;
653 if (intr & USB_DEV_INTR_USB_RESET) {/* usb reset from host? */
654 logf("usb reset\n");
655 reset_endpoints(1);
656 usb_core_bus_reset();
657 intr &= ~USB_DEV_INTR_USB_RESET;
659 if (intr & USB_DEV_INTR_USB_SUSPEND) {/* suspend req from host? */
660 logf("usb suspend\n");
661 intr &= ~USB_DEV_INTR_USB_SUSPEND;
663 if (intr & USB_DEV_INTR_SOF) {/* sof received */
664 logf("sof\n");
665 intr &= ~USB_DEV_INTR_SOF;
667 if (intr & USB_DEV_INTR_SVC) {/* device status changed */
668 logf("svc: %08x otg: %08x\n", (int)USB_DEV_STS, (int)USB_OTG_CSR);
669 intr &= ~USB_DEV_INTR_SVC;
671 if (intr & USB_DEV_INTR_ENUM_DONE) {/* speed enumeration complete */
672 int spd = USB_DEV_STS & USB_DEV_STS_MASK_SPD; /* Enumerated Speed */
674 logf("speed enum complete: ");
675 if (spd == USB_DEV_STS_SPD_HS) logf("hs\n");
676 if (spd == USB_DEV_STS_SPD_FS) logf("fs\n");
677 if (spd == USB_DEV_STS_SPD_LS) logf("ls\n");
679 USB_PHY_EP0_INFO = 0x00200000 |
680 USB_CSR_DIR_OUT |
681 USB_CSR_TYPE_CTL;
682 USB_PHY_EP1_INFO = 0x00200000 |
683 USB_CSR_DIR_IN |
684 USB_CSR_TYPE_CTL;
685 USB_PHY_EP2_INFO = 0x00200001 |
686 USB_CSR_DIR_IN |
687 USB_CSR_TYPE_BULK;
688 USB_PHY_EP3_INFO = 0x00200001 |
689 USB_CSR_DIR_IN |
690 USB_CSR_TYPE_BULK;
691 USB_DEV_CTRL |= USB_DEV_CTRL_APCSR_DONE;
692 USB_IEP_CTRL(0) |= USB_EP_CTRL_ACT;
693 USB_OEP_CTRL(0) |= USB_EP_CTRL_ACT;
694 intr &= ~USB_DEV_INTR_ENUM_DONE;
696 if (intr)
697 panicf("usb devirq 0x%x", intr);
700 if (!(USB_DEV_CTRL & USB_DEV_CTRL_RDE)){
701 logf("re-enabling receive DMA\n");
702 USB_DEV_CTRL |= USB_DEV_CTRL_RDE;
707 /* (not essential? , not implemented in usb-tcc.c) */
708 void usb_drv_set_test_mode(int mode)
710 (void)mode;
713 /* handled internally by controller */
714 void usb_drv_set_address(int address)
716 (void)address;
719 void usb_drv_stall(int ep, bool stall, bool in)
721 if (stall) USB_EP_CTRL(ep, in) |= USB_EP_CTRL_STALL;
722 else USB_EP_CTRL(ep, in) &= ~USB_EP_CTRL_STALL;
725 bool usb_drv_stalled(int ep, bool in)
727 return USB_EP_CTRL(ep, in) & USB_EP_CTRL_STALL;
730 #else
732 void usb_attach(void)
736 void usb_drv_init(void)
740 void usb_drv_exit(void)
744 int usb_drv_port_speed(void)
746 return 0;
749 int usb_drv_request_endpoint(int type, int dir)
751 (void)type;
752 (void)dir;
754 return -1;
757 void usb_drv_release_endpoint(int ep)
759 (void)ep;
762 void usb_drv_cancel_all_transfers(void)
766 void usb_drv_set_test_mode(int mode)
768 (void)mode;
771 void usb_drv_set_address(int address)
773 (void)address;
776 int usb_drv_recv(int ep, void *ptr, int len)
778 (void)ep;
779 (void)ptr;
780 (void)len;
782 return -1;
785 int usb_drv_send(int ep, void *ptr, int len)
787 (void)ep;
788 (void)ptr;
789 (void)len;
791 return -1;
794 int usb_drv_send_nonblocking(int ep, void *ptr, int len)
796 (void)ep;
797 (void)ptr;
798 (void)len;
800 return -1;
803 void usb_drv_stall(int ep, bool stall, bool in)
805 (void)ep;
806 (void)stall;
807 (void)in;
810 bool usb_drv_stalled(int ep, bool in)
812 (void)ep;
813 (void)in;
815 return 0;
818 #endif