Merge tag 'fsl-qoriq-2022-10-18' of https://source.denx.de/u-boot/custodians/u-boot...
[platform/kernel/u-boot.git] / drivers / phy / phy-imx8mq-usb.c
1 // 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>
12 #include <linux/bitfield.h>
13 #include <linux/bitops.h>
14 #include <linux/delay.h>
15 #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
73 enum imx8mpq_phy_type {
74         IMX8MQ_PHY,
75         IMX8MP_PHY,
76 };
77
78 struct imx8mq_usb_phy {
79 #if CONFIG_IS_ENABLED(CLK)
80         struct clk phy_clk;
81 #endif
82         void __iomem *base;
83         enum imx8mpq_phy_type type;
84 };
85
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 },
89         {},
90 };
91
92 static 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
121 static 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
160 static 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
171 static 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
194 static 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
212 static int imx8mq_usb_phy_exit(struct phy *usb_phy)
213 {
214         return imx8mq_usb_phy_power_off(usb_phy);
215 }
216
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,
222 };
223
224 int imx8mq_usb_phy_probe(struct udevice *dev)
225 {
226         struct imx8mq_usb_phy *priv = dev_get_priv(dev);
227
228         priv->type = dev_get_driver_data(dev);
229         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
248 U_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 };