1 // SPDX-License-Identifier: GPL-2.0+
11 #include <generic-phy.h>
12 #include <linux/bitfield.h>
13 #include <linux/bitops.h>
14 #include <linux/delay.h>
15 #include <linux/err.h>
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)
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)
36 #define PHY_CTRL2_TXENABLEN0 BIT(8)
37 #define PHY_CTRL2_OTG_DISABLE BIT(9)
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
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
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)
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)
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)
73 enum imx8mpq_phy_type {
78 struct imx8mq_usb_phy {
79 #if CONFIG_IS_ENABLED(CLK)
83 enum imx8mpq_phy_type type;
86 static const struct udevice_id imx8mq_usb_phy_of_match[] = {
87 { .compatible = "fsl,imx8mq-usb-phy", .data = IMX8MQ_PHY },
88 { .compatible = "fsl,imx8mp-usb-phy", .data = IMX8MP_PHY },
92 static int imx8mq_usb_phy_init(struct phy *usb_phy)
94 struct udevice *dev = usb_phy->dev;
95 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
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);
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);
110 value = readl(imx_phy->base + PHY_CTRL2);
111 value |= PHY_CTRL2_TXENABLEN0;
112 writel(value, imx_phy->base + PHY_CTRL2);
114 value = readl(imx_phy->base + PHY_CTRL1);
115 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
116 writel(value, imx_phy->base + PHY_CTRL1);
121 static int imx8mp_usb_phy_init(struct phy *usb_phy)
123 struct udevice *dev = usb_phy->dev;
124 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
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);
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);
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);
143 value = readl(imx_phy->base + PHY_CTRL0);
144 value |= PHY_CTRL0_REF_SSP_EN;
145 writel(value, imx_phy->base + PHY_CTRL0);
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);
153 value = readl(imx_phy->base + PHY_CTRL1);
154 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
155 writel(value, imx_phy->base + PHY_CTRL1);
160 static int imx8mpq_usb_phy_init(struct phy *usb_phy)
162 struct udevice *dev = usb_phy->dev;
163 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
165 if (imx_phy->type == IMX8MP_PHY)
166 return imx8mp_usb_phy_init(usb_phy);
168 return imx8mq_usb_phy_init(usb_phy);
171 static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
173 struct udevice *dev = usb_phy->dev;
174 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
177 #if CONFIG_IS_ENABLED(CLK)
179 ret = clk_enable(&imx_phy->phy_clk);
181 printf("Failed to enable usb phy clock\n");
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);
194 static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
196 struct udevice *dev = usb_phy->dev;
197 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
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);
205 #if CONFIG_IS_ENABLED(CLK)
206 clk_disable(&imx_phy->phy_clk);
212 static int imx8mq_usb_phy_exit(struct phy *usb_phy)
214 return imx8mq_usb_phy_power_off(usb_phy);
217 struct phy_ops imx8mq_usb_phy_ops = {
218 .init = imx8mpq_usb_phy_init,
219 .power_on = imx8mq_usb_phy_power_on,
220 .power_off = imx8mq_usb_phy_power_off,
221 .exit = imx8mq_usb_phy_exit,
224 int imx8mq_usb_phy_probe(struct udevice *dev)
226 struct imx8mq_usb_phy *priv = dev_get_priv(dev);
228 priv->type = dev_get_driver_data(dev);
229 priv->base = dev_read_addr_ptr(dev);
234 #if CONFIG_IS_ENABLED(CLK)
237 /* Assigned clock already set clock */
238 ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
240 printf("Failed to get usb phy clock\n");
248 U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
249 .name = "nxp_imx8mq_usb_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),