blob: 3f6227f993f91a6276ba74829eec9e1efbd94a7c [file] [log] [blame]
Jonas Karlmana937c3d2023-08-21 22:30:28 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Rockchip IO Voltage Domain driver
4 *
5 * Ported from linux drivers/soc/rockchip/io-domain.c
6 */
7
8#include <common.h>
9#include <dm.h>
10#include <dm/device_compat.h>
11#include <regmap.h>
12#include <syscon.h>
13#include <power/regulator.h>
14
15#define MAX_SUPPLIES 16
16
17/*
18 * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
19 * "Recommended Operating Conditions" for "Digital GPIO". When the typical
20 * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V.
21 *
22 * They are used like this:
23 * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
24 * SoC we're at 3.3.
25 * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
26 * that to be an error.
27 */
28#define MAX_VOLTAGE_1_8 1980000
29#define MAX_VOLTAGE_3_3 3600000
30
31#define RK3568_PMU_GRF_IO_VSEL0 0x0140
32#define RK3568_PMU_GRF_IO_VSEL1 0x0144
33#define RK3568_PMU_GRF_IO_VSEL2 0x0148
34
35struct rockchip_iodomain_soc_data {
36 int grf_offset;
37 const char *supply_names[MAX_SUPPLIES];
38 int (*write)(struct regmap *grf, int idx, int uV);
39};
40
41static int rk3568_iodomain_write(struct regmap *grf, int idx, int uV)
42{
43 u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
44 u32 val0, val1;
45 int b;
46
47 switch (idx) {
48 case 0: /* pmuio1 */
49 break;
50 case 1: /* pmuio2 */
51 b = idx;
52 val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
53 b = idx + 4;
54 val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
55
56 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val0);
57 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val1);
58 break;
59 case 3: /* vccio2 */
60 break;
61 case 2: /* vccio1 */
62 case 4: /* vccio3 */
63 case 5: /* vccio4 */
64 case 6: /* vccio5 */
65 case 7: /* vccio6 */
66 case 8: /* vccio7 */
67 b = idx - 1;
68 val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
69 val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
70
71 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL0, val0);
72 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL1, val1);
73 break;
74 default:
75 return -EINVAL;
76 }
77
78 return 0;
79}
80
81static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = {
82 .grf_offset = 0x140,
83 .supply_names = {
84 NULL,
85 "pmuio2-supply",
86 "vccio1-supply",
87 NULL,
88 "vccio3-supply",
89 "vccio4-supply",
90 "vccio5-supply",
91 "vccio6-supply",
92 "vccio7-supply",
93 },
94 .write = rk3568_iodomain_write,
95};
96
97static const struct udevice_id rockchip_iodomain_ids[] = {
98 {
99 .compatible = "rockchip,rk3568-pmu-io-voltage-domain",
100 .data = (ulong)&soc_data_rk3568_pmu,
101 },
102 { }
103};
104
105static int rockchip_iodomain_bind(struct udevice *dev)
106{
107 /*
108 * According to the Hardware Design Guide, IO-domain configuration must
109 * be consistent with the power supply voltage (1.8V or 3.3V).
110 * Probe after bind to configure IO-domain voltage early during boot.
111 */
112 dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
113
114 return 0;
115}
116
117static int rockchip_iodomain_probe(struct udevice *dev)
118{
119 struct rockchip_iodomain_soc_data *soc_data =
120 (struct rockchip_iodomain_soc_data *)dev_get_driver_data(dev);
121 struct regmap *grf;
122 int ret;
123
124 grf = syscon_get_regmap(dev_get_parent(dev));
125 if (IS_ERR(grf))
126 return PTR_ERR(grf);
127
128 for (int i = 0; i < MAX_SUPPLIES; i++) {
129 const char *supply_name = soc_data->supply_names[i];
130 struct udevice *reg;
131 int uV;
132
133 if (!supply_name)
134 continue;
135
136 ret = device_get_supply_regulator(dev, supply_name, &reg);
137 if (ret)
138 continue;
139
140 ret = regulator_autoset(reg);
141 if (ret && ret != -EALREADY && ret != -EMEDIUMTYPE &&
142 ret != -ENOSYS)
143 continue;
144
145 uV = regulator_get_value(reg);
146 if (uV <= 0)
147 continue;
148
149 if (uV > MAX_VOLTAGE_3_3) {
150 dev_crit(dev, "%s: %d uV is too high. May damage SoC!\n",
151 supply_name, uV);
152 continue;
153 }
154
155 soc_data->write(grf, i, uV);
156 }
157
158 return 0;
159}
160
161U_BOOT_DRIVER(rockchip_iodomain) = {
162 .name = "rockchip_iodomain",
163 .id = UCLASS_NOP,
164 .of_match = rockchip_iodomain_ids,
165 .bind = rockchip_iodomain_bind,
166 .probe = rockchip_iodomain_probe,
167};