1*f1ba13f8SMasahiro Yamada /* 2*f1ba13f8SMasahiro Yamada * STiH407 family DWC3 specific Glue layer 3*f1ba13f8SMasahiro Yamada * 4*f1ba13f8SMasahiro Yamada * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 5*f1ba13f8SMasahiro Yamada * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics. 6*f1ba13f8SMasahiro Yamada * 7*f1ba13f8SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 8*f1ba13f8SMasahiro Yamada */ 9*f1ba13f8SMasahiro Yamada 10*f1ba13f8SMasahiro Yamada #include <common.h> 11*f1ba13f8SMasahiro Yamada #include <asm/io.h> 12*f1ba13f8SMasahiro Yamada #include <dm.h> 13*f1ba13f8SMasahiro Yamada #include <errno.h> 14*f1ba13f8SMasahiro Yamada #include <fdtdec.h> 15*f1ba13f8SMasahiro Yamada #include <linux/libfdt.h> 16*f1ba13f8SMasahiro Yamada #include <dm/lists.h> 17*f1ba13f8SMasahiro Yamada #include <regmap.h> 18*f1ba13f8SMasahiro Yamada #include <reset-uclass.h> 19*f1ba13f8SMasahiro Yamada #include <syscon.h> 20*f1ba13f8SMasahiro Yamada #include <usb.h> 21*f1ba13f8SMasahiro Yamada 22*f1ba13f8SMasahiro Yamada #include <linux/usb/dwc3.h> 23*f1ba13f8SMasahiro Yamada #include <linux/usb/otg.h> 24*f1ba13f8SMasahiro Yamada #include <dwc3-sti-glue.h> 25*f1ba13f8SMasahiro Yamada 26*f1ba13f8SMasahiro Yamada DECLARE_GLOBAL_DATA_PTR; 27*f1ba13f8SMasahiro Yamada 28*f1ba13f8SMasahiro Yamada /* 29*f1ba13f8SMasahiro Yamada * struct sti_dwc3_glue_platdata - dwc3 STi glue driver private structure 30*f1ba13f8SMasahiro Yamada * @syscfg_base: addr for the glue syscfg 31*f1ba13f8SMasahiro Yamada * @glue_base: addr for the glue registers 32*f1ba13f8SMasahiro Yamada * @syscfg_offset: usb syscfg control offset 33*f1ba13f8SMasahiro Yamada * @powerdown_ctl: rest controller for powerdown signal 34*f1ba13f8SMasahiro Yamada * @softreset_ctl: reset controller for softreset signal 35*f1ba13f8SMasahiro Yamada * @mode: drd static host/device config 36*f1ba13f8SMasahiro Yamada */ 37*f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata { 38*f1ba13f8SMasahiro Yamada phys_addr_t syscfg_base; 39*f1ba13f8SMasahiro Yamada phys_addr_t glue_base; 40*f1ba13f8SMasahiro Yamada phys_addr_t syscfg_offset; 41*f1ba13f8SMasahiro Yamada struct reset_ctl powerdown_ctl; 42*f1ba13f8SMasahiro Yamada struct reset_ctl softreset_ctl; 43*f1ba13f8SMasahiro Yamada enum usb_dr_mode mode; 44*f1ba13f8SMasahiro Yamada }; 45*f1ba13f8SMasahiro Yamada 46*f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata *plat) 47*f1ba13f8SMasahiro Yamada { 48*f1ba13f8SMasahiro Yamada unsigned long val; 49*f1ba13f8SMasahiro Yamada 50*f1ba13f8SMasahiro Yamada val = readl(plat->syscfg_base + plat->syscfg_offset); 51*f1ba13f8SMasahiro Yamada 52*f1ba13f8SMasahiro Yamada val &= USB3_CONTROL_MASK; 53*f1ba13f8SMasahiro Yamada 54*f1ba13f8SMasahiro Yamada switch (plat->mode) { 55*f1ba13f8SMasahiro Yamada case USB_DR_MODE_PERIPHERAL: 56*f1ba13f8SMasahiro Yamada val &= ~(USB3_DELAY_VBUSVALID 57*f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) 58*f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 59*f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); 60*f1ba13f8SMasahiro Yamada 61*f1ba13f8SMasahiro Yamada val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID; 62*f1ba13f8SMasahiro Yamada break; 63*f1ba13f8SMasahiro Yamada 64*f1ba13f8SMasahiro Yamada case USB_DR_MODE_HOST: 65*f1ba13f8SMasahiro Yamada val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID 66*f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) 67*f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 68*f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); 69*f1ba13f8SMasahiro Yamada 70*f1ba13f8SMasahiro Yamada val |= USB3_DELAY_VBUSVALID; 71*f1ba13f8SMasahiro Yamada break; 72*f1ba13f8SMasahiro Yamada 73*f1ba13f8SMasahiro Yamada default: 74*f1ba13f8SMasahiro Yamada pr_err("Unsupported mode of operation %d\n", plat->mode); 75*f1ba13f8SMasahiro Yamada return -EINVAL; 76*f1ba13f8SMasahiro Yamada } 77*f1ba13f8SMasahiro Yamada writel(val, plat->syscfg_base + plat->syscfg_offset); 78*f1ba13f8SMasahiro Yamada 79*f1ba13f8SMasahiro Yamada return 0; 80*f1ba13f8SMasahiro Yamada } 81*f1ba13f8SMasahiro Yamada 82*f1ba13f8SMasahiro Yamada static void sti_dwc3_glue_init(struct sti_dwc3_glue_platdata *plat) 83*f1ba13f8SMasahiro Yamada { 84*f1ba13f8SMasahiro Yamada unsigned long reg; 85*f1ba13f8SMasahiro Yamada 86*f1ba13f8SMasahiro Yamada reg = readl(plat->glue_base + CLKRST_CTRL); 87*f1ba13f8SMasahiro Yamada 88*f1ba13f8SMasahiro Yamada reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION; 89*f1ba13f8SMasahiro Yamada reg &= ~SW_PIPEW_RESET_N; 90*f1ba13f8SMasahiro Yamada 91*f1ba13f8SMasahiro Yamada writel(reg, plat->glue_base + CLKRST_CTRL); 92*f1ba13f8SMasahiro Yamada 93*f1ba13f8SMasahiro Yamada /* configure mux for vbus, powerpresent and bvalid signals */ 94*f1ba13f8SMasahiro Yamada reg = readl(plat->glue_base + USB2_VBUS_MNGMNT_SEL1); 95*f1ba13f8SMasahiro Yamada 96*f1ba13f8SMasahiro Yamada reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) | 97*f1ba13f8SMasahiro Yamada SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) | 98*f1ba13f8SMasahiro Yamada SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG); 99*f1ba13f8SMasahiro Yamada 100*f1ba13f8SMasahiro Yamada writel(reg, plat->glue_base + USB2_VBUS_MNGMNT_SEL1); 101*f1ba13f8SMasahiro Yamada 102*f1ba13f8SMasahiro Yamada setbits_le32(plat->glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N); 103*f1ba13f8SMasahiro Yamada } 104*f1ba13f8SMasahiro Yamada 105*f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) 106*f1ba13f8SMasahiro Yamada { 107*f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); 108*f1ba13f8SMasahiro Yamada struct udevice *syscon; 109*f1ba13f8SMasahiro Yamada struct regmap *regmap; 110*f1ba13f8SMasahiro Yamada int ret; 111*f1ba13f8SMasahiro Yamada u32 reg[4]; 112*f1ba13f8SMasahiro Yamada 113*f1ba13f8SMasahiro Yamada ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), 114*f1ba13f8SMasahiro Yamada "reg", reg, ARRAY_SIZE(reg)); 115*f1ba13f8SMasahiro Yamada if (ret) { 116*f1ba13f8SMasahiro Yamada pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret); 117*f1ba13f8SMasahiro Yamada return ret; 118*f1ba13f8SMasahiro Yamada } 119*f1ba13f8SMasahiro Yamada 120*f1ba13f8SMasahiro Yamada plat->glue_base = reg[0]; 121*f1ba13f8SMasahiro Yamada plat->syscfg_offset = reg[2]; 122*f1ba13f8SMasahiro Yamada 123*f1ba13f8SMasahiro Yamada /* get corresponding syscon phandle */ 124*f1ba13f8SMasahiro Yamada ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg", 125*f1ba13f8SMasahiro Yamada &syscon); 126*f1ba13f8SMasahiro Yamada if (ret) { 127*f1ba13f8SMasahiro Yamada pr_err("unable to find syscon device (%d)\n", ret); 128*f1ba13f8SMasahiro Yamada return ret; 129*f1ba13f8SMasahiro Yamada } 130*f1ba13f8SMasahiro Yamada 131*f1ba13f8SMasahiro Yamada /* get syscfg-reg base address */ 132*f1ba13f8SMasahiro Yamada regmap = syscon_get_regmap(syscon); 133*f1ba13f8SMasahiro Yamada if (!regmap) { 134*f1ba13f8SMasahiro Yamada pr_err("unable to find regmap\n"); 135*f1ba13f8SMasahiro Yamada return -ENODEV; 136*f1ba13f8SMasahiro Yamada } 137*f1ba13f8SMasahiro Yamada plat->syscfg_base = regmap->base; 138*f1ba13f8SMasahiro Yamada 139*f1ba13f8SMasahiro Yamada /* get powerdown reset */ 140*f1ba13f8SMasahiro Yamada ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl); 141*f1ba13f8SMasahiro Yamada if (ret) { 142*f1ba13f8SMasahiro Yamada pr_err("can't get powerdown reset for %s (%d)", dev->name, ret); 143*f1ba13f8SMasahiro Yamada return ret; 144*f1ba13f8SMasahiro Yamada } 145*f1ba13f8SMasahiro Yamada 146*f1ba13f8SMasahiro Yamada /* get softreset reset */ 147*f1ba13f8SMasahiro Yamada ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl); 148*f1ba13f8SMasahiro Yamada if (ret) 149*f1ba13f8SMasahiro Yamada pr_err("can't get soft reset for %s (%d)", dev->name, ret); 150*f1ba13f8SMasahiro Yamada 151*f1ba13f8SMasahiro Yamada return ret; 152*f1ba13f8SMasahiro Yamada }; 153*f1ba13f8SMasahiro Yamada 154*f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_bind(struct udevice *dev) 155*f1ba13f8SMasahiro Yamada { 156*f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); 157*f1ba13f8SMasahiro Yamada int dwc3_node; 158*f1ba13f8SMasahiro Yamada 159*f1ba13f8SMasahiro Yamada /* check if one subnode is present */ 160*f1ba13f8SMasahiro Yamada dwc3_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev)); 161*f1ba13f8SMasahiro Yamada if (dwc3_node <= 0) { 162*f1ba13f8SMasahiro Yamada pr_err("Can't find subnode for %s\n", dev->name); 163*f1ba13f8SMasahiro Yamada return -ENODEV; 164*f1ba13f8SMasahiro Yamada } 165*f1ba13f8SMasahiro Yamada 166*f1ba13f8SMasahiro Yamada /* check if the subnode compatible string is the dwc3 one*/ 167*f1ba13f8SMasahiro Yamada if (fdt_node_check_compatible(gd->fdt_blob, dwc3_node, 168*f1ba13f8SMasahiro Yamada "snps,dwc3") != 0) { 169*f1ba13f8SMasahiro Yamada pr_err("Can't find dwc3 subnode for %s\n", dev->name); 170*f1ba13f8SMasahiro Yamada return -ENODEV; 171*f1ba13f8SMasahiro Yamada } 172*f1ba13f8SMasahiro Yamada 173*f1ba13f8SMasahiro Yamada /* retrieve the DWC3 dual role mode */ 174*f1ba13f8SMasahiro Yamada plat->mode = usb_get_dr_mode(dwc3_node); 175*f1ba13f8SMasahiro Yamada if (plat->mode == USB_DR_MODE_UNKNOWN) 176*f1ba13f8SMasahiro Yamada /* by default set dual role mode to HOST */ 177*f1ba13f8SMasahiro Yamada plat->mode = USB_DR_MODE_HOST; 178*f1ba13f8SMasahiro Yamada 179*f1ba13f8SMasahiro Yamada return dm_scan_fdt_dev(dev); 180*f1ba13f8SMasahiro Yamada } 181*f1ba13f8SMasahiro Yamada 182*f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_probe(struct udevice *dev) 183*f1ba13f8SMasahiro Yamada { 184*f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); 185*f1ba13f8SMasahiro Yamada int ret; 186*f1ba13f8SMasahiro Yamada 187*f1ba13f8SMasahiro Yamada /* deassert both powerdown and softreset */ 188*f1ba13f8SMasahiro Yamada ret = reset_deassert(&plat->powerdown_ctl); 189*f1ba13f8SMasahiro Yamada if (ret < 0) { 190*f1ba13f8SMasahiro Yamada pr_err("DWC3 powerdown reset deassert failed: %d", ret); 191*f1ba13f8SMasahiro Yamada return ret; 192*f1ba13f8SMasahiro Yamada } 193*f1ba13f8SMasahiro Yamada 194*f1ba13f8SMasahiro Yamada ret = reset_deassert(&plat->softreset_ctl); 195*f1ba13f8SMasahiro Yamada if (ret < 0) { 196*f1ba13f8SMasahiro Yamada pr_err("DWC3 soft reset deassert failed: %d", ret); 197*f1ba13f8SMasahiro Yamada goto softreset_err; 198*f1ba13f8SMasahiro Yamada } 199*f1ba13f8SMasahiro Yamada 200*f1ba13f8SMasahiro Yamada ret = sti_dwc3_glue_drd_init(plat); 201*f1ba13f8SMasahiro Yamada if (ret) 202*f1ba13f8SMasahiro Yamada goto init_err; 203*f1ba13f8SMasahiro Yamada 204*f1ba13f8SMasahiro Yamada sti_dwc3_glue_init(plat); 205*f1ba13f8SMasahiro Yamada 206*f1ba13f8SMasahiro Yamada return 0; 207*f1ba13f8SMasahiro Yamada 208*f1ba13f8SMasahiro Yamada init_err: 209*f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->softreset_ctl); 210*f1ba13f8SMasahiro Yamada if (ret < 0) { 211*f1ba13f8SMasahiro Yamada pr_err("DWC3 soft reset deassert failed: %d", ret); 212*f1ba13f8SMasahiro Yamada return ret; 213*f1ba13f8SMasahiro Yamada } 214*f1ba13f8SMasahiro Yamada 215*f1ba13f8SMasahiro Yamada softreset_err: 216*f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->powerdown_ctl); 217*f1ba13f8SMasahiro Yamada if (ret < 0) 218*f1ba13f8SMasahiro Yamada pr_err("DWC3 powerdown reset deassert failed: %d", ret); 219*f1ba13f8SMasahiro Yamada 220*f1ba13f8SMasahiro Yamada return ret; 221*f1ba13f8SMasahiro Yamada } 222*f1ba13f8SMasahiro Yamada 223*f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_remove(struct udevice *dev) 224*f1ba13f8SMasahiro Yamada { 225*f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); 226*f1ba13f8SMasahiro Yamada int ret; 227*f1ba13f8SMasahiro Yamada 228*f1ba13f8SMasahiro Yamada /* assert both powerdown and softreset */ 229*f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->powerdown_ctl); 230*f1ba13f8SMasahiro Yamada if (ret < 0) { 231*f1ba13f8SMasahiro Yamada pr_err("DWC3 powerdown reset deassert failed: %d", ret); 232*f1ba13f8SMasahiro Yamada return ret; 233*f1ba13f8SMasahiro Yamada } 234*f1ba13f8SMasahiro Yamada 235*f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->softreset_ctl); 236*f1ba13f8SMasahiro Yamada if (ret < 0) 237*f1ba13f8SMasahiro Yamada pr_err("DWC3 soft reset deassert failed: %d", ret); 238*f1ba13f8SMasahiro Yamada 239*f1ba13f8SMasahiro Yamada return ret; 240*f1ba13f8SMasahiro Yamada } 241*f1ba13f8SMasahiro Yamada 242*f1ba13f8SMasahiro Yamada static const struct udevice_id sti_dwc3_glue_ids[] = { 243*f1ba13f8SMasahiro Yamada { .compatible = "st,stih407-dwc3" }, 244*f1ba13f8SMasahiro Yamada { } 245*f1ba13f8SMasahiro Yamada }; 246*f1ba13f8SMasahiro Yamada 247*f1ba13f8SMasahiro Yamada U_BOOT_DRIVER(dwc3_sti_glue) = { 248*f1ba13f8SMasahiro Yamada .name = "dwc3_sti_glue", 249*f1ba13f8SMasahiro Yamada .id = UCLASS_MISC, 250*f1ba13f8SMasahiro Yamada .of_match = sti_dwc3_glue_ids, 251*f1ba13f8SMasahiro Yamada .ofdata_to_platdata = sti_dwc3_glue_ofdata_to_platdata, 252*f1ba13f8SMasahiro Yamada .probe = sti_dwc3_glue_probe, 253*f1ba13f8SMasahiro Yamada .remove = sti_dwc3_glue_remove, 254*f1ba13f8SMasahiro Yamada .bind = sti_dwc3_glue_bind, 255*f1ba13f8SMasahiro Yamada .platdata_auto_alloc_size = sizeof(struct sti_dwc3_glue_platdata), 256*f1ba13f8SMasahiro Yamada .flags = DM_FLAG_ALLOC_PRIV_DMA, 257*f1ba13f8SMasahiro Yamada }; 258