1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 * Copyright (C) 2023 Bhupesh Sharma <bhupesh.sharma@linaro.org> 5 * 6 * Based on Linux driver 7 */ 8 9#include <dm.h> 10#include <dm/device_compat.h> 11#include <dm/devres.h> 12#include <generic-phy.h> 13#include <malloc.h> 14#include <reset.h> 15 16#include <asm/io.h> 17#include <linux/bitops.h> 18#include <linux/delay.h> 19#include <linux/iopoll.h> 20 21#define USB2_PHY_USB_PHY_UTMI_CTRL0 (0x3c) 22#define SLEEPM BIT(0) 23#define OPMODE_MASK GENMASK(4, 3) 24#define OPMODE_NORMAL (0x00) 25#define OPMODE_NONDRIVING BIT(3) 26#define TERMSEL BIT(5) 27 28#define USB2_PHY_USB_PHY_UTMI_CTRL5 (0x50) 29#define POR BIT(1) 30 31#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) 32#define SIDDQ BIT(2) 33#define RETENABLEN BIT(3) 34#define FSEL_MASK GENMASK(6, 4) 35#define FSEL_DEFAULT (0x3 << 4) 36 37#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1 (0x58) 38#define VBUSVLDEXTSEL0 BIT(4) 39#define PLLBTUNE BIT(5) 40 41#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2 (0x5c) 42#define VREGBYPASS BIT(0) 43 44#define USB2_PHY_USB_PHY_HS_PHY_CTRL1 (0x60) 45#define VBUSVLDEXT0 BIT(0) 46 47#define USB2_PHY_USB_PHY_HS_PHY_CTRL2 (0x64) 48#define USB2_AUTO_RESUME BIT(0) 49#define USB2_SUSPEND_N BIT(2) 50#define USB2_SUSPEND_N_SEL BIT(3) 51 52#define USB2_PHY_USB_PHY_CFG0 (0x94) 53#define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN BIT(0) 54#define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1) 55 56#define USB2_PHY_USB_PHY_REFCLK_CTRL (0xa0) 57#define REFCLK_SEL_MASK GENMASK(1, 0) 58#define REFCLK_SEL_DEFAULT (0x2 << 0) 59 60struct qcom_snps_hsphy { 61 void __iomem *base; 62 struct reset_ctl_bulk resets; 63}; 64 65/* 66 * We should just be able to use clrsetbits_le32() here, but this results 67 * in crashes on some boards. This is suspected to be because of some bus 68 * arbitration quirks with the PHY (i.e. it takes several bus clock cycles 69 * for the write to actually go through). The readl_relaxed() at the end will 70 * block until the write is completed (and all registers updated), and thus 71 * ensure that we don't access the PHY registers when they're in an 72 * undetermined state. 73 */ 74static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, 75 u32 mask, u32 val) 76{ 77 u32 reg; 78 79 reg = readl_relaxed(base + offset); 80 81 reg &= ~mask; 82 reg |= val & mask; 83 writel_relaxed(reg, base + offset); 84 85 /* Ensure above write is completed */ 86 readl_relaxed(base + offset); 87} 88 89static int qcom_snps_hsphy_usb_init(struct phy *phy) 90{ 91 struct qcom_snps_hsphy *priv = dev_get_priv(phy->dev); 92 93 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_CFG0, 94 UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 95 UTMI_PHY_CMN_CTRL_OVERRIDE_EN); 96 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_UTMI_CTRL5, POR, 97 POR); 98 qcom_snps_hsphy_write_mask(priv->base, 99 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0, FSEL_MASK, 0); 100 qcom_snps_hsphy_write_mask(priv->base, 101 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1, 102 PLLBTUNE, PLLBTUNE); 103 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_REFCLK_CTRL, 104 REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK); 105 qcom_snps_hsphy_write_mask(priv->base, 106 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1, 107 VBUSVLDEXTSEL0, VBUSVLDEXTSEL0); 108 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1, 109 VBUSVLDEXT0, VBUSVLDEXT0); 110 111 qcom_snps_hsphy_write_mask(priv->base, 112 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2, 113 VREGBYPASS, VREGBYPASS); 114 115 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2, 116 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N, 117 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N); 118 119 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_UTMI_CTRL0, 120 SLEEPM, SLEEPM); 121 122 qcom_snps_hsphy_write_mask( 123 priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0, SIDDQ, 0); 124 125 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_UTMI_CTRL5, POR, 126 0); 127 128 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2, 129 USB2_SUSPEND_N_SEL, 0); 130 131 qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_CFG0, 132 UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0); 133 134 return 0; 135} 136 137static int qcom_snps_hsphy_power_on(struct phy *phy) 138{ 139 struct qcom_snps_hsphy *priv = dev_get_priv(phy->dev); 140 int ret; 141 142 ret = reset_deassert_bulk(&priv->resets); 143 if (ret) 144 return ret; 145 146 ret = qcom_snps_hsphy_usb_init(phy); 147 if (ret) 148 return ret; 149 150 return 0; 151} 152 153static int qcom_snps_hsphy_power_off(struct phy *phy) 154{ 155 struct qcom_snps_hsphy *priv = dev_get_priv(phy->dev); 156 157 reset_assert_bulk(&priv->resets); 158 159 return 0; 160} 161 162static int qcom_snps_hsphy_phy_probe(struct udevice *dev) 163{ 164 struct qcom_snps_hsphy *priv = dev_get_priv(dev); 165 int ret; 166 167 priv->base = dev_read_addr_ptr(dev); 168 if (IS_ERR(priv->base)) 169 return PTR_ERR(priv->base); 170 171 ret = reset_get_bulk(dev, &priv->resets); 172 if (ret < 0) { 173 printf("failed to get resets, ret = %d\n", ret); 174 return ret; 175 } 176 177 reset_deassert_bulk(&priv->resets); 178 179 return 0; 180} 181 182static struct phy_ops qcom_snps_hsphy_phy_ops = { 183 .power_on = qcom_snps_hsphy_power_on, 184 .power_off = qcom_snps_hsphy_power_off, 185}; 186 187static const struct udevice_id qcom_snps_hsphy_phy_ids[] = { 188 { .compatible = "qcom,sm8150-usb-hs-phy" }, 189 { .compatible = "qcom,usb-snps-hs-5nm-phy" }, 190 { .compatible = "qcom,usb-snps-hs-7nm-phy" }, 191 { .compatible = "qcom,usb-snps-femto-v2-phy" }, 192 {} 193}; 194 195U_BOOT_DRIVER(qcom_usb_qcom_snps_hsphy) = { 196 .name = "qcom-snps-hsphy", 197 .id = UCLASS_PHY, 198 .of_match = qcom_snps_hsphy_phy_ids, 199 .ops = &qcom_snps_hsphy_phy_ops, 200 .probe = qcom_snps_hsphy_phy_probe, 201 .priv_auto = sizeof(struct qcom_snps_hsphy), 202}; 203