[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, &reg);
> +               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