xref: /rk3399_rockchip-uboot/drivers/phy/phy-rockchip-inno-usb2.c (revision 21016d27c500da4326bdc59cd3505fcd85d236db)
1 /*
2  * Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:    GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <generic-phy.h>
10 #include <syscon.h>
11 #include <asm/io.h>
12 #include <asm/arch/clock.h>
13 
14 #define U2PHY_BIT_WRITEABLE_SHIFT	16
15 #define CHG_DCD_MAX_RETRIES		6
16 #define CHG_PRI_MAX_RETRIES		2
17 #define CHG_DCD_POLL_TIME		100	/* millisecond */
18 #define CHG_PRIMARY_DET_TIME		40	/* millisecond */
19 #define CHG_SECONDARY_DET_TIME		40	/* millisecond */
20 
21 struct rockchip_usb2phy;
22 
23 enum power_supply_type {
24 	POWER_SUPPLY_TYPE_UNKNOWN = 0,
25 	POWER_SUPPLY_TYPE_USB,		/* Standard Downstream Port */
26 	POWER_SUPPLY_TYPE_USB_DCP,	/* Dedicated Charging Port */
27 	POWER_SUPPLY_TYPE_USB_CDP,	/* Charging Downstream Port */
28 	POWER_SUPPLY_TYPE_USB_FLOATING,	/* DCP without shorting D+/D- */
29 };
30 
31 enum rockchip_usb2phy_port_id {
32 	USB2PHY_PORT_OTG,
33 	USB2PHY_PORT_HOST,
34 	USB2PHY_NUM_PORTS,
35 };
36 
37 struct usb2phy_reg {
38 	u32	offset;
39 	u32	bitend;
40 	u32	bitstart;
41 	u32	disable;
42 	u32	enable;
43 };
44 
45 /**
46  * struct rockchip_chg_det_reg: usb charger detect registers
47  * @cp_det: charging port detected successfully.
48  * @dcp_det: dedicated charging port detected successfully.
49  * @dp_det: assert data pin connect successfully.
50  * @idm_sink_en: open dm sink curren.
51  * @idp_sink_en: open dp sink current.
52  * @idp_src_en: open dm source current.
53  * @rdm_pdwn_en: open dm pull down resistor.
54  * @vdm_src_en: open dm voltage source.
55  * @vdp_src_en: open dp voltage source.
56  * @opmode: utmi operational mode.
57  */
58 struct rockchip_chg_det_reg {
59 	struct usb2phy_reg	cp_det;
60 	struct usb2phy_reg	dcp_det;
61 	struct usb2phy_reg	dp_det;
62 	struct usb2phy_reg	idm_sink_en;
63 	struct usb2phy_reg	idp_sink_en;
64 	struct usb2phy_reg	idp_src_en;
65 	struct usb2phy_reg	rdm_pdwn_en;
66 	struct usb2phy_reg	vdm_src_en;
67 	struct usb2phy_reg	vdp_src_en;
68 	struct usb2phy_reg	opmode;
69 };
70 
71 /**
72  * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
73  * @phy_sus: phy suspend register.
74  * @bvalid_det_en: vbus valid rise detection enable register.
75  * @bvalid_det_st: vbus valid rise detection status register.
76  * @bvalid_det_clr: vbus valid rise detection clear register.
77  * @ls_det_en: linestate detection enable register.
78  * @ls_det_st: linestate detection state register.
79  * @ls_det_clr: linestate detection clear register.
80  * @iddig_output: iddig output from grf.
81  * @iddig_en: utmi iddig select between grf and phy,
82  *	      0: from phy; 1: from grf
83  * @idfall_det_en: id fall detection enable register.
84  * @idfall_det_st: id fall detection state register.
85  * @idfall_det_clr: id fall detection clear register.
86  * @idrise_det_en: id rise detection enable register.
87  * @idrise_det_st: id rise detection state register.
88  * @idrise_det_clr: id rise detection clear register.
89  * @utmi_avalid: utmi vbus avalid status register.
90  * @utmi_bvalid: utmi vbus bvalid status register.
91  * @utmi_iddig: otg port id pin status register.
92  * @utmi_ls: utmi linestate state register.
93  * @utmi_hstdet: utmi host disconnect register.
94  * @vbus_det_en: vbus detect function power down register.
95  */
96 struct rockchip_usb2phy_port_cfg {
97 	struct usb2phy_reg	phy_sus;
98 	struct usb2phy_reg	bvalid_det_en;
99 	struct usb2phy_reg	bvalid_det_st;
100 	struct usb2phy_reg	bvalid_det_clr;
101 	struct usb2phy_reg	ls_det_en;
102 	struct usb2phy_reg	ls_det_st;
103 	struct usb2phy_reg	ls_det_clr;
104 	struct usb2phy_reg	iddig_output;
105 	struct usb2phy_reg	iddig_en;
106 	struct usb2phy_reg	idfall_det_en;
107 	struct usb2phy_reg	idfall_det_st;
108 	struct usb2phy_reg	idfall_det_clr;
109 	struct usb2phy_reg	idrise_det_en;
110 	struct usb2phy_reg	idrise_det_st;
111 	struct usb2phy_reg	idrise_det_clr;
112 	struct usb2phy_reg	utmi_avalid;
113 	struct usb2phy_reg	utmi_bvalid;
114 	struct usb2phy_reg	utmi_iddig;
115 	struct usb2phy_reg	utmi_ls;
116 	struct usb2phy_reg	utmi_hstdet;
117 	struct usb2phy_reg	vbus_det_en;
118 };
119 
120 /**
121  * struct rockchip_usb2phy_cfg: usb-phy configuration.
122  * @reg: the address offset of grf for usb-phy config.
123  * @num_ports: specify how many ports that the phy has.
124  * @phy_tuning: phy default parameters tunning.
125  * @clkout_ctl: keep on/turn off output clk of phy.
126  * @chg_det: charger detection registers.
127  */
128 struct rockchip_usb2phy_cfg {
129 	u32	reg;
130 	u32	num_ports;
131 	int (*phy_tuning)(struct rockchip_usb2phy *);
132 	struct usb2phy_reg	clkout_ctl;
133 	const struct rockchip_usb2phy_port_cfg	port_cfgs[USB2PHY_NUM_PORTS];
134 	const struct rockchip_chg_det_reg	chg_det;
135 };
136 
137 /**
138  * @dcd_retries: The retry count used to track Data contact
139  *		 detection process.
140  * @primary_retries: The retry count used to do usb bc detection
141  *		     primary stage.
142  * @grf: General Register Files register base.
143  * @usbgrf_base : USB General Register Files register base.
144  * @phy_cfg: phy register configuration, assigned by driver data.
145  */
146 struct rockchip_usb2phy {
147 	u8		dcd_retries;
148 	u8		primary_retries;
149 	void __iomem	*grf_base;
150 	void __iomem	*usbgrf_base;
151 	const struct rockchip_usb2phy_cfg	*phy_cfg;
152 };
153 
154 static inline void __iomem *get_reg_base(struct rockchip_usb2phy *rphy)
155 {
156 	return !rphy->usbgrf_base ? rphy->grf_base : rphy->usbgrf_base;
157 }
158 
159 static inline int property_enable(void __iomem *base,
160 				  const struct usb2phy_reg *reg, bool en)
161 {
162 	u32 val, mask, tmp;
163 
164 	tmp = en ? reg->enable : reg->disable;
165 	mask = GENMASK(reg->bitend, reg->bitstart);
166 	val = (tmp << reg->bitstart) | (mask << U2PHY_BIT_WRITEABLE_SHIFT);
167 
168 	return writel(val, base + reg->offset);
169 }
170 
171 static inline bool property_enabled(void __iomem *base,
172 				    const struct usb2phy_reg *reg)
173 {
174 	u32 tmp, orig;
175 	u32 mask = GENMASK(reg->bitend, reg->bitstart);
176 
177 	orig = readl(base + reg->offset);
178 
179 	tmp = (orig & mask) >> reg->bitstart;
180 
181 	return tmp == reg->enable;
182 }
183 
184 static const char *chg_to_string(enum power_supply_type chg_type)
185 {
186 	switch (chg_type) {
187 	case POWER_SUPPLY_TYPE_USB:
188 		return "USB_SDP_CHARGER";
189 	case POWER_SUPPLY_TYPE_USB_DCP:
190 		return "USB_DCP_CHARGER";
191 	case POWER_SUPPLY_TYPE_USB_CDP:
192 		return "USB_CDP_CHARGER";
193 	case POWER_SUPPLY_TYPE_USB_FLOATING:
194 		return "USB_FLOATING_CHARGER";
195 	default:
196 		return "INVALID_CHARGER";
197 	}
198 }
199 
200 static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy,
201 				    bool en)
202 {
203 	void __iomem *base = get_reg_base(rphy);
204 
205 	property_enable(base, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en);
206 	property_enable(base, &rphy->phy_cfg->chg_det.idp_src_en, en);
207 }
208 
209 static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy,
210 					    bool en)
211 {
212 	void __iomem *base = get_reg_base(rphy);
213 
214 	property_enable(base, &rphy->phy_cfg->chg_det.vdp_src_en, en);
215 	property_enable(base, &rphy->phy_cfg->chg_det.idm_sink_en, en);
216 }
217 
218 static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy,
219 					      bool en)
220 {
221 	void __iomem *base = get_reg_base(rphy);
222 
223 	property_enable(base, &rphy->phy_cfg->chg_det.vdm_src_en, en);
224 	property_enable(base, &rphy->phy_cfg->chg_det.idp_sink_en, en);
225 }
226 
227 static bool rockchip_chg_primary_det_retry(struct rockchip_usb2phy *rphy)
228 {
229 	bool vout = false;
230 
231 	while (rphy->primary_retries--) {
232 		/* voltage source on DP, probe on DM */
233 		rockchip_chg_enable_primary_det(rphy, true);
234 		mdelay(CHG_PRIMARY_DET_TIME);
235 		vout = property_enabled(rphy->grf_base,
236 					&rphy->phy_cfg->chg_det.cp_det);
237 		if (vout)
238 			break;
239 	}
240 
241 	return vout;
242 }
243 
244 int rockchip_chg_get_type(void)
245 {
246 	const struct rockchip_usb2phy_cfg *phy_cfgs;
247 	enum power_supply_type chg_type;
248 	struct rockchip_usb2phy rphy;
249 	struct udevice *dev;
250 	ofnode u2phy_node, grf_node;
251 	fdt_size_t size;
252 	u32 reg, index;
253 	bool is_dcd, vout;
254 	int ret;
255 
256 	u2phy_node = ofnode_null();
257 	grf_node = ofnode_null();
258 
259 	u2phy_node = ofnode_path("/usb2-phy");
260 
261 	if (!ofnode_valid(u2phy_node)) {
262 		grf_node = ofnode_path("/syscon-usb");
263 		if (ofnode_valid(grf_node))
264 			u2phy_node = ofnode_find_subnode(grf_node,
265 							 "usb2-phy");
266 	}
267 
268 	if (!ofnode_valid(u2phy_node)) {
269 		printf("%s: missing u2phy node\n", __func__);
270 		return -EINVAL;
271 	}
272 
273 	if (ofnode_valid(grf_node)) {
274 		rphy.grf_base =
275 			(void __iomem *)ofnode_get_addr_size(grf_node,
276 							     "reg", &size);
277 	} else {
278 		if (ofnode_read_bool(u2phy_node, "rockchip,grf"))
279 			rphy.grf_base =
280 				syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
281 	}
282 
283 	if (rphy.grf_base <= 0) {
284 		dev_err(dev, "get syscon grf failed\n");
285 		return -EINVAL;
286 	}
287 
288 	if (ofnode_read_u32(u2phy_node, "reg", &reg)) {
289 		printf("%s: could not read reg\n", __func__);
290 		return -EINVAL;
291 	}
292 
293 	if (ofnode_read_bool(u2phy_node, "rockchip,usbgrf")) {
294 		rphy.usbgrf_base =
295 			syscon_get_first_range(ROCKCHIP_SYSCON_USBGRF);
296 		if (rphy.usbgrf_base <= 0) {
297 			dev_err(dev, "get syscon usbgrf failed\n");
298 			return -EINVAL;
299 		}
300 	} else {
301 		rphy.usbgrf_base = NULL;
302 	}
303 
304 	ret = uclass_get_device_by_ofnode(UCLASS_PHY, u2phy_node, &dev);
305 	if (ret) {
306 		printf("%s: uclass_get_device_by_ofnode failed: %d\n",
307 		       __func__, ret);
308 		return ret;
309 	}
310 
311 	phy_cfgs =
312 		(const struct rockchip_usb2phy_cfg *)dev_get_driver_data(dev);
313 	if (!phy_cfgs) {
314 		printf("%s: unable to get phy_cfgs\n", __func__);
315 		return -EINVAL;
316 	}
317 
318 	/* find out a proper config which can be matched with dt. */
319 	index = 0;
320 	while (phy_cfgs[index].reg) {
321 		if (phy_cfgs[index].reg == reg) {
322 			rphy.phy_cfg = &phy_cfgs[index];
323 			break;
324 		}
325 		++index;
326 	}
327 
328 	if (!rphy.phy_cfg) {
329 		printf("%s: no phy-config can be matched\n", __func__);
330 		return -EINVAL;
331 	}
332 
333 	rphy.dcd_retries = CHG_DCD_MAX_RETRIES;
334 	rphy.primary_retries = CHG_PRI_MAX_RETRIES;
335 
336 	/* stage 1, start DCD processing stage */
337 	rockchip_chg_enable_dcd(&rphy, true);
338 
339 	while (rphy.dcd_retries--) {
340 		mdelay(CHG_DCD_POLL_TIME);
341 
342 		/* get data contact detection status */
343 		is_dcd = property_enabled(rphy.grf_base,
344 					  &rphy.phy_cfg->chg_det.dp_det);
345 
346 		if (is_dcd || !rphy.dcd_retries) {
347 			/*
348 			 * stage 2, turn off DCD circuitry, then
349 			 * voltage source on DP, probe on DM.
350 			 */
351 			rockchip_chg_enable_dcd(&rphy, false);
352 			rockchip_chg_enable_primary_det(&rphy, true);
353 			break;
354 		}
355 	}
356 
357 	mdelay(CHG_PRIMARY_DET_TIME);
358 	vout = property_enabled(rphy.grf_base,
359 				&rphy.phy_cfg->chg_det.cp_det);
360 	rockchip_chg_enable_primary_det(&rphy, false);
361 	if (vout) {
362 		/* stage 3, voltage source on DM, probe on DP */
363 		rockchip_chg_enable_secondary_det(&rphy, true);
364 	} else {
365 		if (!rphy.dcd_retries) {
366 			/* floating charger found */
367 			chg_type = POWER_SUPPLY_TYPE_USB_FLOATING;
368 			goto out;
369 		} else {
370 			/*
371 			 * Retry some times to make sure that it's
372 			 * really a USB SDP charger.
373 			 */
374 			vout = rockchip_chg_primary_det_retry(&rphy);
375 			if (vout) {
376 				/* stage 3, voltage source on DM, probe on DP */
377 				rockchip_chg_enable_secondary_det(&rphy, true);
378 			} else {
379 				/* USB SDP charger found */
380 				chg_type = POWER_SUPPLY_TYPE_USB;
381 				goto out;
382 			}
383 		}
384 	}
385 
386 	mdelay(CHG_SECONDARY_DET_TIME);
387 	vout = property_enabled(rphy.grf_base,
388 				&rphy.phy_cfg->chg_det.dcp_det);
389 	/* stage 4, turn off voltage source */
390 	rockchip_chg_enable_secondary_det(&rphy, false);
391 	if (vout)
392 		chg_type = POWER_SUPPLY_TYPE_USB_DCP;
393 	else
394 		chg_type = POWER_SUPPLY_TYPE_USB_CDP;
395 
396 out:
397 	debug("charger is %s\n", chg_to_string(chg_type));
398 
399 	return chg_type;
400 }
401 
402 static int rockchip_usb2phy_init(struct phy *phy)
403 {
404 	struct rockchip_usb2phy *rphy;
405 	const struct rockchip_usb2phy_port_cfg *port_cfg;
406 	void __iomem *base;
407 
408 	rphy = dev_get_priv(phy->dev);
409 	base = get_reg_base(rphy);
410 
411 	if (phy->id == USB2PHY_PORT_OTG) {
412 		port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
413 	} else if (phy->id == USB2PHY_PORT_HOST) {
414 		port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
415 	} else {
416 		dev_err(phy->dev, "phy id %lu not support", phy->id);
417 		return -EINVAL;
418 	}
419 
420 	property_enable(base, &port_cfg->phy_sus, false);
421 
422 	/* waiting for the utmi_clk to become stable */
423 	udelay(2000);
424 
425 	return 0;
426 }
427 
428 static int rockchip_usb2phy_exit(struct phy *phy)
429 {
430 	struct rockchip_usb2phy *rphy;
431 	const struct rockchip_usb2phy_port_cfg *port_cfg;
432 	void __iomem *base;
433 
434 	rphy = dev_get_priv(phy->dev);
435 	base = get_reg_base(rphy);
436 
437 	if (phy->id == USB2PHY_PORT_OTG) {
438 		port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
439 	} else if (phy->id == USB2PHY_PORT_HOST) {
440 		port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
441 	} else {
442 		dev_err(phy->dev, "phy id %lu not support", phy->id);
443 		return -EINVAL;
444 	}
445 
446 	property_enable(base, &port_cfg->phy_sus, true);
447 
448 	return 0;
449 }
450 
451 static int rockchip_usb2phy_probe(struct udevice *dev)
452 {
453 	const struct rockchip_usb2phy_cfg *phy_cfgs;
454 	struct rockchip_usb2phy *rphy = dev_get_priv(dev);
455 	struct udevice *parent = dev->parent;
456 	u32 reg, index;
457 
458 	if (!strncmp(parent->name, "root_driver", 11) &&
459 	    dev_read_bool(dev, "rockchip,grf"))
460 		rphy->grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
461 	else
462 		rphy->grf_base = (void __iomem *)dev_read_addr(parent);
463 
464 	if (rphy->grf_base <= 0) {
465 		dev_err(dev, "get syscon grf failed\n");
466 		return -EINVAL;
467 	}
468 
469 	if (dev_read_bool(dev, "rockchip,usbgrf")) {
470 		rphy->usbgrf_base =
471 			syscon_get_first_range(ROCKCHIP_SYSCON_USBGRF);
472 		if (rphy->usbgrf_base <= 0) {
473 			dev_err(dev, "get syscon usbgrf failed\n");
474 			return -EINVAL;
475 		}
476 	} else {
477 		rphy->usbgrf_base = NULL;
478 	}
479 
480 	if (ofnode_read_u32(dev_ofnode(dev), "reg", &reg)) {
481 		dev_err(dev, "could not read reg\n");
482 		return -EINVAL;
483 	}
484 
485 	phy_cfgs =
486 		(const struct rockchip_usb2phy_cfg *)dev_get_driver_data(dev);
487 	if (!phy_cfgs) {
488 		dev_err(dev, "unable to get phy_cfgs\n");
489 		return -EINVAL;
490 	}
491 
492 	/* find out a proper config which can be matched with dt. */
493 	index = 0;
494 	while (phy_cfgs[index].reg) {
495 		if (phy_cfgs[index].reg == reg) {
496 			rphy->phy_cfg = &phy_cfgs[index];
497 			break;
498 		}
499 		++index;
500 	}
501 
502 	if (!rphy->phy_cfg) {
503 		dev_err(dev, "no phy-config can be matched\n");
504 		return -EINVAL;
505 	}
506 
507 	return 0;
508 }
509 
510 static struct phy_ops rockchip_usb2phy_ops = {
511 	.init = rockchip_usb2phy_init,
512 	.exit = rockchip_usb2phy_exit,
513 };
514 
515 static const struct rockchip_usb2phy_cfg rk312x_phy_cfgs[] = {
516 	{
517 		.reg = 0x17c,
518 		.num_ports	= 2,
519 		.clkout_ctl	= { 0x0190, 15, 15, 1, 0 },
520 		.port_cfgs	= {
521 			[USB2PHY_PORT_OTG] = {
522 				.phy_sus	= { 0x017c, 8, 0, 0, 0x1d1 },
523 				.bvalid_det_en	= { 0x017c, 14, 14, 0, 1 },
524 				.bvalid_det_st	= { 0x017c, 15, 15, 0, 1 },
525 				.bvalid_det_clr	= { 0x017c, 15, 15, 0, 1 },
526 				.iddig_output	= { 0x017c, 10, 10, 0, 1 },
527 				.iddig_en	= { 0x017c, 9, 9, 0, 1 },
528 				.idfall_det_en  = { 0x01a0, 2, 2, 0, 1 },
529 				.idfall_det_st  = { 0x01a0, 3, 3, 0, 1 },
530 				.idfall_det_clr = { 0x01a0, 3, 3, 0, 1 },
531 				.idrise_det_en  = { 0x01a0, 0, 0, 0, 1 },
532 				.idrise_det_st  = { 0x01a0, 1, 1, 0, 1 },
533 				.idrise_det_clr = { 0x01a0, 1, 1, 0, 1 },
534 				.ls_det_en	= { 0x017c, 12, 12, 0, 1 },
535 				.ls_det_st	= { 0x017c, 13, 13, 0, 1 },
536 				.ls_det_clr	= { 0x017c, 13, 13, 0, 1 },
537 				.utmi_bvalid	= { 0x014c, 5, 5, 0, 1 },
538 				.utmi_iddig	= { 0x014c, 8, 8, 0, 1 },
539 				.utmi_ls	= { 0x014c, 7, 6, 0, 1 },
540 			},
541 			[USB2PHY_PORT_HOST] = {
542 				.phy_sus	= { 0x0194, 8, 0, 0, 0x1d1 },
543 				.ls_det_en	= { 0x0194, 14, 14, 0, 1 },
544 				.ls_det_st	= { 0x0194, 15, 15, 0, 1 },
545 				.ls_det_clr	= { 0x0194, 15, 15, 0, 1 }
546 			}
547 		},
548 		.chg_det = {
549 			.opmode		= { 0x017c, 3, 0, 5, 1 },
550 			.cp_det		= { 0x02c0, 6, 6, 0, 1 },
551 			.dcp_det	= { 0x02c0, 5, 5, 0, 1 },
552 			.dp_det		= { 0x02c0, 7, 7, 0, 1 },
553 			.idm_sink_en	= { 0x0184, 8, 8, 0, 1 },
554 			.idp_sink_en	= { 0x0184, 7, 7, 0, 1 },
555 			.idp_src_en	= { 0x0184, 9, 9, 0, 1 },
556 			.rdm_pdwn_en	= { 0x0184, 10, 10, 0, 1 },
557 			.vdm_src_en	= { 0x0184, 12, 12, 0, 1 },
558 			.vdp_src_en	= { 0x0184, 11, 11, 0, 1 },
559 		},
560 	},
561 	{ /* sentinel */ }
562 };
563 
564 static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = {
565 	{
566 		.reg = 0x100,
567 		.num_ports	= 2,
568 		.clkout_ctl	= { 0x108, 4, 4, 1, 0 },
569 		.port_cfgs	= {
570 			[USB2PHY_PORT_OTG] = {
571 				.phy_sus	= { 0x0100, 8, 0, 0, 0x1d1 },
572 				.bvalid_det_en	= { 0x0110, 2, 2, 0, 1 },
573 				.bvalid_det_st	= { 0x0114, 2, 2, 0, 1 },
574 				.bvalid_det_clr = { 0x0118, 2, 2, 0, 1 },
575 				.iddig_output	= { 0x0100, 10, 10, 0, 1 },
576 				.iddig_en	= { 0x0100, 9, 9, 0, 1 },
577 				.idfall_det_en	= { 0x0110, 5, 5, 0, 1 },
578 				.idfall_det_st	= { 0x0114, 5, 5, 0, 1 },
579 				.idfall_det_clr = { 0x0118, 5, 5, 0, 1 },
580 				.idrise_det_en	= { 0x0110, 4, 4, 0, 1 },
581 				.idrise_det_st	= { 0x0114, 4, 4, 0, 1 },
582 				.idrise_det_clr = { 0x0118, 4, 4, 0, 1 },
583 				.ls_det_en	= { 0x0110, 0, 0, 0, 1 },
584 				.ls_det_st	= { 0x0114, 0, 0, 0, 1 },
585 				.ls_det_clr	= { 0x0118, 0, 0, 0, 1 },
586 				.utmi_avalid	= { 0x0120, 10, 10, 0, 1 },
587 				.utmi_bvalid	= { 0x0120, 9, 9, 0, 1 },
588 				.utmi_iddig	= { 0x0120, 6, 6, 0, 1 },
589 				.utmi_ls	= { 0x0120, 5, 4, 0, 1 },
590 				.vbus_det_en	= { 0x001c, 15, 15, 1, 0 },
591 			},
592 			[USB2PHY_PORT_HOST] = {
593 				.phy_sus	= { 0x104, 8, 0, 0, 0x1d1 },
594 				.ls_det_en	= { 0x110, 1, 1, 0, 1 },
595 				.ls_det_st	= { 0x114, 1, 1, 0, 1 },
596 				.ls_det_clr	= { 0x118, 1, 1, 0, 1 },
597 				.utmi_ls	= { 0x120, 17, 16, 0, 1 },
598 				.utmi_hstdet	= { 0x120, 19, 19, 0, 1 }
599 			}
600 		},
601 		.chg_det = {
602 			.opmode		= { 0x0100, 3, 0, 5, 1 },
603 			.cp_det		= { 0x0120, 24, 24, 0, 1 },
604 			.dcp_det	= { 0x0120, 23, 23, 0, 1 },
605 			.dp_det		= { 0x0120, 25, 25, 0, 1 },
606 			.idm_sink_en	= { 0x0108, 8, 8, 0, 1 },
607 			.idp_sink_en	= { 0x0108, 7, 7, 0, 1 },
608 			.idp_src_en	= { 0x0108, 9, 9, 0, 1 },
609 			.rdm_pdwn_en	= { 0x0108, 10, 10, 0, 1 },
610 			.vdm_src_en	= { 0x0108, 12, 12, 0, 1 },
611 			.vdp_src_en	= { 0x0108, 11, 11, 0, 1 },
612 		},
613 	},
614 	{ /* sentinel */ }
615 };
616 
617 static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = {
618 	{
619 		.reg = 0x100,
620 		.num_ports	= 2,
621 		.clkout_ctl	= { 0x108, 4, 4, 1, 0 },
622 		.port_cfgs	= {
623 			[USB2PHY_PORT_OTG] = {
624 				.phy_sus	= { 0x0100, 8, 0, 0, 0x1d1 },
625 				.bvalid_det_en	= { 0x0680, 3, 3, 0, 1 },
626 				.bvalid_det_st	= { 0x0690, 3, 3, 0, 1 },
627 				.bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 },
628 				.ls_det_en	= { 0x0680, 2, 2, 0, 1 },
629 				.ls_det_st	= { 0x0690, 2, 2, 0, 1 },
630 				.ls_det_clr	= { 0x06a0, 2, 2, 0, 1 },
631 				.utmi_bvalid	= { 0x0804, 10, 10, 0, 1 },
632 				.utmi_ls	= { 0x0804, 13, 12, 0, 1 },
633 			},
634 			[USB2PHY_PORT_HOST] = {
635 				.phy_sus	= { 0x0104, 8, 0, 0, 0x1d1 },
636 				.ls_det_en	= { 0x0680, 4, 4, 0, 1 },
637 				.ls_det_st	= { 0x0690, 4, 4, 0, 1 },
638 				.ls_det_clr	= { 0x06a0, 4, 4, 0, 1 },
639 				.utmi_ls	= { 0x0804, 9, 8, 0, 1 },
640 				.utmi_hstdet	= { 0x0804, 7, 7, 0, 1 }
641 			}
642 		},
643 		.chg_det = {
644 			.opmode		= { 0x0100, 3, 0, 5, 1 },
645 			.cp_det		= { 0x0804, 1, 1, 0, 1 },
646 			.dcp_det	= { 0x0804, 0, 0, 0, 1 },
647 			.dp_det		= { 0x0804, 2, 2, 0, 1 },
648 			.idm_sink_en	= { 0x0108, 8, 8, 0, 1 },
649 			.idp_sink_en	= { 0x0108, 7, 7, 0, 1 },
650 			.idp_src_en	= { 0x0108, 9, 9, 0, 1 },
651 			.rdm_pdwn_en	= { 0x0108, 10, 10, 0, 1 },
652 			.vdm_src_en	= { 0x0108, 12, 12, 0, 1 },
653 			.vdp_src_en	= { 0x0108, 11, 11, 0, 1 },
654 		},
655 	},
656 	{ /* sentinel */ }
657 };
658 
659 static const struct udevice_id rockchip_usb2phy_ids[] = {
660 	{ .compatible = "rockchip,rk3128-usb2phy", .data = (ulong)&rk312x_phy_cfgs },
661 	{ .compatible = "rockchip,rk3328-usb2phy", .data = (ulong)&rk3328_phy_cfgs },
662 	{ .compatible = "rockchip,rv1108-usb2phy", .data = (ulong)&rv1108_phy_cfgs },
663 	{ }
664 };
665 
666 U_BOOT_DRIVER(rockchip_usb2phy) = {
667 	.name		= "rockchip_usb2phy",
668 	.id		= UCLASS_PHY,
669 	.of_match	= rockchip_usb2phy_ids,
670 	.ops		= &rockchip_usb2phy_ops,
671 	.probe		= rockchip_usb2phy_probe,
672 	.priv_auto_alloc_size = sizeof(struct rockchip_usb2phy),
673 };
674