1ba92ee06SRamneek Mehresh /* 2*707c866fSRajesh Bhagat * Copyright 2015,2016 Freescale Semiconductor, Inc. 3ba92ee06SRamneek Mehresh * 4ba92ee06SRamneek Mehresh * FSL USB HOST xHCI Controller 5ba92ee06SRamneek Mehresh * 6ba92ee06SRamneek Mehresh * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com> 7ba92ee06SRamneek Mehresh * 8ba92ee06SRamneek Mehresh * SPDX-License-Identifier: GPL-2.0+ 9ba92ee06SRamneek Mehresh */ 10ba92ee06SRamneek Mehresh 11ba92ee06SRamneek Mehresh #include <common.h> 12ba92ee06SRamneek Mehresh #include <usb.h> 13ba92ee06SRamneek Mehresh #include <asm-generic/errno.h> 14ba92ee06SRamneek Mehresh #include <linux/compat.h> 15ba92ee06SRamneek Mehresh #include <linux/usb/xhci-fsl.h> 16ba92ee06SRamneek Mehresh #include <linux/usb/dwc3.h> 17ba92ee06SRamneek Mehresh #include "xhci.h" 18ef53b8c4SSriram Dash #include <fsl_errata.h> 19ef53b8c4SSriram Dash #include <fsl_usb.h> 20*707c866fSRajesh Bhagat #include <dm.h> 21ba92ee06SRamneek Mehresh 22ba92ee06SRamneek Mehresh /* Declare global data pointer */ 23ba92ee06SRamneek Mehresh DECLARE_GLOBAL_DATA_PTR; 24ba92ee06SRamneek Mehresh 25*707c866fSRajesh Bhagat #ifndef CONFIG_DM_USB 26ba92ee06SRamneek Mehresh static struct fsl_xhci fsl_xhci; 27ba92ee06SRamneek Mehresh unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR; 28*707c866fSRajesh Bhagat #else 29*707c866fSRajesh Bhagat struct xhci_fsl_priv { 30*707c866fSRajesh Bhagat struct xhci_ctrl xhci; 31*707c866fSRajesh Bhagat fdt_addr_t hcd_base; 32*707c866fSRajesh Bhagat struct fsl_xhci ctx; 33*707c866fSRajesh Bhagat }; 34*707c866fSRajesh Bhagat #endif 35ba92ee06SRamneek Mehresh 36ba92ee06SRamneek Mehresh __weak int __board_usb_init(int index, enum usb_init_type init) 37ba92ee06SRamneek Mehresh { 38ba92ee06SRamneek Mehresh return 0; 39ba92ee06SRamneek Mehresh } 40ba92ee06SRamneek Mehresh 41ef53b8c4SSriram Dash static int erratum_a008751(void) 42ef53b8c4SSriram Dash { 43ef53b8c4SSriram Dash #if defined(CONFIG_TARGET_LS2080AQDS) || defined(CONFIG_TARGET_LS2080ARDB) 44ef53b8c4SSriram Dash u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE; 45ef53b8c4SSriram Dash writel(SCFG_USB3PRM1CR_INIT, scfg + SCFG_USB3PRM1CR / 4); 46ef53b8c4SSriram Dash return 0; 47ef53b8c4SSriram Dash #endif 48ef53b8c4SSriram Dash return 1; 49ef53b8c4SSriram Dash } 50ef53b8c4SSriram Dash 51ef53b8c4SSriram Dash static void fsl_apply_xhci_errata(void) 52ef53b8c4SSriram Dash { 53ef53b8c4SSriram Dash int ret; 54ef53b8c4SSriram Dash if (has_erratum_a008751()) { 55ef53b8c4SSriram Dash ret = erratum_a008751(); 56ef53b8c4SSriram Dash if (ret != 0) 57ef53b8c4SSriram Dash puts("Failed to apply erratum a008751\n"); 58ef53b8c4SSriram Dash } 59ef53b8c4SSriram Dash } 60ef53b8c4SSriram Dash 61ba92ee06SRamneek Mehresh static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci) 62ba92ee06SRamneek Mehresh { 63ba92ee06SRamneek Mehresh int ret = 0; 64ba92ee06SRamneek Mehresh 65ba92ee06SRamneek Mehresh ret = dwc3_core_init(fsl_xhci->dwc3_reg); 66ba92ee06SRamneek Mehresh if (ret) { 67ba92ee06SRamneek Mehresh debug("%s:failed to initialize core\n", __func__); 68ba92ee06SRamneek Mehresh return ret; 69ba92ee06SRamneek Mehresh } 70ba92ee06SRamneek Mehresh 71ba92ee06SRamneek Mehresh /* We are hard-coding DWC3 core to Host Mode */ 72ba92ee06SRamneek Mehresh dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 73ba92ee06SRamneek Mehresh 74667f4dd9SNikhil Badola /* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */ 75667f4dd9SNikhil Badola dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT); 76667f4dd9SNikhil Badola 77ba92ee06SRamneek Mehresh return ret; 78ba92ee06SRamneek Mehresh } 79ba92ee06SRamneek Mehresh 80ba92ee06SRamneek Mehresh static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci) 81ba92ee06SRamneek Mehresh { 82ba92ee06SRamneek Mehresh /* 83ba92ee06SRamneek Mehresh * Currently fsl socs do not support PHY shutdown from 84ba92ee06SRamneek Mehresh * sw. But this support may be added in future socs. 85ba92ee06SRamneek Mehresh */ 86ba92ee06SRamneek Mehresh return 0; 87ba92ee06SRamneek Mehresh } 88ba92ee06SRamneek Mehresh 89*707c866fSRajesh Bhagat #ifdef CONFIG_DM_USB 90*707c866fSRajesh Bhagat static int xhci_fsl_probe(struct udevice *dev) 91*707c866fSRajesh Bhagat { 92*707c866fSRajesh Bhagat struct xhci_fsl_priv *priv = dev_get_priv(dev); 93*707c866fSRajesh Bhagat struct xhci_hccr *hccr; 94*707c866fSRajesh Bhagat struct xhci_hcor *hcor; 95*707c866fSRajesh Bhagat 96*707c866fSRajesh Bhagat int ret = 0; 97*707c866fSRajesh Bhagat 98*707c866fSRajesh Bhagat /* 99*707c866fSRajesh Bhagat * Get the base address for XHCI controller from the device node 100*707c866fSRajesh Bhagat */ 101*707c866fSRajesh Bhagat priv->hcd_base = dev_get_addr(dev); 102*707c866fSRajesh Bhagat if (priv->hcd_base == FDT_ADDR_T_NONE) { 103*707c866fSRajesh Bhagat debug("Can't get the XHCI register base address\n"); 104*707c866fSRajesh Bhagat return -ENXIO; 105*707c866fSRajesh Bhagat } 106*707c866fSRajesh Bhagat priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base; 107*707c866fSRajesh Bhagat priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) + 108*707c866fSRajesh Bhagat DWC3_REG_OFFSET); 109*707c866fSRajesh Bhagat 110*707c866fSRajesh Bhagat fsl_apply_xhci_errata(); 111*707c866fSRajesh Bhagat 112*707c866fSRajesh Bhagat ret = fsl_xhci_core_init(&priv->ctx); 113*707c866fSRajesh Bhagat if (ret < 0) { 114*707c866fSRajesh Bhagat puts("Failed to initialize xhci\n"); 115*707c866fSRajesh Bhagat return ret; 116*707c866fSRajesh Bhagat } 117*707c866fSRajesh Bhagat 118*707c866fSRajesh Bhagat hccr = (struct xhci_hccr *)(priv->ctx.hcd); 119*707c866fSRajesh Bhagat hcor = (struct xhci_hcor *)((uintptr_t) hccr 120*707c866fSRajesh Bhagat + HC_LENGTH(xhci_readl(&hccr->cr_capbase))); 121*707c866fSRajesh Bhagat 122*707c866fSRajesh Bhagat debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n", 123*707c866fSRajesh Bhagat (uintptr_t)hccr, (uintptr_t)hcor, 124*707c866fSRajesh Bhagat (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase))); 125*707c866fSRajesh Bhagat 126*707c866fSRajesh Bhagat return xhci_register(dev, hccr, hcor); 127*707c866fSRajesh Bhagat } 128*707c866fSRajesh Bhagat 129*707c866fSRajesh Bhagat static int xhci_fsl_remove(struct udevice *dev) 130*707c866fSRajesh Bhagat { 131*707c866fSRajesh Bhagat struct xhci_fsl_priv *priv = dev_get_priv(dev); 132*707c866fSRajesh Bhagat int ret; 133*707c866fSRajesh Bhagat 134*707c866fSRajesh Bhagat fsl_xhci_core_exit(&priv->ctx); 135*707c866fSRajesh Bhagat 136*707c866fSRajesh Bhagat ret = xhci_deregister(dev); 137*707c866fSRajesh Bhagat if (ret) 138*707c866fSRajesh Bhagat return ret; 139*707c866fSRajesh Bhagat 140*707c866fSRajesh Bhagat return 0; 141*707c866fSRajesh Bhagat } 142*707c866fSRajesh Bhagat 143*707c866fSRajesh Bhagat static const struct udevice_id xhci_usb_ids[] = { 144*707c866fSRajesh Bhagat { .compatible = "fsl,layerscape-dwc3", }, 145*707c866fSRajesh Bhagat { } 146*707c866fSRajesh Bhagat }; 147*707c866fSRajesh Bhagat 148*707c866fSRajesh Bhagat U_BOOT_DRIVER(xhci_fsl) = { 149*707c866fSRajesh Bhagat .name = "xhci_fsl", 150*707c866fSRajesh Bhagat .id = UCLASS_USB, 151*707c866fSRajesh Bhagat .of_match = xhci_usb_ids, 152*707c866fSRajesh Bhagat .probe = xhci_fsl_probe, 153*707c866fSRajesh Bhagat .remove = xhci_fsl_remove, 154*707c866fSRajesh Bhagat .ops = &xhci_usb_ops, 155*707c866fSRajesh Bhagat .platdata_auto_alloc_size = sizeof(struct usb_platdata), 156*707c866fSRajesh Bhagat .priv_auto_alloc_size = sizeof(struct xhci_fsl_priv), 157*707c866fSRajesh Bhagat .flags = DM_FLAG_ALLOC_PRIV_DMA, 158*707c866fSRajesh Bhagat }; 159*707c866fSRajesh Bhagat #else 160ba92ee06SRamneek Mehresh int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) 161ba92ee06SRamneek Mehresh { 162ba92ee06SRamneek Mehresh struct fsl_xhci *ctx = &fsl_xhci; 163ba92ee06SRamneek Mehresh int ret = 0; 164ba92ee06SRamneek Mehresh 165ba92ee06SRamneek Mehresh ctx->hcd = (struct xhci_hccr *)ctr_addr[index]; 166ba92ee06SRamneek Mehresh ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 167ba92ee06SRamneek Mehresh 168ba92ee06SRamneek Mehresh ret = board_usb_init(index, USB_INIT_HOST); 169ba92ee06SRamneek Mehresh if (ret != 0) { 170ba92ee06SRamneek Mehresh puts("Failed to initialize board for USB\n"); 171ba92ee06SRamneek Mehresh return ret; 172ba92ee06SRamneek Mehresh } 173ba92ee06SRamneek Mehresh 174ef53b8c4SSriram Dash fsl_apply_xhci_errata(); 175ef53b8c4SSriram Dash 176ba92ee06SRamneek Mehresh ret = fsl_xhci_core_init(ctx); 177ba92ee06SRamneek Mehresh if (ret < 0) { 178ba92ee06SRamneek Mehresh puts("Failed to initialize xhci\n"); 179ba92ee06SRamneek Mehresh return ret; 180ba92ee06SRamneek Mehresh } 181ba92ee06SRamneek Mehresh 182ba92ee06SRamneek Mehresh *hccr = (struct xhci_hccr *)ctx->hcd; 1837e5a32fcSNikhil Badola *hcor = (struct xhci_hcor *)((uintptr_t) *hccr 184ba92ee06SRamneek Mehresh + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 185ba92ee06SRamneek Mehresh 1867e5a32fcSNikhil Badola debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n", 1877e5a32fcSNikhil Badola (uintptr_t)*hccr, (uintptr_t)*hcor, 1887e5a32fcSNikhil Badola (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 189ba92ee06SRamneek Mehresh 190ba92ee06SRamneek Mehresh return ret; 191ba92ee06SRamneek Mehresh } 192ba92ee06SRamneek Mehresh 193ba92ee06SRamneek Mehresh void xhci_hcd_stop(int index) 194ba92ee06SRamneek Mehresh { 195ba92ee06SRamneek Mehresh struct fsl_xhci *ctx = &fsl_xhci; 196ba92ee06SRamneek Mehresh 197ba92ee06SRamneek Mehresh fsl_xhci_core_exit(ctx); 198ba92ee06SRamneek Mehresh } 199*707c866fSRajesh Bhagat #endif 200