1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2009 by Michael Sparmann
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 ****************************************************************************/
24 #include "usb-target.h"
32 #include "usb-s3c6400x.h"
47 struct wakeup complete
;
50 static struct ep_type endpoints
[USB_NUM_ENDPOINTS
];
51 static struct usb_ctrlrequest ctrlreq USB_DEVBSS_ATTR
;
53 int usb_drv_port_speed(void)
55 return (DSTS
& 2) == 0 ? 1 : 0;
58 static void reset_endpoints(int reinit
)
61 for (i
= 0; i
< sizeof(endpoints
)/sizeof(struct ep_type
); i
++)
63 if (reinit
) endpoints
[i
].active
= false;
64 endpoints
[i
].busy
= false;
66 endpoints
[i
].done
= true;
67 wakeup_signal(&endpoints
[i
].complete
);
69 DIEPCTL0
= 0x8800; /* EP0 IN ACTIVE NEXT=1 */
70 DOEPCTL0
= 0x8000; /* EP0 OUT ACTIVE */
71 DOEPTSIZ0
= 0x20080040; /* EP0 OUT Transfer Size:
72 64 Bytes, 1 Packet, 1 Setup Packet */
74 DOEPCTL0
|= 0x84000000; /* EP0 OUT ENABLE CLEARNAK */
77 /* The size is getting set to zero, because we don't know
78 whether we are Full Speed or High Speed at this stage */
79 /* EP1 IN INACTIVE DATA0 SIZE=0 NEXT=3 */
80 DIEPCTL1
= 0x10001800;
81 /* EP2 OUT INACTIVE DATA0 SIZE=0 */
82 DOEPCTL2
= 0x10000000;
83 /* EP3 IN INACTIVE DATA0 SIZE=0 NEXT=0 */
84 DIEPCTL3
= 0x10000000;
85 /* EP4 OUT INACTIVE DATA0 SIZE=0 */
86 DOEPCTL4
= 0x10000000;
91 DIEPCTL1
= (DIEPCTL1
& ~0x00008000) | 0x10000000;
92 DOEPCTL2
= (DOEPCTL2
& ~0x00008000) | 0x10000000;
93 DIEPCTL3
= (DIEPCTL3
& ~0x00008000) | 0x10000000;
94 DOEPCTL4
= (DOEPCTL4
& ~0x00008000) | 0x10000000;
96 DAINTMSK
= 0xFFFFFFFF; /* Enable interrupts on all EPs */
99 int usb_drv_request_endpoint(int type
, int dir
)
104 if (dir
== USB_DIR_IN
) ep
= 1;
107 while (ep
< USB_NUM_ENDPOINTS
)
109 if (!endpoints
[ep
].active
)
111 endpoints
[ep
].active
= true;
113 uint32_t newbits
= (type
<< 18) | 0x10000000;
114 if (dir
) DIEPCTL(ep
) = (DIEPCTL(ep
) & ~0x000C0000) | newbits
;
115 else DOEPCTL(ep
) = (DOEPCTL(ep
) & ~0x000C0000) | newbits
;
124 void usb_drv_release_endpoint(int ep
)
128 if (ep
< 1 || ep
> USB_NUM_ENDPOINTS
) return;
130 endpoints
[ep
].active
= false;
133 static void usb_reset(void)
137 DCTL
= 0x802; /* Soft Disconnect */
139 OPHYPWR
= 0; /* PHY: Power up */
142 OPHYCLK
= SYNOPSYSOTG_CLOCK
;
143 ORSTCON
= 1; /* PHY: Assert Software Reset */
144 for (i
= 0; i
< 50; i
++);
145 ORSTCON
= 0; /* PHY: Deassert Software Reset */
148 GRSTCTL
= 1; /* OTG: Assert Software Reset */
149 while (GRSTCTL
& 1); /* Wait for OTG to ack reset */
150 while (!(GRSTCTL
& 0x80000000)); /* Wait for OTG AHB master idle */
152 GRXFSIZ
= 0x00000200; /* RX FIFO: 512 bytes */
153 GNPTXFSIZ
= 0x02000200; /* Non-periodic TX FIFO: 512 bytes */
154 GAHBCFG
= SYNOPSYSOTG_AHBCFG
;
155 GUSBCFG
= 0x1408; /* OTG: 16bit PHY and some reserved bits */
157 DCFG
= 4; /* Address 0 */
158 DCTL
= 0x800; /* Soft Reconnect */
159 DIEPMSK
= 0x0D; /* IN EP interrupt mask */
160 DOEPMSK
= 0x0D; /* IN EP interrupt mask */
161 DAINTMSK
= 0xFFFFFFFF; /* Enable interrupts on all endpoints */
162 GINTMSK
= 0xC3000; /* Interrupt mask: IN event, OUT event, bus reset */
168 void INT_USB_FUNC(void)
171 uint32_t ints
= GINTSTS
;
173 if (ints
& 0x1000) /* bus reset */
175 DCFG
= 4; /* Address 0 */
177 usb_core_bus_reset();
180 if (ints
& 0x2000) /* enumeration done, we now know the speed */
182 /* Set up the maximum packet sizes accordingly */
183 uint32_t maxpacket
= usb_drv_port_speed() ? 512 : 64;
184 DIEPCTL1
= (DIEPCTL1
& ~0x000003FF) | maxpacket
;
185 DOEPCTL2
= (DOEPCTL2
& ~0x000003FF) | maxpacket
;
186 DIEPCTL3
= (DIEPCTL3
& ~0x000003FF) | maxpacket
;
187 DOEPCTL4
= (DOEPCTL4
& ~0x000003FF) | maxpacket
;
190 if (ints
& 0x40000) /* IN EP event */
191 for (i
= 0; i
< 4; i
+= i
+ 1) // 0, 1, 3
192 if ((epints
= DIEPINT(i
)))
194 if (epints
& 1) /* Transfer completed */
197 int bytes
= endpoints
[i
].size
- (DIEPTSIZ(i
) & 0x3FFFF);
198 if (endpoints
[i
].busy
)
200 endpoints
[i
].busy
= false;
202 endpoints
[i
].done
= true;
203 usb_core_transfer_complete(i
, USB_DIR_IN
, 0, bytes
);
204 wakeup_signal(&endpoints
[i
].complete
);
207 if (epints
& 4) /* AHB error */
208 panicf("USB: AHB error on IN EP%d", i
);
209 if (epints
& 8) /* Timeout */
211 if (endpoints
[i
].busy
)
213 endpoints
[i
].busy
= false;
215 endpoints
[i
].done
= true;
216 wakeup_signal(&endpoints
[i
].complete
);
222 if (ints
& 0x80000) /* OUT EP event */
223 for (i
= 0; i
< USB_NUM_ENDPOINTS
; i
+= 2)
224 if ((epints
= DOEPINT(i
)))
226 if (epints
& 1) /* Transfer completed */
229 int bytes
= endpoints
[i
].size
- (DOEPTSIZ(i
) & 0x3FFFF);
230 if (endpoints
[i
].busy
)
232 endpoints
[i
].busy
= false;
234 endpoints
[i
].done
= true;
235 usb_core_transfer_complete(i
, USB_DIR_OUT
, 0, bytes
);
236 wakeup_signal(&endpoints
[i
].complete
);
239 if (epints
& 4) /* AHB error */
240 panicf("USB: AHB error on OUT EP%d", i
);
241 if (epints
& 8) /* SETUP phase done */
246 if (ctrlreq
.bRequest
== 5)
248 /* Already set the new address here,
249 before passing the packet to the core.
250 See below (usb_drv_set_address) for details. */
251 DCFG
= (DCFG
& ~0x7F0) | (ctrlreq
.wValue
<< 4);
253 usb_core_control_request(&ctrlreq
);
255 else panicf("USB: SETUP done on OUT EP%d!?", i
);
257 /* Make sure EP0 OUT is set up to accept the next request */
260 DOEPTSIZ0
= 0x20080040;
262 DOEPCTL0
|= 0x84000000;
270 void usb_drv_set_address(int address
)
273 /* Ignored intentionally, because the controller requires us to set the
274 new address before sending the response for some reason. So we'll
275 already set it when the control request arrives, before passing that
276 into the USB core, which will then call this dummy function. */
279 static void ep_send(int ep
, const void *ptr
, int length
)
281 endpoints
[ep
].busy
= true;
282 endpoints
[ep
].size
= length
;
283 DIEPCTL(ep
) |= 0x8000; /* EPx OUT ACTIVE */
284 int blocksize
= usb_drv_port_speed() ? 512 : 64;
285 int packets
= (length
+ blocksize
- 1) / blocksize
;
288 DIEPTSIZ(ep
) = 1 << 19; /* one empty packet */
293 DIEPTSIZ(ep
) = length
| (packets
<< 19);
297 DIEPCTL(ep
) |= 0x84000000; /* EPx OUT ENABLE CLEARNAK */
300 static void ep_recv(int ep
, void *ptr
, int length
)
302 endpoints
[ep
].busy
= true;
303 endpoints
[ep
].size
= length
;
304 DOEPCTL(ep
) &= ~0x20000; /* EPx UNSTALL */
305 DOEPCTL(ep
) |= 0x8000; /* EPx OUT ACTIVE */
306 int blocksize
= usb_drv_port_speed() ? 512 : 64;
307 int packets
= (length
+ blocksize
- 1) / blocksize
;
310 DOEPTSIZ(ep
) = 1 << 19; /* one empty packet */
315 DOEPTSIZ(ep
) = length
| (packets
<< 19);
319 DOEPCTL(ep
) |= 0x84000000; /* EPx OUT ENABLE CLEARNAK */
322 int usb_drv_send(int endpoint
, void *ptr
, int length
)
325 endpoints
[endpoint
].done
= false;
326 ep_send(endpoint
, ptr
, length
);
327 while (!endpoints
[endpoint
].done
&& endpoints
[endpoint
].busy
)
328 wakeup_wait(&endpoints
[endpoint
].complete
, TIMEOUT_BLOCK
);
329 return endpoints
[endpoint
].rc
;
332 int usb_drv_send_nonblocking(int endpoint
, void *ptr
, int length
)
334 ep_send(endpoint
& 0x7f, ptr
, length
);
338 int usb_drv_recv(int endpoint
, void* ptr
, int length
)
340 ep_recv(endpoint
& 0x7f, ptr
, length
);
344 void usb_drv_cancel_all_transfers(void)
346 int flags
= disable_irq_save();
351 void usb_drv_set_test_mode(int mode
)
356 bool usb_drv_stalled(int endpoint
, bool in
)
358 if (in
) return DIEPCTL(endpoint
) & 0x00200000 ? true : false;
359 else return DOEPCTL(endpoint
) & 0x00200000 ? true : false;
362 void usb_drv_stall(int endpoint
, bool stall
, bool in
)
366 if (stall
) DIEPCTL(endpoint
) |= 0x00200000;
367 else DIEPCTL(endpoint
) &= ~0x00200000;
371 if (stall
) DOEPCTL(endpoint
) |= 0x00200000;
372 else DOEPCTL(endpoint
) &= ~0x00200000;
376 void usb_drv_init(void)
378 /* Enable USB clock */
379 #if CONFIG_CPU==S5L8701
382 INTMSK
|= INTMSK_USB_OTG
;
383 #elif CONFIG_CPU==S5L8702
386 VIC0INTENABLE
|= 1 << 19;
390 /* reset the beast */
394 void usb_drv_exit(void)
396 DCTL
= 0x802; /* Soft Disconnect */
398 ORSTCON
= 1; /* Put the PHY into reset (needed to get current down) */
399 PCGCCTL
= 1; /* Shut down PHY clock */
400 OPHYPWR
= 0xF; /* PHY: Power down */
402 #if CONFIG_CPU==S5L8701
405 #elif CONFIG_CPU==S5L8702
411 void usb_init_device(void)
414 for (i
= 0; i
< sizeof(endpoints
)/sizeof(struct ep_type
); i
++)
415 wakeup_init(&endpoints
[i
].complete
);
417 /* Power up the core clocks to allow writing
418 to some registers needed to power it down */
420 #if CONFIG_CPU==S5L8701
423 INTMSK
|= INTMSK_USB_OTG
;
424 #elif CONFIG_CPU==S5L8702
427 VIC0INTENABLE
|= 1 << 19;
433 void usb_enable(bool on
)
435 if (on
) usb_core_init();
436 else usb_core_exit();
439 void usb_attach(void)
446 if (charger_inserted())
448 return USB_EXTRACTED
;
452 void usb_init_device(void)
454 DCTL
= 0x802; /* Soft Disconnect */
456 ORSTCON
= 1; /* Put the PHY into reset (needed to get current down) */
457 PCGCCTL
= 1; /* Shut down PHY clock */
458 OPHYPWR
= 0xF; /* PHY: Power down */
460 #if CONFIG_CPU==S5L8701
463 #elif CONFIG_CPU==S5L8702
469 void usb_enable(bool on
)
474 /* Always return false for now */
477 return USB_EXTRACTED
;