1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright © 2010 Amaury Pouly
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 ****************************************************************************/
25 #include "clock-target.h"
36 #include "usb-drv-as3525v2.h"
39 static int __in_ep_list
[NUM_IN_EP
] = {IN_EP_LIST
};
40 static int __out_ep_list
[NUM_OUT_EP
] = {OUT_EP_LIST
};
41 static int __in_ep_list_ep0
[NUM_IN_EP
+ 1] = {0, IN_EP_LIST
};
42 static int __out_ep_list_ep0
[NUM_OUT_EP
+ 1] = {0, OUT_EP_LIST
};
44 /* iterate through each in/out ep except EP0
45 * 'counter' is the counter, 'ep' is the actual value */
46 #define FOR_EACH_EP(list, size, counter, ep) \
47 for(counter = 0, ep = (list)[0]; \
49 counter++, ep = (list)[counter])
51 #define FOR_EACH_IN_EP_EX(include_ep0, counter, ep) \
52 FOR_EACH_EP(include_ep0 ? __in_ep_list_ep0 : __in_ep_list, \
53 include_ep0 ? NUM_IN_EP : NUM_IN_EP + 1, counter, ep)
55 #define FOR_EACH_OUT_EP_EX(include_ep0, counter, ep) \
56 FOR_EACH_EP(include_ep0 ? __out_ep_list_ep0 : __out_ep_list, \
57 include_ep0 ? NUM_OUT_EP : NUM_OUT_EP + 1, counter, ep)
59 #define FOR_EACH_IN_EP(counter, ep) \
60 FOR_EACH_IN_EP_EX(false, counter, ep)
62 #define FOR_EACH_IN_EP_AND_EP0(counter, ep) \
63 FOR_EACH_IN_EP_EX(true, counter, ep)
65 #define FOR_EACH_OUT_EP(counter, ep) \
66 FOR_EACH_OUT_EP_EX(false, counter, ep)
68 #define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \
69 FOR_EACH_OUT_EP_EX(true, counter, ep)
78 struct wakeup complete
;
82 static struct usb_endpoint endpoints
[USB_NUM_ENDPOINTS
][2];
83 static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR
;
87 logf("usb-drv: attach");
91 static void usb_delay(void)
101 static void as3525v2_connect(void)
103 logf("usb-drv: init as3525v2");
104 /* 1) enable usb core clock */
105 CGU_PERI
|= CGU_USB_CLOCK_ENABLE
;
107 /* 2) enable usb phy clock */
109 CGU_USB
= 1<<5 /* enable */
110 | (CLK_DIV(AS3525_PLLA_FREQ
, 60000000)) << 2
111 | 1; /* source = PLLA */
113 /* 3) clear "stop pclk" */
116 /* 4) clear "power clamp" */
119 /* 5) clear "reset power down module" */
122 /* 6) set "power on program done" */
123 DCTL
|= DCTL_pwronprgdone
;
125 /* 7) core soft reset */
126 GRSTCTL
|= GRSTCTL_csftrst
;
128 /* 8) hclk soft reset */
129 GRSTCTL
|= GRSTCTL_hsftrst
;
131 /* 9) flush and reset everything */
134 /* 10) force device mode*/
135 GUSBCFG
&= ~GUSBCFG_force_host_mode
;
136 GUSBCFG
|= GUSBCFG_force_device_mode
;
138 /* 11) Do something that is probably CCU related but undocumented*/
139 CCU_USB_THINGY
&= ~0x1000;
141 CCU_USB_THINGY
&= ~0x300000;
143 /* 12) reset usb core parameters (dev addr, speed, ...) */
148 static void as3525v2_disconnect(void)
152 static void enable_device_interrupts(void)
154 /* Clear any pending interrupt */
155 GINTSTS
= 0xffffffff;
156 /* Clear any pending otg interrupt */
157 GOTGINT
= 0xffffffff;
158 /* Enable interrupts */
159 GINTMSK
= GINTMSK_usbreset
163 | GINTMSK_disconnect
;
166 static void flush_tx_fifos(int nums
)
170 GRSTCTL
= (nums
<< GRSTCTL_txfnum_bitp
)
171 | GRSTCTL_txfflsh_flush
;
172 while(GRSTCTL
& GRSTCTL_txfflsh_flush
&& i
< 0x300)
174 if(GRSTCTL
& GRSTCTL_txfflsh_flush
)
175 panicf("usb-drv: hang of flush tx fifos (%x)", nums
);
176 /* wait 3 phy clocks */
180 static void flush_rx_fifos(void)
184 GRSTCTL
= GRSTCTL_rxfflsh_flush
;
185 while(GRSTCTL
& GRSTCTL_rxfflsh_flush
&& i
< 0x300)
187 if(GRSTCTL
& GRSTCTL_rxfflsh_flush
)
188 panicf("usb-drv: hang of flush rx fifos");
189 /* wait 3 phy clocks */
193 static void prepare_setup_ep0(void)
196 clean_dcache_range((void*)&ep0_setup_pkt
, sizeof ep0_setup_pkt
); /* force write back */
197 DOEPDMA(0) = (unsigned long)&ep0_setup_pkt
; /* virtual address=physical address */
199 /* Setup EP0 OUT with the following parameters:
201 * setup packet count = 1
202 * transfer size = 8 (setup packet)
204 DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp
)
205 | (1 << DEPTSIZ0_pkcnt_bitp
)
208 /* Enable endpoint, clear nak */
209 DOEPCTL(0) |= DEPCTL_epena
| DEPCTL_cnak
;
211 if(!(DOEPCTL(0) & DEPCTL_epena
))
212 panicf("usb-drv: failed to enable EP0 !");
215 static void reset_endpoints(void)
218 /* disable all endpoints except EP0 */
219 FOR_EACH_IN_EP(i
, ep
)
220 if(DIEPCTL(ep
) & DEPCTL_epena
)
221 DIEPCTL(ep
) = DEPCTL_epdis
| DEPCTL_snak
;
225 FOR_EACH_OUT_EP(i
, ep
)
226 if(DOEPCTL(ep
) & DEPCTL_epena
)
227 DOEPCTL(ep
) = DEPCTL_epdis
| DEPCTL_snak
;
231 /* 64 bytes packet size, active endpoint */
232 DOEPCTL(0) = (DEPCTL_MPS_64
<< DEPCTL_mps_bitp
) | DEPCTL_usbactep
;
233 DIEPCTL(0) = (DEPCTL_MPS_64
<< DEPCTL_mps_bitp
) | DEPCTL_usbactep
;
238 static void cancel_all_transfers(bool cancel_ep0
)
240 logf("usb-drv: cancel all transfers");
241 int flags
= disable_irq_save();
243 FOR_EACH_IN_EP_EX(cancel_ep0
, i
, ep
)
245 endpoints
[ep
][DIR_IN
].status
= 1;
246 endpoints
[ep
][DIR_IN
].wait
= false;
247 endpoints
[ep
][DIR_IN
].busy
= false;
248 wakeup_signal(&endpoints
[ep
][DIR_IN
].complete
);
249 DIEPCTL(ep
) = (DIEPCTL(ep
) & ~DEPCTL_usbactep
) | DEPCTL_epdis
;
251 FOR_EACH_OUT_EP_EX(cancel_ep0
, i
, ep
)
253 endpoints
[ep
][DIR_OUT
].status
= 1;
254 endpoints
[ep
][DIR_OUT
].wait
= false;
255 endpoints
[ep
][DIR_OUT
].busy
= false;
256 wakeup_signal(&endpoints
[ep
][DIR_OUT
].complete
);
257 DOEPCTL(ep
) = (DOEPCTL(ep
) & ~DEPCTL_usbactep
) | DEPCTL_epdis
;
263 static void core_dev_init(void)
266 /* Restart the phy clock */
268 /* Set phy speed : high speed */
269 DCFG
= (DCFG
& ~bitm(DCFG
, devspd
)) | DCFG_devspd_hs_phy_hs
;
271 /* Check hardware capabilities */
272 if(extract(GHWCFG2
, arch
) != GHWCFG2_ARCH_INTERNAL_DMA
)
273 panicf("usb-drv: wrong architecture (%ld)", extract(GHWCFG2
, arch
));
274 if(extract(GHWCFG2
, hs_phy_type
) != GHWCFG2_PHY_TYPE_UTMI
)
275 panicf("usb-drv: wrong HS phy type (%ld)", extract(GHWCFG2
, hs_phy_type
));
276 if(extract(GHWCFG2
, fs_phy_type
) != GHWCFG2_PHY_TYPE_UNSUPPORTED
)
277 panicf("usb-drv: wrong FS phy type (%ld)", extract(GHWCFG2
, fs_phy_type
));
278 if(extract(GHWCFG4
, utmi_phy_data_width
) != 0x2)
279 panicf("usb-drv: wrong utmi data width (%ld)", extract(GHWCFG4
, utmi_phy_data_width
));
280 if(!(GHWCFG4
& GHWCFG4_ded_fifo_en
)) /* it seems to be multiple tx fifo support */
281 panicf("usb-drv: no multiple tx fifo");
283 #ifdef USE_CUSTOM_FIFO_LAYOUT
284 if(!(GHWCFG2
& GHWCFG2_dyn_fifo
))
285 panicf("usb-drv: no dynamic fifo");
286 if(GRXFSIZ
!= DATA_FIFO_DEPTH
)
287 panicf("usb-drv: wrong data fifo size");
288 #endif /* USE_CUSTOM_FIFO_LAYOUT */
290 /* do some logging */
292 logf("hwcfg1: %08lx", GHWCFG1);
293 logf("hwcfg2: %08lx", GHWCFG2);
294 logf("hwcfg3: %08lx", GHWCFG3);
295 logf("hwcfg4: %08lx", GHWCFG4);
298 if(USB_NUM_ENDPOINTS
!= extract(GHWCFG2
, num_ep
))
299 panicf("usb-drv: wrong endpoint number");
301 FOR_EACH_IN_EP_AND_EP0(i
, ep
)
303 int type
= (GHWCFG1
>> GHWCFG1_epdir_bitp(ep
)) & GHWCFG1_epdir_bits
;
304 if(type
!= GHWCFG1_EPDIR_BIDIR
&& type
!= GHWCFG1_EPDIR_IN
)
305 panicf("usb-drv: EP%d is no IN or BIDIR", ep
);
307 FOR_EACH_OUT_EP_AND_EP0(i
, ep
)
309 int type
= (GHWCFG1
>> GHWCFG1_epdir_bitp(ep
)) & GHWCFG1_epdir_bits
;
310 if(type
!= GHWCFG1_EPDIR_BIDIR
&& type
!= GHWCFG1_EPDIR_OUT
)
311 panicf("usb-drv: EP%d is no OUT or BIDIR", ep
);
314 /* Setup interrupt masks for endpoints */
315 /* Setup interrupt masks */
316 DOEPMSK
= DOEPINT_setup
| DOEPINT_xfercompl
| DOEPINT_ahberr
;
317 DIEPMSK
= DIEPINT_xfercompl
| DIEPINT_timeout
| DIEPINT_ahberr
;
318 DAINTMSK
= 0xffffffff;
322 /* fixme: threshold tweaking only takes place if we use multiple tx fifos it seems */
323 /* only dump them for now, leave threshold disabled */
325 logf("threshold control:");
326 logf(" non_iso_thr_en: %d", (DTHRCTL & DTHRCTL_non_iso_thr_en) ? 1 : 0);
327 logf(" iso_thr_en: %d", (DTHRCTL & DTHRCTL_iso_thr_en) ? 1 : 0);
328 logf(" tx_thr_len: %lu", extract(DTHRCTL, tx_thr_len));
329 logf(" rx_thr_en: %d", (DTHRCTL & DTHRCTL_rx_thr_en) ? 1 : 0);
330 logf(" rx_thr_len: %lu", extract(DTHRCTL, rx_thr_len));
333 /* enable USB interrupts */
334 enable_device_interrupts();
337 static void core_init(void)
340 DCTL
|= DCTL_sftdiscon
;
341 /* Select UTMI+ 16 */
342 GUSBCFG
|= GUSBCFG_phy_if
;
344 /* fixme: the current code is for internal DMA only, the clip+ architecture
345 * define the internal DMA model */
346 /* Set burstlen and enable DMA*/
347 GAHBCFG
= (GAHBCFG_INT_DMA_BURST_INCR4
<< GAHBCFG_hburstlen_bitp
)
348 | GAHBCFG_dma_enable
;
349 /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */
350 GUSBCFG
&= ~(GUSBCFG_srpcap
| GUSBCFG_hnpcapp
);
352 /* perform device model specific init */
356 DCTL
&= ~DCTL_sftdiscon
;
359 static void enable_global_interrupts(void)
361 VIC_INT_ENABLE
= INTERRUPT_USB
;
362 GAHBCFG
|= GAHBCFG_glblintrmsk
;
365 static void disable_global_interrupts(void)
367 GAHBCFG
&= ~GAHBCFG_glblintrmsk
;
368 VIC_INT_EN_CLEAR
= INTERRUPT_USB
;
371 void usb_drv_init(void)
374 logf("usb_drv_init");
377 /* Enable PHY and clocks (but leave pullups disabled) */
379 logf("usb-drv: synopsis id: %lx", GSNPSID
);
382 FOR_EACH_IN_EP_AND_EP0(i
, ep
)
383 wakeup_init(&endpoints
[ep
][DIR_IN
].complete
);
384 FOR_EACH_OUT_EP_AND_EP0(i
, ep
)
385 wakeup_init(&endpoints
[ep
][DIR_OUT
].complete
);
386 /* Enable global interrupts */
387 enable_global_interrupts();
390 void usb_drv_exit(void)
392 logf("usb_drv_exit");
394 disable_global_interrupts();
395 as3525v2_disconnect();
399 static void handle_ep_int(int ep
, bool dir_in
)
401 struct usb_endpoint
*endpoint
= &endpoints
[ep
][dir_in
];
404 if(DIEPINT(ep
) & DIEPINT_ahberr
)
405 panicf("usb-drv: ahb error on EP%d IN", ep
);
406 if(DIEPINT(ep
) & DIEPINT_xfercompl
)
408 logf("usb-drv: xfer complete on EP%d IN", ep
);
411 endpoint
->busy
= false;
412 endpoint
->status
= 0;
413 /* works even for PE0 */
414 int transfered
= endpoint
->len
- (DIEPTSIZ(ep
) & DEPTSIZ_xfersize_bits
);
415 logf("len=%d reg=%ld xfer=%d", endpoint
->len
,
416 (DIEPTSIZ(ep
) & DEPTSIZ_xfersize_bits
),
418 invalidate_dcache_range((void *)DIEPDMA(ep
), transfered
);
419 DIEPCTL(ep
) |= DEPCTL_snak
;
420 /* if the transfer length is 0 on EP0, this is a ack
421 * so we setup EP0 to receive next setup */
422 if(ep
== 0 && endpoint
->len
== 0)
424 usb_core_transfer_complete(ep
, USB_DIR_IN
, 0, transfered
);
425 wakeup_signal(&endpoint
->complete
);
428 if(DIEPINT(ep
) & DIEPINT_timeout
)
430 logf("usb-drv: timeout on EP%d IN", ep
);
433 endpoint
->busy
= false;
434 endpoint
->status
= 1;
435 /* for safety, act as if no bytes as been transfered */
437 DIEPCTL(ep
) |= DEPCTL_snak
;
438 usb_core_transfer_complete(ep
, USB_DIR_IN
, 1, 0);
439 wakeup_signal(&endpoint
->complete
);
442 /* clear interrupts */
443 DIEPINT(ep
) = DIEPINT(ep
);
447 if(DOEPINT(ep
) & DOEPINT_ahberr
)
448 panicf("usb-drv: ahb error on EP%d OUT", ep
);
449 if(DOEPINT(ep
) & DOEPINT_xfercompl
)
451 logf("usb-drv: xfer complete on EP%d OUT", ep
);
454 endpoint
->busy
= false;
455 endpoint
->status
= 0;
456 /* works even for EP0 */
457 int transfered
= endpoint
->len
- (DOEPTSIZ(ep
) & DEPTSIZ_xfersize_bits
);
458 logf("len=%d reg=%ld xfer=%d", endpoint
->len
,
459 (DOEPTSIZ(ep
) & DEPTSIZ_xfersize_bits
),
461 invalidate_dcache_range((void *)DOEPDMA(ep
), transfered
);
462 /* if the transfer length is 0 on EP0, this is a ack
463 * so we setup EP0 to receive next setup */
464 if(ep
== 0 && endpoint
->len
== 0)
467 DOEPCTL(ep
) |= DEPCTL_snak
;
468 usb_core_transfer_complete(ep
, USB_DIR_OUT
, 0, transfered
);
469 wakeup_signal(&endpoint
->complete
);
472 if(DOEPINT(ep
) & DOEPINT_setup
)
474 logf("usb-drv: setup on EP%d OUT", ep
);
476 panicf("usb-drv: setup not on EP0, this is impossible");
477 DOEPCTL(ep
) |= DEPCTL_snak
;
478 /* handle the set address here because of a bug in the usb core */
479 invalidate_dcache_range((void*)&ep0_setup_pkt
, sizeof ep0_setup_pkt
); /* force write back */
480 logf(" rt=%x r=%x", ep0_setup_pkt
.bRequestType
, ep0_setup_pkt
.bRequest
);
481 if(ep0_setup_pkt
.bRequestType
== USB_TYPE_STANDARD
&&
482 ep0_setup_pkt
.bRequest
== USB_REQ_SET_ADDRESS
)
483 usb_drv_set_address(ep0_setup_pkt
.wValue
);
484 usb_core_control_request(&ep0_setup_pkt
);
486 /* clear interrupts */
487 DOEPINT(ep
) = DOEPINT(ep
);
491 static void handle_ep_ints(void)
493 logf("usb-drv: ep int");
494 /* we must read it */
495 unsigned long daint
= DAINT
;
498 FOR_EACH_IN_EP_AND_EP0(i
, ep
)
499 if(daint
& DAINT_IN_EP(ep
))
500 handle_ep_int(ep
, true);
501 FOR_EACH_OUT_EP_AND_EP0(i
, ep
)
502 if(daint
& DAINT_OUT_EP(ep
))
503 handle_ep_int(ep
, false);
505 /* write back to clear status */
509 /* interrupt service routine */
512 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
513 * so AND it with the actual mask */
514 unsigned long sts
= GINTSTS
& GINTMSK
;
517 if(sts
& GINTMSK_usbreset
)
519 logf("usb-drv: bus reset");
521 /* Clear the Remote Wakeup Signalling */
522 //DCTL &= ~DCTL_rmtwkupsig;
524 cancel_all_transfers(true);
526 flush_tx_fifos(0x10);
531 /* Reset Device Address */
532 DCFG
&= ~bitm(DCFG
, devadr
);
534 usb_core_bus_reset();
537 if(sts
& GINTMSK_enumdone
)
539 logf("usb-drv: enum done");
542 if(usb_drv_port_speed())
547 /* fixme: change EP0 mps here */
550 if(sts
& (GINTMSK_outepintr
| GINTMSK_inepintr
))
555 if(sts
& GINTMSK_disconnect
)
557 panicf("usb-drv: disconnect");
558 cancel_all_transfers(true);
565 int usb_drv_port_speed(void)
567 switch(extract(DSTS
, enumspd
))
569 case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ
:
571 case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ
:
572 case DSTS_ENUMSPD_FS_PHY_48MHZ
:
575 case DSTS_ENUMSPD_LS_PHY_6MHZ
:
576 panicf("usb-drv: LS is not supported");
579 panicf("usb-drv: wtf is this speed ?");
584 int usb_drv_request_endpoint(int type
, int dir
)
588 logf("usb-drv: request endpoint (type=%d,dir=%s)", type
, dir
== USB_DIR_IN
? "IN" : "OUT");
592 void usb_drv_release_endpoint(int ep
)
594 //logf("usb-drv: release EP%d %s", EP_NUM(ep), EP_DIR(ep) == DIR_IN ? "IN" : "OUT");
595 endpoints
[EP_NUM(ep
)][EP_DIR(ep
)].active
= false;
598 void usb_drv_cancel_all_transfers()
600 cancel_all_transfers(false);
603 static int usb_drv_transfer(int ep
, void *ptr
, int len
, bool dir_in
, bool blocking
)
606 logf("usb-drv: xfer EP%d, len=%d, dir_in=%d, blocking=%d", ep
,
607 len
, dir_in
, blocking
);
609 volatile unsigned long *epctl
= dir_in
? &DIEPCTL(ep
) : &DOEPCTL(ep
);
610 volatile unsigned long *eptsiz
= dir_in
? &DIEPTSIZ(ep
) : &DOEPTSIZ(ep
);
611 volatile unsigned long *epdma
= dir_in
? &DIEPDMA(ep
) : &DOEPDMA(ep
);
612 struct usb_endpoint
*endpoint
= &endpoints
[ep
][dir_in
];
613 #define DEPCTL *epctl
614 #define DEPTSIZ *eptsiz
615 #define DEPDMA *epdma
617 if(DEPCTL
& DEPCTL_stall
)
619 logf("usb-drv: cannot receive/send on a stalled endpoint");
624 logf("usb-drv: EP%d %s is already busy", ep
, dir_in
? "IN" : "OUT");
626 endpoint
->busy
= true;
628 endpoint
->wait
= blocking
;
629 DEPCTL
|= DEPCTL_usbactep
;
632 int nb_packets
= (len
+ mps
- 1) / mps
;
635 DEPTSIZ
= 1 << DEPTSIZ_pkcnt_bitp
;
637 DEPTSIZ
= (nb_packets
<< DEPTSIZ_pkcnt_bitp
) | len
;
638 clean_dcache_range(ptr
, len
);
639 DEPDMA
= (unsigned long)ptr
;
640 DEPCTL
|= DEPCTL_epena
| DEPCTL_cnak
;
642 /* fixme: check if endpoint was really enabled ? */
645 wakeup_wait(&endpoint
->complete
, TIMEOUT_BLOCK
);
646 if(endpoint
->status
!= 0)
655 int usb_drv_recv(int ep
, void *ptr
, int len
)
657 return usb_drv_transfer(ep
, ptr
, len
, false, false);
660 int usb_drv_send(int ep
, void *ptr
, int len
)
662 return usb_drv_transfer(ep
, ptr
, len
, true, true);
665 int usb_drv_send_nonblocking(int ep
, void *ptr
, int len
)
667 return usb_drv_transfer(ep
, ptr
, len
, true, false);
671 void usb_drv_set_test_mode(int mode
)
676 void usb_drv_set_address(int address
)
678 /* ignore it if addres is already set */
679 if(extract(DCFG
, devadr
) == 0)
681 logf("usb-drv: set address %x", address
);
682 DCFG
= (DCFG
& ~bitm(DCFG
, devadr
)) | (address
<< DCFG_devadr_bitp
);
686 void usb_drv_stall(int ep
, bool stall
, bool in
)
691 logf("usb-drv: %sstall EP%d %s", stall
? "" : "un", ep
, in
? "IN" : "OUT");
694 bool usb_drv_stalled(int ep
, bool in
)