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 ****************************************************************************/
25 #define OTGBASE 0x38800000
26 #define PHYBASE 0x3C400000
27 #include "usb-s3c6400x.h"
47 struct wakeup complete
;
50 static struct ep_type endpoints
[5];
51 static struct usb_ctrlrequest ctrlreq USB_DEVBSS_ATTR
;
53 int usb_drv_port_speed(void)
55 return (DSTS
& 2) == 0 ? 1 : 0;
58 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 */
73 DOEPDMA0
= (uint32_t)&ctrlreq
;
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;
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 */
140 ORSTCON
= 1; /* PHY: Assert Software Reset */
141 for (i
= 0; i
< 50; i
++);
142 ORSTCON
= 0; /* PHY: Deassert Software Reset */
143 OPHYCLK
= 0; /* PHY: 48MHz clock */
145 GRSTCTL
= 1; /* OTG: Assert Software Reset */
146 while (GRSTCTL
& 1); /* Wait for OTG to ack reset */
147 while (!(GRSTCTL
& 0x80000000)); /* Wait for OTG AHB master idle */
149 GAHBCFG
= 0x27; /* OTG AHB config: Unmask ints, burst length 4, DMA on */
150 GUSBCFG
= 0x1408; /* OTG: 16bit PHY and some reserved bits */
152 DCFG
= 4; /* Address 0 */
153 DCTL
= 0x800; /* Soft Reconnect */
154 DIEPMSK
= 0x0D; /* IN EP interrupt mask */
155 DOEPMSK
= 0x0D; /* IN EP interrupt mask */
156 GINTMSK
= 0xC3000; /* Interrupt mask: IN event, OUT event, bus reset */
162 void INT_USB_FUNC(void)
165 if (GINTSTS
& 0x1000) /* bus reset */
167 DCFG
= 4; /* Address 0 */
169 usb_core_bus_reset();
172 if (GINTSTS
& 0x2000) /* enumeration done, we now know the speed */
174 /* Set up the maximum packet sizes accordingly */
175 uint32_t maxpacket
= usb_drv_port_speed() ? 512 : 64;
176 DIEPCTL1
= (DIEPCTL1
& ~0x000003FF) | maxpacket
;
177 DOEPCTL2
= (DOEPCTL2
& ~0x000003FF) | maxpacket
;
178 DIEPCTL3
= (DIEPCTL3
& ~0x000003FF) | maxpacket
;
179 DOEPCTL4
= (DOEPCTL4
& ~0x000003FF) | maxpacket
;
182 if (GINTSTS
& 0x40000) /* IN EP event */
183 for (i
= 0; i
< 5; i
++)
184 if (i
!= 2 && i
!= 4 && DIEPINT(i
))
186 if (DIEPINT(i
) & 1) /* Transfer completed */
189 int bytes
= endpoints
[i
].size
- (DIEPTSIZ(i
) & 0x3FFFF);
190 if (endpoints
[i
].busy
)
192 endpoints
[i
].busy
= false;
194 endpoints
[i
].done
= true;
195 usb_core_transfer_complete(i
, USB_DIR_IN
, 0, bytes
);
196 wakeup_signal(&endpoints
[i
].complete
);
199 if (DIEPINT(i
) & 4) /* AHB error */
200 panicf("USB: AHB error on IN EP%d", i
);
201 if (DIEPINT(i
) & 8) /* Timeout */
203 if (endpoints
[i
].busy
)
205 endpoints
[i
].busy
= false;
207 endpoints
[i
].done
= true;
208 wakeup_signal(&endpoints
[i
].complete
);
211 DIEPINT(i
) = DIEPINT(i
);
214 if (GINTSTS
& 0x80000) /* OUT EP event */
215 for (i
= 0; i
< 5; i
+= 2)
218 if (DOEPINT(i
) & 1) /* Transfer completed */
221 int bytes
= endpoints
[i
].size
- (DOEPTSIZ(i
) & 0x3FFFF);
222 if (endpoints
[i
].busy
)
224 endpoints
[i
].busy
= false;
226 endpoints
[i
].done
= true;
227 usb_core_transfer_complete(i
, USB_DIR_OUT
, 0, bytes
);
228 wakeup_signal(&endpoints
[i
].complete
);
231 if (DOEPINT(i
) & 4) /* AHB error */
232 panicf("USB: AHB error on OUT EP%d", i
);
233 if (DOEPINT(i
) & 8) /* SETUP phase done */
238 if (ctrlreq
.bRequest
== 5)
240 /* Already set the new address here,
241 before passing the packet to the core.
242 See below (usb_drv_set_address) for details. */
243 DCFG
= (DCFG
& ~0x7F0) | (ctrlreq
.wValue
<< 4);
245 usb_core_control_request(&ctrlreq
);
247 else panicf("USB: SETUP done on OUT EP%d!?", i
);
249 /* Make sure EP0 OUT is set up to accept the next request */
252 DOEPTSIZ0
= 0x20080040;
253 DOEPDMA0
= (uint32_t)&ctrlreq
;
254 DOEPCTL0
|= 0x84000000;
256 DOEPINT(i
) = DOEPINT(i
);
262 void usb_drv_set_address(int address
)
265 /* Ignored intentionally, because the controller requires us to set the
266 new address before sending the response for some reason. So we'll
267 already set it when the control request arrives, before passing that
268 into the USB core, which will then call this dummy function. */
271 void ep_send(int ep
, void *ptr
, int length
)
273 endpoints
[ep
].busy
= true;
274 endpoints
[ep
].size
= length
;
275 DIEPCTL(ep
) |= 0x8000; /* EPx OUT ACTIVE */
276 int blocksize
= usb_drv_port_speed() ? 512 : 64;
277 int packets
= (length
+ blocksize
- 1) / blocksize
;
280 DIEPTSIZ(ep
) = 1 << 19; /* one empty packet */
281 DIEPDMA(ep
) = 0x10000000; /* dummy address */
285 DIEPTSIZ(ep
) = length
| (packets
<< 19);
286 DIEPDMA(ep
) = (uint32_t)ptr
;
289 DIEPCTL(ep
) |= 0x84000000; /* EPx OUT ENABLE CLEARNAK */
292 void ep_recv(int ep
, void *ptr
, int length
)
294 endpoints
[ep
].busy
= true;
295 endpoints
[ep
].size
= length
;
296 DOEPCTL(ep
) &= ~0x20000; /* EPx UNSTALL */
297 DOEPCTL(ep
) |= 0x8000; /* EPx OUT ACTIVE */
298 int blocksize
= usb_drv_port_speed() ? 512 : 64;
299 int packets
= (length
+ blocksize
- 1) / blocksize
;
302 DOEPTSIZ(ep
) = 1 << 19; /* one empty packet */
303 DOEPDMA(ep
) = 0x10000000; /* dummy address */
307 DOEPTSIZ(ep
) = length
| (packets
<< 19);
308 DOEPDMA(ep
) = (uint32_t)ptr
;
311 DOEPCTL(ep
) |= 0x84000000; /* EPx OUT ENABLE CLEARNAK */
314 int usb_drv_send(int endpoint
, void *ptr
, int length
)
317 endpoints
[endpoint
].done
= false;
318 ep_send(endpoint
, ptr
, length
);
319 while (!endpoints
[endpoint
].done
&& endpoints
[endpoint
].busy
)
320 wakeup_wait(&endpoints
[endpoint
].complete
, TIMEOUT_BLOCK
);
321 return endpoints
[endpoint
].rc
;
324 int usb_drv_send_nonblocking(int endpoint
, void *ptr
, int length
)
326 ep_send(endpoint
& 0x7f, ptr
, length
);
330 int usb_drv_recv(int endpoint
, void* ptr
, int length
)
332 ep_recv(endpoint
& 0x7f, ptr
, length
);
336 void usb_drv_cancel_all_transfers(void)
338 int flags
= disable_irq_save();
343 void usb_drv_set_test_mode(int mode
)
348 bool usb_drv_stalled(int endpoint
, bool in
)
350 if (in
) return DIEPCTL(endpoint
) & 0x00200000 ? true : false;
351 else return DOEPCTL(endpoint
) & 0x00200000 ? true : false;
354 void usb_drv_stall(int endpoint
, bool stall
, bool in
)
358 if (stall
) DIEPCTL(endpoint
) |= 0x00200000;
359 else DIEPCTL(endpoint
) &= ~0x00200000;
363 if (stall
) DOEPCTL(endpoint
) |= 0x00200000;
364 else DOEPCTL(endpoint
) &= ~0x00200000;
368 void usb_drv_init(void)
370 /* Enable USB clock */
376 INTMSK
|= INTMSK_USB_OTG
;
378 /* reset the beast */
382 void usb_drv_exit(void)
384 DCTL
= 0x802; /* Soft Disconnect */
386 ORSTCON
= 1; /* Put the PHY into reset (needed to get current down) */
387 PCGCCTL
= 1; /* Shut down PHY clock */
388 OPHYPWR
= 0xF; /* PHY: Power down */
394 void usb_init_device(void)
397 for (i
= 0; i
< sizeof(endpoints
)/sizeof(struct ep_type
); i
++)
398 wakeup_init(&endpoints
[i
].complete
);
402 void usb_enable(bool on
)
404 if (on
) usb_core_init();
405 else usb_core_exit();
408 void usb_attach(void)
415 if (charger_inserted())
417 return USB_EXTRACTED
;
421 void usb_init_device(void)
423 DCTL
= 0x802; /* Soft Disconnect */
425 ORSTCON
= 1; /* Put the PHY into reset (needed to get current down) */
426 PCGCCTL
= 1; /* Shut down PHY clock */
427 OPHYPWR
= 0xF; /* PHY: Power down */
433 void usb_enable(bool on
)
438 /* Always return false for now */
441 return USB_EXTRACTED
;