
Hi Jonas,
On Sun, 6 Aug 2023 at 06:04, Jonas Karlman jonas@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@kwiboo.se
Cc: Jianqun Xu jay.xu@rock-chips.com Cc: Heiko Stuebner heiko@sntech.de Cc: Doug Anderson dianders@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@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