blob: 69f01de5553828eae10053d60443ec48eaeebb0a [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>
17
18#define PHY_CTRL0 0x0
19#define PHY_CTRL0_REF_SSP_EN BIT(2)
20#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
21#define PHY_CTRL0_FSEL_24M 0x2a
22#define PHY_CTRL0_FSEL_100M 0x27
23#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
24#define PHY_CTRL0_SSC_RANGE_4003PPM (0x2 << 21)
25
26#define PHY_CTRL1 0x4
27#define PHY_CTRL1_RESET BIT(0)
28#define PHY_CTRL1_COMMONONN BIT(1)
29#define PHY_CTRL1_ATERESET BIT(3)
30#define PHY_CTRL1_DCDENB BIT(17)
31#define PHY_CTRL1_CHRGSEL BIT(18)
32#define PHY_CTRL1_VDATSRCENB0 BIT(19)
33#define PHY_CTRL1_VDATDETENB0 BIT(20)
34
35#define PHY_CTRL2 0x8
36#define PHY_CTRL2_TXENABLEN0 BIT(8)
37#define PHY_CTRL2_OTG_DISABLE BIT(9)
38
39#define PHY_CTRL3 0xc
40#define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
41#define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
42#define PHY_CTRL3_TXPREEMP_TUNE_SHIFT 15
43#define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
44#define PHY_CTRL3_TXRISE_TUNE_SHIFT 20
45/* 1111: +24% ... 0000: -6% step: 2% */
46#define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
47#define PHY_CTRL3_TXVREF_TUNE_SHIFT 22
48#define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29)
49#define PHY_CTRL3_TX_VBOOST_LEVEL_SHIFT 29
50
51#define PHY_CTRL4 0x10
52#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
53#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT 15
54
55#define PHY_CTRL5 0x14
56#define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
57#define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
58#define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
59#define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
60#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
61
62#define PHY_CTRL6 0x18
63#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
64#define PHY_CTRL6_ALT_CLK_EN BIT(1)
65#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
66
67#define PHY_STS0 0x40
68#define PHY_STS0_OTGSESSVLD BIT(7)
69#define PHY_STS0_CHGDET BIT(4)
70#define PHY_STS0_FSVPLUS BIT(3)
71#define PHY_STS0_FSVMINUS BIT(2)
72
Marek Vasut77ee5d32022-04-01 03:18:31 +020073enum imx8mpq_phy_type {
74 IMX8MQ_PHY,
75 IMX8MP_PHY,
76};
77
Ye Li4266dc12021-02-21 08:26:21 -080078struct imx8mq_usb_phy {
79#if CONFIG_IS_ENABLED(CLK)
80 struct clk phy_clk;
81#endif
82 void __iomem *base;
Marek Vasut77ee5d32022-04-01 03:18:31 +020083 enum imx8mpq_phy_type type;
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;
176
177#if CONFIG_IS_ENABLED(CLK)
178 int ret;
179 ret = clk_enable(&imx_phy->phy_clk);
180 if (ret) {
181 printf("Failed to enable usb phy clock\n");
182 return ret;
183 }
184#endif
185
186 /* Disable rx term override */
187 value = readl(imx_phy->base + PHY_CTRL6);
188 value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
189 writel(value, imx_phy->base + PHY_CTRL6);
190
191 return 0;
192}
193
194static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
195{
196 struct udevice *dev = usb_phy->dev;
197 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
198 u32 value;
199
200 /* Override rx term to be 0 */
201 value = readl(imx_phy->base + PHY_CTRL6);
202 value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
203 writel(value, imx_phy->base + PHY_CTRL6);
204
205#if CONFIG_IS_ENABLED(CLK)
206 clk_disable(&imx_phy->phy_clk);
207#endif
208
209 return 0;
210}
211
212static int imx8mq_usb_phy_exit(struct phy *usb_phy)
213{
214 return imx8mq_usb_phy_power_off(usb_phy);
215}
216
217struct phy_ops imx8mq_usb_phy_ops = {
Marek Vasut77ee5d32022-04-01 03:18:31 +0200218 .init = imx8mpq_usb_phy_init,
Ye Li4266dc12021-02-21 08:26:21 -0800219 .power_on = imx8mq_usb_phy_power_on,
220 .power_off = imx8mq_usb_phy_power_off,
221 .exit = imx8mq_usb_phy_exit,
222};
223
224int imx8mq_usb_phy_probe(struct udevice *dev)
225{
226 struct imx8mq_usb_phy *priv = dev_get_priv(dev);
227
Marek Vasut77ee5d32022-04-01 03:18:31 +0200228 priv->type = dev_get_driver_data(dev);
Ye Li4266dc12021-02-21 08:26:21 -0800229 priv->base = dev_read_addr_ptr(dev);
230
231 if (!priv->base)
232 return -EINVAL;
233
234#if CONFIG_IS_ENABLED(CLK)
235 int ret;
236
237 /* Assigned clock already set clock */
238 ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
239 if (ret) {
240 printf("Failed to get usb phy clock\n");
241 return ret;
242 }
243#endif
244
245 return 0;
246}
247
248U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
249 .name = "nxp_imx8mq_usb_phy",
250 .id = UCLASS_PHY,
251 .of_match = imx8mq_usb_phy_of_match,
252 .probe = imx8mq_usb_phy_probe,
253 .ops = &imx8mq_usb_phy_ops,
254 .priv_auto = sizeof(struct imx8mq_usb_phy),
255};