blob: b660eadecf1ca0057ceeb80de030330cd6df4232 [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
7#include <common.h>
8#include <asm/io.h>
9#include <dm.h>
10#include <errno.h>
11#include <generic-phy.h>
Marek Vasut77ee5d32022-04-01 03:18:31 +020012#include <linux/bitfield.h>
Ye Li4266dc12021-02-21 08:26:21 -080013#include <linux/bitops.h>
Marek Vasut77ee5d32022-04-01 03:18:31 +020014#include <linux/delay.h>
Ye Li4266dc12021-02-21 08:26:21 -080015#include <linux/err.h>
16#include <clk.h>
Tim Harveyc90729c2023-07-13 11:56:07 -070017#include <dm/device_compat.h>
18#include <power/regulator.h>
Ye Li4266dc12021-02-21 08:26:21 -080019
20#define PHY_CTRL0 0x0
21#define PHY_CTRL0_REF_SSP_EN BIT(2)
22#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
23#define PHY_CTRL0_FSEL_24M 0x2a
24#define PHY_CTRL0_FSEL_100M 0x27
25#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
26#define PHY_CTRL0_SSC_RANGE_4003PPM (0x2 << 21)
27
28#define PHY_CTRL1 0x4
29#define PHY_CTRL1_RESET BIT(0)
30#define PHY_CTRL1_COMMONONN BIT(1)
31#define PHY_CTRL1_ATERESET BIT(3)
32#define PHY_CTRL1_DCDENB BIT(17)
33#define PHY_CTRL1_CHRGSEL BIT(18)
34#define PHY_CTRL1_VDATSRCENB0 BIT(19)
35#define PHY_CTRL1_VDATDETENB0 BIT(20)
36
37#define PHY_CTRL2 0x8
38#define PHY_CTRL2_TXENABLEN0 BIT(8)
39#define PHY_CTRL2_OTG_DISABLE BIT(9)
40
41#define PHY_CTRL3 0xc
42#define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
43#define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
44#define PHY_CTRL3_TXPREEMP_TUNE_SHIFT 15
45#define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
46#define PHY_CTRL3_TXRISE_TUNE_SHIFT 20
47/* 1111: +24% ... 0000: -6% step: 2% */
48#define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
49#define PHY_CTRL3_TXVREF_TUNE_SHIFT 22
50#define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29)
51#define PHY_CTRL3_TX_VBOOST_LEVEL_SHIFT 29
52
53#define PHY_CTRL4 0x10
54#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
55#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT 15
56
57#define PHY_CTRL5 0x14
58#define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
59#define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
60#define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
61#define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
62#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
63
64#define PHY_CTRL6 0x18
65#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
66#define PHY_CTRL6_ALT_CLK_EN BIT(1)
67#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
68
69#define PHY_STS0 0x40
70#define PHY_STS0_OTGSESSVLD BIT(7)
71#define PHY_STS0_CHGDET BIT(4)
72#define PHY_STS0_FSVPLUS BIT(3)
73#define PHY_STS0_FSVMINUS BIT(2)
74
Marek Vasut77ee5d32022-04-01 03:18:31 +020075enum imx8mpq_phy_type {
76 IMX8MQ_PHY,
77 IMX8MP_PHY,
78};
79
Ye Li4266dc12021-02-21 08:26:21 -080080struct imx8mq_usb_phy {
Ye Li4266dc12021-02-21 08:26:21 -080081 struct clk phy_clk;
Ye Li4266dc12021-02-21 08:26:21 -080082 void __iomem *base;
Marek Vasut77ee5d32022-04-01 03:18:31 +020083 enum imx8mpq_phy_type type;
Tim Harveyc90729c2023-07-13 11:56:07 -070084 struct udevice *vbus_supply;
Ye Li4266dc12021-02-21 08:26:21 -080085};
86
87static const struct udevice_id imx8mq_usb_phy_of_match[] = {
Marek Vasut77ee5d32022-04-01 03:18:31 +020088 { .compatible = "fsl,imx8mq-usb-phy", .data = IMX8MQ_PHY },
89 { .compatible = "fsl,imx8mp-usb-phy", .data = IMX8MP_PHY },
Ye Li4266dc12021-02-21 08:26:21 -080090 {},
91};
92
93static int imx8mq_usb_phy_init(struct phy *usb_phy)
94{
95 struct udevice *dev = usb_phy->dev;
96 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
97 u32 value;
98
99 value = readl(imx_phy->base + PHY_CTRL1);
100 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
101 PHY_CTRL1_COMMONONN);
102 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
103 writel(value, imx_phy->base + PHY_CTRL1);
104
105 value = readl(imx_phy->base + PHY_CTRL0);
106 value |= PHY_CTRL0_REF_SSP_EN;
107 value &= ~PHY_CTRL0_SSC_RANGE_MASK;
108 value |= PHY_CTRL0_SSC_RANGE_4003PPM;
109 writel(value, imx_phy->base + PHY_CTRL0);
110
111 value = readl(imx_phy->base + PHY_CTRL2);
112 value |= PHY_CTRL2_TXENABLEN0;
113 writel(value, imx_phy->base + PHY_CTRL2);
114
115 value = readl(imx_phy->base + PHY_CTRL1);
116 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
117 writel(value, imx_phy->base + PHY_CTRL1);
118
119 return 0;
120}
121
Marek Vasut77ee5d32022-04-01 03:18:31 +0200122static int imx8mp_usb_phy_init(struct phy *usb_phy)
123{
124 struct udevice *dev = usb_phy->dev;
125 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
126 u32 value;
127
128 /* USB3.0 PHY signal fsel for 24M ref */
129 value = readl(imx_phy->base + PHY_CTRL0);
130 value &= ~PHY_CTRL0_FSEL_MASK;
131 value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M);
132 writel(value, imx_phy->base + PHY_CTRL0);
133
134 /* Disable alt_clk_en and use internal MPLL clocks */
135 value = readl(imx_phy->base + PHY_CTRL6);
136 value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN);
137 writel(value, imx_phy->base + PHY_CTRL6);
138
139 value = readl(imx_phy->base + PHY_CTRL1);
140 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0);
141 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
142 writel(value, imx_phy->base + PHY_CTRL1);
143
144 value = readl(imx_phy->base + PHY_CTRL0);
145 value |= PHY_CTRL0_REF_SSP_EN;
146 writel(value, imx_phy->base + PHY_CTRL0);
147
148 value = readl(imx_phy->base + PHY_CTRL2);
149 value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE;
150 writel(value, imx_phy->base + PHY_CTRL2);
151
152 udelay(10);
153
154 value = readl(imx_phy->base + PHY_CTRL1);
155 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
156 writel(value, imx_phy->base + PHY_CTRL1);
157
158 return 0;
159}
160
161static int imx8mpq_usb_phy_init(struct phy *usb_phy)
162{
163 struct udevice *dev = usb_phy->dev;
164 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
165
166 if (imx_phy->type == IMX8MP_PHY)
167 return imx8mp_usb_phy_init(usb_phy);
168 else
169 return imx8mq_usb_phy_init(usb_phy);
170}
171
Ye Li4266dc12021-02-21 08:26:21 -0800172static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
173{
174 struct udevice *dev = usb_phy->dev;
175 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
176 u32 value;
Tim Harveyc90729c2023-07-13 11:56:07 -0700177 int ret;
Ye Li4266dc12021-02-21 08:26:21 -0800178
Tim Harveye3380e12023-07-13 11:56:08 -0700179 if (CONFIG_IS_ENABLED(CLK)) {
180 ret = clk_enable(&imx_phy->phy_clk);
181 if (ret) {
182 dev_err(dev, "Failed to enable usb phy clock: %d\n", ret);
183 return ret;
184 }
Ye Li4266dc12021-02-21 08:26:21 -0800185 }
Ye Li4266dc12021-02-21 08:26:21 -0800186
Tim Harveyc90729c2023-07-13 11:56:07 -0700187 if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
188 ret = regulator_set_enable_if_allowed(imx_phy->vbus_supply, true);
189 if (ret && ret != -ENOSYS) {
190 dev_err(dev, "Failed to enable VBUS regulator: %d\n", ret);
191 goto err;
192 }
193 }
194
Ye Li4266dc12021-02-21 08:26:21 -0800195 /* Disable rx term override */
196 value = readl(imx_phy->base + PHY_CTRL6);
197 value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
198 writel(value, imx_phy->base + PHY_CTRL6);
199
200 return 0;
Tim Harveyc90729c2023-07-13 11:56:07 -0700201
202err:
Tim Harveye3380e12023-07-13 11:56:08 -0700203 if (CONFIG_IS_ENABLED(CLK))
204 clk_disable(&imx_phy->phy_clk);
Tim Harveyc90729c2023-07-13 11:56:07 -0700205 return ret;
Ye Li4266dc12021-02-21 08:26:21 -0800206}
207
208static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
209{
210 struct udevice *dev = usb_phy->dev;
211 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
212 u32 value;
Tim Harveyc90729c2023-07-13 11:56:07 -0700213 int ret;
Ye Li4266dc12021-02-21 08:26:21 -0800214
215 /* Override rx term to be 0 */
216 value = readl(imx_phy->base + PHY_CTRL6);
217 value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
218 writel(value, imx_phy->base + PHY_CTRL6);
219
Tim Harveye3380e12023-07-13 11:56:08 -0700220 if (CONFIG_IS_ENABLED(CLK))
221 clk_disable(&imx_phy->phy_clk);
Ye Li4266dc12021-02-21 08:26:21 -0800222
Tim Harveyc90729c2023-07-13 11:56:07 -0700223 if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
224 ret = regulator_set_enable_if_allowed(imx_phy->vbus_supply, false);
225 if (ret && ret != -ENOSYS) {
226 dev_err(dev, "Failed to disable VBUS regulator: %d\n", ret);
227 return ret;
228 }
229 }
230
Ye Li4266dc12021-02-21 08:26:21 -0800231 return 0;
232}
233
234static int imx8mq_usb_phy_exit(struct phy *usb_phy)
235{
236 return imx8mq_usb_phy_power_off(usb_phy);
237}
238
239struct phy_ops imx8mq_usb_phy_ops = {
Marek Vasut77ee5d32022-04-01 03:18:31 +0200240 .init = imx8mpq_usb_phy_init,
Ye Li4266dc12021-02-21 08:26:21 -0800241 .power_on = imx8mq_usb_phy_power_on,
242 .power_off = imx8mq_usb_phy_power_off,
243 .exit = imx8mq_usb_phy_exit,
244};
245
246int imx8mq_usb_phy_probe(struct udevice *dev)
247{
248 struct imx8mq_usb_phy *priv = dev_get_priv(dev);
Tim Harveyc90729c2023-07-13 11:56:07 -0700249 int ret;
Ye Li4266dc12021-02-21 08:26:21 -0800250
Marek Vasut77ee5d32022-04-01 03:18:31 +0200251 priv->type = dev_get_driver_data(dev);
Ye Li4266dc12021-02-21 08:26:21 -0800252 priv->base = dev_read_addr_ptr(dev);
253
254 if (!priv->base)
255 return -EINVAL;
256
Tim Harveye3380e12023-07-13 11:56:08 -0700257 if (CONFIG_IS_ENABLED(CLK)) {
258 ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
259 if (ret) {
260 dev_err(dev, "Failed to get usb phy clock %d\n", ret);
261 return ret;
262 }
Ye Li4266dc12021-02-21 08:26:21 -0800263 }
Tim Harveye3380e12023-07-13 11:56:08 -0700264
Tim Harveyc90729c2023-07-13 11:56:07 -0700265 if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
266 ret = device_get_supply_regulator(dev, "vbus-supply",
267 &priv->vbus_supply);
268 if (ret && ret != -ENOENT) {
269 dev_err(dev, "Failed to get VBUS regulator: %d\n", ret);
270 return ret;
271 }
272 }
Ye Li4266dc12021-02-21 08:26:21 -0800273
274 return 0;
275}
276
277U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
278 .name = "nxp_imx8mq_usb_phy",
279 .id = UCLASS_PHY,
280 .of_match = imx8mq_usb_phy_of_match,
281 .probe = imx8mq_usb_phy_probe,
282 .ops = &imx8mq_usb_phy_ops,
283 .priv_auto = sizeof(struct imx8mq_usb_phy),
284};