1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 4 * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics. 5 */ 6 7 #include <common.h> 8 #include <asm/io.h> 9 #include <bitfield.h> 10 #include <dm.h> 11 #include <errno.h> 12 #include <fdtdec.h> 13 #include <generic-phy.h> 14 #include <linux/libfdt.h> 15 #include <regmap.h> 16 #include <reset-uclass.h> 17 #include <syscon.h> 18 #include <wait_bit.h> 19 20 #include <linux/bitops.h> 21 #include <linux/compat.h> 22 23 DECLARE_GLOBAL_DATA_PTR; 24 25 /* Default PHY_SEL and REFCLKSEL configuration */ 26 #define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6 27 28 /* ports parameters overriding */ 29 #define STIH407_USB_PICOPHY_PARAM_DEF 0x39a4dc 30 31 #define PHYPARAM_REG 1 32 #define PHYCTRL_REG 2 33 #define PHYPARAM_NB 3 34 35 struct sti_usb_phy { 36 struct regmap *regmap; 37 struct reset_ctl global_ctl; 38 struct reset_ctl port_ctl; 39 int param; 40 int ctrl; 41 }; 42 43 static int sti_usb_phy_deassert(struct sti_usb_phy *phy) 44 { 45 int ret; 46 47 ret = reset_deassert(&phy->global_ctl); 48 if (ret < 0) { 49 pr_err("PHY global deassert failed: %d", ret); 50 return ret; 51 } 52 53 ret = reset_deassert(&phy->port_ctl); 54 if (ret < 0) 55 pr_err("PHY port deassert failed: %d", ret); 56 57 return ret; 58 } 59 60 static int sti_usb_phy_init(struct phy *usb_phy) 61 { 62 struct udevice *dev = usb_phy->dev; 63 struct sti_usb_phy *phy = dev_get_priv(dev); 64 void __iomem *reg; 65 66 /* set ctrl picophy value */ 67 reg = (void __iomem *)phy->regmap->ranges[0].start + phy->ctrl; 68 /* CTRL_PORT mask is 0x1f */ 69 clrsetbits_le32(reg, 0x1f, STIH407_USB_PICOPHY_CTRL_PORT_CONF); 70 71 /* set ports parameters overriding */ 72 reg = (void __iomem *)phy->regmap->ranges[0].start + phy->param; 73 /* PARAM_DEF mask is 0xffffffff */ 74 clrsetbits_le32(reg, 0xffffffff, STIH407_USB_PICOPHY_PARAM_DEF); 75 76 return sti_usb_phy_deassert(phy); 77 } 78 79 static int sti_usb_phy_exit(struct phy *usb_phy) 80 { 81 struct udevice *dev = usb_phy->dev; 82 struct sti_usb_phy *phy = dev_get_priv(dev); 83 int ret; 84 85 ret = reset_assert(&phy->port_ctl); 86 if (ret < 0) { 87 pr_err("PHY port assert failed: %d", ret); 88 return ret; 89 } 90 91 ret = reset_assert(&phy->global_ctl); 92 if (ret < 0) 93 pr_err("PHY global assert failed: %d", ret); 94 95 return ret; 96 } 97 98 struct phy_ops sti_usb_phy_ops = { 99 .init = sti_usb_phy_init, 100 .exit = sti_usb_phy_exit, 101 }; 102 103 int sti_usb_phy_probe(struct udevice *dev) 104 { 105 struct sti_usb_phy *priv = dev_get_priv(dev); 106 struct udevice *syscon; 107 struct ofnode_phandle_args syscfg_phandle; 108 u32 cells[PHYPARAM_NB]; 109 int ret, count; 110 111 /* get corresponding syscon phandle */ 112 ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0, 113 &syscfg_phandle); 114 115 if (ret < 0) { 116 pr_err("Can't get syscfg phandle: %d\n", ret); 117 return ret; 118 } 119 120 ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node, 121 &syscon); 122 if (ret) { 123 pr_err("unable to find syscon device (%d)\n", ret); 124 return ret; 125 } 126 127 priv->regmap = syscon_get_regmap(syscon); 128 if (!priv->regmap) { 129 pr_err("unable to find regmap\n"); 130 return -ENODEV; 131 } 132 133 /* get phy param offset */ 134 count = fdtdec_get_int_array_count(gd->fdt_blob, dev_of_offset(dev), 135 "st,syscfg", cells, 136 ARRAY_SIZE(cells)); 137 138 if (count < 0) { 139 pr_err("Bad PHY st,syscfg property %d\n", count); 140 return -EINVAL; 141 } 142 143 if (count > PHYPARAM_NB) { 144 pr_err("Unsupported PHY param count %d\n", count); 145 return -EINVAL; 146 } 147 148 priv->param = cells[PHYPARAM_REG]; 149 priv->ctrl = cells[PHYCTRL_REG]; 150 151 /* get global reset control */ 152 ret = reset_get_by_name(dev, "global", &priv->global_ctl); 153 if (ret) { 154 pr_err("can't get global reset for %s (%d)", dev->name, ret); 155 return ret; 156 } 157 158 /* get port reset control */ 159 ret = reset_get_by_name(dev, "port", &priv->port_ctl); 160 if (ret) { 161 pr_err("can't get port reset for %s (%d)", dev->name, ret); 162 return ret; 163 } 164 165 return 0; 166 } 167 168 static const struct udevice_id sti_usb_phy_ids[] = { 169 { .compatible = "st,stih407-usb2-phy" }, 170 { } 171 }; 172 173 U_BOOT_DRIVER(sti_usb_phy) = { 174 .name = "sti_usb_phy", 175 .id = UCLASS_PHY, 176 .of_match = sti_usb_phy_ids, 177 .probe = sti_usb_phy_probe, 178 .ops = &sti_usb_phy_ops, 179 .priv_auto_alloc_size = sizeof(struct sti_usb_phy), 180 }; 181