blob: 75763046adc1cbdc0a8f386acb69f1104ac21d07 [file] [log] [blame]
Ye Li4266dc12021-02-21 08:26:21 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021 NXP
4 *
5 */
6
Ye Li4266dc12021-02-21 08:26:21 -08007#include <asm/io.h>
8#include <dm.h>
9#include <errno.h>
10#include <generic-phy.h>
Marek Vasut77ee5d32022-04-01 03:18:31 +020011#include <linux/bitfield.h>
Ye Li4266dc12021-02-21 08:26:21 -080012#include <linux/bitops.h>
Marek Vasut77ee5d32022-04-01 03:18:31 +020013#include <linux/delay.h>
Ye Li4266dc12021-02-21 08:26:21 -080014#include <linux/err.h>
15#include <clk.h>
Tim Harveyc90729c2023-07-13 11:56:07 -070016#include <dm/device_compat.h>
17#include <power/regulator.h>
Ye Li4266dc12021-02-21 08:26:21 -080018
19#define PHY_CTRL0 0x0
20#define PHY_CTRL0_REF_SSP_EN BIT(2)
21#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
22#define PHY_CTRL0_FSEL_24M 0x2a
23#define PHY_CTRL0_FSEL_100M 0x27
24#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
25#define PHY_CTRL0_SSC_RANGE_4003PPM (0x2 << 21)
26
27#define PHY_CTRL1 0x4
28#define PHY_CTRL1_RESET BIT(0)
29#define PHY_CTRL1_COMMONONN BIT(1)
30#define PHY_CTRL1_ATERESET BIT(3)
31#define PHY_CTRL1_DCDENB BIT(17)
32#define PHY_CTRL1_CHRGSEL BIT(18)
33#define PHY_CTRL1_VDATSRCENB0 BIT(19)
34#define PHY_CTRL1_VDATDETENB0 BIT(20)
35
36#define PHY_CTRL2 0x8
37#define PHY_CTRL2_TXENABLEN0 BIT(8)
38#define PHY_CTRL2_OTG_DISABLE BIT(9)
39
40#define PHY_CTRL3 0xc
41#define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
42#define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
43#define PHY_CTRL3_TXPREEMP_TUNE_SHIFT 15
44#define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
45#define PHY_CTRL3_TXRISE_TUNE_SHIFT 20
46/* 1111: +24% ... 0000: -6% step: 2% */
47#define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
48#define PHY_CTRL3_TXVREF_TUNE_SHIFT 22
49#define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29)
50#define PHY_CTRL3_TX_VBOOST_LEVEL_SHIFT 29
51
52#define PHY_CTRL4 0x10
53#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
54#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT 15
55
56#define PHY_CTRL5 0x14
57#define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
58#define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
59#define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
60#define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
61#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
62
63#define PHY_CTRL6 0x18
64#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
65#define PHY_CTRL6_ALT_CLK_EN BIT(1)
66#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
67
68#define PHY_STS0 0x40
69#define PHY_STS0_OTGSESSVLD BIT(7)
70#define PHY_STS0_CHGDET BIT(4)
71#define PHY_STS0_FSVPLUS BIT(3)
72#define PHY_STS0_FSVMINUS BIT(2)
73
Marek Vasut77ee5d32022-04-01 03:18:31 +020074enum imx8mpq_phy_type {
75 IMX8MQ_PHY,
76 IMX8MP_PHY,
77};
78
Ye Li4266dc12021-02-21 08:26:21 -080079struct imx8mq_usb_phy {
Ye Li4266dc12021-02-21 08:26:21 -080080 struct clk phy_clk;
Ye Li4266dc12021-02-21 08:26:21 -080081 void __iomem *base;
Marek Vasut77ee5d32022-04-01 03:18:31 +020082 enum imx8mpq_phy_type type;
Tim Harveyc90729c2023-07-13 11:56:07 -070083 struct udevice *vbus_supply;
Ye Li4266dc12021-02-21 08:26:21 -080084};
85
86static const struct udevice_id imx8mq_usb_phy_of_match[] = {
Marek Vasut77ee5d32022-04-01 03:18:31 +020087 { .compatible = "fsl,imx8mq-usb-phy", .data = IMX8MQ_PHY },
88 { .compatible = "fsl,imx8mp-usb-phy", .data = IMX8MP_PHY },
Ye Li4266dc12021-02-21 08:26:21 -080089 {},
90};
91
92static int imx8mq_usb_phy_init(struct phy *usb_phy)
93{
94 struct udevice *dev = usb_phy->dev;
95 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
96 u32 value;
97
98 value = readl(imx_phy->base + PHY_CTRL1);
99 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
100 PHY_CTRL1_COMMONONN);
101 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
102 writel(value, imx_phy->base + PHY_CTRL1);
103
104 value = readl(imx_phy->base + PHY_CTRL0);
105 value |= PHY_CTRL0_REF_SSP_EN;
106 value &= ~PHY_CTRL0_SSC_RANGE_MASK;
107 value |= PHY_CTRL0_SSC_RANGE_4003PPM;
108 writel(value, imx_phy->base + PHY_CTRL0);
109
110 value = readl(imx_phy->base + PHY_CTRL2);
111 value |= PHY_CTRL2_TXENABLEN0;
112 writel(value, imx_phy->base + PHY_CTRL2);
113
114 value = readl(imx_phy->base + PHY_CTRL1);
115 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
116 writel(value, imx_phy->base + PHY_CTRL1);
117
118 return 0;
119}
120
Marek Vasut77ee5d32022-04-01 03:18:31 +0200121static int imx8mp_usb_phy_init(struct phy *usb_phy)
122{
123 struct udevice *dev = usb_phy->dev;
124 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
125 u32 value;
126
127 /* USB3.0 PHY signal fsel for 24M ref */
128 value = readl(imx_phy->base + PHY_CTRL0);
129 value &= ~PHY_CTRL0_FSEL_MASK;
130 value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M);
131 writel(value, imx_phy->base + PHY_CTRL0);
132
133 /* Disable alt_clk_en and use internal MPLL clocks */
134 value = readl(imx_phy->base + PHY_CTRL6);
135 value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN);
136 writel(value, imx_phy->base + PHY_CTRL6);
137
138 value = readl(imx_phy->base + PHY_CTRL1);
139 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0);
140 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
141 writel(value, imx_phy->base + PHY_CTRL1);
142
143 value = readl(imx_phy->base + PHY_CTRL0);
144 value |= PHY_CTRL0_REF_SSP_EN;
145 writel(value, imx_phy->base + PHY_CTRL0);
146
147 value = readl(imx_phy->base + PHY_CTRL2);
148 value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE;
149 writel(value, imx_phy->base + PHY_CTRL2);
150
151 udelay(10);
152
153 value = readl(imx_phy->base + PHY_CTRL1);
154 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
155 writel(value, imx_phy->base + PHY_CTRL1);
156
157 return 0;
158}
159
160static int imx8mpq_usb_phy_init(struct phy *usb_phy)
161{
162 struct udevice *dev = usb_phy->dev;
163 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
164
165 if (imx_phy->type == IMX8MP_PHY)
166 return imx8mp_usb_phy_init(usb_phy);
167 else
168 return imx8mq_usb_phy_init(usb_phy);
169}
170
Ye Li4266dc12021-02-21 08:26:21 -0800171static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
172{
173 struct udevice *dev = usb_phy->dev;
174 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
175 u32 value;
Tim Harveyc90729c2023-07-13 11:56:07 -0700176 int ret;
Ye Li4266dc12021-02-21 08:26:21 -0800177
Tim Harveye3380e12023-07-13 11:56:08 -0700178 if (CONFIG_IS_ENABLED(CLK)) {
179 ret = clk_enable(&imx_phy->phy_clk);
180 if (ret) {
181 dev_err(dev, "Failed to enable usb phy clock: %d\n", ret);
182 return ret;
183 }
Ye Li4266dc12021-02-21 08:26:21 -0800184 }
Ye Li4266dc12021-02-21 08:26:21 -0800185
Tim Harveyc90729c2023-07-13 11:56:07 -0700186 if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
187 ret = regulator_set_enable_if_allowed(imx_phy->vbus_supply, true);
188 if (ret && ret != -ENOSYS) {
189 dev_err(dev, "Failed to enable VBUS regulator: %d\n", ret);
190 goto err;
191 }
192 }
193
Ye Li4266dc12021-02-21 08:26:21 -0800194 /* Disable rx term override */
195 value = readl(imx_phy->base + PHY_CTRL6);
196 value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
197 writel(value, imx_phy->base + PHY_CTRL6);
198
199 return 0;
Tim Harveyc90729c2023-07-13 11:56:07 -0700200
201err:
Tim Harveye3380e12023-07-13 11:56:08 -0700202 if (CONFIG_IS_ENABLED(CLK))
203 clk_disable(&imx_phy->phy_clk);
Tim Harveyc90729c2023-07-13 11:56:07 -0700204 return ret;
Ye Li4266dc12021-02-21 08:26:21 -0800205}
206
207static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
208{
209 struct udevice *dev = usb_phy->dev;
210 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
211 u32 value;
Tim Harveyc90729c2023-07-13 11:56:07 -0700212 int ret;
Ye Li4266dc12021-02-21 08:26:21 -0800213
214 /* Override rx term to be 0 */
215 value = readl(imx_phy->base + PHY_CTRL6);
216 value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
217 writel(value, imx_phy->base + PHY_CTRL6);
218
Tim Harveye3380e12023-07-13 11:56:08 -0700219 if (CONFIG_IS_ENABLED(CLK))
220 clk_disable(&imx_phy->phy_clk);
Ye Li4266dc12021-02-21 08:26:21 -0800221
Tim Harveyc90729c2023-07-13 11:56:07 -0700222 if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
223 ret = regulator_set_enable_if_allowed(imx_phy->vbus_supply, false);
224 if (ret && ret != -ENOSYS) {
225 dev_err(dev, "Failed to disable VBUS regulator: %d\n", ret);
226 return ret;
227 }
228 }
229
Ye Li4266dc12021-02-21 08:26:21 -0800230 return 0;
231}
232
Ye Li4266dc12021-02-21 08:26:21 -0800233struct phy_ops imx8mq_usb_phy_ops = {
Marek Vasut77ee5d32022-04-01 03:18:31 +0200234 .init = imx8mpq_usb_phy_init,
Ye Li4266dc12021-02-21 08:26:21 -0800235 .power_on = imx8mq_usb_phy_power_on,
236 .power_off = imx8mq_usb_phy_power_off,
Ye Li4266dc12021-02-21 08:26:21 -0800237};
238
239int imx8mq_usb_phy_probe(struct udevice *dev)
240{
241 struct imx8mq_usb_phy *priv = dev_get_priv(dev);
Tim Harveyc90729c2023-07-13 11:56:07 -0700242 int ret;
Ye Li4266dc12021-02-21 08:26:21 -0800243
Marek Vasut77ee5d32022-04-01 03:18:31 +0200244 priv->type = dev_get_driver_data(dev);
Ye Li4266dc12021-02-21 08:26:21 -0800245 priv->base = dev_read_addr_ptr(dev);
246
247 if (!priv->base)
248 return -EINVAL;
249
Tim Harveye3380e12023-07-13 11:56:08 -0700250 if (CONFIG_IS_ENABLED(CLK)) {
251 ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
252 if (ret) {
253 dev_err(dev, "Failed to get usb phy clock %d\n", ret);
254 return ret;
255 }
Ye Li4266dc12021-02-21 08:26:21 -0800256 }
Tim Harveye3380e12023-07-13 11:56:08 -0700257
Tim Harveyc90729c2023-07-13 11:56:07 -0700258 if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
259 ret = device_get_supply_regulator(dev, "vbus-supply",
260 &priv->vbus_supply);
261 if (ret && ret != -ENOENT) {
262 dev_err(dev, "Failed to get VBUS regulator: %d\n", ret);
263 return ret;
264 }
265 }
Ye Li4266dc12021-02-21 08:26:21 -0800266
267 return 0;
268}
269
270U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
271 .name = "nxp_imx8mq_usb_phy",
272 .id = UCLASS_PHY,
273 .of_match = imx8mq_usb_phy_of_match,
274 .probe = imx8mq_usb_phy_probe,
275 .ops = &imx8mq_usb_phy_ops,
276 .priv_auto = sizeof(struct imx8mq_usb_phy),
277};