From: Jonas Karlman Date: Mon, 21 Aug 2023 22:30:28 +0000 (+0000) Subject: rockchip: Port IO-domain driver for RK3568 from linux X-Git-Url: http://git.dujemihanovic.xyz/img/static/git-favicon.png?a=commitdiff_plain;h=09329df25f69f76751691c5a6d7a9e6f6567bc4c;p=u-boot.git rockchip: Port IO-domain driver for RK3568 from linux 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 Reviewed-by: Simon Glass Reviewed-by: Kever Yang --- diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c930e4a361..fccd9b89b8 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 fd8805f34b..b67b82358a 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 0000000000..3f6227f993 --- /dev/null +++ b/drivers/misc/rockchip-io-domain.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip IO Voltage Domain driver + * + * Ported from linux drivers/soc/rockchip/io-domain.c + */ + +#include +#include +#include +#include +#include +#include + +#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) +{ + /* + * According to the Hardware Design Guide, IO-domain configuration must + * be consistent with the power supply voltage (1.8V or 3.3V). + * Probe after bind to configure IO-domain voltage early during boot. + */ + 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, +};