diff options
Diffstat (limited to 'firmware/target/arm/usb-s3c6400x.c')
-rw-r--r-- | firmware/target/arm/usb-s3c6400x.c | 575 |
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 | ||
45 | static inline void discard_dma_buffer_cache(void) {} | ||
46 | #else | ||
47 | #define UNCACHED_ADDR | ||
48 | #define PHYSICAL_ADDR | ||
49 | static 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 */ |
43 | struct ep_type | 53 | struct 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 | ||
63 | static const uint8_t in_ep_list[] = {0, 1, 3, 5}; | ||
64 | static const uint8_t out_ep_list[] = {0, 2, 4}; | ||
65 | |||
66 | /* state of EP0 (to correctly schedule setup packet enqueing) */ | ||
67 | enum 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] */ | ||
83 | static 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) */ | ||
93 | static union { | ||
94 | struct usb_ctrlrequest header; /* 8 bytes */ | ||
95 | unsigned char payload[64]; | ||
96 | } _ep0_setup_pkt USB_DEVBSS_ATTR; | ||
97 | |||
98 | static struct usb_ctrlrequest *ep0_setup_pkt = UNCACHED_ADDR(&_ep0_setup_pkt.header); | ||
99 | |||
100 | /* state of EP0 */ | ||
101 | static enum ep0state ep0_state; | ||
102 | |||
53 | bool usb_drv_stalled(int endpoint, bool in) | 103 | bool 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 | ||
75 | static void ep_transfer(int ep, void *ptr, int length, bool out); | 125 | static 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 | |||
76 | int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) | 159 | int 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 */ | ||
113 | static const uint8_t in_ep_list[] = {0, 1, 3, 5}; | ||
114 | static const uint8_t out_ep_list[] = {0, 2, 4}; | ||
115 | |||
116 | /* state of EP0 (to correctly schedule setup packet enqueing) */ | ||
117 | enum 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] */ | ||
133 | static 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) */ | ||
143 | static union { | ||
144 | struct usb_ctrlrequest header; /* 8 bytes */ | ||
145 | unsigned char payload[64]; | ||
146 | } _ep0_setup_pkt USB_DEVBSS_ATTR; | ||
147 | |||
148 | static struct usb_ctrlrequest *ep0_setup_pkt = AS3525_UNCACHED_ADDR(&_ep0_setup_pkt.header); | ||
149 | |||
150 | /* state of EP0 */ | ||
151 | static enum ep0state ep0_state; | ||
152 | |||
153 | void usb_attach(void) | 195 | void usb_attach(void) |
154 | { | 196 | { |
197 | usb_enable(true); // s5l only ? | ||
155 | /* Nothing to do */ | 198 | /* Nothing to do */ |
156 | } | 199 | } |
157 | 200 | ||
158 | static void prepare_setup_ep0(void) | 201 | static 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 | ||
225 | void usb_drv_init(void) | 269 | void 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 | ||
359 | static 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 | |||
394 | void 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 | |||
416 | void 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 | ||
315 | static void handle_ep_int(int ep, bool out) | 436 | static 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 | ||
393 | void INT_USB(void) | 524 | void 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 | ||
462 | void usb_drv_release_endpoint(int ep) | 593 | void 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 | ||
472 | static 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 | ||
506 | int usb_drv_send(int ep, void *ptr, int len) | 606 | int 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 | |||
518 | static 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) */ | ||
527 | static union | ||
528 | { | ||
529 | struct usb_ctrlrequest header; /* 8 bytes */ | ||
530 | unsigned char payload[64]; | ||
531 | } ctrlreq USB_DEVBSS_ATTR; | ||
532 | |||
533 | static volatile bool inflight = false; | ||
534 | static volatile bool plugged = false; | ||
535 | |||
536 | static 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 | |||
575 | int 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 | |||
591 | void 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 | |||
602 | static 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 | |||
637 | static 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 */ | ||
703 | void 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 | |||
732 | static 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 | |||
764 | int 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 | |||
774 | void usb_drv_cancel_all_transfers(void) | ||
775 | { | ||
776 | int flags = disable_irq_save(); | ||
777 | reset_endpoints(0); | ||
778 | restore_irq(flags); | ||
779 | } | ||
780 | |||
781 | void 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 | |||
804 | void 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 | |||
824 | void usb_attach(void) | ||
825 | { | ||
826 | usb_enable(true); | ||
827 | } | ||
828 | #endif // CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */ | ||