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_IN_EP(counter, ep) \
47 for(counter = 0, ep = __in_ep_list[0]; counter < NUM_IN_EP; counter++, ep = __in_ep_list[counter])
49 #define FOR_EACH_IN_EP_AND_EP0(counter, ep) \
50 for(counter = 0, ep = __in_ep_list_ep0[0]; counter <= NUM_IN_EP; counter++, ep = __in_ep_list_ep0[counter])
52 #define FOR_EACH_OUT_EP(counter, ep) \
53 for(counter = 0, ep = __out_ep_list[0]; counter < NUM_OUT_EP; counter++, ep = __out_ep_list[counter])
55 #define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \
56 for(counter = 0, ep = __out_ep_list_ep0[0]; counter <= NUM_OUT_EP; counter++, ep = __out_ep_list_ep0[counter])
65 struct wakeup complete
;
68 /* NOTE: the following structure is not used to EP0
69 * and make the assumption that each endpoint is
70 * either IN or OUT but not bidirectional */
71 static struct usb_endpoint endpoints
[USB_NUM_ENDPOINTS
];
72 static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR
;
80 static void usb_delay(void)
90 static void as3525v2_connect(void)
92 logf("usb: init as3525v2");
93 /* 1) enable usb core clock */
94 CGU_PERI
|= CGU_USB_CLOCK_ENABLE
;
96 /* 2) enable usb phy clock */
98 CGU_USB
= 1<<5 /* enable */
99 | (CLK_DIV(AS3525_PLLA_FREQ
, 60000000)) << 2
100 | 1; /* source = PLLA */
102 /* 3) clear "stop pclk" */
105 /* 4) clear "power clamp" */
108 /* 5) clear "reset power down module" */
111 /* 6) set "power on program done" */
112 DCTL
|= DCTL_pwronprgdone
;
114 /* 7) core soft reset */
115 GRSTCTL
|= GRSTCTL_csftrst
;
117 /* 8) hclk soft reset */
118 GRSTCTL
|= GRSTCTL_hsftrst
;
120 /* 9) flush and reset everything */
123 /* 10) force device mode*/
124 GUSBCFG
&= ~GUSBCFG_force_host_mode
;
125 GUSBCFG
|= GUSBCFG_force_device_mode
;
127 /* 11) Do something that is probably CCU related but undocumented*/
128 CCU_USB_THINGY
&= ~0x1000;
130 CCU_USB_THINGY
&= ~0x300000;
132 /* 12) reset usb core parameters (dev addr, speed, ...) */
137 static void enable_device_interrupts(void)
139 /* Clear any pending interrupt */
140 GINTSTS
= 0xffffffff;
141 /* Clear any pending otg interrupt */
142 GOTGINT
= 0xffffffff;
143 /* Enable interrupts */
144 GINTMSK
= GINTMSK_usbreset
149 | GINTMSK_disconnect
;
152 static void flush_tx_fifos(int nums
)
156 GRSTCTL
= (nums
<< GRSTCTL_txfnum_bitp
)
157 | GRSTCTL_txfflsh_flush
;
158 while(GRSTCTL
& GRSTCTL_txfflsh_flush
&& i
< 0x300)
160 if(GRSTCTL
& GRSTCTL_txfflsh_flush
)
161 panicf("usb: hang of flush tx fifos (%x)", nums
);
162 /* wait 3 phy clocks */
166 static void reset_endpoints(void)
169 /* disable all endpoints except EP0 */
170 FOR_EACH_IN_EP(i
, ep
)
171 if(DIEPCTL(ep
) & DEPCTL_epena
)
172 DIEPCTL(ep
) = DEPCTL_epdis
| DEPCTL_snak
;
176 FOR_EACH_OUT_EP(i
, ep
)
177 if(DOEPCTL(ep
) & DEPCTL_epena
)
178 DOEPCTL(ep
) = DEPCTL_epdis
| DEPCTL_snak
;
181 /* Setup EP0 OUT with the following parameters:
183 * setup packet count = 1
184 * transfer size = 8 (setup packet)
185 * Setup EP0 IN/OUT with 64 byte maximum packet size and activate both. Enable transfer on EP0 OUT
187 DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp
)
188 | (1 << DEPTSIZ0_pkcnt_bitp
)
192 clean_dcache_range((void*)&ep0_setup_pkt
, sizeof ep0_setup_pkt
); /* force write back */
193 DOEPDMA(0) = (unsigned long)&ep0_setup_pkt
; /* virtual address=physical address */
195 /* Enable endpoint, clear nak */
196 DOEPCTL(0) = DEPCTL_epena
| DEPCTL_cnak
| DEPCTL_usbactep
197 | (DEPCTL_MPS_64
<< DEPCTL_mps_bitp
);
199 /* 64 bytes packet size, active endpoint */
200 DIEPCTL(0) = (DEPCTL_MPS_64
<< DEPCTL_mps_bitp
)
204 static void core_dev_init(void)
206 unsigned int num_in_ep
= 0;
207 unsigned int num_out_ep
= 0;
209 /* Restart the phy clock */
211 /* Set phy speed : high speed */
212 DCFG
= (DCFG
& ~bitm(DCFG
, devspd
)) | DCFG_devspd_hs_phy_hs
;
214 /* Check hardware capabilities */
215 if(extract(GHWCFG2
, arch
) != GHWCFG2_ARCH_INTERNAL_DMA
)
216 panicf("usb: wrong architecture (%ld)", extract(GHWCFG2
, arch
));
217 if(extract(GHWCFG2
, hs_phy_type
) != GHWCFG2_PHY_TYPE_UTMI
)
218 panicf("usb: wrong HS phy type (%ld)", extract(GHWCFG2
, hs_phy_type
));
219 if(extract(GHWCFG2
, fs_phy_type
) != GHWCFG2_PHY_TYPE_UNSUPPORTED
)
220 panicf("usb: wrong FS phy type (%ld)", extract(GHWCFG2
, fs_phy_type
));
221 if(extract(GHWCFG4
, utmi_phy_data_width
) != 0x2)
222 panicf("usb: wrong utmi data width (%ld)", extract(GHWCFG4
, utmi_phy_data_width
));
223 if(!(GHWCFG4
& GHWCFG4_ded_fifo_en
)) /* it seems to be multiple tx fifo support */
224 panicf("usb: no multiple tx fifo");
226 #ifdef USE_CUSTOM_FIFO_LAYOUT
227 if(!(GHWCFG2
& GHWCFG2_dyn_fifo
))
228 panicf("usb: no dynamic fifo");
229 if(GRXFSIZ
!= DATA_FIFO_DEPTH
)
230 panicf("usb: wrong data fifo size");
231 #endif /* USE_CUSTOM_FIFO_LAYOUT */
233 /* do some logging */
234 logf("hwcfg1: %08lx", GHWCFG1
);
235 logf("hwcfg2: %08lx", GHWCFG2
);
236 logf("hwcfg3: %08lx", GHWCFG3
);
237 logf("hwcfg4: %08lx", GHWCFG4
);
239 logf("%ld endpoints", extract(GHWCFG2
, num_ep
));
242 for(i
= 0; i
< extract(GHWCFG2
, num_ep
); i
++)
244 bool in
= false, out
= false;
245 switch((GHWCFG1
>> GHWCFG1_epdir_bitp(i
)) & GHWCFG1_epdir_bits
)
247 case GHWCFG1_EPDIR_BIDIR
: in
= out
= true; break;
248 case GHWCFG1_EPDIR_IN
: in
= true; break;
249 case GHWCFG1_EPDIR_OUT
: out
= true; break;
250 default: panicf("usb: invalid epdir");
252 /* don't count EP0 which is special and always bidirectional */
257 logf(" EP%d: IN=%s OUT=%s", i
, in
? "yes" : "no", out
? "yes" : "no");
260 if(num_in_ep
!= extract(GHWCFG4
, num_in_ep
))
261 panicf("usb: num in ep mismatch(%d,%lu)", num_in_ep
, extract(GHWCFG4
, num_in_ep
));
262 if(num_in_ep
!= NUM_IN_EP
)
263 panicf("usb: num in ep static mismatch(%u,%u)", num_in_ep
, NUM_IN_EP
);
264 if(num_out_ep
!= NUM_OUT_EP
)
265 panicf("usb: num out ep static mismatch(%u,%u)", num_out_ep
, NUM_OUT_EP
);
267 logf("%d in ep, %d out ep", num_in_ep
, num_out_ep
);
270 logf(" tot fifo sz: %lx", extract(GHWCFG3
, dfifo_len
));
271 logf(" rx fifo: [%04x,+%4lx]", 0, GRXFSIZ
);
272 logf(" nptx fifo: [%04lx,+%4lx]", GET_FIFOSIZE_START_ADR(GNPTXFSIZ
),
273 GET_FIFOSIZE_DEPTH(GNPTXFSIZ
));
275 #ifdef USE_CUSTOM_FIFO_LAYOUT
277 /* Organize FIFO as follow:
278 * 0 -> rxfsize : RX fifo
279 * rxfsize -> rxfsize + nptxfsize : TX fifo for first IN ep
280 * rxfsize + nptxfsize -> rxfsize + 2 * nptxfsize : TX fifo for second IN ep
281 * rxfsize + 2 * nptxfsize -> rxfsize + 3 * nptxfsize : TX fifo for third IN ep
285 unsigned short adr
= 0;
286 unsigned short depth
= RX_FIFO_SIZE
;
289 depth
= NPTX_FIFO_SIZE
;
290 GNPTXFSIZ
= MAKE_FIFOSIZE_DATA(adr
, depth
);
293 for(i
= 1; i
<= NUM_IN_EP
; i
++)
295 depth
= EPTX_FIFO_SIZE
;
296 DIEPTXFSIZ(i
) = MAKE_FIFOSIZE_DATA(adr
, depth
);
300 if(adr
> DATA_FIFO_DEPTH
)
301 panicf("usb: total data fifo size exceeded");
302 #endif /* USE_CUSTOM_FIFO_LAYOUT */
304 for(i
= 1; i
<= NUM_IN_EP
; i
++)
306 logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i
,
307 GET_FIFOSIZE_START_ADR(DIEPTXFSIZ(i
)),
308 GET_FIFOSIZE_DEPTH(DIEPTXFSIZ(i
)));
311 /* Setup interrupt masks for endpoints */
312 /* Setup interrupt masks */
313 DOEPMSK
= DOEPINT_setup
| DOEPINT_xfercompl
| DOEPINT_ahberr
;
314 DIEPMSK
= DIEPINT_xfercompl
| DIEPINT_timeout
| DIEPINT_ahberr
;
315 DAINTMSK
= 0xffffffff;
319 /* fixme: threshold tweaking only takes place if we use multiple tx fifos it seems */
320 /* only dump them for now, leave threshold disabled */
322 logf("threshold control:");
323 logf(" non_iso_thr_en: %d", (DTHRCTL & DTHRCTL_non_iso_thr_en) ? 1 : 0);
324 logf(" iso_thr_en: %d", (DTHRCTL & DTHRCTL_iso_thr_en) ? 1 : 0);
325 logf(" tx_thr_len: %lu", extract(DTHRCTL, tx_thr_len));
326 logf(" rx_thr_en: %d", (DTHRCTL & DTHRCTL_rx_thr_en) ? 1 : 0);
327 logf(" rx_thr_len: %lu", extract(DTHRCTL, rx_thr_len));
330 /* enable USB interrupts */
331 enable_device_interrupts();
334 static void core_init(void)
337 DCTL
|= DCTL_sftdiscon
;
338 /* Select UTMI+ 16 */
339 GUSBCFG
|= GUSBCFG_phy_if
;
341 /* fixme: the current code is for internal DMA only, the clip+ architecture
342 * define the internal DMA model */
343 /* Set burstlen and enable DMA*/
344 GAHBCFG
= (GAHBCFG_INT_DMA_BURST_INCR4
<< GAHBCFG_hburstlen_bitp
)
345 | GAHBCFG_dma_enable
;
346 /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */
347 GUSBCFG
&= ~(GUSBCFG_srpcap
| GUSBCFG_hnpcapp
);
349 /* perform device model specific init */
353 DCTL
&= ~DCTL_sftdiscon
;
356 static void enable_global_interrupts(void)
358 VIC_INT_ENABLE
= INTERRUPT_USB
;
359 GAHBCFG
|= GAHBCFG_glblintrmsk
;
362 static void disable_global_interrupts(void)
364 GAHBCFG
&= ~GAHBCFG_glblintrmsk
;
365 VIC_INT_EN_CLEAR
= INTERRUPT_USB
;
368 void usb_drv_init(void)
370 logf("usb_drv_init");
371 /* Enable PHY and clocks (but leave pullups disabled) */
373 logf("usb: synopsis id: %lx", GSNPSID
);
376 /* Enable global interrupts */
377 enable_global_interrupts();
380 void usb_drv_exit(void)
382 logf("usb_drv_exit");
384 disable_global_interrupts();
387 static void handle_ep_int(int ep
, bool dir_in
)
391 if(DIEPINT(ep
) & DIEPINT_ahberr
)
392 panicf("usb: ahb error on EP%d IN", ep
);
393 if(DIEPINT(ep
) & DIEPINT_xfercompl
)
395 logf("usb: xfer complete on EP%d IN", ep
);
396 if(endpoints
[ep
].busy
)
398 endpoints
[ep
].busy
= false;
399 endpoints
[ep
].status
= 0;
400 endpoints
[ep
].done
= true;
401 /* works even for PE0 */
402 int transfered
= endpoints
[ep
].len
- (DIEPTSIZ(ep
) & DEPTSIZ_xfersize_bits
);
403 clean_dcache_range((void *)DIEPDMA(ep
), transfered
);
404 usb_core_transfer_complete(ep
, USB_DIR_IN
, 0, transfered
);
407 if(DIEPINT(ep
) & DIEPINT_timeout
)
409 logf("usb: timeout on EP%d IN", ep
);
410 if(endpoints
[ep
].busy
)
412 endpoints
[ep
].busy
= false;
413 endpoints
[ep
].status
= 1;
414 endpoints
[ep
].done
= true;
415 /* for safety, act as if no bytes as been transfered */
416 endpoints
[ep
].len
= 0;
417 usb_core_transfer_complete(ep
, USB_DIR_IN
, 1, 0);
418 wakeup_signal(&endpoints
[ep
].complete
);
421 /* clear interrupts */
422 DIEPINT(ep
) = DIEPINT(ep
);
426 if(DOEPINT(ep
) & DOEPINT_ahberr
)
427 panicf("usb: ahb error on EP%d OUT", ep
);
428 if(DOEPINT(ep
) & DOEPINT_xfercompl
)
430 logf("usb: xfer complete on EP%d OUT", ep
);
431 if(endpoints
[ep
].busy
)
433 endpoints
[ep
].busy
= false;
434 endpoints
[ep
].status
= 0;
435 endpoints
[ep
].done
= true;
436 /* works even for PE0 */
437 int transfered
= endpoints
[ep
].len
- (DOEPTSIZ(ep
) & DEPTSIZ_xfersize_bits
);
438 clean_dcache_range((void *)DOEPDMA(ep
), transfered
);
439 usb_core_transfer_complete(ep
, USB_DIR_OUT
, 0, transfered
);
442 if(DOEPINT(ep
) & DOEPINT_setup
)
444 logf("usb: setup on EP%d OUT", ep
);
446 panicf("usb: setup not on EP0, this is impossible");
447 clean_dcache_range((void*)&ep0_setup_pkt
, sizeof ep0_setup_pkt
); /* force write back */
448 usb_core_control_request(&ep0_setup_pkt
);
450 /* setup EP0 for the next transfer */
451 DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp
) | (1 << DEPTSIZ0_pkcnt_bitp
) | 8;
452 DOEPDMA(0) = (unsigned long)&ep0_setup_pkt
; /* virtual address=physical address */
453 DOEPCTL(0) |= DEPCTL_epena
| DEPCTL_cnak
;
455 /* clear interrupts */
456 DOEPINT(ep
) = DOEPINT(ep
);
460 static void handle_ep_ints(void)
463 /* we must read it */
464 unsigned long daint
= DAINT
;
467 FOR_EACH_IN_EP_AND_EP0(i
, ep
)
468 if(daint
& DAINT_IN_EP(ep
))
469 handle_ep_int(ep
, true);
470 FOR_EACH_OUT_EP_AND_EP0(i
, ep
)
471 if(daint
& DAINT_OUT_EP(ep
))
472 handle_ep_int(ep
, false);
474 /* write back to clear status */
478 /* interrupt service routine */
481 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
482 * so AND it with the actual mask */
483 unsigned long sts
= GINTSTS
& GINTMSK
;
486 if(sts
& GINTMSK_usbreset
)
488 logf("usb: bus reset");
490 /* Clear the Remote Wakeup Signalling */
491 DCTL
&= ~DCTL_rmtwkupsig
;
494 flush_tx_fifos(0x10);
498 /* Reset Device Address */
499 DCFG
&= bitm(DCFG
, devadr
);
501 usb_core_bus_reset();
504 if(sts
& GINTMSK_enumdone
)
506 logf("usb: enum done");
509 switch(extract(DSTS
, enumspd
))
511 case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ
:
514 case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ
:
515 case DSTS_ENUMSPD_FS_PHY_48MHZ
:
518 case DSTS_ENUMSPD_LS_PHY_6MHZ
:
519 panicf("usb: LS is not supported");
522 /* fixme: change EP0 mps here */
525 if(sts
& (GINTMSK_outepintr
| GINTMSK_inepintr
))
531 if(sts
& GINTMSK_otgintr
)
533 panicf("usb: otg int");
539 int usb_drv_port_speed(void)
544 int usb_drv_request_endpoint(int type
, int dir
)
551 void usb_drv_release_endpoint(int ep
)
556 void usb_drv_cancel_all_transfers(void)
560 int usb_drv_recv(int ep
, void *ptr
, int len
)
568 int usb_drv_send(int ep
, void *ptr
, int len
)
576 int usb_drv_send_nonblocking(int ep
, void *ptr
, int len
)
585 void usb_drv_set_test_mode(int mode
)
590 void usb_drv_set_address(int address
)
595 void usb_drv_stall(int ep
, bool stall
, bool in
)
602 bool usb_drv_stalled(int ep
, bool in
)