
Port the Rockchip IO-domain driver for RK3568 from linux.
The driver auto probe after bind to configure IO-domain based on the regulator voltage. Compared to the linux driver this driver is not notified about regulator voltage changes and only configure IO-domain based on the initial voltage autoset by the regulator.
It is not recommended to enable MMC_IO_VOLTAGE or the mmc signal voltage and IO-domain may end up out of sync.
Based on the linux commit 28b05a64e47c ("soc: rockchip: io-domain: add rk3568 support").
Signed-off-by: Jonas Karlman jonas@kwiboo.se --- Cc: Jianqun Xu jay.xu@rock-chips.com Cc: Heiko Stuebner heiko@sntech.de Cc: Doug Anderson dianders@chromium.org --- drivers/misc/Kconfig | 9 ++ drivers/misc/Makefile | 1 + drivers/misc/rockchip-io-domain.c | 157 ++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/misc/rockchip-io-domain.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b9f5c7a37aed..d160ce693939 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -101,6 +101,15 @@ config ROCKCHIP_OTP addressing and a length or through child-nodes that are generated based on the e-fuse map retrieved from the DTS.
+config ROCKCHIP_IODOMAIN + bool "Rockchip IO-domain driver support" + depends on DM_REGULATOR && ARCH_ROCKCHIP + default y if ROCKCHIP_RK3568 + help + Enable support for IO-domains in Rockchip SoCs. It is necessary + for the IO-domain setting of the SoC to match the voltage supplied + by the regulators. + config SIFIVE_OTP bool "SiFive eMemory OTP driver" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index fd8805f34bd9..b67b82358a6c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o +obj-$(CONFIG_$(SPL_TPL_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_SIFIVE_OTP) += sifive-otp.o obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o diff --git a/drivers/misc/rockchip-io-domain.c b/drivers/misc/rockchip-io-domain.c new file mode 100644 index 000000000000..e458e3a17e2d --- /dev/null +++ b/drivers/misc/rockchip-io-domain.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <common.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <regmap.h> +#include <syscon.h> +#include <power/regulator.h> + +#define MAX_SUPPLIES 16 + +/* + * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under + * "Recommended Operating Conditions" for "Digital GPIO". When the typical + * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V. + * + * They are used like this: + * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the + * SoC we're at 3.3. + * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider + * that to be an error. + */ +#define MAX_VOLTAGE_1_8 1980000 +#define MAX_VOLTAGE_3_3 3600000 + +#define RK3568_PMU_GRF_IO_VSEL0 (0x0140) +#define RK3568_PMU_GRF_IO_VSEL1 (0x0144) +#define RK3568_PMU_GRF_IO_VSEL2 (0x0148) + +struct rockchip_iodomain_soc_data { + int grf_offset; + const char *supply_names[MAX_SUPPLIES]; + int (*write)(struct regmap *grf, int idx, int uV); +}; + +static int rk3568_iodomain_write(struct regmap *grf, int idx, int uV) +{ + u32 is_3v3 = uV > MAX_VOLTAGE_1_8; + u32 val0, val1; + int b; + + switch (idx) { + case 0: /* pmuio1 */ + break; + case 1: /* pmuio2 */ + b = idx; + val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b)); + b = idx + 4; + val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0); + + regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val0); + regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val1); + break; + case 3: /* vccio2 */ + break; + case 2: /* vccio1 */ + case 4: /* vccio3 */ + case 5: /* vccio4 */ + case 6: /* vccio5 */ + case 7: /* vccio6 */ + case 8: /* vccio7 */ + b = idx - 1; + val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b)); + val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0); + + regmap_write(grf, RK3568_PMU_GRF_IO_VSEL0, val0); + regmap_write(grf, RK3568_PMU_GRF_IO_VSEL1, val1); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = { + .grf_offset = 0x140, + .supply_names = { + NULL, + "pmuio2-supply", + "vccio1-supply", + NULL, + "vccio3-supply", + "vccio4-supply", + "vccio5-supply", + "vccio6-supply", + "vccio7-supply", + }, + .write = rk3568_iodomain_write, +}; + +static const struct udevice_id rockchip_iodomain_ids[] = { + { + .compatible = "rockchip,rk3568-pmu-io-voltage-domain", + .data = (ulong)&soc_data_rk3568_pmu, + }, + { } +}; + +static int rockchip_iodomain_bind(struct udevice *dev) +{ + dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); + + return 0; +} + +static int rockchip_iodomain_probe(struct udevice *dev) +{ + struct rockchip_iodomain_soc_data *soc_data = + (struct rockchip_iodomain_soc_data *)dev_get_driver_data(dev); + struct regmap *grf; + int ret; + + grf = syscon_get_regmap(dev_get_parent(dev)); + if (IS_ERR(grf)) + return PTR_ERR(grf); + + for (int i = 0; i < MAX_SUPPLIES; i++) { + const char *supply_name = soc_data->supply_names[i]; + struct udevice *reg; + int uV; + + if (!supply_name) + continue; + + ret = device_get_supply_regulator(dev, supply_name, ®); + if (ret) + continue; + + ret = regulator_autoset(reg); + if (ret && ret != -EALREADY && ret != -EMEDIUMTYPE && + ret != -ENOSYS) + continue; + + uV = regulator_get_value(reg); + if (uV <= 0) + continue; + + if (uV > MAX_VOLTAGE_3_3) { + dev_crit(dev, "%s: %d uV is too high. May damage SoC!\n", + supply_name, uV); + continue; + } + + soc_data->write(grf, i, uV); + } + + return 0; +} + +U_BOOT_DRIVER(rockchip_iodomain) = { + .name = "rockchip_iodomain", + .id = UCLASS_NOP, + .of_match = rockchip_iodomain_ids, + .bind = rockchip_iodomain_bind, + .probe = rockchip_iodomain_probe, +};