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.c575
1 files changed, 181 insertions, 394 deletions
diff --git a/firmware/target/arm/usb-s3c6400x.c b/firmware/target/arm/usb-s3c6400x.c
index 7bcfcedc89..48521aa622 100644
--- a/firmware/target/arm/usb-s3c6400x.c
+++ b/firmware/target/arm/usb-s3c6400x.c
@@ -39,6 +39,16 @@
39//#define LOGF_ENABLE 39//#define LOGF_ENABLE
40#include "logf.h" 40#include "logf.h"
41 41
42#if CONFIG_CPU == AS3525v2
43#define UNCACHED_ADDR AS3525_UNCACHED_ADDR
44#define PHYSICAL_ADDR AS3525_PHYSICAL_ADDR
45static inline void discard_dma_buffer_cache(void) {}
46#else
47#define UNCACHED_ADDR
48#define PHYSICAL_ADDR
49static inline void discard_dma_buffer_cache(void) { commit_discard_dcache(); }
50#endif
51
42/* store per endpoint, per direction, information */ 52/* store per endpoint, per direction, information */
43struct ep_type 53struct ep_type
44{ 54{
@@ -50,6 +60,46 @@ struct ep_type
50 bool busy; /* true is a transfer is pending */ 60 bool busy; /* true is a transfer is pending */
51}; 61};
52 62
63static const uint8_t in_ep_list[] = {0, 1, 3, 5};
64static const uint8_t out_ep_list[] = {0, 2, 4};
65
66/* state of EP0 (to correctly schedule setup packet enqueing) */
67enum ep0state
68{
69 /* Setup packet is enqueud, waiting for actual data */
70 EP0_WAIT_SETUP = 0,
71 /* Waiting for ack (either IN or OUT) */
72 EP0_WAIT_ACK = 1,
73 /* Ack complete, waiting for data (either IN or OUT)
74 * This state is necessary because if both ack and data complete in the
75 * same interrupt, we might process data completion before ack completion
76 * so we need this bizarre state */
77 EP0_WAIT_DATA = 2,
78 /* Setup packet complete, waiting for ack and data */
79 EP0_WAIT_DATA_ACK = 3,
80};
81
82/* endpoints[ep_num][DIR_IN/DIR_OUT] */
83static struct ep_type endpoints[USB_NUM_ENDPOINTS][2];
84/* setup packet for EP0 */
85
86/* USB control requests may be up to 64 bytes in size.
87 Even though we never use anything more than the 8 header bytes,
88 we are required to accept request packets of up to 64 bytes size.
89 Provide buffer space for these additional payload bytes so that
90 e.g. write descriptor requests (which are rejected by us, but the
91 payload is transferred anyway) do not cause memory corruption.
92 Fixes FS#12310. -- Michael Sparmann (theseven) */
93static union {
94 struct usb_ctrlrequest header; /* 8 bytes */
95 unsigned char payload[64];
96} _ep0_setup_pkt USB_DEVBSS_ATTR;
97
98static struct usb_ctrlrequest *ep0_setup_pkt = UNCACHED_ADDR(&_ep0_setup_pkt.header);
99
100/* state of EP0 */
101static enum ep0state ep0_state;
102
53bool usb_drv_stalled(int endpoint, bool in) 103bool usb_drv_stalled(int endpoint, bool in)
54{ 104{
55 return DEPCTL(endpoint, !in) & DEPCTL_stall; 105 return DEPCTL(endpoint, !in) & DEPCTL_stall;
@@ -72,7 +122,40 @@ void usb_drv_set_address(int address)
72 into the USB core, which will then call this dummy function. */ 122 into the USB core, which will then call this dummy function. */
73} 123}
74 124
75static void ep_transfer(int ep, void *ptr, int length, bool out); 125static void ep_transfer(int ep, void *ptr, int len, bool out)
126{
127 /* disable interrupts to avoid any race */
128 int oldlevel = disable_irq_save();
129
130 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
131 endpoint->busy = true;
132 endpoint->size = len;
133 endpoint->status = -1;
134
135 if (out)
136 DEPCTL(ep, out) &= ~DEPCTL_stall;
137
138 int mps = usb_drv_port_speed() ? 512 : 64;
139 int nb_packets = (len + mps - 1) / mps;
140 if (nb_packets == 0)
141 nb_packets = 1;
142
143 DEPDMA(ep, out) = len ? (void*)PHYSICAL_ADDR(ptr) : NULL;
144 DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
145 if(out)
146 discard_dcache_range(ptr, len);
147 else
148 commit_dcache_range(ptr, len);
149
150 logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
151
152// if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length));
153
154 DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
155
156 restore_irq(oldlevel);
157}
158
76int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) 159int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
77{ 160{
78 ep_transfer(EP_NUM(endpoint), ptr, length, false); 161 ep_transfer(EP_NUM(endpoint), ptr, length, false);
@@ -109,55 +192,15 @@ void usb_drv_set_test_mode(int mode)
109 DCTL = (DCTL & ~bitm(DCTL, tstctl)) | (mode << DCTL_tstctl_bitp); 192 DCTL = (DCTL & ~bitm(DCTL, tstctl)) | (mode << DCTL_tstctl_bitp);
110} 193}
111 194
112#if CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */
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) 195void usb_attach(void)
154{ 196{
197 usb_enable(true); // s5l only ?
155 /* Nothing to do */ 198 /* Nothing to do */
156} 199}
157 200
158static void prepare_setup_ep0(void) 201static void prepare_setup_ep0(void)
159{ 202{
160 DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt); 203 DEPDMA(0, true) = (void*)PHYSICAL_ADDR(&_ep0_setup_pkt);
161 DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp) 204 DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp)
162 | (1 << DEPTSIZ0_pkcnt_bitp) 205 | (1 << DEPTSIZ0_pkcnt_bitp)
163 | 8; 206 | 8;
@@ -183,7 +226,7 @@ static void reset_endpoints(void)
183 endpoint->active = false; 226 endpoint->active = false;
184 endpoint->busy = false; 227 endpoint->busy = false;
185 endpoint->status = -1; 228 endpoint->status = -1;
186 endpoint->done = false; 229 endpoint->done = true;
187 semaphore_release(&endpoint->complete); 230 semaphore_release(&endpoint->complete);
188 231
189 if (i != 0) 232 if (i != 0)
@@ -222,6 +265,7 @@ static void cancel_all_transfers(bool cancel_ep0)
222 restore_irq(flags); 265 restore_irq(flags);
223} 266}
224 267
268#if CONFIG_CPU == AS3525v2
225void usb_drv_init(void) 269void usb_drv_init(void)
226{ 270{
227 for (int i = 0; i < USB_NUM_ENDPOINTS; i++) 271 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
@@ -311,10 +355,89 @@ void usb_drv_exit(void)
311 CGU_USB = 0; 355 CGU_USB = 0;
312 bitclr32(&CGU_PERI, CGU_USB_CLOCK_ENABLE); 356 bitclr32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
313} 357}
358#elif CONFIG_CPU == S5L8701 || CONFIG_CPU == S5L8702
359static void usb_reset(void)
360{
361 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
362
363 OPHYPWR = 0; /* PHY: Power up */
364 udelay(10);
365 OPHYUNK1 = 1;
366 OPHYUNK2 = 0xE3F;
367 ORSTCON = 1; /* PHY: Assert Software Reset */
368 udelay(10);
369 ORSTCON = 0; /* PHY: Deassert Software Reset */
370 OPHYUNK3 = 0x600;
371 OPHYCLK = SYNOPSYSOTG_CLOCK;
372 udelay(400);
373
374 GRSTCTL = GRSTCTL_csftrst; /* OTG: Assert Software Reset */
375 while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */
376 while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */
377
378 GRXFSIZ = 1024;
379 GNPTXFSIZ = (256 << 16) | 1024;
380
381 GAHBCFG = SYNOPSYSOTG_AHBCFG;
382 GUSBCFG = (1 << 12) | (1 << 10) | GUSBCFG_phy_if; /* OTG: 16bit PHY and some reserved bits */
383
384 DCFG = DCFG_nzstsouthshk; /* Address 0 */
385 DCTL = DCTL_pwronprgdone; /* Soft Reconnect */
386 DIEPMSK = DIEPINT_timeout | DEPINT_ahberr | DEPINT_xfercompl;
387 DOEPMSK = DOEPINT_setup | DEPINT_ahberr | DEPINT_xfercompl;
388 DAINTMSK = 0xFFFFFFFF; /* Enable interrupts on all endpoints */
389 GINTMSK = GINTMSK_outepintr | GINTMSK_inepintr | GINTMSK_usbreset | GINTMSK_enumdone;
390
391 reset_endpoints();
392}
393
394void usb_drv_init(void)
395{
396 for (unsigned i = 0; i < sizeof(endpoints)/(2*sizeof(struct ep_type)); i++)
397 for (unsigned dir = 0; dir < 2; dir++)
398 semaphore_init(&endpoints[i][dir].complete, 1, 0);
399
400 /* Enable USB clock */
401#if CONFIG_CPU==S5L8701
402 PWRCON &= ~0x4000;
403 PWRCONEXT &= ~0x800;
404 INTMSK |= INTMSK_USB_OTG;
405#elif CONFIG_CPU==S5L8702
406 PWRCON(0) &= ~0x4;
407 PWRCON(1) &= ~0x8;
408 VIC0INTENABLE |= 1 << 19;
409#endif
410 PCGCCTL = 0;
411
412 /* reset the beast */
413 usb_reset();
414}
415
416void usb_drv_exit(void)
417{
418 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
419
420 OPHYPWR = 0xF; /* PHY: Power down */
421 udelay(10);
422 ORSTCON = 7; /* Put the PHY into reset (needed to get current down) */
423 udelay(10);
424 PCGCCTL = 1; /* Shut down PHY clock */
425
426#if CONFIG_CPU==S5L8701
427 PWRCON |= 0x4000;
428 PWRCONEXT |= 0x800;
429#elif CONFIG_CPU==S5L8702
430 PWRCON(0) |= 0x4;
431 PWRCON(1) |= 0x8;
432#endif
433}
434#endif
314 435
315static void handle_ep_int(int ep, bool out) 436static void handle_ep_int(int ep, bool out)
316{ 437{
317 unsigned long sts = DEPINT(ep, out); 438 unsigned long sts = DEPINT(ep, out);
439 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
440
318 logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts); 441 logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts);
319 442
320 if(sts & DEPINT_ahberr) 443 if(sts & DEPINT_ahberr)
@@ -322,7 +445,7 @@ static void handle_ep_int(int ep, bool out)
322 445
323 if(sts & DEPINT_xfercompl) 446 if(sts & DEPINT_xfercompl)
324 { 447 {
325 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; 448 discard_dma_buffer_cache();
326 if(endpoint->busy) 449 if(endpoint->busy)
327 { 450 {
328 endpoint->busy = false; 451 endpoint->busy = false;
@@ -357,11 +480,19 @@ static void handle_ep_int(int ep, bool out)
357 } 480 }
358 } 481 }
359 482
360 if(!out && (sts & DIEPINT_timeout)) 483 if(!out && (sts & DIEPINT_timeout)) {
361 panicf("usb-drv: timeout on EP%d IN", ep); 484 if (endpoint->busy)
485 {
486 endpoint->busy = false;
487 endpoint->status = 1;
488 endpoint->done = true;
489 semaphore_release(&endpoint->complete);
490 }
491 }
362 492
363 if(out && (sts & DOEPINT_setup)) 493 if(out && (sts & DOEPINT_setup))
364 { 494 {
495 discard_dma_buffer_cache();
365 if(ep != 0) 496 if(ep != 0)
366 panicf("usb-drv: setup not on EP0, this is impossible"); 497 panicf("usb-drv: setup not on EP0, this is impossible");
367 if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0) 498 if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0)
@@ -390,7 +521,7 @@ static void handle_ep_int(int ep, bool out)
390 DEPINT(ep, out) = sts; 521 DEPINT(ep, out) = sts;
391} 522}
392 523
393void INT_USB(void) 524void INT_USB_FUNC(void)
394{ 525{
395 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source 526 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
396 * so AND it with the actual mask */ 527 * so AND it with the actual mask */
@@ -461,6 +592,8 @@ int usb_drv_request_endpoint(int type, int dir)
461 592
462void usb_drv_release_endpoint(int ep) 593void usb_drv_release_endpoint(int ep)
463{ 594{
595 if ((ep & 0x7f) == 0)
596 return;
464 endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; 597 endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
465} 598}
466 599
@@ -469,39 +602,6 @@ void usb_drv_cancel_all_transfers()
469 cancel_all_transfers(false); 602 cancel_all_transfers(false);
470} 603}
471 604
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
485 int mps = usb_drv_port_speed() ? 512 : 64;
486 int nb_packets = (len + mps - 1) / mps;
487 if (nb_packets == 0)
488 nb_packets = 1;
489
490 DEPDMA(ep, out) = len ? (void*)AS3525_PHYSICAL_ADDR(ptr) : NULL;
491 DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
492 if(out)
493 discard_dcache_range(ptr, len);
494 else
495 commit_dcache_range(ptr, len);
496
497 logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
498
499// if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length));
500
501 DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
502
503 restore_irq(oldlevel);
504}
505 605
506int usb_drv_send(int ep, void *ptr, int len) 606int usb_drv_send(int ep, void *ptr, int len)
507{ 607{
@@ -513,316 +613,3 @@ int usb_drv_send(int ep, void *ptr, int len)
513 semaphore_wait(&endpoint->complete, TIMEOUT_BLOCK); 613 semaphore_wait(&endpoint->complete, TIMEOUT_BLOCK);
514 return endpoint->status; 614 return endpoint->status;
515} 615}
516#else
517
518static struct ep_type endpoints[USB_NUM_ENDPOINTS][2];
519
520/* USB control requests may be up to 64 bytes in size.
521 Even though we never use anything more than the 8 header bytes,
522 we are required to accept request packets of up to 64 bytes size.
523 Provide buffer space for these additional payload bytes so that
524 e.g. write descriptor requests (which are rejected by us, but the
525 payload is transferred anyway) do not cause memory corruption.
526 Fixes FS#12310. -- Michael Sparmann (theseven) */
527static union
528{
529 struct usb_ctrlrequest header; /* 8 bytes */
530 unsigned char payload[64];
531} ctrlreq USB_DEVBSS_ATTR;
532
533static volatile bool inflight = false;
534static volatile bool plugged = false;
535
536static void reset_endpoints(int reinit)
537{
538 for (unsigned i = 0; i < sizeof(endpoints)/(2*sizeof(struct ep_type)); i++)
539 for (unsigned dir = 0; dir < 2; dir++)
540 {
541 if (reinit) endpoints[i][dir].active = false;
542 endpoints[i][dir].busy = false;
543 endpoints[i][dir].status = -1;
544 endpoints[i][dir].done = true;
545 semaphore_release(&endpoints[i][dir].complete);
546 }
547
548 DEPCTL(0, false) = DEPCTL_usbactep | (1 << DEPCTL_nextep_bitp);
549 DEPCTL(0, true) = DEPCTL_usbactep;
550 DEPTSIZ(0, true) = (1 << DEPTSIZ_pkcnt_bitp) | (1 << DEPTSIZ0_supcnt_bitp) | 64;
551
552 DEPDMA(0, true) = &ctrlreq;
553 DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;
554 /* HACK: Enable all endpoints here, because we have no other chance to do it */
555 if (reinit)
556 {
557 /* The size is getting set to zero, because we don't know
558 whether we are Full Speed or High Speed at this stage */
559 DEPCTL(1, false) = DEPCTL_usbactep | DEPCTL_setd0pid | (3 << DEPCTL_nextep_bitp);
560 DEPCTL(2, true) = DEPCTL_usbactep | DEPCTL_setd0pid;
561 DEPCTL(3, false) = DEPCTL_usbactep | DEPCTL_setd0pid | (0 << DEPCTL_nextep_bitp);
562 DEPCTL(4, true) = DEPCTL_usbactep | DEPCTL_setd0pid;
563 }
564 else
565 {
566 DEPCTL(1, false) = DEPCTL(1, false) | DEPCTL_usbactep | DEPCTL_setd0pid;
567 DEPCTL(2, true) = DEPCTL(2, true) | DEPCTL_usbactep | DEPCTL_setd0pid;
568 DEPCTL(3, false) = DEPCTL(3, false) | DEPCTL_usbactep | DEPCTL_setd0pid;
569 DEPCTL(4, true) = DEPCTL(4, true) | DEPCTL_usbactep | DEPCTL_setd0pid;
570 }
571 DAINTMSK = 0xFFFFFFFF; /* Enable interrupts on all EPs */
572 inflight = false;
573}
574
575int usb_drv_request_endpoint(int type, int dir)
576{
577 bool out = dir == USB_DIR_OUT;
578 for(size_t ep = out ? 2 : 1; ep < USB_NUM_ENDPOINTS; ep += 2) {
579 if (!endpoints[ep][out ? DIR_OUT : DIR_IN].active)
580 {
581 endpoints[ep][out ? DIR_OUT : DIR_IN].active = true;
582 DEPCTL(ep, out) = (DEPCTL(ep, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp)) |
583 (type << DEPCTL_eptype_bitp);
584 return ep | dir;
585 }
586 }
587
588 return -1;
589}
590
591void usb_drv_release_endpoint(int ep)
592{
593 bool out = !(ep & USB_DIR_IN);
594 ep = ep & 0x7f;
595
596 if (ep < 1 || ep > USB_NUM_ENDPOINTS)
597 return;
598
599 endpoints[ep][out ? DIR_OUT : DIR_IN].active = false;
600}
601
602static void usb_reset(void)
603{
604 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
605
606 OPHYPWR = 0; /* PHY: Power up */
607 udelay(10);
608 OPHYUNK1 = 1;
609 OPHYUNK2 = 0xE3F;
610 ORSTCON = 1; /* PHY: Assert Software Reset */
611 udelay(10);
612 ORSTCON = 0; /* PHY: Deassert Software Reset */
613 OPHYUNK3 = 0x600;
614 OPHYCLK = SYNOPSYSOTG_CLOCK;
615 udelay(400);
616
617 GRSTCTL = GRSTCTL_csftrst; /* OTG: Assert Software Reset */
618 while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */
619 while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */
620
621 GRXFSIZ = 1024;
622 GNPTXFSIZ = (256 << 16) | 1024;
623
624 GAHBCFG = SYNOPSYSOTG_AHBCFG;
625 GUSBCFG = (1 << 12) | (1 << 10) | GUSBCFG_phy_if; /* OTG: 16bit PHY and some reserved bits */
626
627 DCFG = DCFG_nzstsouthshk; /* Address 0 */
628 DCTL = DCTL_pwronprgdone; /* Soft Reconnect */
629 DIEPMSK = DIEPINT_timeout | DEPINT_ahberr | DEPINT_xfercompl;
630 DOEPMSK = DOEPINT_setup | DEPINT_ahberr | DEPINT_xfercompl;
631 DAINTMSK = 0xFFFFFFFF; /* Enable interrupts on all endpoints */
632 GINTMSK = GINTMSK_outepintr | GINTMSK_inepintr | GINTMSK_usbreset | GINTMSK_enumdone;
633
634 reset_endpoints(1);
635}
636
637static void handle_ep_int(bool out)
638{
639 static const uint8_t eps[2][3] = { /* IN */ {0, 1, 3}, /* OUT */ {0, 2, 4}};
640 for (int i = 0; i < 3; i++)
641 {
642 int ep = eps[!!out][i];
643 uint32_t epints = DEPINT(ep, out);
644 if (!epints)
645 continue;
646
647 if (epints & DEPINT_xfercompl)
648 {
649 if (!out) inflight = false;
650 commit_discard_dcache();
651 int bytes = endpoints[ep][out ? DIR_OUT : DIR_IN].size - (DEPTSIZ(ep, out) & (DEPTSIZ_xfersize_bits < DEPTSIZ_xfersize_bitp));
652 if (endpoints[ep][out ? DIR_OUT : DIR_IN].busy)
653 {
654 endpoints[ep][out ? DIR_OUT : DIR_IN].busy = false;
655 endpoints[ep][out ? DIR_OUT : DIR_IN].status = 0;
656 endpoints[ep][out ? DIR_OUT : DIR_IN].done = true;
657 usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, bytes);
658 semaphore_release(&endpoints[ep][out ? DIR_OUT : DIR_IN].complete);
659 }
660 }
661
662 if (epints & DEPINT_ahberr)
663 panicf("USB: AHB error on EP%d (dir %d)", ep, out);
664
665 if (!out && (epints & DIEPINT_timeout))
666 {
667 if (endpoints[ep][out ? DIR_OUT : DIR_IN].busy)
668 {
669 endpoints[ep][out ? DIR_OUT : DIR_IN].busy = false;
670 endpoints[ep][out ? DIR_OUT : DIR_IN].status = 1;
671 endpoints[ep][out ? DIR_OUT : DIR_IN].done = true;
672 semaphore_release(&endpoints[ep][out ? DIR_OUT : DIR_IN].complete);
673 }
674 }
675
676 if (out && (epints & DOEPINT_setup))
677 {
678 commit_discard_dcache();
679 if (ep != 0)
680 panicf("USB: SETUP done on OUT EP%d!?", ep);
681
682 /* Set the new address here, before passing the packet to the core.
683 See usb_drv_set_address() for details. */
684 if (ctrlreq.header.bRequest == USB_REQ_SET_ADDRESS)
685 DCFG = (DCFG & ~(DCFG_devadr_bits << DCFG_devadr_bitp))
686 | (ctrlreq.header.wValue << DCFG_devadr_bitp);
687
688 usb_core_control_request(&ctrlreq.header);
689 }
690
691 /* Make sure EP0 OUT is set up to accept the next request */
692 if (out && ep == 0)
693 {
694 DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 64;
695 DEPDMA(0, true) = &ctrlreq;
696 DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;
697 }
698 DEPINT(ep, out) = epints;
699 }
700}
701
702/* IRQ handler */
703void INT_USB_FUNC(void)
704{
705 uint32_t ints = GINTSTS;
706 if (ints & GINTMSK_usbreset)
707 {
708 DCFG = DCFG_nzstsouthshk; /* Address 0 */
709 reset_endpoints(1);
710 usb_core_bus_reset();
711 }
712
713 if (ints & GINTMSK_enumdone) /* enumeration done, we now know the speed */
714 {
715 /* Set up the maximum packet sizes accordingly */
716 uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp;
717 DEPCTL(1, false) = (DEPCTL(1, false) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket;
718 DEPCTL(2, true) = (DEPCTL(2, true) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket;
719 DEPCTL(3, false) = (DEPCTL(3, false) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket;
720 DEPCTL(4, true) = (DEPCTL(4, true) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket;
721 }
722
723 if (ints & GINTMSK_inepintr)
724 handle_ep_int(false);
725
726 if (ints & GINTMSK_outepintr)
727 handle_ep_int(true);
728
729 GINTSTS = ints;
730}
731
732static void ep_transfer(int ep, void *ptr, int len, bool out)
733{
734 while (!out && inflight && plugged);
735 if (!plugged) return;
736
737 /* disable interrupts to avoid any race */
738 int oldlevel = disable_irq_save();
739 if (!out) inflight = true;
740 endpoints[ep][out ? DIR_OUT : DIR_IN].busy = true;
741 endpoints[ep][out ? DIR_OUT : DIR_IN].size = len;
742
743 if (out) DEPCTL(ep, out) &= ~DEPCTL_stall;
744
745
746 int mps = usb_drv_port_speed() ? 512 : 64;
747 int nb_packets = (len + mps - 1) / mps;
748 if (nb_packets == 0)
749 nb_packets = 1;
750
751 DEPDMA(ep, out) = len ? ptr : NULL;
752 DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
753
754 if(out) discard_dcache_range(ptr, len);
755 else commit_dcache_range(ptr, len);
756
757 logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
758
759 DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
760
761 restore_irq(oldlevel);
762}
763
764int usb_drv_send(int endpoint, void *ptr, int length)
765{
766 endpoint = EP_NUM(endpoint);
767 endpoints[endpoint][1].done = false;
768 ep_transfer(endpoint, ptr, length, false);
769 while (!endpoints[endpoint][1].done && endpoints[endpoint][1].busy)
770 semaphore_wait(&endpoints[endpoint][1].complete, TIMEOUT_BLOCK);
771 return endpoints[endpoint][1].status;
772}
773
774void usb_drv_cancel_all_transfers(void)
775{
776 int flags = disable_irq_save();
777 reset_endpoints(0);
778 restore_irq(flags);
779}
780
781void usb_drv_init(void)
782{
783 for (unsigned i = 0; i < sizeof(endpoints)/(2*sizeof(struct ep_type)); i++)
784 for (unsigned dir = 0; dir < 2; dir++)
785 semaphore_init(&endpoints[i][dir].complete, 1, 0);
786
787 /* Enable USB clock */
788#if CONFIG_CPU==S5L8701
789 PWRCON &= ~0x4000;
790 PWRCONEXT &= ~0x800;
791 INTMSK |= INTMSK_USB_OTG;
792#elif CONFIG_CPU==S5L8702
793 PWRCON(0) &= ~0x4;
794 PWRCON(1) &= ~0x8;
795 VIC0INTENABLE |= 1 << 19;
796#endif
797 PCGCCTL = 0;
798
799 /* reset the beast */
800 plugged = true;
801 usb_reset();
802}
803
804void usb_drv_exit(void)
805{
806 plugged = false;
807 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
808
809 OPHYPWR = 0xF; /* PHY: Power down */
810 udelay(10);
811 ORSTCON = 7; /* Put the PHY into reset (needed to get current down) */
812 udelay(10);
813 PCGCCTL = 1; /* Shut down PHY clock */
814
815#if CONFIG_CPU==S5L8701
816 PWRCON |= 0x4000;
817 PWRCONEXT |= 0x800;
818#elif CONFIG_CPU==S5L8702
819 PWRCON(0) |= 0x4;
820 PWRCON(1) |= 0x8;
821#endif
822}
823
824void usb_attach(void)
825{
826 usb_enable(true);
827}
828#endif // CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */