1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2016 Rockchip, Inc. 4 * Authors: Daniel Meng <daniel.meng@rock-chips.com> 5 */ 6 #include <common.h> 7 #include <dm.h> 8 #include <malloc.h> 9 #include <usb.h> 10 #include <watchdog.h> 11 #include <linux/errno.h> 12 #include <linux/compat.h> 13 #include <linux/usb/dwc3.h> 14 #include <power/regulator.h> 15 16 #include "xhci.h" 17 18 struct rockchip_xhci_platdata { 19 fdt_addr_t hcd_base; 20 struct udevice *vbus_supply; 21 }; 22 23 /* 24 * Contains pointers to register base addresses 25 * for the usb controller. 26 */ 27 struct rockchip_xhci { 28 struct usb_platdata usb_plat; 29 struct xhci_ctrl ctrl; 30 struct xhci_hccr *hcd; 31 struct dwc3 *dwc3_reg; 32 }; 33 34 static int xhci_usb_ofdata_to_platdata(struct udevice *dev) 35 { 36 struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); 37 int ret = 0; 38 39 /* 40 * Get the base address for XHCI controller from the device node 41 */ 42 plat->hcd_base = dev_read_addr(dev); 43 if (plat->hcd_base == FDT_ADDR_T_NONE) { 44 pr_err("Can't get the XHCI register base address\n"); 45 return -ENXIO; 46 } 47 48 /* Vbus regulator */ 49 ret = device_get_supply_regulator(dev, "vbus-supply", 50 &plat->vbus_supply); 51 if (ret) 52 debug("Can't get VBus regulator!\n"); 53 54 return 0; 55 } 56 57 /* 58 * rockchip_dwc3_phy_setup() - Configure USB PHY Interface of DWC3 Core 59 * @dwc: Pointer to our controller context structure 60 * @dev: Pointer to ulcass device 61 */ 62 static void rockchip_dwc3_phy_setup(struct dwc3 *dwc3_reg, 63 struct udevice *dev) 64 { 65 u32 reg; 66 u32 utmi_bits; 67 68 /* Set dwc3 usb2 phy config */ 69 reg = readl(&dwc3_reg->g_usb2phycfg[0]); 70 71 if (dev_read_bool(dev, "snps,dis-enblslpm-quirk")) 72 reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; 73 74 utmi_bits = dev_read_u32_default(dev, "snps,phyif-utmi-bits", -1); 75 if (utmi_bits == 16) { 76 reg |= DWC3_GUSB2PHYCFG_PHYIF; 77 reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK; 78 reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT; 79 } else if (utmi_bits == 8) { 80 reg &= ~DWC3_GUSB2PHYCFG_PHYIF; 81 reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK; 82 reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_8BIT; 83 } 84 85 if (dev_read_bool(dev, "snps,dis-u2-freeclk-exists-quirk")) 86 reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; 87 88 if (dev_read_bool(dev, "snps,dis-u2-susphy-quirk")) 89 reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 90 91 writel(reg, &dwc3_reg->g_usb2phycfg[0]); 92 } 93 94 static int rockchip_xhci_core_init(struct rockchip_xhci *rkxhci, 95 struct udevice *dev) 96 { 97 int ret; 98 99 ret = dwc3_core_init(rkxhci->dwc3_reg); 100 if (ret) { 101 pr_err("failed to initialize core\n"); 102 return ret; 103 } 104 105 rockchip_dwc3_phy_setup(rkxhci->dwc3_reg, dev); 106 107 /* We are hard-coding DWC3 core to Host Mode */ 108 dwc3_set_mode(rkxhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 109 110 return 0; 111 } 112 113 static int rockchip_xhci_core_exit(struct rockchip_xhci *rkxhci) 114 { 115 return 0; 116 } 117 118 static int xhci_usb_probe(struct udevice *dev) 119 { 120 struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); 121 struct rockchip_xhci *ctx = dev_get_priv(dev); 122 struct xhci_hcor *hcor; 123 int ret; 124 125 ctx->hcd = (struct xhci_hccr *)plat->hcd_base; 126 ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 127 hcor = (struct xhci_hcor *)((uint64_t)ctx->hcd + 128 HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); 129 130 if (plat->vbus_supply) { 131 ret = regulator_set_enable(plat->vbus_supply, true); 132 if (ret) { 133 pr_err("XHCI: failed to set VBus supply\n"); 134 return ret; 135 } 136 } 137 138 ret = rockchip_xhci_core_init(ctx, dev); 139 if (ret) { 140 pr_err("XHCI: failed to initialize controller\n"); 141 return ret; 142 } 143 144 return xhci_register(dev, ctx->hcd, hcor); 145 } 146 147 static int xhci_usb_remove(struct udevice *dev) 148 { 149 struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); 150 struct rockchip_xhci *ctx = dev_get_priv(dev); 151 int ret; 152 153 ret = xhci_deregister(dev); 154 if (ret) 155 return ret; 156 ret = rockchip_xhci_core_exit(ctx); 157 if (ret) 158 return ret; 159 160 if (plat->vbus_supply) { 161 ret = regulator_set_enable(plat->vbus_supply, false); 162 if (ret) 163 pr_err("XHCI: failed to set VBus supply\n"); 164 } 165 166 return ret; 167 } 168 169 static const struct udevice_id xhci_usb_ids[] = { 170 { .compatible = "rockchip,rk3399-xhci" }, 171 { .compatible = "rockchip,rk3328-xhci" }, 172 { } 173 }; 174 175 U_BOOT_DRIVER(usb_xhci) = { 176 .name = "xhci_rockchip", 177 .id = UCLASS_USB, 178 .of_match = xhci_usb_ids, 179 .ofdata_to_platdata = xhci_usb_ofdata_to_platdata, 180 .probe = xhci_usb_probe, 181 .remove = xhci_usb_remove, 182 .ops = &xhci_usb_ops, 183 .bind = dm_scan_fdt_dev, 184 .platdata_auto_alloc_size = sizeof(struct rockchip_xhci_platdata), 185 .priv_auto_alloc_size = sizeof(struct rockchip_xhci), 186 .flags = DM_FLAG_ALLOC_PRIV_DMA, 187 }; 188 189 static const struct udevice_id usb_phy_ids[] = { 190 { .compatible = "rockchip,rk3399-usb3-phy" }, 191 { .compatible = "rockchip,rk3328-usb3-phy" }, 192 { } 193 }; 194 195 U_BOOT_DRIVER(usb_phy) = { 196 .name = "usb_phy_rockchip", 197 .of_match = usb_phy_ids, 198 }; 199