[PATCH 3/3] rockchip: Port IO-domain driver for RK3568 from linux

Jonas Karlman jonas at kwiboo.se
Mon Aug 7 04:17:52 CEST 2023


Hi Simon,
On 2023-08-07 03:33, Simon Glass wrote:
> 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

Will do in a v2.

> 
> Do we need the RK3568_ prefix?

Yes, this only imports the RK3568 parts almost 1:1 from linux at this
stage. Support for other SoCs should be added in the future so that we
can move away from having to hard-code IO-domain settings in board init.

RockPro64 configures two IO-domains in misc_init_r, that can be dropped
and would be handled by this driver once RK3399 support has been ported.
https://source.denx.de/u-boot/u-boot/-/blob/master/board/pine64/rockpro64_rk3399/rockpro64-rk3399.c#L20-32

Linux driver has support for 10 different SoCs:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/soc/rockchip/io-domain.c#n510

> 
>> +
>> +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?

So that the driver auto probe as early as possible. Is there any other
way of telling that this device must be probed? There is no real
consumer of this device so lazy loading it does not work.

> 
>> +
>> +       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?

No, it exists to configure the different VCCIO-domains in 1.8V or 3.3V
mode to match the voltage of the input supply of a IO-domain. In order
to do that it needs to probe each IO-domains input supply regulator.

To quote from a reference schematics [1] for RK3568:

When the IO domain power supply voltage is 1.8V, the IO domain voltage
configuration in DTS must be set to 1.8V mode. If it is misconfigured to
3.3V mode, the IO function of this power domain will be abnormally;

When the IO domain power supply voltage is 3.3V, the IO domain voltage
configuration in DTS must be set to 3.3V mode. If it is misconfigured to
1.8V mode, the IO in this power domain will be in overvoltage state, and
the IO will be damaged after long-term operation.

On RK3568 an issue with ethernet was observed, TX packages would not
reach the network, yet RX packages was received. Turned out that the
VCCIO-domain was default configured in 3.3V, and input supply provided
and PHY expected 1.8V.

[1] http://opensource.rock-chips.com/images/5/56/RK3568_hardware_reference_20220806.zip

Regards,
Jonas

> 
>> +       .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