1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2025 Linaro Ltd.
4 * Sam Protsenko <semen.protsenko@linaro.org>
5 *
6 * Samsung Exynos SoC series USB DRD PHY driver.
7 * Based on Linux kernel PHY driver: drivers/phy/samsung/phy-exynos5-usbdrd.c
8 */
9
10 #include <clk.h>
11 #include <dm.h>
12 #include <generic-phy.h>
13 #include <regmap.h>
14 #include <syscon.h>
15 #include <asm/io.h>
16 #include <dm/device_compat.h>
17 #include <linux/bitfield.h>
18 #include <linux/bitops.h>
19 #include <linux/delay.h>
20
21 /* Offset of PMU register controlling USB PHY output isolation */
22 #define EXYNOS_USBDRD_PHY_CONTROL 0x0704
23 #define EXYNOS_PHY_ENABLE BIT(0)
24
25 /* Exynos USB PHY registers */
26 #define EXYNOS5_FSEL_9MHZ6 0x0
27 #define EXYNOS5_FSEL_10MHZ 0x1
28 #define EXYNOS5_FSEL_12MHZ 0x2
29 #define EXYNOS5_FSEL_19MHZ2 0x3
30 #define EXYNOS5_FSEL_20MHZ 0x4
31 #define EXYNOS5_FSEL_24MHZ 0x5
32 #define EXYNOS5_FSEL_26MHZ 0x6
33 #define EXYNOS5_FSEL_50MHZ 0x7
34
35 /* Exynos850: USB DRD PHY registers */
36 #define EXYNOS850_DRD_LINKCTRL 0x04
37 #define LINKCTRL_FORCE_QACT BIT(8)
38 #define LINKCTRL_BUS_FILTER_BYPASS GENMASK(7, 4)
39
40 #define EXYNOS850_DRD_CLKRST 0x20
41 #define CLKRST_LINK_SW_RST BIT(0)
42 #define CLKRST_PORT_RST BIT(1)
43 #define CLKRST_PHY_SW_RST BIT(3)
44
45 #define EXYNOS850_DRD_SSPPLLCTL 0x30
46 #define SSPPLLCTL_FSEL GENMASK(2, 0)
47
48 #define EXYNOS850_DRD_UTMI 0x50
49 #define UTMI_FORCE_SLEEP BIT(0)
50 #define UTMI_FORCE_SUSPEND BIT(1)
51 #define UTMI_DM_PULLDOWN BIT(2)
52 #define UTMI_DP_PULLDOWN BIT(3)
53 #define UTMI_FORCE_BVALID BIT(4)
54 #define UTMI_FORCE_VBUSVALID BIT(5)
55
56 #define EXYNOS850_DRD_HSP 0x54
57 #define HSP_COMMONONN BIT(8)
58 #define HSP_EN_UTMISUSPEND BIT(9)
59 #define HSP_VBUSVLDEXT BIT(12)
60 #define HSP_VBUSVLDEXTSEL BIT(13)
61 #define HSP_FSV_OUT_EN BIT(24)
62
63 #define EXYNOS850_DRD_HSP_TEST 0x5c
64 #define HSP_TEST_SIDDQ BIT(24)
65
66 #define KHZ 1000
67 #define MHZ (KHZ * KHZ)
68
69 /**
70 * struct exynos_usbdrd_phy - driver data for Exynos USB PHY
71 * @reg_phy: USB PHY controller register memory base
72 * @clk: clock for register access
73 * @core_clk: core clock for phy (ref clock)
74 * @reg_pmu: regmap for PMU block
75 * @extrefclk: frequency select settings when using 'separate reference clocks'
76 */
77 struct exynos_usbdrd_phy {
78 void __iomem *reg_phy;
79 struct clk *clk;
80 struct clk *core_clk;
81 struct regmap *reg_pmu;
82 u32 extrefclk;
83 };
84
exynos_usbdrd_phy_isol(struct regmap * reg_pmu,bool isolate)85 static void exynos_usbdrd_phy_isol(struct regmap *reg_pmu, bool isolate)
86 {
87 unsigned int val;
88
89 if (!reg_pmu)
90 return;
91
92 val = isolate ? 0 : EXYNOS_PHY_ENABLE;
93 regmap_update_bits(reg_pmu, EXYNOS_USBDRD_PHY_CONTROL,
94 EXYNOS_PHY_ENABLE, val);
95 }
96
97 /*
98 * Convert the supplied clock rate to the value that can be written to the PHY
99 * register.
100 */
exynos_rate_to_clk(unsigned long rate,u32 * reg)101 static unsigned int exynos_rate_to_clk(unsigned long rate, u32 *reg)
102 {
103 switch (rate) {
104 case 9600 * KHZ:
105 *reg = EXYNOS5_FSEL_9MHZ6;
106 break;
107 case 10 * MHZ:
108 *reg = EXYNOS5_FSEL_10MHZ;
109 break;
110 case 12 * MHZ:
111 *reg = EXYNOS5_FSEL_12MHZ;
112 break;
113 case 19200 * KHZ:
114 *reg = EXYNOS5_FSEL_19MHZ2;
115 break;
116 case 20 * MHZ:
117 *reg = EXYNOS5_FSEL_20MHZ;
118 break;
119 case 24 * MHZ:
120 *reg = EXYNOS5_FSEL_24MHZ;
121 break;
122 case 26 * MHZ:
123 *reg = EXYNOS5_FSEL_26MHZ;
124 break;
125 case 50 * MHZ:
126 *reg = EXYNOS5_FSEL_50MHZ;
127 break;
128 default:
129 return -EINVAL;
130 }
131
132 return 0;
133 }
134
exynos850_usbdrd_utmi_init(struct phy * phy)135 static void exynos850_usbdrd_utmi_init(struct phy *phy)
136 {
137 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
138 void __iomem *regs_base = phy_drd->reg_phy;
139 u32 reg;
140
141 /*
142 * Disable HWACG (hardware auto clock gating control). This will force
143 * QACTIVE signal in Q-Channel interface to HIGH level, to make sure
144 * the PHY clock is not gated by the hardware.
145 */
146 reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
147 reg |= LINKCTRL_FORCE_QACT;
148 writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
149
150 /* Start PHY Reset (POR=high) */
151 reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
152 reg |= CLKRST_PHY_SW_RST;
153 writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
154
155 /* Enable UTMI+ */
156 reg = readl(regs_base + EXYNOS850_DRD_UTMI);
157 reg &= ~(UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP | UTMI_DP_PULLDOWN |
158 UTMI_DM_PULLDOWN);
159 writel(reg, regs_base + EXYNOS850_DRD_UTMI);
160
161 /* Set PHY clock and control HS PHY */
162 reg = readl(regs_base + EXYNOS850_DRD_HSP);
163 reg |= HSP_EN_UTMISUSPEND | HSP_COMMONONN;
164 writel(reg, regs_base + EXYNOS850_DRD_HSP);
165
166 /* Set VBUS Valid and D+ pull-up control by VBUS pad usage */
167 reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
168 reg |= FIELD_PREP(LINKCTRL_BUS_FILTER_BYPASS, 0xf);
169 writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
170
171 reg = readl(regs_base + EXYNOS850_DRD_UTMI);
172 reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
173 writel(reg, regs_base + EXYNOS850_DRD_UTMI);
174
175 reg = readl(regs_base + EXYNOS850_DRD_HSP);
176 reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
177 writel(reg, regs_base + EXYNOS850_DRD_HSP);
178
179 reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL);
180 reg &= ~SSPPLLCTL_FSEL;
181 switch (phy_drd->extrefclk) {
182 case EXYNOS5_FSEL_50MHZ:
183 reg |= FIELD_PREP(SSPPLLCTL_FSEL, 7);
184 break;
185 case EXYNOS5_FSEL_26MHZ:
186 reg |= FIELD_PREP(SSPPLLCTL_FSEL, 6);
187 break;
188 case EXYNOS5_FSEL_24MHZ:
189 reg |= FIELD_PREP(SSPPLLCTL_FSEL, 2);
190 break;
191 case EXYNOS5_FSEL_20MHZ:
192 reg |= FIELD_PREP(SSPPLLCTL_FSEL, 1);
193 break;
194 case EXYNOS5_FSEL_19MHZ2:
195 reg |= FIELD_PREP(SSPPLLCTL_FSEL, 0);
196 break;
197 default:
198 dev_warn(phy->dev, "unsupported ref clk: %#.2x\n",
199 phy_drd->extrefclk);
200 break;
201 }
202 writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL);
203
204 /* Power up PHY analog blocks */
205 reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
206 reg &= ~HSP_TEST_SIDDQ;
207 writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
208
209 /* Finish PHY reset (POR=low) */
210 udelay(10); /* required before doing POR=low */
211 reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
212 reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST);
213 writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
214 udelay(75); /* required after POR=low for guaranteed PHY clock */
215
216 /* Disable single ended signal out */
217 reg = readl(regs_base + EXYNOS850_DRD_HSP);
218 reg &= ~HSP_FSV_OUT_EN;
219 writel(reg, regs_base + EXYNOS850_DRD_HSP);
220 }
221
exynos850_usbdrd_utmi_exit(struct phy * phy)222 static void exynos850_usbdrd_utmi_exit(struct phy *phy)
223 {
224 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
225 void __iomem *regs_base = phy_drd->reg_phy;
226 u32 reg;
227
228 /* Set PHY clock and control HS PHY */
229 reg = readl(regs_base + EXYNOS850_DRD_UTMI);
230 reg &= ~(UTMI_DP_PULLDOWN | UTMI_DM_PULLDOWN);
231 reg |= UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP;
232 writel(reg, regs_base + EXYNOS850_DRD_UTMI);
233
234 /* Power down PHY analog blocks */
235 reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
236 reg |= HSP_TEST_SIDDQ;
237 writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
238
239 /* Link reset */
240 reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
241 reg |= CLKRST_LINK_SW_RST;
242 writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
243 udelay(10); /* required before doing POR=low */
244 reg &= ~CLKRST_LINK_SW_RST;
245 writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
246 }
247
exynos_usbdrd_phy_init(struct phy * phy)248 static int exynos_usbdrd_phy_init(struct phy *phy)
249 {
250 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
251 int ret;
252
253 ret = clk_prepare_enable(phy_drd->clk);
254 if (ret)
255 return ret;
256
257 exynos850_usbdrd_utmi_init(phy);
258
259 clk_disable_unprepare(phy_drd->clk);
260
261 return 0;
262 }
263
exynos_usbdrd_phy_exit(struct phy * phy)264 static int exynos_usbdrd_phy_exit(struct phy *phy)
265 {
266 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
267 int ret;
268
269 ret = clk_prepare_enable(phy_drd->clk);
270 if (ret)
271 return ret;
272
273 exynos850_usbdrd_utmi_exit(phy);
274
275 clk_disable_unprepare(phy_drd->clk);
276
277 return 0;
278 }
279
exynos_usbdrd_phy_power_on(struct phy * phy)280 static int exynos_usbdrd_phy_power_on(struct phy *phy)
281 {
282 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
283 int ret;
284
285 dev_dbg(phy->dev, "Request to power_on usbdrd_phy phy\n");
286
287 ret = clk_prepare_enable(phy_drd->core_clk);
288 if (ret)
289 return ret;
290
291 /* Power-on PHY */
292 exynos_usbdrd_phy_isol(phy_drd->reg_pmu, false);
293
294 return 0;
295 }
296
exynos_usbdrd_phy_power_off(struct phy * phy)297 static int exynos_usbdrd_phy_power_off(struct phy *phy)
298 {
299 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
300
301 dev_dbg(phy->dev, "Request to power_off usbdrd_phy phy\n");
302
303 /* Power-off the PHY */
304 exynos_usbdrd_phy_isol(phy_drd->reg_pmu, true);
305
306 clk_disable_unprepare(phy_drd->core_clk);
307
308 return 0;
309 }
310
exynos_usbdrd_phy_init_clk(struct udevice * dev)311 static int exynos_usbdrd_phy_init_clk(struct udevice *dev)
312 {
313 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev);
314 unsigned long ref_rate;
315 int err;
316
317 phy_drd->clk = devm_clk_get(dev, "phy");
318 if (IS_ERR(phy_drd->clk)) {
319 err = PTR_ERR(phy_drd->clk);
320 dev_err(dev, "Failed to get phy clock (err=%d)\n", err);
321 return err;
322 }
323
324 phy_drd->core_clk = devm_clk_get(dev, "ref");
325 if (IS_ERR(phy_drd->core_clk)) {
326 err = PTR_ERR(phy_drd->core_clk);
327 dev_err(dev, "Failed to get ref clock (err=%d)\n", err);
328 return err;
329 }
330
331 ref_rate = clk_get_rate(phy_drd->core_clk);
332 err = exynos_rate_to_clk(ref_rate, &phy_drd->extrefclk);
333 if (err) {
334 dev_err(dev, "Clock rate %lu not supported\n", ref_rate);
335 return err;
336 }
337
338 return 0;
339 }
340
exynos_usbdrd_phy_probe(struct udevice * dev)341 static int exynos_usbdrd_phy_probe(struct udevice *dev)
342 {
343 struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev);
344 int err;
345
346 phy_drd->reg_phy = dev_read_addr_ptr(dev);
347 if (!phy_drd->reg_phy)
348 return -EINVAL;
349
350 err = exynos_usbdrd_phy_init_clk(dev);
351 if (err)
352 return err;
353
354 phy_drd->reg_pmu = syscon_regmap_lookup_by_phandle(dev,
355 "samsung,pmu-syscon");
356 if (IS_ERR(phy_drd->reg_pmu)) {
357 err = PTR_ERR(phy_drd->reg_pmu);
358 dev_err(dev, "Failed to lookup PMU regmap\n");
359 return err;
360 }
361
362 return 0;
363 }
364
365 static const struct phy_ops exynos_usbdrd_phy_ops = {
366 .init = exynos_usbdrd_phy_init,
367 .exit = exynos_usbdrd_phy_exit,
368 .power_on = exynos_usbdrd_phy_power_on,
369 .power_off = exynos_usbdrd_phy_power_off,
370 };
371
372 static const struct udevice_id exynos_usbdrd_phy_of_match[] = {
373 {
374 .compatible = "samsung,exynos850-usbdrd-phy",
375 },
376 { }
377 };
378
379 U_BOOT_DRIVER(exynos_usbdrd_phy) = {
380 .name = "exynos-usbdrd-phy",
381 .id = UCLASS_PHY,
382 .of_match = exynos_usbdrd_phy_of_match,
383 .probe = exynos_usbdrd_phy_probe,
384 .ops = &exynos_usbdrd_phy_ops,
385 .priv_auto = sizeof(struct exynos_usbdrd_phy),
386 };
387