Hi Jonas, On Sun, 6 Aug 2023 at 06:04, Jonas Karlman <[email protected]> wrote: > > 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 <[email protected]> > --- > Cc: Jianqun Xu <[email protected]> > Cc: Heiko Stuebner <[email protected]> > Cc: Doug Anderson <[email protected]> > --- > 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
Reviewed-by: Simon Glass <[email protected]> nits below > > 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) Drop brackets Do we need the RK3568_ prefix? > + > +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); Why is this needed? > + > + 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, So this just exists to probe some power supplies at the start? > + .of_match = rockchip_iodomain_ids, > + .bind = rockchip_iodomain_bind, > + .probe = rockchip_iodomain_probe, > +}; > -- > 2.41.0 > Regards, Simon

