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"
45 unsigned int received
;
52 static struct usb_endpoint endpoints
[USB_NUM_ENDPOINTS
*2];
54 static struct usb_ctrlrequest ep0_setup_pkt
;
62 static void usb_delay(void)
69 static void as3525v2_connect(void)
71 logf("usb: init as3525v2");
72 /* 1) enable usb core clock */
73 CGU_PERI
|= CGU_USB_CLOCK_ENABLE
;
75 /* 2) enable usb phy clock */
78 /* 3) clear "stop pclk" */
81 /* 4) clear "power clamp" */
84 /* 5) clear "reset power down module" */
87 /* 6) set "power on program done" */
88 USB_DCTL
|= USB_DCTL_pwronprgdone
;
90 /* 7) core soft reset */
91 USB_GRSTCTL
|= USB_GRSTCTL_csftrst
;
93 /* 8) hclk soft reset */
94 USB_GRSTCTL
|= USB_GRSTCTL_hsftrst
;
96 /* 9) flush and reset everything */
99 /* 10) force device mode*/
100 USB_GUSBCFG
&= ~USB_GUSBCFG_force_host_mode
;
101 USB_GUSBCFG
|= USB_GUSBCFG_force_device_mode
;
103 /* 11) Do something that is probably CCU related but undocumented*/
104 CCU_USB_THINGY
&= ~0x1000;
106 CCU_USB_THINGY
&= ~0x300000;
108 /* 12) reset usb core parameters (dev addr, speed, ...) */
113 static void usb_enable_common_interrupts(void)
115 /* Clear any pending otg interrupt */
116 USB_GOTGINT
= 0xffffffff;
117 /* Clear any pending interrupt */
118 USB_GINTSTS
= 0Xffffffff;
119 /* Enable interrupts */
120 USB_GINTMSK
= USB_GINTMSK_otgintr
121 | USB_GINTMSK_conidstschng
122 | USB_GINTMSK_disconnect
;
125 static void usb_enable_device_interrupts(void)
127 /* Disable all interrupts */
129 /* Clear any pending interrupt */
130 USB_GINTSTS
= 0xffffffff;
131 /* Enable common interrupts */
132 usb_enable_common_interrupts();
133 /* Enable interrupts */
134 USB_GINTMSK
|= USB_GINTMSK_usbreset
135 | USB_GINTMSK_enumdone
136 | USB_GINTMSK_inepintr
137 | USB_GINTMSK_outepintr
;
140 static void usb_flush_tx_fifos(int nums
)
144 USB_GRSTCTL
= (USB_GRSTCTL
& (~USB_GRSTCTL_txfnum_bits
))
145 | (nums
<< USB_GRSTCTL_txfnum_bit_pos
)
146 | USB_GRSTCTL_txfflsh_flush
;
147 while(USB_GRSTCTL
& USB_GRSTCTL_txfflsh_flush
&& i
< 0x300)
149 if(USB_GRSTCTL
& USB_GRSTCTL_txfflsh_flush
)
150 panicf("usb: hang of flush tx fifos (%x)", nums
);
151 /* wait 3 phy clocks */
155 static void usb_flush_rx_fifo(void)
159 USB_GRSTCTL
= USB_GRSTCTL_rxfflsh_flush
;
160 while(USB_GRSTCTL
& USB_GRSTCTL_rxfflsh_flush
&& i
< 0x300)
162 if(USB_GRSTCTL
& USB_GRSTCTL_rxfflsh_flush
)
163 panicf("usb: hang of flush rx fifo");
164 /* wait 3 phy clocks */
168 static void core_reset(void)
171 /* Wait for AHB master IDLE state. */
172 while((USB_GRSTCTL
& USB_GRSTCTL_ahbidle
) == 0)
174 /* Core Soft Reset */
175 USB_GRSTCTL
|= USB_GRSTCTL_csftrst
;
176 /* Waits for the hardware to clear reset bit */
177 while(USB_GRSTCTL
& USB_GRSTCTL_csftrst
&& i
< 0x300)
180 if(USB_GRSTCTL
& USB_GRSTCTL_csftrst
)
181 panicf("oops, usb core soft reset hang :(");
183 /* Wait for 3 PHY Clocks */
187 static void core_dev_init(void)
189 unsigned int usb_num_in_ep
= 0;
190 unsigned int usb_num_out_ep
= 0;
192 /* Restart the phy clock */
194 /* Set phy speed : high speed */
195 USB_DCFG
= (USB_DCFG
& (~USB_DCFG_devspd_bits
)) | USB_DCFG_devspd_hs_phy_hs
;
196 /* Set periodic frame interval */
197 USB_DCFG
= (USB_DCFG
& (~USB_DCFG_perfrint_bits
)) | (USB_DCFG_FRAME_INTERVAL_80
<< USB_DCFG_perfrint_bit_pos
);
199 /* Check hardware capabilities */
200 if(USB_GHWCFG2_ARCH
!= USB_INT_DMA_ARCH
)
201 panicf("usb: wrong architecture (%ld)", USB_GHWCFG2_ARCH
);
202 if(USB_GHWCFG2_HS_PHY_TYPE
!= USB_PHY_TYPE_UTMI
)
203 panicf("usb: wrong HS phy type (%ld)", USB_GHWCFG2_HS_PHY_TYPE
);
204 if(USB_GHWCFG2_FS_PHY_TYPE
!= USB_PHY_TYPE_UNSUPPORTED
)
205 panicf("usb: wrong FS phy type (%ld)", USB_GHWCFG2_FS_PHY_TYPE
);
206 if(USB_GHWCFG4_UTMI_PHY_DATA_WIDTH
!= 0x2)
207 panicf("usb: wrong utmi data width (%ld)", USB_GHWCFG4_UTMI_PHY_DATA_WIDTH
);
208 if(USB_GHWCFG4_DED_FIFO_EN
!= 1) /* it seems to be multiple tx fifo support */
209 panicf("usb: no multiple tx fifo");
211 logf("hwcfg1: %08lx", USB_GHWCFG1
);
212 logf("hwcfg2: %08lx", USB_GHWCFG2
);
213 logf("hwcfg3: %08lx", USB_GHWCFG3
);
214 logf("hwcfg4: %08lx", USB_GHWCFG4
);
216 logf("%ld endpoints", USB_GHWCFG2_NUM_EP
);
219 for(i
= 0; i
< USB_GHWCFG2_NUM_EP
; i
++)
221 if(USB_GHWCFG1_IN_EP(i
))
223 if(USB_GHWCFG1_OUT_EP(i
))
225 logf(" EP%d: IN=%ld OUT=%ld", i
, USB_GHWCFG1_IN_EP(i
), USB_GHWCFG1_OUT_EP(i
));
228 if(usb_num_in_ep
!= USB_GHWCFG4_NUM_IN_EP
)
229 panicf("usb: num in ep mismatch(%d,%lu)", usb_num_in_ep
, USB_GHWCFG4_NUM_IN_EP
);
230 if(usb_num_in_ep
!= USB_NUM_IN_EP
)
231 panicf("usb: num in ep static mismatch(%u,%u)", usb_num_in_ep
, USB_NUM_IN_EP
);
232 if(usb_num_out_ep
!= USB_NUM_OUT_EP
)
233 panicf("usb: num out ep static mismatch(%u,%u)", usb_num_out_ep
, USB_NUM_OUT_EP
);
235 logf("%d in ep, %d out ep", usb_num_in_ep
, usb_num_out_ep
);
237 logf(" tot fifo sz: %lx", USB_GHWCFG3_DFIFO_LEN
);
238 logf(" rx fifo: [%04x,+%4lx]", 0, USB_GRXFSIZ
);
239 logf(" nptx fifo: [%04lx,+%4lx]", USB_GET_FIFOSIZE_START_ADR(USB_GNPTXFSIZ
),
240 USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ
));
241 for(i
= 1; i
<= USB_NUM_IN_EP
; i
++)
243 logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i
,
244 USB_GET_FIFOSIZE_START_ADR(USB_DIEPTXFSIZ(i
)),
245 USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i
)));
248 /* flush the fifos */
249 usb_flush_tx_fifos(0x10); /* flush all */
252 /* flush learning queue */
253 USB_GRSTCTL
= USB_GRSTCTL_intknqflsh
;
255 /* Clear all pending device interrupts */
258 USB_DAINT
= 0xffffffff;
261 for(i
= 0; i
<= USB_NUM_IN_EP
; i
++)
263 /* disable endpoint if enabled */
264 if(USB_DIEPCTL(i
) & USB_DEPCTL_epena
)
265 USB_DIEPCTL(i
) = USB_DEPCTL_epdis
| USB_DEPCTL_snak
;
271 USB_DIEPINT(i
) = 0xff;
274 for(i
= 0; i
<= USB_NUM_OUT_EP
; i
++)
276 /* disable endpoint if enabled */
277 if(USB_DOEPCTL(i
) & USB_DEPCTL_epena
)
278 USB_DOEPCTL(i
) = USB_DEPCTL_epdis
| USB_DEPCTL_snak
;
284 USB_DOEPINT(i
) = 0xff;
287 /* fixme: threshold tweaking only takes place if we use multiple tx fifos it seems */
288 /* only dump them for now, leave threshold disabled */
289 logf("threshold control:");
290 logf(" non_iso_thr_en: %d", (USB_DTHRCTL
& USB_DTHRCTL_non_iso_thr_en
) ? 1 : 0);
291 logf(" iso_thr_en: %d", (USB_DTHRCTL
& USB_DTHRCTL_iso_thr_en
) ? 1 : 0);
292 logf(" tx_thr_len: %lu", (USB_DTHRCTL
& USB_DTHRCTL_tx_thr_len_bits
) >> USB_DTHRCTL_tx_thr_len_bit_pos
);
293 logf(" rx_thr_en: %d", (USB_DTHRCTL
& USB_DTHRCTL_rx_thr_en
) ? 1 : 0);
294 logf(" rx_thr_len: %lu", (USB_DTHRCTL
& USB_DTHRCTL_rx_thr_len_bits
) >> USB_DTHRCTL_rx_thr_len_bit_pos
);
296 /* enable USB interrupts */
297 usb_enable_device_interrupts();
299 /* enable fifo underrun interrupt ? */
300 USB_DIEPMSK
|= USB_DIEPINT_txfifoundrn
;
303 static void core_init(void)
305 /* Setup phy for high speed */
306 USB_GUSBCFG
&= ~USB_GUSBCFG_ulpi_ext_vbus_drv
;
307 /* Disable external TS Dline pulsing (???) */
308 USB_GUSBCFG
&= ~USB_GUSBCFG_term_sel_dl_pulse
;
313 USB_GUSBCFG
&= ~USB_GUSBCFG_ulpi_utmi_sel
;
314 /* Select UTMI+ 16 */
315 USB_GUSBCFG
|= USB_GUSBCFG_phy_if
;
319 /* fixme: the linux code does that but the clip+ doesn't use ULPI it seems */
320 USB_GUSBCFG
&= ~(USB_GUSBCFG_ulpi_fsls
| USB_GUSBCFG_ulpi_clk_sus_m
);
322 /* fixme: the current code is for internal DMA only, the clip+ architecture
323 * define the internal DMA model */
324 /* Set burstlen and enable DMA*/
325 USB_GAHBCFG
= (USB_GAHBCFG_INT_DMA_BURST_INCR
<< USB_GAHBCFG_hburstlen_bit_pos
)
326 | USB_GAHBCFG_dma_enable
;
327 /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */
328 USB_GUSBCFG
&= ~(USB_GUSBCFG_srpcap
| USB_GUSBCFG_hnpcapp
);
330 /* enable basic interrupts */
331 usb_enable_common_interrupts();
333 /* perform device model specific init */
337 static void usb_enable_global_interrupts(void)
339 VIC_INT_ENABLE
= INTERRUPT_USB
;
340 USB_GAHBCFG
|= USB_GAHBCFG_glblintrmsk
;
343 static void usb_disable_global_interrupts(void)
345 USB_GAHBCFG
&= ~USB_GAHBCFG_glblintrmsk
;
346 VIC_INT_EN_CLEAR
= INTERRUPT_USB
;
349 void usb_drv_init(void)
351 logf("usb_drv_init");
352 /* Enable PHY and clocks (but leave pullups disabled) */
354 /* Disable global interrupts */
355 usb_disable_global_interrupts();
356 logf("usb: synopsis id: %lx", USB_GSNPSID
);
359 /* Enable global interrupts */
360 usb_enable_global_interrupts();
363 void usb_drv_exit(void)
365 logf("usb_drv_exit");
368 int usb_drv_port_speed(void)
373 int usb_drv_request_endpoint(int type
, int dir
)
380 void usb_drv_release_endpoint(int ep
)
385 void usb_drv_cancel_all_transfers(void)
389 int usb_drv_recv(int ep
, void *ptr
, int len
)
397 int usb_drv_send(int ep
, void *ptr
, int len
)
405 int usb_drv_send_nonblocking(int ep
, void *ptr
, int len
)
413 static void activate_ep0(void)
415 /* Setup EP0 OUT to receive setup packets and
416 * EP0 IN to transmit packets
417 * The setup takes enumeration speed into account
420 /* Setup packet size of IN ep based of enumerated speed */
421 switch((USB_DSTS
& USB_DSTS_enumspd_bits
) >> USB_DSTS_enumspd_bit_pos
)
423 case USB_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ
:
424 case USB_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ
:
425 case USB_DSTS_ENUMSPD_FS_PHY_48MHZ
:
426 /* Use 64 bytes packet size */
427 USB_DIEPCTL(0) = (USB_DIEPCTL(0) & (~USB_DEPCTL_mps_bits
))
428 | (USB_DEPCTL_MPS_64
<< USB_DEPCTL_mps_bit_pos
);
430 case USB_DSTS_ENUMSPD_LS_PHY_6MHZ
:
431 USB_DIEPCTL(0) = (USB_DIEPCTL(0) & (~USB_DEPCTL_mps_bits
))
432 | (USB_DEPCTL_MPS_8
<< USB_DEPCTL_mps_bit_pos
);
435 panicf("usb: invalid enum speed");
438 /* Enable OUT ep for receive */
439 USB_DOEPCTL(0) |= USB_DEPCTL_epena
;
441 /* Clear non periodic NAK for IN ep */
442 USB_DCTL
|= USB_DCTL_cgnpinnak
;
445 static void ep0_out_start(void)
447 /* Setup EP0 OUT with the following parameters:
449 * setup packet count = 1
450 * transfer size = 8 (=sizeof setup packet)
453 USB_DOEPTSIZ(0) = (1 << USB_DEPTSIZ0_supcnt_bit_pos
)
454 | (1 << USB_DEPTSIZ0_pkcnt_bit_pos
)
458 clean_dcache_range((void*)&ep0_setup_pkt
, sizeof ep0_setup_pkt
); /* force write back */
459 USB_DOEPDMA(0) = (unsigned long)&ep0_setup_pkt
; /* virtual address=physical address */
462 USB_DOEPCTL(0) |= USB_DEPCTL_epena
| USB_DEPCTL_usbactep
;
465 static bool handle_usb_reset(void)
468 logf("usb: bus reset");
470 /* Clear the Remote Wakeup Signalling */
471 USB_DCTL
&= ~USB_DCTL_rmtwkupsig
;
473 /* Set NAK for all OUT EPs */
474 for(i
= 0; i
<= USB_NUM_OUT_EP
; i
++)
475 USB_DOEPCTL(i
) = USB_DEPCTL_snak
;
477 /* Flush the NP Tx FIFO */
478 usb_flush_tx_fifos(0);
480 /* Flush the Learning Queue */
481 USB_GRSTCTL
= USB_GRSTCTL_intknqflsh
;
483 /* Setup interrupt masks */
484 USB_DAINTMSK
= USB_DAINT_IN_EP(0) | USB_DAINT_OUT_EP(0);
485 USB_DOEPMSK
= USB_DOEPINT_setup
| USB_DOEPINT_xfercompl
| USB_DOEPINT_ahberr
486 | USB_DOEPINT_epdisabled
;
487 USB_DIEPMSK
= USB_DIEPINT_xfercompl
| USB_DIEPINT_timeout
488 | USB_DIEPINT_epdisabled
| USB_DIEPINT_ahberr
489 | USB_DIEPINT_intknepmis
;
491 /* Reset Device Address */
492 USB_DCFG
&= ~USB_DCFG_devadr_bits
;
494 /* setup EP0 to receive SETUP packets */
496 /* Clear interrupt */
497 USB_GINTSTS
= USB_GINTMSK_usbreset
;
502 static bool handle_enum_done(void)
504 logf("usb: enum done");
506 /* Enable EP0 to receive SETUP packets */
509 /* Set USB turnaround time
510 * fixme: unsure about this */
511 //USB_GUSBCFG = (USB_GUSBCFG & ~USB_GUSBCFG_usbtrdtim_bits) | (5 << USB_GUSBCFG_usbtrdtim_bit_pos);
512 //panicf("usb: turnaround time is %d", (USB_GUSBCFG & USB_GUSBCFG_usbtrdtim_bits) >> USB_GUSBCFG_usbtrdtim_bit_pos);
514 /* Clear interrupt */
515 USB_GINTSTS
= USB_GINTMSK_enumdone
;
520 static bool handle_in_ep_int(void)
522 logf("usb: in ep int");
526 static bool handle_out_ep_int(void)
528 logf("usb: out ep int");
532 static void dump_intsts(char *buffer
, size_t size
, unsigned long sts
)
536 #define DUMP_CASE(name) \
537 if(sts & USB_GINTMSK_##name) strcat(buffer, #name " ");
539 DUMP_CASE(modemismatch
)
543 DUMP_CASE(nptxfempty
)
545 DUMP_CASE(goutnakeff
)
547 DUMP_CASE(erlysuspend
)
548 DUMP_CASE(usbsuspend
)
551 DUMP_CASE(isooutdrop
)
553 DUMP_CASE(epmismatch
)
556 DUMP_CASE(incomplisoin
)
557 DUMP_CASE(incomplisoout
)
561 DUMP_CASE(conidstschng
)
562 DUMP_CASE(disconnect
)
563 DUMP_CASE(sessreqintr
)
566 buffer
[strlen(buffer
) - 1] = 0;
569 /* interrupt service routine */
572 static char buffer
[256];
573 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
574 * so AND it with the actual mask */
575 unsigned long sts
= USB_GINTSTS
& USB_GINTMSK
;
576 unsigned long handled_one
= 0; /* mask of all listed one (either handled or not) */
578 #define HANDLED_CASE(bitmask, callfn) \
579 handled_one |= bitmask; \
586 #define UNHANDLED_CASE(bitmask) \
587 handled_one |= bitmask; \
592 HANDLED_CASE(USB_GINTMSK_usbreset
, handle_usb_reset
)
593 HANDLED_CASE(USB_GINTMSK_enumdone
, handle_enum_done
)
594 HANDLED_CASE(USB_GINTMSK_inepintr
, handle_in_ep_int
)
595 HANDLED_CASE(USB_GINTMSK_outepintr
, handle_out_ep_int
)
598 UNHANDLED_CASE(USB_GINTMSK_otgintr
)
599 UNHANDLED_CASE(USB_GINTMSK_conidstschng
)
600 UNHANDLED_CASE(USB_GINTMSK_disconnect
)
603 if(sts
& ~handled_one
)
609 dump_intsts(buffer
, sizeof buffer
, sts
);
610 panicf("unhandled usb int: %lx (%s)", sts
, buffer
);
613 dump_intsts(buffer
, sizeof buffer
, sts
);
614 panicf("error in usb int: %lx (%s)", sts
, buffer
);
617 void usb_drv_set_test_mode(int mode
)
622 void usb_drv_set_address(int address
)
627 void usb_drv_stall(int ep
, bool stall
, bool in
)
634 bool usb_drv_stalled(int ep
, bool in
)