[PATCH 3/3] rockchip: Port IO-domain driver for RK3568 from linux
Simon Glass
sjg at chromium.org
Mon Aug 7 03:33:48 CEST 2023
Hi Jonas,
On Sun, 6 Aug 2023 at 06:04, Jonas Karlman <jonas at kwiboo.se> 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 <jonas at kwiboo.se>
> ---
> Cc: Jianqun Xu <jay.xu at rock-chips.com>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: Doug Anderson <dianders at 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
Reviewed-by: Simon Glass <sjg at chromium.org>
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
More information about the U-Boot
mailing list