summaryrefslogtreecommitdiff
path: root/firmware/target/arm/usb-s3c6400x.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/usb-s3c6400x.c')
-rw-r--r--firmware/target/arm/usb-s3c6400x.c408
1 files changed, 407 insertions, 1 deletions
diff --git a/firmware/target/arm/usb-s3c6400x.c b/firmware/target/arm/usb-s3c6400x.c
index 43c9f2fd77..2b221b1963 100644
--- a/firmware/target/arm/usb-s3c6400x.c
+++ b/firmware/target/arm/usb-s3c6400x.c
@@ -36,6 +36,9 @@
36#include <inttypes.h> 36#include <inttypes.h>
37#include "power.h" 37#include "power.h"
38 38
39//#define LOGF_ENABLE
40#include "logf.h"
41
39/* store per endpoint, per direction, information */ 42/* store per endpoint, per direction, information */
40struct ep_type 43struct ep_type
41{ 44{
@@ -107,7 +110,410 @@ void usb_drv_set_test_mode(int mode)
107} 110}
108 111
109#if CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */ 112#if CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */
110# include "as3525/usb-drv-as3525v2.c" 113static const uint8_t in_ep_list[] = {0, 1, 3, 5};
114static const uint8_t out_ep_list[] = {0, 2, 4};
115
116/* state of EP0 (to correctly schedule setup packet enqueing) */
117enum ep0state
118{
119 /* Setup packet is enqueud, waiting for actual data */
120 EP0_WAIT_SETUP = 0,
121 /* Waiting for ack (either IN or OUT) */
122 EP0_WAIT_ACK = 1,
123 /* Ack complete, waiting for data (either IN or OUT)
124 * This state is necessary because if both ack and data complete in the
125 * same interrupt, we might process data completion before ack completion
126 * so we need this bizarre state */
127 EP0_WAIT_DATA = 2,
128 /* Setup packet complete, waiting for ack and data */
129 EP0_WAIT_DATA_ACK = 3,
130};
131
132/* endpoints[ep_num][DIR_IN/DIR_OUT] */
133static struct ep_type endpoints[USB_NUM_ENDPOINTS][2];
134/* setup packet for EP0 */
135
136/* USB control requests may be up to 64 bytes in size.
137 Even though we never use anything more than the 8 header bytes,
138 we are required to accept request packets of up to 64 bytes size.
139 Provide buffer space for these additional payload bytes so that
140 e.g. write descriptor requests (which are rejected by us, but the
141 payload is transferred anyway) do not cause memory corruption.
142 Fixes FS#12310. -- Michael Sparmann (theseven) */
143static union {
144 struct usb_ctrlrequest header; /* 8 bytes */
145 unsigned char payload[64];
146} _ep0_setup_pkt USB_DEVBSS_ATTR;
147
148static struct usb_ctrlrequest *ep0_setup_pkt = AS3525_UNCACHED_ADDR(&_ep0_setup_pkt.header);
149
150/* state of EP0 */
151static enum ep0state ep0_state;
152
153void usb_attach(void)
154{
155 /* Nothing to do */
156}
157
158static void prepare_setup_ep0(void)
159{
160 DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt);
161 DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp)
162 | (1 << DEPTSIZ0_pkcnt_bitp)
163 | 8;
164 DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;
165
166 ep0_state = EP0_WAIT_SETUP;
167}
168
169static size_t num_eps(bool out)
170{
171 return out ? sizeof(out_ep_list) : sizeof(in_ep_list);
172}
173
174static void reset_endpoints(void)
175{
176 for (int dir = 0; dir < 2; dir++)
177 {
178 bool out = dir == DIR_OUT;
179 for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
180 {
181 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
182 struct ep_type *endpoint = &endpoints[ep][out];
183 endpoint->active = false;
184 endpoint->busy = false;
185 endpoint->status = -1;
186 endpoint->done = false;
187 semaphore_release(&endpoint->complete);
188
189 if (i != 0)
190 DEPCTL(ep, out) = DEPCTL_setd0pid;
191 }
192 DEPCTL(0, out) = /*(DEPCTL_MPS_64 << DEPCTL_mps_bitp) | */ DEPCTL_usbactep;
193 }
194
195 /* Setup next chain for IN eps */
196 for (unsigned i = 0; i < num_eps(false); i++)
197 {
198 int ep = in_ep_list[i];
199 int next_ep = in_ep_list[(i + 1) % num_eps(false)];
200 DEPCTL(ep, false) |= next_ep << DEPCTL_nextep_bitp;
201 }
202
203 prepare_setup_ep0();
204}
205
206static void cancel_all_transfers(bool cancel_ep0)
207{
208 int flags = disable_irq_save();
209
210 for (int dir = 0; dir < 2; dir++)
211 for (unsigned i = !!cancel_ep0; i < num_eps(dir == DIR_OUT); i++)
212 {
213 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
214 struct ep_type *endpoint = &endpoints[ep][dir == DIR_OUT];
215 endpoint->status = -1;
216 endpoint->busy = false;
217 endpoint->done = false;
218 semaphore_release(&endpoint->complete);
219 DEPCTL(ep, dir) = (DEPCTL(ep, dir) & ~DEPCTL_usbactep);
220 }
221
222 restore_irq(flags);
223}
224
225void usb_drv_init(void)
226{
227 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
228 for (int dir = 0; dir < 2; dir++)
229 semaphore_init(&endpoints[i][dir].complete, 1, 0);
230
231 bitset32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
232 CCU_USB = (CCU_USB & ~(3<<24)) | (1 << 24); /* ?? */
233 /* PHY clock */
234 CGU_USB = 1<<5 /* enable */
235 | 0 << 2
236 | 0; /* source = ? (24MHz crystal?) */
237
238 PCGCCTL = 0;
239 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
240
241 GRSTCTL = GRSTCTL_csftrst;
242 while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */
243 while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */
244
245 GRXFSIZ = 512;
246 GNPTXFSIZ = MAKE_FIFOSIZE_DATA(512);
247
248 /* FIXME: the current code is for internal DMA only, the clip+ architecture
249 * defines the internal DMA model */
250 GAHBCFG = (GAHBCFG_INT_DMA_BURST_INCR << GAHBCFG_hburstlen_bitp)
251 | GAHBCFG_dma_enable | GAHBCFG_glblintrmsk;
252
253 /* Select UTMI+ 16 */
254 GUSBCFG = GUSBCFG_force_device_mode | GUSBCFG_phy_if | 7 << GUSBCFG_toutcal_bitp;
255
256 /* Do something that is probably CCU related but undocumented*/
257 CCU_USB |= 0x1000;
258 CCU_USB &= ~0x300000;
259
260 DCFG = DCFG_nzstsouthshk | DCFG_devspd_hs_phy_hs; /* Address 0, high speed */
261 DCTL = DCTL_pwronprgdone;
262
263 /* Check hardware capabilities */
264 if(extract(GHWCFG2, arch) != GHWCFG2_ARCH_INTERNAL_DMA)
265 panicf("usb-drv: wrong architecture (%ld)", extract(GHWCFG2, arch));
266 if(extract(GHWCFG2, hs_phy_type) != GHWCFG2_PHY_TYPE_UTMI)
267 panicf("usb-drv: wrong HS phy type (%ld)", extract(GHWCFG2, hs_phy_type));
268 if(extract(GHWCFG2, fs_phy_type) != GHWCFG2_PHY_TYPE_UNSUPPORTED)
269 panicf("usb-drv: wrong FS phy type (%ld)", extract(GHWCFG2, fs_phy_type));
270 if(extract(GHWCFG4, utmi_phy_data_width) != 0x2)
271 panicf("usb-drv: wrong utmi data width (%ld)", extract(GHWCFG4, utmi_phy_data_width));
272 if(!(GHWCFG4 & GHWCFG4_ded_fifo_en)) /* it seems to be multiple tx fifo support */
273 panicf("usb-drv: no multiple tx fifo");
274
275 if(USB_NUM_ENDPOINTS != extract(GHWCFG2, num_ep))
276 panicf("usb-drv: wrong endpoint number");
277
278 for (int dir = 0; dir < 2; dir++)
279 for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
280 {
281 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
282 int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits;
283 int flag = (dir == DIR_IN) ? GHWCFG1_EPDIR_IN : GHWCFG1_EPDIR_OUT;
284 if(type != GHWCFG1_EPDIR_BIDIR && type != flag)
285 panicf("usb-drv: EP%d not in correct direction", ep);
286 }
287
288 DOEPMSK = DEPINT_xfercompl | DEPINT_ahberr | DOEPINT_setup;
289 DIEPMSK = DEPINT_xfercompl | DEPINT_ahberr | DIEPINT_timeout;
290 DAINTMSK = 0xffffffff;
291
292 reset_endpoints();
293
294 GINTMSK = GINTMSK_usbreset
295 | GINTMSK_enumdone
296 | GINTMSK_inepintr
297 | GINTMSK_outepintr
298 | GINTMSK_disconnect;
299
300 VIC_INT_ENABLE = INTERRUPT_USB;
301}
302
303void usb_drv_exit(void)
304{
305 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
306
307 VIC_INT_EN_CLEAR = INTERRUPT_USB;
308
309 sleep(HZ/20);
310
311 CGU_USB = 0;
312 bitclr32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
313}
314
315static void handle_ep_int(int ep, bool out)
316{
317 unsigned long sts = DEPINT(ep, out);
318 logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts);
319
320 if(sts & DEPINT_ahberr)
321 panicf("usb-drv: ahb error on EP%d %s", ep, out ? "OUT" : "IN");
322
323 if(sts & DEPINT_xfercompl)
324 {
325 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
326 if(endpoint->busy)
327 {
328 endpoint->busy = false;
329 endpoint->status = 0;
330 /* works even for EP0 */
331 int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits);
332 int transfered = endpoint->size - size;
333 if(ep == 0)
334 {
335 bool is_ack = endpoint->size == 0;
336 switch(ep0_state)
337 {
338 case EP0_WAIT_SETUP:
339 panicf("usb-drv: EP0 completion while waiting for SETUP");
340 case EP0_WAIT_DATA_ACK:
341 ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK;
342 break;
343 case EP0_WAIT_ACK:
344 case EP0_WAIT_DATA:
345 if((!is_ack && ep0_state == EP0_WAIT_ACK) || (is_ack && ep0_state == EP0_WAIT_DATA))
346 panicf("usb-drv: bad EP0 state");
347
348 prepare_setup_ep0();
349 break;
350 }
351 }
352 if (!out)
353 endpoint->size = size;
354 usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered);
355 endpoint->done = true;
356 semaphore_release(&endpoint->complete);
357 }
358 }
359
360 if(!out && (sts & DIEPINT_timeout))
361 panicf("usb-drv: timeout on EP%d IN", ep);
362
363 if(out && (sts & DOEPINT_setup))
364 {
365 if(ep != 0)
366 panicf("usb-drv: setup not on EP0, this is impossible");
367 if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0)
368 {
369 logf("usb-drv: ignore spurious setup (xfersize=%ld)", DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
370 prepare_setup_ep0();
371 }
372 else
373 {
374 if(ep0_state == EP0_WAIT_SETUP)
375 {
376 bool data_phase = ep0_setup_pkt->wLength != 0;
377 ep0_state = data_phase ? EP0_WAIT_DATA_ACK : EP0_WAIT_ACK;
378 }
379
380 logf(" rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest);
381
382 if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD &&
383 ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS)
384 DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp);
385
386 usb_core_control_request(ep0_setup_pkt);
387 }
388 }
389
390 DEPINT(ep, out) = sts;
391}
392
393void INT_USB(void)
394{
395 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
396 * so AND it with the actual mask */
397 unsigned long sts = GINTSTS & GINTMSK;
398 logf("usb-drv: INT 0x%lx", sts);
399
400 if(sts & GINTMSK_usbreset)
401 {
402 DCFG &= ~bitm(DCFG, devadr); /* Address 0 */
403 reset_endpoints();
404 usb_core_bus_reset();
405 }
406
407 if(sts & GINTMSK_enumdone) /* enumeration done, we now know the speed */
408 {
409 /* Set up the maximum packet sizes accordingly */
410 uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp;
411 for (int dir = 0; dir < 2; dir++)
412 {
413 bool out = dir == DIR_OUT;
414 for (unsigned i = 1; i < num_eps(out); i++)
415 {
416 int ep = (out ? out_ep_list : in_ep_list)[i];
417 DEPCTL(ep, out) &= ~(DEPCTL_mps_bits << DEPCTL_mps_bitp);
418 DEPCTL(ep, out) |= maxpacket;
419 }
420 }
421 }
422
423 if(sts & (GINTMSK_outepintr | GINTMSK_inepintr))
424 {
425 unsigned long daint = DAINT;
426
427 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
428 {
429 if (daint & DAINT_IN_EP(i))
430 handle_ep_int(i, false);
431 if (daint & DAINT_OUT_EP(i))
432 handle_ep_int(i, true);
433 }
434
435 DAINT = daint;
436 }
437
438 if(sts & GINTMSK_disconnect)
439 cancel_all_transfers(true);
440
441 GINTSTS = sts;
442}
443
444int usb_drv_request_endpoint(int type, int dir)
445{
446 bool out = dir == USB_DIR_OUT;
447 for (unsigned i = 1; i < num_eps(out); i++)
448 {
449 int ep = (out ? out_ep_list : in_ep_list)[i];
450 bool *active = &endpoints[ep][out ? DIR_OUT : DIR_IN].active;
451 if(*active)
452 continue;
453 *active = true;
454 DEPCTL(ep, out) = (DEPCTL(ep, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
455 | DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
456 return ep | dir;
457 }
458
459 return -1;
460}
461
462void usb_drv_release_endpoint(int ep)
463{
464 endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
465}
466
467void usb_drv_cancel_all_transfers()
468{
469 cancel_all_transfers(false);
470}
471
472static void ep_transfer(int ep, void *ptr, int len, bool out)
473{
474 /* disable interrupts to avoid any race */
475 int oldlevel = disable_irq_save();
476
477 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
478 endpoint->busy = true;
479 endpoint->size = len;
480 endpoint->status = -1;
481
482 if (out)
483 DEPCTL(ep, out) &= ~DEPCTL_stall;
484 DEPCTL(ep, out) |= DEPCTL_usbactep;
485
486 int mps = usb_drv_port_speed() ? 512 : 64;
487 int nb_packets = (len + mps - 1) / mps;
488 if (nb_packets == 0)
489 nb_packets = 1;
490
491 DEPDMA(ep, out) = len
492 ? (void*)AS3525_PHYSICAL_ADDR(ptr)
493 : (void*)0x10000000;
494 DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
495 if(out)
496 discard_dcache_range(ptr, len);
497 else
498 commit_dcache_range(ptr, len);
499
500 logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
501
502 DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
503
504 restore_irq(oldlevel);
505}
506
507int usb_drv_send(int ep, void *ptr, int len)
508{
509 ep = EP_NUM(ep);
510 struct ep_type *endpoint = &endpoints[ep][1];
511 endpoint->done = false;
512 ep_transfer(ep, ptr, len, false);
513 while (endpoint->busy && !endpoint->done)
514 semaphore_wait(&endpoint->complete, TIMEOUT_BLOCK);
515 return endpoint->status;
516}
111#else 517#else
112 518
113static struct ep_type endpoints[USB_NUM_ENDPOINTS]; 519static struct ep_type endpoints[USB_NUM_ENDPOINTS];