1 /* 2 * Faraday USB 2.0 EHCI Controller 3 * 4 * (C) Copyright 2010 Faraday Technology 5 * Dante Su <dantesu@faraday-tech.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <asm/io.h> 12 #include <usb.h> 13 #include <usb/fusbh200.h> 14 #include <usb/fotg210.h> 15 16 #include "ehci.h" 17 18 #ifndef CONFIG_USB_EHCI_BASE_LIST 19 #define CONFIG_USB_EHCI_BASE_LIST { CONFIG_USB_EHCI_BASE } 20 #endif 21 22 union ehci_faraday_regs { 23 struct fusbh200_regs usb; 24 struct fotg210_regs otg; 25 }; 26 27 static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs) 28 { 29 return !readl(®s->usb.easstr); 30 } 31 32 /* 33 * Create the appropriate control structures to manage 34 * a new EHCI host controller. 35 */ 36 int ehci_hcd_init(int index, enum usb_init_type init, 37 struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor) 38 { 39 struct ehci_hccr *hccr; 40 struct ehci_hcor *hcor; 41 union ehci_faraday_regs *regs; 42 uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST; 43 44 if (index < 0 || index >= ARRAY_SIZE(base_list)) 45 return -1; 46 regs = (void __iomem *)base_list[index]; 47 hccr = (struct ehci_hccr *)®s->usb.hccr; 48 hcor = (struct ehci_hcor *)®s->usb.hcor; 49 50 if (ehci_is_fotg2xx(regs)) { 51 /* A-device bus reset */ 52 /* ... Power off A-device */ 53 setbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSDROP); 54 /* ... Drop vbus and bus traffic */ 55 clrbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSREQ); 56 mdelay(1); 57 /* ... Power on A-device */ 58 clrbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSDROP); 59 /* ... Drive vbus and bus traffic */ 60 setbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSREQ); 61 mdelay(1); 62 /* Disable OTG & DEV interrupts, triggered at level-high */ 63 writel(IMR_IRQLH | IMR_OTG | IMR_DEV, ®s->otg.imr); 64 /* Clear all interrupt status */ 65 writel(ISR_HOST | ISR_OTG | ISR_DEV, ®s->otg.isr); 66 } else { 67 /* Interrupt=level-high */ 68 setbits_le32(®s->usb.bmcsr, BMCSR_IRQLH); 69 /* VBUS on */ 70 clrbits_le32(®s->usb.bmcsr, BMCSR_VBUS_OFF); 71 /* Disable all interrupts */ 72 writel(0x00, ®s->usb.bmier); 73 writel(0x1f, ®s->usb.bmisr); 74 } 75 76 *ret_hccr = hccr; 77 *ret_hcor = hcor; 78 79 return 0; 80 } 81 82 /* 83 * Destroy the appropriate control structures corresponding 84 * the the EHCI host controller. 85 */ 86 int ehci_hcd_stop(int index) 87 { 88 return 0; 89 } 90 91 /* 92 * This ehci_set_usbmode() overrides the weak function 93 * in "ehci-hcd.c". 94 */ 95 void ehci_set_usbmode(int index) 96 { 97 /* nothing needs to be done */ 98 } 99 100 /* 101 * This ehci_get_port_speed() overrides the weak function 102 * in "ehci-hcd.c". 103 */ 104 int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) 105 { 106 int spd, ret = PORTSC_PSPD_HS; 107 union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10); 108 109 if (ehci_is_fotg2xx(regs)) 110 spd = OTGCSR_SPD(readl(®s->otg.otgcsr)); 111 else 112 spd = BMCSR_SPD(readl(®s->usb.bmcsr)); 113 114 switch (spd) { 115 case 0: /* full speed */ 116 ret = PORTSC_PSPD_FS; 117 break; 118 case 1: /* low speed */ 119 ret = PORTSC_PSPD_LS; 120 break; 121 case 2: /* high speed */ 122 ret = PORTSC_PSPD_HS; 123 break; 124 default: 125 printf("ehci-faraday: invalid device speed\n"); 126 break; 127 } 128 129 return ret; 130 } 131 132 /* 133 * This ehci_get_portsc_register() overrides the weak function 134 * in "ehci-hcd.c". 135 */ 136 uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port) 137 { 138 /* Faraday EHCI has one and only one portsc register */ 139 if (port) { 140 /* Printing the message would cause a scan failure! */ 141 debug("The request port(%d) is not configured\n", port); 142 return NULL; 143 } 144 145 /* Faraday EHCI PORTSC register offset is 0x20 from hcor */ 146 return (uint32_t *)((uint8_t *)hcor + 0x20); 147 } 148