xref: /rk3399_rockchip-uboot/drivers/power/io-domain/rockchip-io-domain.c (revision 5e8564cf419797f9095431e6eb6f0c00dfa423d2)
1 /* SPDX-License-Identifier:     GPL-2.0+ */
2 /*
3  * (C) Copyright 2018 Rockchip Electronics Co., Ltd
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <dm/of_access.h>
9 #include <regmap.h>
10 #include <syscon.h>
11 #include <asm/arch/clock.h>
12 #include <fdtdec.h>
13 #include <linux/compat.h>
14 #include <linux/err.h>
15 #include <power/regulator.h>
16 
17 #define MAX_SUPPLIES		16
18 
19 /*
20  * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
21  * "Recommended Operating Conditions" for "Digital GPIO".   When the typical
22  * is 3.3V the max is 3.6V.  When the typical is 1.8V the max is 1.98V.
23  *
24  * They are used like this:
25  * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
26  *   SoC we're at 3.3.
27  * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
28  *   that to be an error.
29  */
30 #define MAX_VOLTAGE_1_8	1980000
31 #define MAX_VOLTAGE_3_3	3600000
32 
33 #define PX30_IO_VSEL			0x180
34 #define PX30_IO_VSEL_VCCIO6_SRC		BIT(0)
35 #define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM	1
36 
37 #define RK3288_SOC_CON2			0x24c
38 #define RK3288_SOC_CON2_FLASH0		BIT(7)
39 #define RK3288_SOC_FLASH_SUPPLY_NUM	2
40 
41 #define RK3308_SOC_CON0			0x300
42 #define RK3308_SOC_CON0_VCCIO3		BIT(8)
43 #define RK3308_SOC_VCCIO3_SUPPLY_NUM	3
44 
45 #define RK3328_SOC_CON4			0x410
46 #define RK3328_SOC_CON4_VCCIO2		BIT(7)
47 #define RK3328_SOC_VCCIO2_SUPPLY_NUM	1
48 
49 #define RK3366_SOC_CON6			0x418
50 #define RK3366_SOC_CON6_FLASH0		BIT(14)
51 #define RK3366_SOC_FLASH_SUPPLY_NUM	2
52 
53 #define RK3368_SOC_CON15		0x43c
54 #define RK3368_SOC_CON15_FLASH0		BIT(14)
55 #define RK3368_SOC_FLASH_SUPPLY_NUM	2
56 
57 #define RK3399_PMUGRF_CON0		0x180
58 #define RK3399_PMUGRF_CON0_VSEL		BIT(8)
59 #define RK3399_PMUGRF_VSEL_SUPPLY_NUM	9
60 
61 struct rockchip_iodomain_priv;
62 
63 /**
64  * @supplies: voltage settings matching the register bits.
65  */
66 struct rockchip_iodomain_soc_data {
67 	int grf_offset;
68 	const char *supply_names[MAX_SUPPLIES];
69 	void (*init)(struct rockchip_iodomain_priv *iod);
70 };
71 
72 struct rockchip_iodomain_supply {
73 	struct rockchip_iodomain_priv *iod;
74 	struct udevice *reg;
75 	int idx;
76 };
77 
78 struct rockchip_iodomain_priv {
79 	struct regmap *regmap_base;
80 	struct rockchip_iodomain_soc_data *sdata;
81 	struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
82 };
83 
84 static int rockchip_ofdata_to_platdata(struct udevice *dev)
85 {
86 	struct rockchip_iodomain_priv *priv = dev_get_priv(dev);
87 	struct regmap *regmap;
88 
89 	/* get grf-reg base address */
90 	regmap = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_GRF);
91 	if (IS_ERR(regmap))
92 		return PTR_ERR(regmap);
93 
94 	priv->regmap_base = regmap;
95 
96 	return 0;
97 }
98 
99 static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
100 				   int uV)
101 {
102 	struct rockchip_iodomain_priv *priv = supply->iod;
103 	struct regmap *regmap = priv->regmap_base;
104 	u32 val;
105 	int ret;
106 
107 	/* set value bit */
108 	val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
109 	val <<= supply->idx;
110 
111 	/* apply hiword-mask */
112 	val |= (BIT(supply->idx) << 16);
113 
114 	ret = regmap_write(regmap, priv->sdata->grf_offset, val);
115 	if (ret) {
116 		dev_err(priv->dev, "Couldn't write to GRF\n");
117 		return ret;
118 	}
119 
120 	return 0;
121 }
122 
123 static void px30_iodomain_init(struct rockchip_iodomain_priv *iod)
124 {
125 	int ret;
126 	u32 val;
127 
128 	/* if no VCCIO0 supply we should leave things alone */
129 	if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
130 		return;
131 
132 	/*
133 	 * set vccio0 iodomain to also use this framework
134 	 * instead of a special gpio.
135 	 */
136 	val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
137 	ret = regmap_write(iod->regmap_base, PX30_IO_VSEL, val);
138 	if (ret < 0)
139 		dev_warn(iod->dev, "couldn't update vccio0 ctrl\n");
140 }
141 
142 static void rk3288_iodomain_init(struct rockchip_iodomain_priv *iod)
143 {
144 	int ret;
145 	u32 val;
146 
147 	/* if no flash supply we should leave things alone */
148 	if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
149 		return;
150 
151 	/*
152 	 * set flash0 iodomain to also use this framework
153 	 * instead of a special gpio.
154 	 */
155 	val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
156 	ret = regmap_write(iod->regmap_base, RK3288_SOC_CON2, val);
157 	if (ret < 0)
158 		dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
159 }
160 
161 static void rk3308_iodomain_init(struct rockchip_iodomain_priv *iod)
162 {
163 	int ret;
164 	u32 val;
165 
166 	/* if no vccio3 supply we should leave things alone */
167 	if (!iod->supplies[RK3308_SOC_VCCIO3_SUPPLY_NUM].reg)
168 		return;
169 
170 	/*
171 	 * set vccio3 iodomain to also use this framework
172 	 * instead of a special gpio.
173 	 */
174 	val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16);
175 	ret = regmap_write(iod->regmap_base, RK3308_SOC_CON0, val);
176 	if (ret < 0)
177 		dev_warn(iod->dev, "couldn't update vccio3 vsel ctrl\n");
178 }
179 
180 static void rk3328_iodomain_init(struct rockchip_iodomain_priv *iod)
181 {
182 	int ret;
183 	u32 val;
184 
185 	/* if no vccio2 supply we should leave things alone */
186 	if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
187 		return;
188 
189 	/*
190 	 * set vccio2 iodomain to also use this framework
191 	 * instead of a special gpio.
192 	 */
193 	val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
194 	ret = regmap_write(iod->regmap_base, RK3328_SOC_CON4, val);
195 	if (ret < 0)
196 		dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
197 }
198 
199 static void rk3366_iodomain_init(struct rockchip_iodomain_priv *iod)
200 {
201 	int ret;
202 	u32 val;
203 
204 	/* if no flash supply we should leave things alone */
205 	if (!iod->supplies[RK3366_SOC_FLASH_SUPPLY_NUM].reg)
206 		return;
207 
208 	/*
209 	 * set flash0 iodomain to also use this framework
210 	 * instead of a special gpio.
211 	 */
212 	val = RK3366_SOC_CON6_FLASH0 | (RK3366_SOC_CON6_FLASH0 << 16);
213 	ret = regmap_write(iod->regmap_base, RK3368_SOC_CON15, val);
214 	if (ret < 0)
215 		dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
216 }
217 
218 static void rk3368_iodomain_init(struct rockchip_iodomain_priv *iod)
219 {
220 	int ret;
221 	u32 val;
222 
223 	/* if no flash supply we should leave things alone */
224 	if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
225 		return;
226 
227 	/*
228 	 * set flash0 iodomain to also use this framework
229 	 * instead of a special gpio.
230 	 */
231 	val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
232 	ret = regmap_write(iod->regmap_base, RK3368_SOC_CON15, val);
233 	if (ret < 0)
234 		dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
235 }
236 
237 static void rk3399_pmu_iodomain_init(struct rockchip_iodomain_priv *iod)
238 {
239 	int ret;
240 	u32 val;
241 
242 	/* if no pmu io supply we should leave things alone */
243 	if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
244 		return;
245 
246 	/*
247 	 * set pmu io iodomain to also use this framework
248 	 * instead of a special gpio.
249 	 */
250 	val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
251 	ret = regmap_write(iod->regmap_base, RK3399_PMUGRF_CON0, val);
252 	if (ret < 0)
253 		dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
254 }
255 
256 static const struct rockchip_iodomain_soc_data soc_data_px30 = {
257 	.grf_offset = 0x180,
258 	.supply_names = {
259 		NULL,
260 		"vccio6",
261 		"vccio1",
262 		"vccio2",
263 		"vccio3",
264 		"vccio4",
265 		"vccio5",
266 		"vccio-oscgpi",
267 	},
268 	.init = px30_iodomain_init,
269 };
270 
271 static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
272 	.grf_offset = 0x100,
273 	.supply_names = {
274 		NULL,
275 		NULL,
276 		NULL,
277 		NULL,
278 		NULL,
279 		NULL,
280 		NULL,
281 		NULL,
282 		NULL,
283 		NULL,
284 		NULL,
285 		NULL,
286 		NULL,
287 		NULL,
288 		"pmuio1",
289 		"pmuio2",
290 	},
291 };
292 
293 /*
294  * On the rk3188 the io-domains are handled by a shared register with the
295  * lower 8 bits being still being continuing drive-strength settings.
296  */
297 static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
298 	.grf_offset = 0x104,
299 	.supply_names = {
300 		NULL,
301 		NULL,
302 		NULL,
303 		NULL,
304 		NULL,
305 		NULL,
306 		NULL,
307 		NULL,
308 		"ap0",
309 		"ap1",
310 		"cif",
311 		"flash",
312 		"vccio0",
313 		"vccio1",
314 		"lcdc0",
315 		"lcdc1",
316 	},
317 };
318 
319 static const struct rockchip_iodomain_soc_data soc_data_rk322x = {
320 	.grf_offset = 0x418,
321 	.supply_names = {
322 		"vccio1",
323 		"vccio2",
324 		"vccio3",
325 		"vccio4",
326 	},
327 };
328 
329 static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
330 	.grf_offset = 0x380,
331 	.supply_names = {
332 		"lcdc",		/* LCDC_VDD */
333 		"dvp",		/* DVPIO_VDD */
334 		"flash0",	/* FLASH0_VDD (emmc) */
335 		"flash1",	/* FLASH1_VDD (sdio1) */
336 		"wifi",		/* APIO3_VDD  (sdio0) */
337 		"bb",		/* APIO5_VDD */
338 		"audio",	/* APIO4_VDD */
339 		"sdcard",	/* SDMMC0_VDD (sdmmc) */
340 		"gpio30",	/* APIO1_VDD */
341 		"gpio1830",	/* APIO2_VDD */
342 	},
343 	.init = rk3288_iodomain_init,
344 };
345 
346 static const struct rockchip_iodomain_soc_data soc_data_rk3308 = {
347 	.grf_offset = 0x300,
348 	.supply_names = {
349 		"vccio0",
350 		"vccio1",
351 		"vccio2",
352 		"vccio3",
353 		"vccio4",
354 		"vccio5",
355 	},
356 	.init = rk3308_iodomain_init,
357 };
358 
359 static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
360 	.grf_offset = 0x410,
361 	.supply_names = {
362 		"vccio1",
363 		"vccio2",
364 		"vccio3",
365 		"vccio4",
366 		"vccio5",
367 		"vccio6",
368 		"pmuio",
369 	},
370 	.init = rk3328_iodomain_init,
371 };
372 
373 static const struct rockchip_iodomain_soc_data soc_data_rk3366 = {
374 	.grf_offset = 0x900,
375 	.supply_names = {
376 		"lcdc",         /* LCDC_IOVDD */
377 		"dvpts",        /* DVP_IOVDD */
378 		"flash",        /* FLASH_IOVDD (emmc) */
379 		"wifibt",       /* APIO1_IOVDD */
380 		NULL,
381 		"audio",        /* AUDIO_IODVDD */
382 		"sdcard",       /* SDMMC_IOVDD (sdmmc) */
383 		"tphdsor",      /* APIO2_IOVDD */
384 	},
385 	.init = rk3366_iodomain_init,
386 };
387 
388 static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
389 	.grf_offset = 0x900,
390 	.supply_names = {
391 		NULL,		/* reserved */
392 		"dvp",		/* DVPIO_VDD */
393 		"flash0",	/* FLASH0_VDD (emmc) */
394 		"wifi",		/* APIO2_VDD (sdio0) */
395 		NULL,
396 		"audio",	/* APIO3_VDD */
397 		"sdcard",	/* SDMMC0_VDD (sdmmc) */
398 		"gpio30",	/* APIO1_VDD */
399 		"gpio1830",	/* APIO4_VDD (gpujtag) */
400 	},
401 	.init = rk3368_iodomain_init,
402 };
403 
404 static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
405 	.grf_offset = 0x100,
406 	.supply_names = {
407 		NULL,
408 		NULL,
409 		NULL,
410 		NULL,
411 		"pmu",	        /*PMU IO domain*/
412 		"vop",	        /*LCDC IO domain*/
413 	},
414 };
415 
416 static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
417 	.grf_offset = 0xe640,
418 	.supply_names = {
419 		"bt656",		/* APIO2_VDD */
420 		"audio",		/* APIO5_VDD */
421 		"sdmmc",		/* SDMMC0_VDD */
422 		"gpio1830",		/* APIO4_VDD */
423 	},
424 };
425 
426 static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
427 	.grf_offset = 0x180,
428 	.supply_names = {
429 		NULL,
430 		NULL,
431 		NULL,
432 		NULL,
433 		NULL,
434 		NULL,
435 		NULL,
436 		NULL,
437 		NULL,
438 		"pmu1830",		/* PMUIO2_VDD */
439 	},
440 	.init = rk3399_pmu_iodomain_init,
441 };
442 
443 static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
444 	.grf_offset = 0x404,
445 	.supply_names = {
446 		NULL,
447 		NULL,
448 		NULL,
449 		NULL,
450 		NULL,
451 		NULL,
452 		NULL,
453 		NULL,
454 		NULL,
455 		NULL,
456 		NULL,
457 		"vccio1",
458 		"vccio2",
459 		"vccio3",
460 		"vccio5",
461 		"vccio6",
462 	},
463 
464 };
465 
466 static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
467 	.grf_offset = 0x104,
468 	.supply_names = {
469 		"pmu",
470 	},
471 };
472 
473 static struct udevice *of_get_regulator(ofnode node, const char *supply)
474 {
475 	char sname[32]; /* 32 is max size of property name */
476 	struct udevice *sudev;
477 	ofnode snode;
478 	u32 phandle;
479 	int ret;
480 
481 	snprintf(sname, 32, "%s-supply", supply);
482 
483 	/* Get regulator and clk */
484 	if (!ofnode_read_u32(node, sname, &phandle)) {
485 		snode = ofnode_get_by_phandle(phandle);
486 		ret = regulator_get_by_devname(snode.np->name, &sudev);
487 		if (ret) {
488 			printf("%s: %s: Get supply(%s) failed, ret=%d",
489 			       __func__,
490 			       sudev->name, snode.np->full_name, ret);
491 			return NULL;
492 		}
493 		debug("IO-DOMAIN: supply: %s\n", snode.np->full_name);
494 	}
495 
496 	return sudev;
497 }
498 
499 static int rockchip_iodomain_probe(struct udevice *dev)
500 {
501 	struct rockchip_iodomain_priv *priv = dev_get_priv(dev);
502 	struct rockchip_iodomain_soc_data *sdata;
503 	int i, ret;
504 
505 	sdata = (struct rockchip_iodomain_soc_data *)dev_get_driver_data(dev);
506 	priv->sdata = sdata;
507 
508 	if (!priv->regmap_base)
509 		return -1;
510 
511 	for (i = 0; i < MAX_SUPPLIES; i++) {
512 		const char *supply_name = priv->sdata->supply_names[i];
513 		struct rockchip_iodomain_supply *supply = &priv->supplies[i];
514 		struct udevice *reg;
515 		u32 uV;
516 
517 		if (!supply_name)
518 			continue;
519 
520 		reg = of_get_regulator(dev_ofnode(dev), supply_name);
521 		if (!reg) {
522 			printf("could not find regulator %s\n", supply_name);
523 			return -1;
524 		}
525 
526 		uV = regulator_get_value(reg);
527 		if (uV < 0) {
528 			printf("could not get voltage from %s\n", reg->name);
529 			return -1;
530 		}
531 
532 		if (uV > MAX_VOLTAGE_3_3) {
533 			printf("%d uV is too high from %s\n", uV, reg->name);
534 			return -1;
535 		}
536 
537 		/* setup our supply */
538 		supply->idx = i;
539 		supply->iod = priv;
540 		supply->reg = reg;
541 
542 		ret = rockchip_iodomain_write(supply, uV);
543 		if (ret)
544 			supply->reg = NULL;
545 	}
546 
547 	if (priv->sdata->init)
548 		priv->sdata->init(priv);
549 
550 	return 0;
551 }
552 
553 static const struct udevice_id rockchip_iodomain_match[] = {
554 	{
555 		.compatible = "rockchip,px30-io-voltage-domain",
556 		.data = (ulong)&soc_data_px30
557 	},
558 	{
559 		.compatible = "rockchip,px30-pmu-io-voltage-domain",
560 		.data = (ulong)&soc_data_px30_pmu
561 	},
562 	{
563 		.compatible = "rockchip,rk3188-io-voltage-domain",
564 		.data = (ulong)&soc_data_rk3188
565 	},
566 	{
567 		.compatible = "rockchip,rk322x-io-voltage-domain",
568 		.data = (ulong)&soc_data_rk322x
569 	},
570 	{
571 		.compatible = "rockchip,rk3288-io-voltage-domain",
572 		.data = (ulong)&soc_data_rk3288
573 	},
574 	{
575 		.compatible = "rockchip,rk3308-io-voltage-domain",
576 		.data = (ulong)&soc_data_rk3308
577 	},
578 	{
579 		.compatible = "rockchip,rk3328-io-voltage-domain",
580 		.data = (ulong)&soc_data_rk3328
581 	},
582 	{
583 		.compatible = "rockchip,rk3366-io-voltage-domain",
584 		.data = (ulong)&soc_data_rk3366
585 	},
586 	{
587 		.compatible = "rockchip,rk3368-io-voltage-domain",
588 		.data = (ulong)&soc_data_rk3368
589 	},
590 	{
591 		.compatible = "rockchip,rk3368-pmu-io-voltage-domain",
592 		.data = (ulong)&soc_data_rk3368_pmu
593 	},
594 	{
595 		.compatible = "rockchip,rk3399-io-voltage-domain",
596 		.data = (ulong)&soc_data_rk3399
597 	},
598 	{
599 		.compatible = "rockchip,rk3399-pmu-io-voltage-domain",
600 		.data = (ulong)&soc_data_rk3399_pmu
601 	},
602 	{
603 		.compatible = "rockchip,rv1108-io-voltage-domain",
604 		.data = (ulong)&soc_data_rv1108
605 	},
606 	{
607 		.compatible = "rockchip,rv1108-pmu-io-voltage-domain",
608 		.data = (ulong)&soc_data_rv1108_pmu
609 	},
610 	{ /* sentinel */ },
611 };
612 
613 U_BOOT_DRIVER(io_domain) = {
614 	.name		= "io_domain",
615 	.id		= UCLASS_IO_DOMAIN,
616 	.of_match	= rockchip_iodomain_match,
617 	.priv_auto_alloc_size = sizeof(struct rockchip_iodomain_priv),
618 	.ofdata_to_platdata	= rockchip_ofdata_to_platdata,
619 	.probe		= rockchip_iodomain_probe,
620 };
621