blob: 025b6049a9f75696424909048b16f297f12fa048 [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
Jonas Karlmana937c3d2023-08-21 22:30:28 +00008#include <dm.h>
9#include <dm/device_compat.h>
10#include <regmap.h>
11#include <syscon.h>
12#include <power/regulator.h>
13
14#define MAX_SUPPLIES 16
15
16/*
17 * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
18 * "Recommended Operating Conditions" for "Digital GPIO". When the typical
19 * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V.
20 *
21 * They are used like this:
22 * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
23 * SoC we're at 3.3.
24 * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
25 * that to be an error.
26 */
27#define MAX_VOLTAGE_1_8 1980000
28#define MAX_VOLTAGE_3_3 3600000
29
Quentin Schulzc36413c2024-06-14 18:54:13 +020030#define PX30_IO_VSEL 0x180
31#define PX30_IO_VSEL_VCCIO6_SRC BIT(0)
32#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1
33
Jonas Karlmancd513182024-07-24 06:58:15 +000034#define RK3308_SOC_CON0 0x300
35#define RK3308_SOC_CON0_VCCIO3 BIT(8)
36#define RK3308_SOC_VCCIO3_SUPPLY_NUM 3
37
Jonas Karlman84677e22024-04-21 20:09:03 +000038#define RK3328_SOC_CON4 0x410
39#define RK3328_SOC_CON4_VCCIO2 BIT(7)
40#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1
41
Jonas Karlman2de30162024-03-12 23:36:15 +000042#define RK3399_PMUGRF_CON0 0x180
43#define RK3399_PMUGRF_CON0_VSEL BIT(8)
44#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9
45
Jonas Karlmana937c3d2023-08-21 22:30:28 +000046#define RK3568_PMU_GRF_IO_VSEL0 0x0140
47#define RK3568_PMU_GRF_IO_VSEL1 0x0144
48#define RK3568_PMU_GRF_IO_VSEL2 0x0148
49
50struct rockchip_iodomain_soc_data {
51 int grf_offset;
52 const char *supply_names[MAX_SUPPLIES];
Jonas Karlman2de30162024-03-12 23:36:15 +000053 int (*write)(struct regmap *grf, uint offset, int idx, int uV);
Jonas Karlmana937c3d2023-08-21 22:30:28 +000054};
55
Jonas Karlman2de30162024-03-12 23:36:15 +000056static int rk3568_iodomain_write(struct regmap *grf, uint offset, int idx, int uV)
Jonas Karlmana937c3d2023-08-21 22:30:28 +000057{
58 u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
59 u32 val0, val1;
60 int b;
61
62 switch (idx) {
63 case 0: /* pmuio1 */
64 break;
65 case 1: /* pmuio2 */
66 b = idx;
67 val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
68 b = idx + 4;
69 val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
70
71 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val0);
72 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val1);
73 break;
74 case 3: /* vccio2 */
75 break;
76 case 2: /* vccio1 */
77 case 4: /* vccio3 */
78 case 5: /* vccio4 */
79 case 6: /* vccio5 */
80 case 7: /* vccio6 */
81 case 8: /* vccio7 */
82 b = idx - 1;
83 val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
84 val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
85
86 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL0, val0);
87 regmap_write(grf, RK3568_PMU_GRF_IO_VSEL1, val1);
88 break;
89 default:
90 return -EINVAL;
91 }
92
93 return 0;
94}
95
Jonas Karlman2de30162024-03-12 23:36:15 +000096static int rockchip_iodomain_write(struct regmap *grf, uint offset, int idx, int uV)
97{
98 u32 val;
99
100 /* set value bit */
101 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
102 val <<= idx;
103
104 /* apply hiword-mask */
105 val |= (BIT(idx) << 16);
106
107 return regmap_write(grf, offset, val);
108}
109
Quentin Schulzc36413c2024-06-14 18:54:13 +0200110static int px30_iodomain_write(struct regmap *grf, uint offset, int idx, int uV)
111{
112 int ret = rockchip_iodomain_write(grf, offset, idx, uV);
113
114 if (!ret && idx == PX30_IO_VSEL_VCCIO6_SUPPLY_NUM) {
115 /*
116 * set vccio6 iodomain to also use this framework
117 * instead of a special gpio.
118 */
119 u32 val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
120 ret = regmap_write(grf, PX30_IO_VSEL, val);
121 }
122
123 return ret;
124}
125
Jonas Karlmancd513182024-07-24 06:58:15 +0000126static int rk3308_iodomain_write(struct regmap *grf, uint offset, int idx, int uV)
127{
128 int ret = rockchip_iodomain_write(grf, offset, idx, uV);
129
130 if (!ret && idx == RK3308_SOC_VCCIO3_SUPPLY_NUM) {
131 /*
132 * set vccio3 iodomain to also use this framework
133 * instead of a special gpio.
134 */
135 u32 val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16);
136 ret = regmap_write(grf, RK3308_SOC_CON0, val);
137 }
138
139 return ret;
140}
141
Jonas Karlman84677e22024-04-21 20:09:03 +0000142static int rk3328_iodomain_write(struct regmap *grf, uint offset, int idx, int uV)
143{
144 int ret = rockchip_iodomain_write(grf, offset, idx, uV);
145
146 if (!ret && idx == RK3328_SOC_VCCIO2_SUPPLY_NUM) {
147 /*
148 * set vccio2 iodomain to also use this framework
149 * instead of a special gpio.
150 */
151 u32 val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
152 ret = regmap_write(grf, RK3328_SOC_CON4, val);
153 }
154
155 return ret;
156}
157
Jonas Karlman2de30162024-03-12 23:36:15 +0000158static int rk3399_pmu_iodomain_write(struct regmap *grf, uint offset, int idx, int uV)
159{
160 int ret = rockchip_iodomain_write(grf, offset, idx, uV);
161
162 if (!ret && idx == RK3399_PMUGRF_VSEL_SUPPLY_NUM) {
163 /*
164 * set pmu io iodomain to also use this framework
165 * instead of a special gpio.
166 */
167 u32 val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
168 ret = regmap_write(grf, RK3399_PMUGRF_CON0, val);
169 }
170
171 return ret;
172}
173
Quentin Schulzc36413c2024-06-14 18:54:13 +0200174static const struct rockchip_iodomain_soc_data soc_data_px30 = {
175 .grf_offset = 0x180,
176 .supply_names = {
177 NULL,
178 "vccio6-supply",
179 "vccio1-supply",
180 "vccio2-supply",
181 "vccio3-supply",
182 "vccio4-supply",
183 "vccio5-supply",
184 "vccio-oscgpi-supply",
185 },
186 .write = px30_iodomain_write,
187};
188
189static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
190 .grf_offset = 0x100,
191 .supply_names = {
192 NULL,
193 NULL,
194 NULL,
195 NULL,
196 NULL,
197 NULL,
198 NULL,
199 NULL,
200 NULL,
201 NULL,
202 NULL,
203 NULL,
204 NULL,
205 NULL,
206 "pmuio1-supply",
207 "pmuio2-supply",
208 },
209 .write = rockchip_iodomain_write,
210};
211
Jonas Karlmancd513182024-07-24 06:58:15 +0000212static const struct rockchip_iodomain_soc_data soc_data_rk3308 = {
213 .grf_offset = 0x300,
214 .supply_names = {
215 "vccio0-supply",
216 "vccio1-supply",
217 "vccio2-supply",
218 "vccio3-supply",
219 "vccio4-supply",
220 "vccio5-supply",
221 },
222 .write = rk3308_iodomain_write,
223};
224
Jonas Karlman84677e22024-04-21 20:09:03 +0000225static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
226 .grf_offset = 0x410,
227 .supply_names = {
228 "vccio1-supply",
229 "vccio2-supply",
230 "vccio3-supply",
231 "vccio4-supply",
232 "vccio5-supply",
233 "vccio6-supply",
234 "pmuio-supply",
235 },
236 .write = rk3328_iodomain_write,
237};
238
Jonas Karlman2de30162024-03-12 23:36:15 +0000239static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
240 .grf_offset = 0xe640,
241 .supply_names = {
242 "bt656-supply", /* APIO2_VDD */
243 "audio-supply", /* APIO5_VDD */
244 "sdmmc-supply", /* SDMMC0_VDD */
245 "gpio1830-supply", /* APIO4_VDD */
246 },
247 .write = rockchip_iodomain_write,
248};
249
250static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
251 .grf_offset = 0x180,
252 .supply_names = {
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 NULL,
259 NULL,
260 NULL,
261 NULL,
262 "pmu1830-supply", /* PMUIO2_VDD */
263 },
264 .write = rk3399_pmu_iodomain_write,
265};
266
Jonas Karlmana937c3d2023-08-21 22:30:28 +0000267static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = {
268 .grf_offset = 0x140,
269 .supply_names = {
270 NULL,
271 "pmuio2-supply",
272 "vccio1-supply",
273 NULL,
274 "vccio3-supply",
275 "vccio4-supply",
276 "vccio5-supply",
277 "vccio6-supply",
278 "vccio7-supply",
279 },
280 .write = rk3568_iodomain_write,
281};
282
283static const struct udevice_id rockchip_iodomain_ids[] = {
284 {
Quentin Schulzc36413c2024-06-14 18:54:13 +0200285 .compatible = "rockchip,px30-io-voltage-domain",
286 .data = (ulong)&soc_data_px30,
287 },
288 {
289 .compatible = "rockchip,px30-pmu-io-voltage-domain",
290 .data = (ulong)&soc_data_px30_pmu,
291 },
292 {
Jonas Karlmancd513182024-07-24 06:58:15 +0000293 .compatible = "rockchip,rk3308-io-voltage-domain",
294 .data = (ulong)&soc_data_rk3308,
295 },
296 {
Jonas Karlman84677e22024-04-21 20:09:03 +0000297 .compatible = "rockchip,rk3328-io-voltage-domain",
298 .data = (ulong)&soc_data_rk3328,
299 },
300 {
Jonas Karlman2de30162024-03-12 23:36:15 +0000301 .compatible = "rockchip,rk3399-io-voltage-domain",
302 .data = (ulong)&soc_data_rk3399,
303 },
304 {
305 .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
306 .data = (ulong)&soc_data_rk3399_pmu,
307 },
308 {
Jonas Karlmana937c3d2023-08-21 22:30:28 +0000309 .compatible = "rockchip,rk3568-pmu-io-voltage-domain",
310 .data = (ulong)&soc_data_rk3568_pmu,
311 },
312 { }
313};
314
315static int rockchip_iodomain_bind(struct udevice *dev)
316{
317 /*
318 * According to the Hardware Design Guide, IO-domain configuration must
319 * be consistent with the power supply voltage (1.8V or 3.3V).
320 * Probe after bind to configure IO-domain voltage early during boot.
321 */
322 dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
323
324 return 0;
325}
326
327static int rockchip_iodomain_probe(struct udevice *dev)
328{
329 struct rockchip_iodomain_soc_data *soc_data =
330 (struct rockchip_iodomain_soc_data *)dev_get_driver_data(dev);
331 struct regmap *grf;
332 int ret;
333
334 grf = syscon_get_regmap(dev_get_parent(dev));
335 if (IS_ERR(grf))
336 return PTR_ERR(grf);
337
338 for (int i = 0; i < MAX_SUPPLIES; i++) {
339 const char *supply_name = soc_data->supply_names[i];
340 struct udevice *reg;
341 int uV;
342
343 if (!supply_name)
344 continue;
345
346 ret = device_get_supply_regulator(dev, supply_name, &reg);
347 if (ret)
348 continue;
349
350 ret = regulator_autoset(reg);
351 if (ret && ret != -EALREADY && ret != -EMEDIUMTYPE &&
352 ret != -ENOSYS)
353 continue;
354
355 uV = regulator_get_value(reg);
356 if (uV <= 0)
357 continue;
358
359 if (uV > MAX_VOLTAGE_3_3) {
360 dev_crit(dev, "%s: %d uV is too high. May damage SoC!\n",
361 supply_name, uV);
362 continue;
363 }
364
Jonas Karlman2de30162024-03-12 23:36:15 +0000365 ret = soc_data->write(grf, soc_data->grf_offset, i, uV);
366 if (ret)
367 dev_err(dev, "%s: Couldn't write to GRF\n", supply_name);
Jonas Karlmana937c3d2023-08-21 22:30:28 +0000368 }
369
370 return 0;
371}
372
373U_BOOT_DRIVER(rockchip_iodomain) = {
374 .name = "rockchip_iodomain",
375 .id = UCLASS_NOP,
376 .of_match = rockchip_iodomain_ids,
377 .bind = rockchip_iodomain_bind,
378 .probe = rockchip_iodomain_probe,
379};