summaryrefslogtreecommitdiff
path: root/firmware/target/arm/usb-drv-arc.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/usb-drv-arc.c')
-rw-r--r--firmware/target/arm/usb-drv-arc.c186
1 files changed, 92 insertions, 94 deletions
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c
index 1cdc0f9e90..99845c2a49 100644
--- a/firmware/target/arm/usb-drv-arc.c
+++ b/firmware/target/arm/usb-drv-arc.c
@@ -9,7 +9,7 @@
9 * 9 *
10 * Driver for ARC USBOTG Device Controller 10 * Driver for ARC USBOTG Device Controller
11 * 11 *
12 * Copyright (C) 2007 by Bjรถrn Stenberg 12 * Copyright (C) 2007 by Bjrn Stenberg
13 * 13 *
14 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -33,11 +33,6 @@
33//#define LOGF_ENABLE 33//#define LOGF_ENABLE
34#include "logf.h" 34#include "logf.h"
35 35
36#if CONFIG_CPU == IMX31L
37#include "avic-imx31.h"
38static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void);
39#endif
40
41/* USB device mode registers (Little Endian) */ 36/* USB device mode registers (Little Endian) */
42 37
43#define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000)) 38#define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000))
@@ -326,8 +321,8 @@ struct transfer_descriptor {
326 unsigned int reserved; 321 unsigned int reserved;
327} __attribute__ ((packed)); 322} __attribute__ ((packed));
328 323
329static struct transfer_descriptor td_array[NUM_ENDPOINTS*2] 324static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2]
330 USBDEVBSS_ATTR __attribute__((aligned(32))); 325 USB_DEVBSS_ATTR __attribute__((aligned(32)));
331 326
332/* manual: 32.13.1 Endpoint Queue Head (dQH) */ 327/* manual: 32.13.1 Endpoint Queue Head (dQH) */
333struct queue_head { 328struct queue_head {
@@ -342,17 +337,10 @@ struct queue_head {
342 unsigned int wait; /* for softwate use, indicates if the transfer is blocking */ 337 unsigned int wait; /* for softwate use, indicates if the transfer is blocking */
343} __attribute__((packed)); 338} __attribute__((packed));
344 339
345#if CONFIG_CPU == IMX31L 340static struct queue_head qh_array[USB_NUM_ENDPOINTS*2]
346static struct queue_head qh_array[NUM_ENDPOINTS*2] 341 USB_QHARRAY_ATTR;
347 QHARRAY_ATTR __attribute__((aligned (2048)));
348#else
349/* This still needs to be 2048 byte aligned, but QHARRAY_ATTR should take
350 care of that */
351static struct queue_head qh_array[NUM_ENDPOINTS*2]
352 QHARRAY_ATTR __attribute__((aligned (4)));
353#endif
354 342
355static struct wakeup transfer_completion_signal[NUM_ENDPOINTS*2] 343static struct wakeup transfer_completion_signal[USB_NUM_ENDPOINTS*2]
356 SHAREDBSS_ATTR; 344 SHAREDBSS_ATTR;
357 345
358static const unsigned int pipe2mask[] = { 346static const unsigned int pipe2mask[] = {
@@ -363,7 +351,7 @@ static const unsigned int pipe2mask[] = {
363 0x10, 0x100000, 351 0x10, 0x100000,
364}; 352};
365 353
366static char ep_allocation[NUM_ENDPOINTS]; 354static char ep_allocation[USB_NUM_ENDPOINTS];
367 355
368/*-------------------------------------------------------------------------*/ 356/*-------------------------------------------------------------------------*/
369static void transfer_completed(void); 357static void transfer_completed(void);
@@ -378,52 +366,46 @@ static void init_control_queue_heads(void);
378static void init_bulk_queue_heads(void); 366static void init_bulk_queue_heads(void);
379static void init_endpoints(void); 367static void init_endpoints(void);
380/*-------------------------------------------------------------------------*/ 368/*-------------------------------------------------------------------------*/
381 369static void usb_drv_stop(void)
382bool usb_drv_powered(void)
383{ 370{
384 return (REG_OTGSC & OTGSC_B_SESSION_VALID) ? true : false; 371 /* disable interrupts */
372 REG_USBINTR = 0;
373 /* stop usb controller (disconnect) */
374 REG_USBCMD &= ~USBCMD_RUN;
385} 375}
386 376
387/* One-time driver startup init */ 377void usb_drv_reset(void)
388void usb_drv_startup(void)
389{ 378{
390#if CONFIG_CPU == IMX31L && defined(BOOTLOADER) 379 int oldlevel = disable_irq_save();
391 /* This is the bootloader - activate the OTG controller or cold
392 * connect later could/will fail */
393 REG_USBCMD &= ~USBCMD_RUN; 380 REG_USBCMD &= ~USBCMD_RUN;
381 restore_irq(oldlevel);
394 382
383#ifdef USB_PORTSCX_PHY_TYPE
384 /* If a PHY type is specified, set it now */
385 REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | USB_PORTSCX_PHY_TYPE;
386#endif
395 sleep(HZ/20); 387 sleep(HZ/20);
396 REG_USBCMD |= USBCMD_CTRL_RESET; 388 REG_USBCMD |= USBCMD_CTRL_RESET;
397 while (REG_USBCMD & USBCMD_CTRL_RESET); 389 while (REG_USBCMD & USBCMD_CTRL_RESET);
390}
398 391
399 /* Set to ULPI */ 392/* One-time driver startup init */
400 REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_ULPI; 393void usb_drv_startup(void)
401 sleep(HZ/10); 394{
402#endif
403
404 /* Initialize all the signal objects once */ 395 /* Initialize all the signal objects once */
405 int i; 396 int i;
406 for(i=0;i<NUM_ENDPOINTS*2;i++) { 397 for(i=0;i<USB_NUM_ENDPOINTS*2;i++) {
407 wakeup_init(&transfer_completion_signal[i]); 398 wakeup_init(&transfer_completion_signal[i]);
408 } 399 }
409} 400}
410 401
411/* manual: 32.14.1 Device Controller Initialization */ 402/* manual: 32.14.1 Device Controller Initialization */
412void usb_drv_init(void) 403static void _usb_drv_init(bool attach)
413{ 404{
414 REG_USBCMD &= ~USBCMD_RUN; 405 usb_drv_reset();
415 sleep(HZ/20);
416 REG_USBCMD |= USBCMD_CTRL_RESET;
417 while (REG_USBCMD & USBCMD_CTRL_RESET);
418
419 406
420 REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; 407 REG_USBMODE = USBMODE_CTRL_MODE_DEVICE;
421 408
422#if CONFIG_CPU == IMX31L
423 /* Set to ULPI */
424 REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_ULPI;
425#endif
426
427#ifdef USB_NO_HIGH_SPEED 409#ifdef USB_NO_HIGH_SPEED
428 /* Force device to full speed */ 410 /* Force device to full speed */
429 /* See 32.9.5.9.2 */ 411 /* See 32.9.5.9.2 */
@@ -436,69 +418,76 @@ void usb_drv_init(void)
436 REG_ENDPOINTLISTADDR = (unsigned int)qh_array; 418 REG_ENDPOINTLISTADDR = (unsigned int)qh_array;
437 REG_DEVICEADDR = 0; 419 REG_DEVICEADDR = 0;
438 420
439 /* enable USB interrupts */ 421#ifdef USB_DETECT_BY_DRV
440 REG_USBINTR = 422 if (!attach) {
441 USBINTR_INT_EN | 423 /* enable RESET interrupt */
442 USBINTR_ERR_INT_EN | 424 REG_USBINTR = USBINTR_RESET_EN;
443 USBINTR_PTC_DETECT_EN | 425 }
444 USBINTR_RESET_EN | 426 else
445 USBINTR_SYS_ERR_EN;
446
447#if CONFIG_CPU == IMX31L
448 avic_enable_int(USB_OTG, IRQ, 7, USB_OTG_HANDLER);
449#else
450 /* enable USB IRQ in CPU */
451 CPU_INT_EN = USB_MASK;
452#endif 427#endif
428 {
429 /* enable USB interrupts */
430 REG_USBINTR =
431 USBINTR_INT_EN |
432 USBINTR_ERR_INT_EN |
433 USBINTR_PTC_DETECT_EN |
434 USBINTR_RESET_EN;
435 }
436
437 usb_drv_int_enable(true);
453 438
454 /* go go go */ 439 /* go go go */
455 REG_USBCMD |= USBCMD_RUN; 440 REG_USBCMD |= USBCMD_RUN;
456 441
457
458 logf("usb_drv_init() finished"); 442 logf("usb_drv_init() finished");
459 logf("usb id %x", REG_ID); 443 logf("usb id %x", REG_ID);
460 logf("usb dciversion %x", REG_DCIVERSION); 444 logf("usb dciversion %x", REG_DCIVERSION);
461 logf("usb dccparams %x", REG_DCCPARAMS); 445 logf("usb dccparams %x", REG_DCCPARAMS);
462 446
463 /* now a bus reset will occur. see bus_reset() */ 447 /* now a bus reset will occur. see bus_reset() */
448 (void)attach;
464} 449}
465 450
466void usb_drv_exit(void) 451/** With USB_DETECT_BY_DRV, attach is distinct from init, otherwise eqivalent. **/
452
453/* USB_DETECT_BY_DRV - enable bus reset detection only
454 * else fully enable driver */
455void usb_drv_init(void)
467{ 456{
468 /* disable interrupts */ 457 _usb_drv_init(false);
469 REG_USBINTR = 0; 458}
470 459
471 /* stop usb controller */ 460#ifdef USB_DETECT_BY_DRV
472 REG_USBCMD &= ~USBCMD_RUN; 461/* fully enable driver */
462void usb_drv_attach(void)
463{
464 sleep(HZ/10);
465 _usb_drv_init(true);
466}
467#endif /* USB_DETECT_BY_DRV */
468
469void usb_drv_exit(void)
470{
471 usb_drv_stop();
473 472
474 /* TODO : is one of these needed to save power ? 473 /* TODO : is one of these needed to save power ?
475 REG_PORTSC1 |= PORTSCX_PHY_LOW_POWER_SPD; 474 REG_PORTSC1 |= PORTSCX_PHY_LOW_POWER_SPD;
476 REG_USBCMD |= USBCMD_CTRL_RESET; 475 REG_USBCMD |= USBCMD_CTRL_RESET;
477 */ 476 */
478 477
479#if CONFIG_CPU == IMX31L 478 usb_drv_int_enable(false);
480 avic_disable_int(USB_OTG);
481#else
482 CPU_INT_DIS = USB_MASK;
483#endif
484
485 cancel_cpu_boost();
486} 479}
487 480
488#if CONFIG_CPU == IMX31L
489static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void)
490#else
491void usb_drv_int(void) 481void usb_drv_int(void)
492#endif
493{ 482{
494 unsigned int status = REG_USBSTS; 483 unsigned int usbintr = REG_USBINTR; /* Only watch enabled ints */
484 unsigned int status = REG_USBSTS & usbintr;
495 485
496#if 0 486#if 0
497 if (status & USBSTS_INT) logf("int: usb ioc"); 487 if (status & USBSTS_INT) logf("int: usb ioc");
498 if (status & USBSTS_ERR) logf("int: usb err"); 488 if (status & USBSTS_ERR) logf("int: usb err");
499 if (status & USBSTS_PORT_CHANGE) logf("int: portchange"); 489 if (status & USBSTS_PORT_CHANGE) logf("int: portchange");
500 if (status & USBSTS_RESET) logf("int: reset"); 490 if (status & USBSTS_RESET) logf("int: reset");
501 if (status & USBSTS_SYS_ERR) logf("int: syserr");
502#endif 491#endif
503 492
504 /* usb transaction interrupt */ 493 /* usb transaction interrupt */
@@ -523,8 +512,18 @@ void usb_drv_int(void)
523 /* reset interrupt */ 512 /* reset interrupt */
524 if (status & USBSTS_RESET) { 513 if (status & USBSTS_RESET) {
525 REG_USBSTS = USBSTS_RESET; 514 REG_USBSTS = USBSTS_RESET;
526 bus_reset(); 515#ifdef USB_DETECT_BY_DRV
527 usb_core_bus_reset(); /* tell mom */ 516 if (UNLIKELY(usbintr == USBINTR_RESET_EN)) {
517 /* USB detected - detach and inform */
518 usb_drv_stop();
519 usb_drv_usb_detect_event();
520 }
521 else
522#endif
523 {
524 bus_reset();
525 usb_core_bus_reset(); /* tell mom */
526 }
528 } 527 }
529 528
530 /* port change */ 529 /* port change */
@@ -588,7 +587,14 @@ int usb_drv_port_speed(void)
588 587
589bool usb_drv_connected(void) 588bool usb_drv_connected(void)
590{ 589{
591 return ((REG_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) !=0); 590 return (REG_PORTSC1 &
591 (PORTSCX_PORT_SUSPEND | PORTSCX_CURRENT_CONNECT_STATUS))
592 == PORTSCX_CURRENT_CONNECT_STATUS;
593}
594
595bool usb_drv_powered(void)
596{
597 return (REG_OTGSC & OTGSC_B_SESSION_VALID) ? true : false;
592} 598}
593 599
594void usb_drv_set_address(int address) 600void usb_drv_set_address(int address)
@@ -628,10 +634,7 @@ void usb_drv_set_test_mode(int mode)
628 REG_PORTSC1 |= PORTSCX_PTC_FORCE_EN; 634 REG_PORTSC1 |= PORTSCX_PTC_FORCE_EN;
629 break; 635 break;
630 } 636 }
631 REG_USBCMD &= ~USBCMD_RUN; 637 usb_drv_reset();
632 sleep(HZ/20);
633 REG_USBCMD |= USBCMD_CTRL_RESET;
634 while (REG_USBCMD & USBCMD_CTRL_RESET);
635 REG_USBCMD |= USBCMD_RUN; 638 REG_USBCMD |= USBCMD_RUN;
636} 639}
637 640
@@ -735,7 +738,7 @@ void usb_drv_cancel_all_transfers(void)
735 while (REG_ENDPTFLUSH); 738 while (REG_ENDPTFLUSH);
736 739
737 memset(td_array, 0, sizeof td_array); 740 memset(td_array, 0, sizeof td_array);
738 for(i=0;i<NUM_ENDPOINTS*2;i++) { 741 for(i=0;i<USB_NUM_ENDPOINTS*2;i++) {
739 if(qh_array[i].wait) { 742 if(qh_array[i].wait) {
740 qh_array[i].wait=0; 743 qh_array[i].wait=0;
741 qh_array[i].status=DTD_STATUS_HALTED; 744 qh_array[i].status=DTD_STATUS_HALTED;
@@ -750,7 +753,7 @@ int usb_drv_request_endpoint(int dir)
750 753
751 bit=(dir & USB_DIR_IN)? 2:1; 754 bit=(dir & USB_DIR_IN)? 2:1;
752 755
753 for (i=1; i < NUM_ENDPOINTS; i++) { 756 for (i=1; i < USB_NUM_ENDPOINTS; i++) {
754 if((ep_allocation[i] & bit)!=0) 757 if((ep_allocation[i] & bit)!=0)
755 continue; 758 continue;
756 ep_allocation[i] |= bit; 759 ep_allocation[i] |= bit;
@@ -819,7 +822,7 @@ static void transfer_completed(void)
819 unsigned int mask = REG_ENDPTCOMPLETE; 822 unsigned int mask = REG_ENDPTCOMPLETE;
820 REG_ENDPTCOMPLETE = mask; 823 REG_ENDPTCOMPLETE = mask;
821 824
822 for (ep=0; ep<NUM_ENDPOINTS; ep++) { 825 for (ep=0; ep<USB_NUM_ENDPOINTS; ep++) {
823 int dir; 826 int dir;
824 for (dir=0; dir<2; dir++) { 827 for (dir=0; dir<2; dir++) {
825 int pipe = ep * 2 + dir; 828 int pipe = ep * 2 + dir;
@@ -869,13 +872,8 @@ static void bus_reset(void)
869 logf("usb: double reset"); 872 logf("usb: double reset");
870 return; 873 return;
871 } 874 }
872#if CONFIG_CPU == IMX31L 875
873 int x;
874 for (x = 0; x < 30000; x++)
875 asm volatile ("");
876#else
877 udelay(100); 876 udelay(100);
878#endif
879 } 877 }
880 if (REG_ENDPTPRIME) { 878 if (REG_ENDPTPRIME) {
881 logf("usb: short reset timeout"); 879 logf("usb: short reset timeout");
@@ -917,7 +915,7 @@ static void init_bulk_queue_heads(void)
917 /* TODO: this should take ep_allocation into account */ 915 /* TODO: this should take ep_allocation into account */
918 916
919 /*** bulk ***/ 917 /*** bulk ***/
920 for(i=1;i<NUM_ENDPOINTS;i++) { 918 for(i=1;i<USB_NUM_ENDPOINTS;i++) {
921 qh_array[i*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; 919 qh_array[i*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
922 qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; 920 qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE;
923 qh_array[i*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; 921 qh_array[i*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
@@ -930,7 +928,7 @@ static void init_endpoints(void)
930 int i; 928 int i;
931 /* TODO: this should take ep_allocation into account */ 929 /* TODO: this should take ep_allocation into account */
932 /* bulk */ 930 /* bulk */
933 for(i=1;i<NUM_ENDPOINTS;i++) { 931 for(i=1;i<USB_NUM_ENDPOINTS;i++) {
934 REG_ENDPTCTRL(i) = 932 REG_ENDPTCTRL(i) =
935 EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | 933 EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE |
936 EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | 934 EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE |