uboot/drivers/usb/host/xhci-fsl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2015,2016 Freescale Semiconductor, Inc.
   4 *
   5 * FSL USB HOST xHCI Controller
   6 *
   7 * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
   8 */
   9
  10#include <common.h>
  11#include <usb.h>
  12#include <linux/errno.h>
  13#include <linux/compat.h>
  14#include <linux/usb/xhci-fsl.h>
  15#include <linux/usb/dwc3.h>
  16#include "xhci.h"
  17#include <fsl_errata.h>
  18#include <fsl_usb.h>
  19#include <dm.h>
  20
  21/* Declare global data pointer */
  22#if !CONFIG_IS_ENABLED(DM_USB)
  23static struct fsl_xhci fsl_xhci;
  24unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR;
  25#else
  26struct xhci_fsl_priv {
  27        struct xhci_ctrl xhci;
  28        fdt_addr_t hcd_base;
  29        struct fsl_xhci ctx;
  30};
  31#endif
  32
  33__weak int __board_usb_init(int index, enum usb_init_type init)
  34{
  35        return 0;
  36}
  37
  38static int erratum_a008751(void)
  39{
  40#if defined(CONFIG_TARGET_LS2080AQDS) || defined(CONFIG_TARGET_LS2080ARDB) ||\
  41                                        defined(CONFIG_TARGET_LS2080AQDS)
  42        u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
  43        writel(SCFG_USB3PRM1CR_INIT, scfg + SCFG_USB3PRM1CR / 4);
  44        return 0;
  45#endif
  46        return 1;
  47}
  48
  49static void fsl_apply_xhci_errata(void)
  50{
  51        int ret;
  52        if (has_erratum_a008751()) {
  53                ret = erratum_a008751();
  54                if (ret != 0)
  55                        puts("Failed to apply erratum a008751\n");
  56        }
  57}
  58
  59static void fsl_xhci_set_beat_burst_length(struct dwc3 *dwc3_reg)
  60{
  61        clrsetbits_le32(&dwc3_reg->g_sbuscfg0, USB3_ENABLE_BEAT_BURST_MASK,
  62                        USB3_ENABLE_BEAT_BURST);
  63        setbits_le32(&dwc3_reg->g_sbuscfg1, USB3_SET_BEAT_BURST_LIMIT);
  64}
  65
  66static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci)
  67{
  68        int ret = 0;
  69
  70        ret = dwc3_core_init(fsl_xhci->dwc3_reg);
  71        if (ret) {
  72                debug("%s:failed to initialize core\n", __func__);
  73                return ret;
  74        }
  75
  76        /* We are hard-coding DWC3 core to Host Mode */
  77        dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
  78
  79        /* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */
  80        dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT);
  81
  82        /* Change beat burst and outstanding pipelined transfers requests */
  83        fsl_xhci_set_beat_burst_length(fsl_xhci->dwc3_reg);
  84
  85        /*
  86         * A-010151: The dwc3 phy TSMC 28-nm HPM 0.9/1.8 V does not
  87         * reliably support Rx Detect in P3 mode(P3 is the default
  88         * setting). Therefore, some USB3.0 devices may not be detected
  89         * reliably in Super Speed mode. So, USB controller to configure
  90         * USB in P2 mode whenever the Receive Detect feature is required.
  91         * whenever the Receive Detect feature is required.
  92         */
  93        if (has_erratum_a010151())
  94                clrsetbits_le32(&fsl_xhci->dwc3_reg->g_usb3pipectl[0],
  95                                DWC3_GUSB3PIPECTL_DISRXDETP3,
  96                                DWC3_GUSB3PIPECTL_DISRXDETP3);
  97
  98        return ret;
  99}
 100
 101static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci)
 102{
 103        /*
 104         * Currently fsl socs do not support PHY shutdown from
 105         * sw. But this support may be added in future socs.
 106         */
 107        return 0;
 108}
 109
 110#if CONFIG_IS_ENABLED(DM_USB)
 111static int xhci_fsl_probe(struct udevice *dev)
 112{
 113        struct xhci_fsl_priv *priv = dev_get_priv(dev);
 114        struct xhci_hccr *hccr;
 115        struct xhci_hcor *hcor;
 116
 117        int ret = 0;
 118
 119        /*
 120         * Get the base address for XHCI controller from the device node
 121         */
 122        priv->hcd_base = devfdt_get_addr(dev);
 123        if (priv->hcd_base == FDT_ADDR_T_NONE) {
 124                debug("Can't get the XHCI register base address\n");
 125                return -ENXIO;
 126        }
 127        priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base;
 128        priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) +
 129                          DWC3_REG_OFFSET);
 130
 131        fsl_apply_xhci_errata();
 132
 133        ret = fsl_xhci_core_init(&priv->ctx);
 134        if (ret < 0) {
 135                puts("Failed to initialize xhci\n");
 136                return ret;
 137        }
 138
 139        hccr = (struct xhci_hccr *)(priv->ctx.hcd);
 140        hcor = (struct xhci_hcor *)((uintptr_t) hccr
 141                                + HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
 142
 143        debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n",
 144              (uintptr_t)hccr, (uintptr_t)hcor,
 145              (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
 146
 147        return xhci_register(dev, hccr, hcor);
 148}
 149
 150static int xhci_fsl_remove(struct udevice *dev)
 151{
 152        struct xhci_fsl_priv *priv = dev_get_priv(dev);
 153
 154        fsl_xhci_core_exit(&priv->ctx);
 155
 156        return xhci_deregister(dev);
 157}
 158
 159static const struct udevice_id xhci_usb_ids[] = {
 160        { .compatible = "fsl,layerscape-dwc3", },
 161        { }
 162};
 163
 164U_BOOT_DRIVER(xhci_fsl) = {
 165        .name   = "xhci_fsl",
 166        .id     = UCLASS_USB,
 167        .of_match = xhci_usb_ids,
 168        .probe = xhci_fsl_probe,
 169        .remove = xhci_fsl_remove,
 170        .ops    = &xhci_usb_ops,
 171        .platdata_auto_alloc_size = sizeof(struct usb_platdata),
 172        .priv_auto_alloc_size = sizeof(struct xhci_fsl_priv),
 173        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 174};
 175#else
 176int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
 177{
 178        struct fsl_xhci *ctx = &fsl_xhci;
 179        int ret = 0;
 180
 181        ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
 182        ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
 183
 184        ret = board_usb_init(index, USB_INIT_HOST);
 185        if (ret != 0) {
 186                puts("Failed to initialize board for USB\n");
 187                return ret;
 188        }
 189
 190        fsl_apply_xhci_errata();
 191
 192        ret = fsl_xhci_core_init(ctx);
 193        if (ret < 0) {
 194                puts("Failed to initialize xhci\n");
 195                return ret;
 196        }
 197
 198        *hccr = (struct xhci_hccr *)ctx->hcd;
 199        *hcor = (struct xhci_hcor *)((uintptr_t) *hccr
 200                                + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
 201
 202        debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n",
 203              (uintptr_t)*hccr, (uintptr_t)*hcor,
 204              (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
 205
 206        return ret;
 207}
 208
 209void xhci_hcd_stop(int index)
 210{
 211        struct fsl_xhci *ctx = &fsl_xhci;
 212
 213        fsl_xhci_core_exit(ctx);
 214}
 215#endif
 216