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