summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2022-09-22 11:31:53 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2022-09-22 11:31:53 +0200
commit52bdc90f16a46e567aec5ca13871ec65f770769a (patch)
tree3dccf41b6f30c60a7ab3f2f04bd2b50f592ce957
parent7771adcb918ee51f8d2869e1da8cefd70f6ecb61 (diff)
parent502c4e819b80a6ccaefbce4af4c55b830b7e2c73 (diff)
downloadbarebox-52bdc90f16a46e567aec5ca13871ec65f770769a.tar.gz
barebox-52bdc90f16a46e567aec5ca13871ec65f770769a.tar.xz
Merge branch 'for-next/rockchip-io-domains' into next
-rw-r--r--arch/arm/boards/radxa-rock3/lowlevel.c4
-rw-r--r--arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c4
-rw-r--r--arch/arm/boards/rockchip-rk3568-evb/lowlevel.c4
-rw-r--r--arch/arm/configs/rockchip_v8_defconfig4
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/rockchip/Kconfig17
-rw-r--r--drivers/soc/rockchip/Makefile6
-rw-r--r--drivers/soc/rockchip/io-domain.c223
9 files changed, 264 insertions, 0 deletions
diff --git a/arch/arm/boards/radxa-rock3/lowlevel.c b/arch/arm/boards/radxa-rock3/lowlevel.c
index 2a449c17ae..a62f60dff8 100644
--- a/arch/arm/boards/radxa-rock3/lowlevel.c
+++ b/arch/arm/boards/radxa-rock3/lowlevel.c
@@ -17,6 +17,10 @@ static noinline void rk3568_start(void)
/*
* Enable vccio4 1.8V and vccio6 1.8V
* Needed for GMAC to work.
+ * FIXME: This is done by the io-domain driver as well, but there
+ * currently is no mechanism to make sure the driver gets probed
+ * before its consumers. Remove this setup once this issue is
+ * resolved.
*/
writel(RK_SETBITS(0x50), 0xfdc20140);
diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
index f79f975080..4336d99365 100644
--- a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
+++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
@@ -18,6 +18,10 @@ static noinline void rk3568_start(void)
/*
* set iodomain vccio6 to 1.8V needed for GMAC1 to work.
* vccio4 (gmac0/switch) needs to stay at 3v3 (default)
+ * FIXME: This is done by the io-domain driver as well, but there
+ * currently is no mechanism to make sure the driver gets probed
+ * before its consumers. Remove this setup once this issue is
+ * resolved.
*/
//set bit 6 in PMU_GRF_IO_VSEL0 for vccio6 1v8
writel(RK_SETBITS(BIT(6)), PMU_GRF_IO_VSEL0);
diff --git a/arch/arm/boards/rockchip-rk3568-evb/lowlevel.c b/arch/arm/boards/rockchip-rk3568-evb/lowlevel.c
index 363639d21b..9ab436135c 100644
--- a/arch/arm/boards/rockchip-rk3568-evb/lowlevel.c
+++ b/arch/arm/boards/rockchip-rk3568-evb/lowlevel.c
@@ -18,6 +18,10 @@ static noinline void rk3568_start(void)
/*
* Enable vccio4 1.8V and vccio6 1.8V
* Needed for GMAC to work.
+ * FIXME: This is done by the io-domain driver as well, but there
+ * currently is no mechanism to make sure the driver gets probed
+ * before its consumers. Remove this setup once this issue is
+ * resolved.
*/
writel(RK_SETBITS(0x50), 0xfdc20140);
diff --git a/arch/arm/configs/rockchip_v8_defconfig b/arch/arm/configs/rockchip_v8_defconfig
index 7fba31ddc3..d673f7f788 100644
--- a/arch/arm/configs/rockchip_v8_defconfig
+++ b/arch/arm/configs/rockchip_v8_defconfig
@@ -139,3 +139,7 @@ CONFIG_FS_FAT_LFN=y
CONFIG_FS_BPKFS=y
CONFIG_FS_UIMAGEFS=y
CONFIG_LZO_DECOMPRESS=y
+CONFIG_I2C_RK3X=y
+CONFIG_MFD_RK808=y
+CONFIG_REGULATOR_RK808=y
+CONFIG_ROCKCHIP_IODOMAIN=y
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 54b69cc42e..c0fe214429 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -2,5 +2,6 @@ menu "SoC drivers"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/kvx/Kconfig"
+source "drivers/soc/rockchip/Kconfig"
endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index a23e81ffb3..9bff737b78 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -2,5 +2,6 @@
obj-$(CONFIG_ARCH_IMX) += imx/
obj-$(CONFIG_KVX) += kvx/
+obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_CPU_SIFIVE) += sifive/
obj-$(CONFIG_SOC_STARFIVE) += starfive/
diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
new file mode 100644
index 0000000000..3484b37e22
--- /dev/null
+++ b/drivers/soc/rockchip/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+if ARCH_ROCKCHIP || COMPILE_TEST
+
+menu "Rockchip SoC drivers"
+
+config ROCKCHIP_IODOMAIN
+ tristate "Rockchip IO domain support"
+ depends on OFDEVICE
+ help
+ Say y here to enable support io domains on Rockchip SoCs. It is
+ necessary for the io domain setting of the SoC to match the
+ voltage supplied by the regulators.
+
+endmenu
+
+endif
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
new file mode 100644
index 0000000000..104fad968e
--- /dev/null
+++ b/drivers/soc/rockchip/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Rockchip Soc drivers
+#
+
+obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o
diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c
new file mode 100644
index 0000000000..ac5724c0e7
--- /dev/null
+++ b/drivers/soc/rockchip/io-domain.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Rockchip IO Voltage Domain driver
+ *
+ * Copyright 2014 MundoReader S.L.
+ * Copyright 2014 Google, Inc.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+#include <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)
+
+struct rockchip_iodomain;
+
+struct rockchip_iodomain_supply {
+ struct rockchip_iodomain *iod;
+ struct regulator *reg;
+ int idx;
+};
+
+struct rockchip_iodomain_soc_data {
+ int grf_offset;
+ const char *supply_names[MAX_SUPPLIES];
+ void (*init)(struct rockchip_iodomain *iod);
+ int (*write)(struct rockchip_iodomain_supply *supply, int uV);
+};
+
+struct rockchip_iodomain {
+ struct device_d *dev;
+ struct regmap *grf;
+ const struct rockchip_iodomain_soc_data *soc_data;
+ struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
+ int (*write)(struct rockchip_iodomain_supply *supply, int uV);
+};
+
+static int rk3568_iodomain_write(struct rockchip_iodomain_supply *supply,
+ int uV)
+{
+ struct rockchip_iodomain *iod = supply->iod;
+ u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
+ u32 val0, val1;
+ int b;
+
+ dev_dbg(iod->dev, "set domain %d to %d uV\n", supply->idx, uV);
+
+ switch (supply->idx) {
+ case 0: /* pmuio1 */
+ break;
+ case 1: /* pmuio2 */
+ b = supply->idx;
+ val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
+ b = supply->idx + 4;
+ val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
+
+ regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val0);
+ regmap_write(iod->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 = supply->idx - 1;
+ val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
+ val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
+
+ regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL0, val0);
+ regmap_write(iod->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 = {
+ "pmuio1",
+ "pmuio2",
+ "vccio1",
+ "vccio2",
+ "vccio3",
+ "vccio4",
+ "vccio5",
+ "vccio6",
+ "vccio7",
+ },
+ .write = rk3568_iodomain_write,
+};
+
+static const struct of_device_id rockchip_iodomain_match[] = {
+ { .compatible = "rockchip,rk3568-pmu-io-voltage-domain",
+ .data = &soc_data_rk3568_pmu },
+ { /* sentinel */ },
+};
+
+static int rockchip_iodomain_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node, *parent;
+ struct rockchip_iodomain *iod;
+ int i, ret = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ iod = xzalloc(sizeof(*iod));
+ iod->dev = dev;
+ iod->soc_data = device_get_match_data(dev);
+
+ if (iod->soc_data->write)
+ iod->write = iod->soc_data->write;
+
+ parent = of_get_parent(np);
+ if (parent) {
+ iod->grf = syscon_node_to_regmap(parent);
+ } else {
+ dev_dbg(dev, "falling back to old binding\n");
+ iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ }
+
+ if (IS_ERR(iod->grf)) {
+ dev_err(dev, "couldn't find grf regmap\n");
+ return PTR_ERR(iod->grf);
+ }
+
+ for (i = 0; i < MAX_SUPPLIES; i++) {
+ const char *supply_name = iod->soc_data->supply_names[i];
+ struct rockchip_iodomain_supply *supply = &iod->supplies[i];
+ struct regulator *reg;
+ int uV;
+
+ if (!supply_name)
+ continue;
+
+ reg = regulator_get(dev, supply_name);
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+
+ /* If a supply wasn't specified, that's OK */
+ if (ret == -ENODEV)
+ continue;
+ else if (ret != -EPROBE_DEFER)
+ dev_err(dev, "couldn't get regulator %s\n",
+ supply_name);
+ goto out;
+ }
+
+ /* set initial correct value */
+ uV = regulator_get_voltage(reg);
+
+ /* must be a regulator we can get the voltage of */
+ if (uV < 0) {
+ dev_err(dev, "Can't determine voltage: %s\n",
+ supply_name);
+ ret = uV;
+ goto out;
+ }
+
+ if (uV > MAX_VOLTAGE_3_3) {
+ dev_crit(dev, "%d uV is too high. May damage SoC!\n",
+ uV);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* setup our supply */
+ supply->idx = i;
+ supply->iod = iod;
+ supply->reg = reg;
+
+ ret = iod->write(supply, uV);
+ if (ret) {
+ supply->reg = NULL;
+ goto out;
+ }
+ }
+
+ if (iod->soc_data->init)
+ iod->soc_data->init(iod);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static struct driver_d rockchip_iodomain_driver = {
+ .name = "rockchip-iodomain",
+ .probe = rockchip_iodomain_probe,
+ .of_compatible = rockchip_iodomain_match,
+};
+coredevice_platform_driver(rockchip_iodomain_driver);