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