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