1ba92ee06SRamneek Mehresh /* 2707c866fSRajesh 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> 135d97dff0SMasahiro Yamada #include <linux/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> 20707c866fSRajesh Bhagat #include <dm.h> 21ba92ee06SRamneek Mehresh 22ba92ee06SRamneek Mehresh /* Declare global data pointer */ 23ba92ee06SRamneek Mehresh DECLARE_GLOBAL_DATA_PTR; 24ba92ee06SRamneek Mehresh 25707c866fSRajesh Bhagat #ifndef CONFIG_DM_USB 26ba92ee06SRamneek Mehresh static struct fsl_xhci fsl_xhci; 27ba92ee06SRamneek Mehresh unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR; 28707c866fSRajesh Bhagat #else 29707c866fSRajesh Bhagat struct xhci_fsl_priv { 30707c866fSRajesh Bhagat struct xhci_ctrl xhci; 31707c866fSRajesh Bhagat fdt_addr_t hcd_base; 32707c866fSRajesh Bhagat struct fsl_xhci ctx; 33707c866fSRajesh Bhagat }; 34707c866fSRajesh 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 61*e915716aSSriram Dash static void fsl_xhci_set_beat_burst_length(struct dwc3 *dwc3_reg) 62*e915716aSSriram Dash { 63*e915716aSSriram Dash clrsetbits_le32(&dwc3_reg->g_sbuscfg0, USB3_ENABLE_BEAT_BURST_MASK, 64*e915716aSSriram Dash USB3_ENABLE_BEAT_BURST); 65*e915716aSSriram Dash setbits_le32(&dwc3_reg->g_sbuscfg1, USB3_SET_BEAT_BURST_LIMIT); 66*e915716aSSriram Dash } 67*e915716aSSriram Dash 68ba92ee06SRamneek Mehresh static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci) 69ba92ee06SRamneek Mehresh { 70ba92ee06SRamneek Mehresh int ret = 0; 71ba92ee06SRamneek Mehresh 72ba92ee06SRamneek Mehresh ret = dwc3_core_init(fsl_xhci->dwc3_reg); 73ba92ee06SRamneek Mehresh if (ret) { 74ba92ee06SRamneek Mehresh debug("%s:failed to initialize core\n", __func__); 75ba92ee06SRamneek Mehresh return ret; 76ba92ee06SRamneek Mehresh } 77ba92ee06SRamneek Mehresh 78ba92ee06SRamneek Mehresh /* We are hard-coding DWC3 core to Host Mode */ 79ba92ee06SRamneek Mehresh dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 80ba92ee06SRamneek Mehresh 81667f4dd9SNikhil Badola /* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */ 82667f4dd9SNikhil Badola dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT); 83667f4dd9SNikhil Badola 84*e915716aSSriram Dash /* Change beat burst and outstanding pipelined transfers requests */ 85*e915716aSSriram Dash fsl_xhci_set_beat_burst_length(fsl_xhci->dwc3_reg); 86*e915716aSSriram Dash 87ba92ee06SRamneek Mehresh return ret; 88ba92ee06SRamneek Mehresh } 89ba92ee06SRamneek Mehresh 90ba92ee06SRamneek Mehresh static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci) 91ba92ee06SRamneek Mehresh { 92ba92ee06SRamneek Mehresh /* 93ba92ee06SRamneek Mehresh * Currently fsl socs do not support PHY shutdown from 94ba92ee06SRamneek Mehresh * sw. But this support may be added in future socs. 95ba92ee06SRamneek Mehresh */ 96ba92ee06SRamneek Mehresh return 0; 97ba92ee06SRamneek Mehresh } 98ba92ee06SRamneek Mehresh 99707c866fSRajesh Bhagat #ifdef CONFIG_DM_USB 100707c866fSRajesh Bhagat static int xhci_fsl_probe(struct udevice *dev) 101707c866fSRajesh Bhagat { 102707c866fSRajesh Bhagat struct xhci_fsl_priv *priv = dev_get_priv(dev); 103707c866fSRajesh Bhagat struct xhci_hccr *hccr; 104707c866fSRajesh Bhagat struct xhci_hcor *hcor; 105707c866fSRajesh Bhagat 106707c866fSRajesh Bhagat int ret = 0; 107707c866fSRajesh Bhagat 108707c866fSRajesh Bhagat /* 109707c866fSRajesh Bhagat * Get the base address for XHCI controller from the device node 110707c866fSRajesh Bhagat */ 111707c866fSRajesh Bhagat priv->hcd_base = dev_get_addr(dev); 112707c866fSRajesh Bhagat if (priv->hcd_base == FDT_ADDR_T_NONE) { 113707c866fSRajesh Bhagat debug("Can't get the XHCI register base address\n"); 114707c866fSRajesh Bhagat return -ENXIO; 115707c866fSRajesh Bhagat } 116707c866fSRajesh Bhagat priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base; 117707c866fSRajesh Bhagat priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) + 118707c866fSRajesh Bhagat DWC3_REG_OFFSET); 119707c866fSRajesh Bhagat 120707c866fSRajesh Bhagat fsl_apply_xhci_errata(); 121707c866fSRajesh Bhagat 122707c866fSRajesh Bhagat ret = fsl_xhci_core_init(&priv->ctx); 123707c866fSRajesh Bhagat if (ret < 0) { 124707c866fSRajesh Bhagat puts("Failed to initialize xhci\n"); 125707c866fSRajesh Bhagat return ret; 126707c866fSRajesh Bhagat } 127707c866fSRajesh Bhagat 128707c866fSRajesh Bhagat hccr = (struct xhci_hccr *)(priv->ctx.hcd); 129707c866fSRajesh Bhagat hcor = (struct xhci_hcor *)((uintptr_t) hccr 130707c866fSRajesh Bhagat + HC_LENGTH(xhci_readl(&hccr->cr_capbase))); 131707c866fSRajesh Bhagat 132707c866fSRajesh Bhagat debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n", 133707c866fSRajesh Bhagat (uintptr_t)hccr, (uintptr_t)hcor, 134707c866fSRajesh Bhagat (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase))); 135707c866fSRajesh Bhagat 136707c866fSRajesh Bhagat return xhci_register(dev, hccr, hcor); 137707c866fSRajesh Bhagat } 138707c866fSRajesh Bhagat 139707c866fSRajesh Bhagat static int xhci_fsl_remove(struct udevice *dev) 140707c866fSRajesh Bhagat { 141707c866fSRajesh Bhagat struct xhci_fsl_priv *priv = dev_get_priv(dev); 142707c866fSRajesh Bhagat 143707c866fSRajesh Bhagat fsl_xhci_core_exit(&priv->ctx); 144707c866fSRajesh Bhagat 1458319aeb1SMasahiro Yamada return xhci_deregister(dev); 146707c866fSRajesh Bhagat } 147707c866fSRajesh Bhagat 148707c866fSRajesh Bhagat static const struct udevice_id xhci_usb_ids[] = { 149707c866fSRajesh Bhagat { .compatible = "fsl,layerscape-dwc3", }, 150707c866fSRajesh Bhagat { } 151707c866fSRajesh Bhagat }; 152707c866fSRajesh Bhagat 153707c866fSRajesh Bhagat U_BOOT_DRIVER(xhci_fsl) = { 154707c866fSRajesh Bhagat .name = "xhci_fsl", 155707c866fSRajesh Bhagat .id = UCLASS_USB, 156707c866fSRajesh Bhagat .of_match = xhci_usb_ids, 157707c866fSRajesh Bhagat .probe = xhci_fsl_probe, 158707c866fSRajesh Bhagat .remove = xhci_fsl_remove, 159707c866fSRajesh Bhagat .ops = &xhci_usb_ops, 160707c866fSRajesh Bhagat .platdata_auto_alloc_size = sizeof(struct usb_platdata), 161707c866fSRajesh Bhagat .priv_auto_alloc_size = sizeof(struct xhci_fsl_priv), 162707c866fSRajesh Bhagat .flags = DM_FLAG_ALLOC_PRIV_DMA, 163707c866fSRajesh Bhagat }; 164707c866fSRajesh Bhagat #else 165ba92ee06SRamneek Mehresh int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) 166ba92ee06SRamneek Mehresh { 167ba92ee06SRamneek Mehresh struct fsl_xhci *ctx = &fsl_xhci; 168ba92ee06SRamneek Mehresh int ret = 0; 169ba92ee06SRamneek Mehresh 170ba92ee06SRamneek Mehresh ctx->hcd = (struct xhci_hccr *)ctr_addr[index]; 171ba92ee06SRamneek Mehresh ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 172ba92ee06SRamneek Mehresh 173ba92ee06SRamneek Mehresh ret = board_usb_init(index, USB_INIT_HOST); 174ba92ee06SRamneek Mehresh if (ret != 0) { 175ba92ee06SRamneek Mehresh puts("Failed to initialize board for USB\n"); 176ba92ee06SRamneek Mehresh return ret; 177ba92ee06SRamneek Mehresh } 178ba92ee06SRamneek Mehresh 179ef53b8c4SSriram Dash fsl_apply_xhci_errata(); 180ef53b8c4SSriram Dash 181ba92ee06SRamneek Mehresh ret = fsl_xhci_core_init(ctx); 182ba92ee06SRamneek Mehresh if (ret < 0) { 183ba92ee06SRamneek Mehresh puts("Failed to initialize xhci\n"); 184ba92ee06SRamneek Mehresh return ret; 185ba92ee06SRamneek Mehresh } 186ba92ee06SRamneek Mehresh 187ba92ee06SRamneek Mehresh *hccr = (struct xhci_hccr *)ctx->hcd; 1887e5a32fcSNikhil Badola *hcor = (struct xhci_hcor *)((uintptr_t) *hccr 189ba92ee06SRamneek Mehresh + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 190ba92ee06SRamneek Mehresh 1917e5a32fcSNikhil Badola debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n", 1927e5a32fcSNikhil Badola (uintptr_t)*hccr, (uintptr_t)*hcor, 1937e5a32fcSNikhil Badola (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 194ba92ee06SRamneek Mehresh 195ba92ee06SRamneek Mehresh return ret; 196ba92ee06SRamneek Mehresh } 197ba92ee06SRamneek Mehresh 198ba92ee06SRamneek Mehresh void xhci_hcd_stop(int index) 199ba92ee06SRamneek Mehresh { 200ba92ee06SRamneek Mehresh struct fsl_xhci *ctx = &fsl_xhci; 201ba92ee06SRamneek Mehresh 202ba92ee06SRamneek Mehresh fsl_xhci_core_exit(ctx); 203ba92ee06SRamneek Mehresh } 204707c866fSRajesh Bhagat #endif 205