1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2023-2024, Linaro Limited 4 * 5 * Based on the Linux phy-qcom-snps-eusb2.c driver 6 */ 7 8#include <clk.h> 9#include <clk-uclass.h> 10#include <dm.h> 11#include <dm/device_compat.h> 12#include <dm/devres.h> 13#include <generic-phy.h> 14#include <malloc.h> 15#include <reset.h> 16 17#include <asm/io.h> 18#include <linux/bitops.h> 19#include <linux/bitfield.h> 20#include <linux/clk-provider.h> 21#include <linux/delay.h> 22 23#define USB_PHY_UTMI_CTRL0 (0x3c) 24#define SLEEPM BIT(0) 25#define OPMODE_MASK GENMASK(4, 3) 26#define OPMODE_NONDRIVING BIT(3) 27 28#define USB_PHY_UTMI_CTRL5 (0x50) 29#define POR BIT(1) 30 31#define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) 32#define PHY_ENABLE BIT(0) 33#define SIDDQ_SEL BIT(1) 34#define SIDDQ BIT(2) 35#define RETENABLEN BIT(3) 36#define FSEL_MASK GENMASK(6, 4) 37#define FSEL_19_2_MHZ_VAL (0x0) 38#define FSEL_38_4_MHZ_VAL (0x4) 39 40#define USB_PHY_CFG_CTRL_1 (0x58) 41#define PHY_CFG_PLL_CPBIAS_CNTRL_MASK GENMASK(7, 1) 42 43#define USB_PHY_CFG_CTRL_2 (0x5c) 44#define PHY_CFG_PLL_FB_DIV_7_0_MASK GENMASK(7, 0) 45#define DIV_7_0_19_2_MHZ_VAL (0x90) 46#define DIV_7_0_38_4_MHZ_VAL (0xc8) 47 48#define USB_PHY_CFG_CTRL_3 (0x60) 49#define PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) 50#define DIV_11_8_19_2_MHZ_VAL (0x1) 51#define DIV_11_8_38_4_MHZ_VAL (0x0) 52 53#define PHY_CFG_PLL_REF_DIV GENMASK(7, 4) 54#define PLL_REF_DIV_VAL (0x0) 55 56#define USB_PHY_HS_PHY_CTRL2 (0x64) 57#define VBUSVLDEXT0 BIT(0) 58#define USB2_SUSPEND_N BIT(2) 59#define USB2_SUSPEND_N_SEL BIT(3) 60#define VBUS_DET_EXT_SEL BIT(4) 61 62#define USB_PHY_CFG_CTRL_4 (0x68) 63#define PHY_CFG_PLL_GMP_CNTRL_MASK GENMASK(1, 0) 64#define PHY_CFG_PLL_INT_CNTRL_MASK GENMASK(7, 2) 65 66#define USB_PHY_CFG_CTRL_5 (0x6c) 67#define PHY_CFG_PLL_PROP_CNTRL_MASK GENMASK(4, 0) 68#define PHY_CFG_PLL_VREF_TUNE_MASK GENMASK(7, 6) 69 70#define USB_PHY_CFG_CTRL_6 (0x70) 71#define PHY_CFG_PLL_VCO_CNTRL_MASK GENMASK(2, 0) 72 73#define USB_PHY_CFG_CTRL_7 (0x74) 74 75#define USB_PHY_CFG_CTRL_8 (0x78) 76#define PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(1, 0) 77#define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2) 78#define PHY_CFG_TX_HS_VREF_TUNE_MASK GENMASK(5, 3) 79#define PHY_CFG_TX_HS_XV_TUNE_MASK GENMASK(7, 6) 80 81#define USB_PHY_CFG_CTRL_9 (0x7c) 82#define PHY_CFG_TX_PREEMP_TUNE_MASK GENMASK(2, 0) 83#define PHY_CFG_TX_RES_TUNE_MASK GENMASK(4, 3) 84#define PHY_CFG_TX_RISE_TUNE_MASK GENMASK(6, 5) 85#define PHY_CFG_RCAL_BYPASS BIT(7) 86 87#define USB_PHY_CFG_CTRL_10 (0x80) 88 89#define USB_PHY_CFG0 (0x94) 90#define DATAPATH_CTRL_OVERRIDE_EN BIT(0) 91#define CMN_CTRL_OVERRIDE_EN BIT(1) 92 93#define UTMI_PHY_CMN_CTRL0 (0x98) 94#define TESTBURNIN BIT(6) 95 96#define USB_PHY_FSEL_SEL (0xb8) 97#define FSEL_SEL BIT(0) 98 99#define USB_PHY_APB_ACCESS_CMD (0x130) 100#define RW_ACCESS BIT(0) 101#define APB_START_CMD BIT(1) 102#define APB_LOGIC_RESET BIT(2) 103 104#define USB_PHY_APB_ACCESS_STATUS (0x134) 105#define ACCESS_DONE BIT(0) 106#define TIMED_OUT BIT(1) 107#define ACCESS_ERROR BIT(2) 108#define ACCESS_IN_PROGRESS BIT(3) 109 110#define USB_PHY_APB_ADDRESS (0x138) 111#define APB_REG_ADDR_MASK GENMASK(7, 0) 112 113#define USB_PHY_APB_WRDATA_LSB (0x13c) 114#define APB_REG_WRDATA_7_0_MASK GENMASK(3, 0) 115 116#define USB_PHY_APB_WRDATA_MSB (0x140) 117#define APB_REG_WRDATA_15_8_MASK GENMASK(7, 4) 118 119#define USB_PHY_APB_RDDATA_LSB (0x144) 120#define APB_REG_RDDATA_7_0_MASK GENMASK(3, 0) 121 122#define USB_PHY_APB_RDDATA_MSB (0x148) 123#define APB_REG_RDDATA_15_8_MASK GENMASK(7, 4) 124 125struct qcom_snps_eusb2_phy_priv { 126 void __iomem *base; 127 struct clk *ref_clk; 128 struct reset_ctl_bulk resets; 129}; 130 131static void qcom_snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset, 132 u32 mask, u32 val) 133{ 134 u32 reg; 135 136 reg = readl_relaxed(base + offset); 137 reg &= ~mask; 138 reg |= val & mask; 139 writel_relaxed(reg, base + offset); 140 141 /* Ensure above write is completed */ 142 readl_relaxed(base + offset); 143} 144 145static void qcom_eusb2_default_parameters(struct qcom_snps_eusb2_phy_priv *qcom_snps_eusb2) 146{ 147 /* default parameters: tx pre-emphasis */ 148 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_9, 149 PHY_CFG_TX_PREEMP_TUNE_MASK, 150 FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0)); 151 152 /* tx rise/fall time */ 153 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_9, 154 PHY_CFG_TX_RISE_TUNE_MASK, 155 FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2)); 156 157 /* source impedance adjustment */ 158 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_9, 159 PHY_CFG_TX_RES_TUNE_MASK, 160 FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1)); 161 162 /* dc voltage level adjustement */ 163 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_8, 164 PHY_CFG_TX_HS_VREF_TUNE_MASK, 165 FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3)); 166 167 /* transmitter HS crossover adjustement */ 168 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_8, 169 PHY_CFG_TX_HS_XV_TUNE_MASK, 170 FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0)); 171} 172 173static int qcom_eusb2_ref_clk_init(struct qcom_snps_eusb2_phy_priv *qcom_snps_eusb2) 174{ 175 unsigned long ref_clk_freq = clk_get_rate(qcom_snps_eusb2->ref_clk); 176 177 switch (ref_clk_freq) { 178 case 19200000: 179 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL_COMMON0, 180 FSEL_MASK, 181 FIELD_PREP(FSEL_MASK, FSEL_19_2_MHZ_VAL)); 182 183 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_2, 184 PHY_CFG_PLL_FB_DIV_7_0_MASK, 185 DIV_7_0_19_2_MHZ_VAL); 186 187 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_3, 188 PHY_CFG_PLL_FB_DIV_11_8_MASK, 189 DIV_11_8_19_2_MHZ_VAL); 190 break; 191 192 case 38400000: 193 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL_COMMON0, 194 FSEL_MASK, 195 FIELD_PREP(FSEL_MASK, FSEL_38_4_MHZ_VAL)); 196 197 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_2, 198 PHY_CFG_PLL_FB_DIV_7_0_MASK, 199 DIV_7_0_38_4_MHZ_VAL); 200 201 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_3, 202 PHY_CFG_PLL_FB_DIV_11_8_MASK, 203 DIV_11_8_38_4_MHZ_VAL); 204 break; 205 206 default: 207 printf("%s: unsupported ref_clk_freq:%lu\n", __func__, ref_clk_freq); 208 return -EINVAL; 209 } 210 211 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_3, 212 PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL); 213 214 return 0; 215} 216 217static int qcom_snps_eusb2_usb_init(struct phy *phy) 218{ 219 struct qcom_snps_eusb2_phy_priv *qcom_snps_eusb2 = dev_get_priv(phy->dev); 220 int ret; 221 222 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG0, 223 CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN); 224 225 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_UTMI_CTRL5, POR, POR); 226 227 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL_COMMON0, 228 PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN); 229 230 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_APB_ACCESS_CMD, 231 APB_LOGIC_RESET, APB_LOGIC_RESET); 232 233 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0); 234 235 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_FSEL_SEL, 236 FSEL_SEL, FSEL_SEL); 237 238 /* update ref_clk related registers */ 239 ret = qcom_eusb2_ref_clk_init(qcom_snps_eusb2); 240 if (ret) 241 return ret; 242 243 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_1, 244 PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 245 FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1)); 246 247 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_4, 248 PHY_CFG_PLL_INT_CNTRL_MASK, 249 FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8)); 250 251 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_4, 252 PHY_CFG_PLL_GMP_CNTRL_MASK, 253 FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1)); 254 255 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_5, 256 PHY_CFG_PLL_PROP_CNTRL_MASK, 257 FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10)); 258 259 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_6, 260 PHY_CFG_PLL_VCO_CNTRL_MASK, 261 FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0)); 262 263 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_CFG_CTRL_5, 264 PHY_CFG_PLL_VREF_TUNE_MASK, 265 FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1)); 266 267 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL2, 268 VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL); 269 270 /* set default parameters */ 271 qcom_eusb2_default_parameters(qcom_snps_eusb2); 272 273 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL2, 274 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N, 275 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N); 276 277 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM); 278 279 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL_COMMON0, 280 SIDDQ_SEL, SIDDQ_SEL); 281 282 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL_COMMON0, 283 SIDDQ, 0); 284 285 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_UTMI_CTRL5, POR, 0); 286 287 qcom_snps_eusb2_hsphy_write_mask(qcom_snps_eusb2->base, USB_PHY_HS_PHY_CTRL2, 288 USB2_SUSPEND_N_SEL, 0); 289 290 return 0; 291} 292 293static int qcom_snps_eusb2_phy_power_on(struct phy *phy) 294{ 295 struct qcom_snps_eusb2_phy_priv *qcom_snps_eusb2 = dev_get_priv(phy->dev); 296 int ret; 297 298 /* TODO Repeater */ 299 300 clk_prepare_enable(qcom_snps_eusb2->ref_clk); 301 302 ret = reset_deassert_bulk(&qcom_snps_eusb2->resets); 303 if (ret) 304 return ret; 305 306 ret = qcom_snps_eusb2_usb_init(phy); 307 if (ret) 308 return ret; 309 310 return 0; 311} 312 313static int qcom_snps_eusb2_phy_power_off(struct phy *phy) 314{ 315 struct qcom_snps_eusb2_phy_priv *qcom_snps_eusb2 = dev_get_priv(phy->dev); 316 317 reset_assert_bulk(&qcom_snps_eusb2->resets); 318 clk_disable_unprepare(qcom_snps_eusb2->ref_clk); 319 320 return 0; 321} 322 323static int qcom_snps_eusb2_phy_probe(struct udevice *dev) 324{ 325 struct qcom_snps_eusb2_phy_priv *qcom_snps_eusb2 = dev_get_priv(dev); 326 int ret; 327 328 qcom_snps_eusb2->base = (void __iomem *)dev_read_addr(dev); 329 if (IS_ERR(qcom_snps_eusb2->base)) 330 return PTR_ERR(qcom_snps_eusb2->base); 331 332 qcom_snps_eusb2->ref_clk = devm_clk_get(dev, "ref"); 333 if (IS_ERR(qcom_snps_eusb2->ref_clk)) { 334 printf("%s: failed to get ref clk %d\n", __func__, ret); 335 return PTR_ERR(qcom_snps_eusb2->ref_clk); 336 } 337 338 ret = reset_get_bulk(dev, &qcom_snps_eusb2->resets); 339 if (ret < 0) { 340 printf("failed to get resets, ret = %d\n", ret); 341 return ret; 342 } 343 344 return 0; 345} 346 347static struct phy_ops qcom_snps_eusb2_phy_ops = { 348 .power_on = qcom_snps_eusb2_phy_power_on, 349 .power_off = qcom_snps_eusb2_phy_power_off, 350}; 351 352static const struct udevice_id qcom_snps_eusb2_phy_ids[] = { 353 { 354 .compatible = "qcom,sm8550-snps-eusb2-phy", 355 }, 356 {} 357}; 358 359U_BOOT_DRIVER(qcom_usb_qcom_snps_eusb2) = { 360 .name = "qcom-snps-eusb2-hsphy", 361 .id = UCLASS_PHY, 362 .of_match = qcom_snps_eusb2_phy_ids, 363 .ops = &qcom_snps_eusb2_phy_ops, 364 .probe = qcom_snps_eusb2_phy_probe, 365 .priv_auto = sizeof(struct qcom_snps_eusb2_phy_priv), 366}; 367