summaryrefslogtreecommitdiffstats
path: root/drivers/soc/rockchip
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/rockchip')
-rw-r--r--drivers/soc/rockchip/Kconfig10
-rw-r--r--drivers/soc/rockchip/Makefile1
-rw-r--r--drivers/soc/rockchip/grf.c134
-rw-r--r--drivers/soc/rockchip/pm_domains.c63
4 files changed, 202 insertions, 6 deletions
diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
index 7140ff825598..20da55d9cbb1 100644
--- a/drivers/soc/rockchip/Kconfig
+++ b/drivers/soc/rockchip/Kconfig
@@ -3,6 +3,16 @@ if ARCH_ROCKCHIP || COMPILE_TEST
#
# Rockchip Soc drivers
#
+
+config ROCKCHIP_GRF
+ bool
+ default y
+ help
+ The General Register Files are a central component providing
+ special additional settings registers for a lot of soc-components.
+ In a lot of cases there also need to be default settings initialized
+ to make some of them conform to expectations of the kernel.
+
config ROCKCHIP_PM_DOMAINS
bool "Rockchip generic power domain"
depends on PM
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
index 3d73d0672d22..c851fa0056d0 100644
--- a/drivers/soc/rockchip/Makefile
+++ b/drivers/soc/rockchip/Makefile
@@ -1,4 +1,5 @@
#
# Rockchip Soc drivers
#
+obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
new file mode 100644
index 000000000000..d61db34ad6dd
--- /dev/null
+++ b/drivers/soc/rockchip/grf.c
@@ -0,0 +1,134 @@
+/*
+ * Rockchip Generic Register Files setup
+ *
+ * Copyright (c) 2016 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+struct rockchip_grf_value {
+ const char *desc;
+ u32 reg;
+ u32 val;
+};
+
+struct rockchip_grf_info {
+ const struct rockchip_grf_value *values;
+ int num_values;
+};
+
+#define RK3036_GRF_SOC_CON0 0x140
+
+static const struct rockchip_grf_value rk3036_defaults[] __initconst = {
+ /*
+ * Disable auto jtag/sdmmc switching that causes issues with the
+ * clock-framework and the mmc controllers making them unreliable.
+ */
+ { "jtag switching", RK3036_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 11) },
+};
+
+static const struct rockchip_grf_info rk3036_grf __initconst = {
+ .values = rk3036_defaults,
+ .num_values = ARRAY_SIZE(rk3036_defaults),
+};
+
+#define RK3288_GRF_SOC_CON0 0x244
+
+static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
+ { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
+};
+
+static const struct rockchip_grf_info rk3288_grf __initconst = {
+ .values = rk3288_defaults,
+ .num_values = ARRAY_SIZE(rk3288_defaults),
+};
+
+#define RK3368_GRF_SOC_CON15 0x43c
+
+static const struct rockchip_grf_value rk3368_defaults[] __initconst = {
+ { "jtag switching", RK3368_GRF_SOC_CON15, HIWORD_UPDATE(0, 1, 13) },
+};
+
+static const struct rockchip_grf_info rk3368_grf __initconst = {
+ .values = rk3368_defaults,
+ .num_values = ARRAY_SIZE(rk3368_defaults),
+};
+
+#define RK3399_GRF_SOC_CON7 0xe21c
+
+static const struct rockchip_grf_value rk3399_defaults[] __initconst = {
+ { "jtag switching", RK3399_GRF_SOC_CON7, HIWORD_UPDATE(0, 1, 12) },
+};
+
+static const struct rockchip_grf_info rk3399_grf __initconst = {
+ .values = rk3399_defaults,
+ .num_values = ARRAY_SIZE(rk3399_defaults),
+};
+
+static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
+ {
+ .compatible = "rockchip,rk3036-grf",
+ .data = (void *)&rk3036_grf,
+ }, {
+ .compatible = "rockchip,rk3288-grf",
+ .data = (void *)&rk3288_grf,
+ }, {
+ .compatible = "rockchip,rk3368-grf",
+ .data = (void *)&rk3368_grf,
+ }, {
+ .compatible = "rockchip,rk3399-grf",
+ .data = (void *)&rk3399_grf,
+ },
+ { /* sentinel */ },
+};
+
+static int __init rockchip_grf_init(void)
+{
+ const struct rockchip_grf_info *grf_info;
+ const struct of_device_id *match;
+ struct device_node *np;
+ struct regmap *grf;
+ int ret, i;
+
+ np = of_find_matching_node_and_match(NULL, rockchip_grf_dt_match,
+ &match);
+ if (!np)
+ return -ENODEV;
+ if (!match || !match->data) {
+ pr_err("%s: missing grf data\n", __func__);
+ return -EINVAL;
+ }
+
+ grf_info = match->data;
+
+ grf = syscon_node_to_regmap(np);
+ if (IS_ERR(grf)) {
+ pr_err("%s: could not get grf syscon\n", __func__);
+ return PTR_ERR(grf);
+ }
+
+ for (i = 0; i < grf_info->num_values; i++) {
+ const struct rockchip_grf_value *val = &grf_info->values[i];
+
+ pr_debug("%s: adjusting %s in %#6x to %#10x\n", __func__,
+ val->desc, val->reg, val->val);
+ ret = regmap_write(grf, val->reg, val->val);
+ if (ret < 0)
+ pr_err("%s: write to %#6x failed with %d\n",
+ __func__, val->reg, ret);
+ }
+
+ return 0;
+}
+postcore_initcall(rockchip_grf_init);
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 1c78c42416c6..796c46a6cbe7 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -19,6 +19,7 @@
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <dt-bindings/power/rk3288-power.h>
+#include <dt-bindings/power/rk3328-power.h>
#include <dt-bindings/power/rk3368-power.h>
#include <dt-bindings/power/rk3399-power.h>
@@ -29,6 +30,8 @@ struct rockchip_domain_info {
int idle_mask;
int ack_mask;
bool active_wakeup;
+ int pwr_w_mask;
+ int req_w_mask;
};
struct rockchip_pmu_info {
@@ -87,9 +90,24 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
+#define DOMAIN_M(pwr, status, req, idle, ack, wakeup) \
+{ \
+ .pwr_w_mask = (pwr >= 0) ? BIT(pwr + 16) : 0, \
+ .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \
+ .status_mask = (status >= 0) ? BIT(status) : 0, \
+ .req_w_mask = (req >= 0) ? BIT(req + 16) : 0, \
+ .req_mask = (req >= 0) ? BIT(req) : 0, \
+ .idle_mask = (idle >= 0) ? BIT(idle) : 0, \
+ .ack_mask = (ack >= 0) ? BIT(ack) : 0, \
+ .active_wakeup = wakeup, \
+}
+
#define DOMAIN_RK3288(pwr, status, req, wakeup) \
DOMAIN(pwr, status, req, req, (req) + 16, wakeup)
+#define DOMAIN_RK3328(pwr, status, req, wakeup) \
+ DOMAIN_M(pwr, pwr, req, (req) + 10, req, wakeup)
+
#define DOMAIN_RK3368(pwr, status, req, wakeup) \
DOMAIN(pwr, status, req, (req) + 16, req, wakeup)
@@ -127,9 +145,13 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
if (pd_info->req_mask == 0)
return 0;
-
- regmap_update_bits(pmu->regmap, pmu->info->req_offset,
- pd_info->req_mask, idle ? -1U : 0);
+ else if (pd_info->req_w_mask)
+ regmap_write(pmu->regmap, pmu->info->req_offset,
+ idle ? (pd_info->req_mask | pd_info->req_w_mask) :
+ pd_info->req_w_mask);
+ else
+ regmap_update_bits(pmu->regmap, pmu->info->req_offset,
+ pd_info->req_mask, idle ? -1U : 0);
dsb(sy);
@@ -230,9 +252,13 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
if (pd->info->pwr_mask == 0)
return;
-
- regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
- pd->info->pwr_mask, on ? 0 : -1U);
+ else if (pd->info->pwr_w_mask)
+ regmap_write(pmu->regmap, pmu->info->pwr_offset,
+ on ? pd->info->pwr_mask :
+ (pd->info->pwr_mask | pd->info->pwr_w_mask));
+ else
+ regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
+ pd->info->pwr_mask, on ? 0 : -1U);
dsb(sy);
@@ -692,6 +718,18 @@ static const struct rockchip_domain_info rk3288_pm_domains[] = {
[RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2, false),
};
+static const struct rockchip_domain_info rk3328_pm_domains[] = {
+ [RK3328_PD_CORE] = DOMAIN_RK3328(-1, 0, 0, false),
+ [RK3328_PD_GPU] = DOMAIN_RK3328(-1, 1, 1, false),
+ [RK3328_PD_BUS] = DOMAIN_RK3328(-1, 2, 2, true),
+ [RK3328_PD_MSCH] = DOMAIN_RK3328(-1, 3, 3, true),
+ [RK3328_PD_PERI] = DOMAIN_RK3328(-1, 4, 4, true),
+ [RK3328_PD_VIDEO] = DOMAIN_RK3328(-1, 5, 5, false),
+ [RK3328_PD_HEVC] = DOMAIN_RK3328(-1, 6, 6, false),
+ [RK3328_PD_VIO] = DOMAIN_RK3328(-1, 8, 8, false),
+ [RK3328_PD_VPU] = DOMAIN_RK3328(-1, 9, 9, false),
+};
+
static const struct rockchip_domain_info rk3368_pm_domains[] = {
[RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6, true),
[RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8, false),
@@ -747,6 +785,15 @@ static const struct rockchip_pmu_info rk3288_pmu = {
.domain_info = rk3288_pm_domains,
};
+static const struct rockchip_pmu_info rk3328_pmu = {
+ .req_offset = 0x414,
+ .idle_offset = 0x484,
+ .ack_offset = 0x484,
+
+ .num_domains = ARRAY_SIZE(rk3328_pm_domains),
+ .domain_info = rk3328_pm_domains,
+};
+
static const struct rockchip_pmu_info rk3368_pmu = {
.pwr_offset = 0x0c,
.status_offset = 0x10,
@@ -783,6 +830,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
.data = (void *)&rk3288_pmu,
},
{
+ .compatible = "rockchip,rk3328-power-controller",
+ .data = (void *)&rk3328_pmu,
+ },
+ {
.compatible = "rockchip,rk3368-power-controller",
.data = (void *)&rk3368_pmu,
},