summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/bcm/Kconfig15
-rw-r--r--drivers/soc/bcm/Makefile1
-rw-r--r--drivers/soc/bcm/brcmstb/Makefile (renamed from drivers/soc/brcmstb/Makefile)0
-rw-r--r--drivers/soc/bcm/brcmstb/biuctrl.c (renamed from drivers/soc/brcmstb/biuctrl.c)1
-rw-r--r--drivers/soc/bcm/brcmstb/common.c (renamed from drivers/soc/brcmstb/common.c)0
-rw-r--r--drivers/soc/brcmstb/Kconfig10
-rw-r--r--drivers/soc/renesas/Makefile1
-rw-r--r--drivers/soc/renesas/r8a7796-sysc.c48
-rw-r--r--drivers/soc/renesas/rcar-sysc.c3
-rw-r--r--drivers/soc/renesas/rcar-sysc.h1
-rw-r--r--drivers/soc/samsung/Kconfig4
-rw-r--r--drivers/soc/samsung/Makefile1
-rw-r--r--drivers/soc/samsung/pm_domains.c245
15 files changed, 320 insertions, 12 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index cb58ef0d9b2c..91d5c05d395f 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,7 +1,6 @@
menu "SOC (System On Chip) specific Drivers"
source "drivers/soc/bcm/Kconfig"
-source "drivers/soc/brcmstb/Kconfig"
source "drivers/soc/fsl/qe/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 380230f03874..b75e3bd0a01e 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,7 +3,6 @@
#
obj-y += bcm/
-obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
obj-y += fsl/
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
index 3066edea184d..97156aeed286 100644
--- a/drivers/soc/bcm/Kconfig
+++ b/drivers/soc/bcm/Kconfig
@@ -1,3 +1,5 @@
+menu "Broadcom SoC drivers"
+
config RASPBERRYPI_POWER
bool "Raspberry Pi power domain driver"
depends on ARCH_BCM2835 || COMPILE_TEST
@@ -7,3 +9,16 @@ config RASPBERRYPI_POWER
help
This enables support for the RPi power domains which can be enabled
or disabled via the RPi firmware.
+
+config SOC_BRCMSTB
+ bool "Broadcom STB SoC drivers"
+ depends on ARM
+ select SOC_BUS
+ help
+ Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
+ This option alone enables only some support code, while the drivers
+ can be enabled individually within this menu.
+
+ If unsure, say N.
+
+endmenu
diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile
index 63aa3eb23087..dc4fced72d21 100644
--- a/drivers/soc/bcm/Makefile
+++ b/drivers/soc/bcm/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
+obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
diff --git a/drivers/soc/brcmstb/Makefile b/drivers/soc/bcm/brcmstb/Makefile
index 9120b2715d3e..9120b2715d3e 100644
--- a/drivers/soc/brcmstb/Makefile
+++ b/drivers/soc/bcm/brcmstb/Makefile
diff --git a/drivers/soc/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c
index 9049c076f9a1..3c39415d484f 100644
--- a/drivers/soc/brcmstb/biuctrl.c
+++ b/drivers/soc/bcm/brcmstb/biuctrl.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
+#include <linux/soc/brcmstb/brcmstb.h>
#define CPU_CREDIT_REG_OFFSET 0x184
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
diff --git a/drivers/soc/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c
index 94e7335553f4..94e7335553f4 100644
--- a/drivers/soc/brcmstb/common.c
+++ b/drivers/soc/bcm/brcmstb/common.c
diff --git a/drivers/soc/brcmstb/Kconfig b/drivers/soc/brcmstb/Kconfig
deleted file mode 100644
index 7fec3b4c80a1..000000000000
--- a/drivers/soc/brcmstb/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-menuconfig SOC_BRCMSTB
- bool "Broadcom STB SoC drivers"
- depends on ARM
- select SOC_BUS
- help
- Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
- This option alone enables only some support code, while the drivers
- can be enabled individually within this menu.
-
- If unsure, say N.
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 151fcd3f025b..cd85cd5e6a01 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o
obj-$(CONFIG_ARCH_R8A7793) += rcar-sysc.o r8a7791-sysc.o
obj-$(CONFIG_ARCH_R8A7794) += rcar-sysc.o r8a7794-sysc.o
obj-$(CONFIG_ARCH_R8A7795) += rcar-sysc.o r8a7795-sysc.o
+obj-$(CONFIG_ARCH_R8A7796) += rcar-sysc.o r8a7796-sysc.o
diff --git a/drivers/soc/renesas/r8a7796-sysc.c b/drivers/soc/renesas/r8a7796-sysc.c
new file mode 100644
index 000000000000..f700c842b9e1
--- /dev/null
+++ b/drivers/soc/renesas/r8a7796-sysc.c
@@ -0,0 +1,48 @@
+/*
+ * Renesas R-Car M3-W System Controller
+ *
+ * Copyright (C) 2016 Glider bvba
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/power/r8a7796-sysc.h>
+
+#include "rcar-sysc.h"
+
+static const struct rcar_sysc_area r8a7796_areas[] __initconst = {
+ { "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+ { "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca57-cpu0", 0x80, 0, R8A7796_PD_CA57_CPU0, R8A7796_PD_CA57_SCU,
+ PD_CPU_NOCR },
+ { "ca57-cpu1", 0x80, 1, R8A7796_PD_CA57_CPU1, R8A7796_PD_CA57_SCU,
+ PD_CPU_NOCR },
+ { "ca53-scu", 0x140, 0, R8A7796_PD_CA53_SCU, R8A7796_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca53-cpu0", 0x200, 0, R8A7796_PD_CA53_CPU0, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu1", 0x200, 1, R8A7796_PD_CA53_CPU1, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu2", 0x200, 2, R8A7796_PD_CA53_CPU2, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu3", 0x200, 3, R8A7796_PD_CA53_CPU3, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "cr7", 0x240, 0, R8A7796_PD_CR7, R8A7796_PD_ALWAYS_ON },
+ { "a3vc", 0x380, 0, R8A7796_PD_A3VC, R8A7796_PD_ALWAYS_ON },
+ { "a2vc0", 0x3c0, 0, R8A7796_PD_A2VC0, R8A7796_PD_A3VC },
+ { "a2vc1", 0x3c0, 1, R8A7796_PD_A2VC1, R8A7796_PD_A3VC },
+ { "3dg-a", 0x100, 0, R8A7796_PD_3DG_A, R8A7796_PD_ALWAYS_ON },
+ { "3dg-b", 0x100, 1, R8A7796_PD_3DG_B, R8A7796_PD_3DG_A },
+ { "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON },
+};
+
+const struct rcar_sysc_info r8a7796_sysc_info __initconst = {
+ .areas = r8a7796_areas,
+ .num_areas = ARRAY_SIZE(r8a7796_areas),
+};
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index 79dbc770895f..fc997d4d2a4a 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -303,6 +303,9 @@ static const struct of_device_id rcar_sysc_matches[] = {
#ifdef CONFIG_ARCH_R8A7795
{ .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
#endif
+#ifdef CONFIG_ARCH_R8A7796
+ { .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
+#endif
{ /* sentinel */ }
};
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h
index 5e766174c2f4..4ac3d7bf7f38 100644
--- a/drivers/soc/renesas/rcar-sysc.h
+++ b/drivers/soc/renesas/rcar-sysc.h
@@ -55,4 +55,5 @@ extern const struct rcar_sysc_info r8a7790_sysc_info;
extern const struct rcar_sysc_info r8a7791_sysc_info;
extern const struct rcar_sysc_info r8a7794_sysc_info;
extern const struct rcar_sysc_info r8a7795_sysc_info;
+extern const struct rcar_sysc_info r8a7796_sysc_info;
#endif /* __SOC_RENESAS_RCAR_SYSC_H__ */
diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
index d7fc123006a3..245533907d1b 100644
--- a/drivers/soc/samsung/Kconfig
+++ b/drivers/soc/samsung/Kconfig
@@ -10,4 +10,8 @@ config EXYNOS_PMU
bool "Exynos PMU controller driver" if COMPILE_TEST
depends on (ARM && ARCH_EXYNOS) || ((ARM || ARM64) && COMPILE_TEST)
+config EXYNOS_PM_DOMAINS
+ bool "Exynos PM domains" if COMPILE_TEST
+ depends on PM_GENERIC_DOMAINS || COMPILE_TEST
+
endif
diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
index f64ac4d80564..3619f2ecddaa 100644
--- a/drivers/soc/samsung/Makefile
+++ b/drivers/soc/samsung/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o exynos3250-pmu.o exynos4-pmu.o \
exynos5250-pmu.o exynos5420-pmu.o
+obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o
diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c
new file mode 100644
index 000000000000..f60515eefb66
--- /dev/null
+++ b/drivers/soc/samsung/pm_domains.c
@@ -0,0 +1,245 @@
+/*
+ * Exynos Generic power domain support.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Implementation of Exynos specific power domain control which is used in
+ * conjunction with runtime-pm. Support for both device-tree and non-device-tree
+ * based power domain support is included.
+ *
+ * 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/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/pm_domain.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/sched.h>
+
+#define MAX_CLK_PER_DOMAIN 4
+
+struct exynos_pm_domain_config {
+ /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
+ u32 local_pwr_cfg;
+};
+
+/*
+ * Exynos specific wrapper around the generic power domain
+ */
+struct exynos_pm_domain {
+ void __iomem *base;
+ char const *name;
+ bool is_off;
+ struct generic_pm_domain pd;
+ struct clk *oscclk;
+ struct clk *clk[MAX_CLK_PER_DOMAIN];
+ struct clk *pclk[MAX_CLK_PER_DOMAIN];
+ struct clk *asb_clk[MAX_CLK_PER_DOMAIN];
+ u32 local_pwr_cfg;
+};
+
+static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
+{
+ struct exynos_pm_domain *pd;
+ void __iomem *base;
+ u32 timeout, pwr;
+ char *op;
+ int i;
+
+ pd = container_of(domain, struct exynos_pm_domain, pd);
+ base = pd->base;
+
+ for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ if (IS_ERR(pd->asb_clk[i]))
+ break;
+ clk_prepare_enable(pd->asb_clk[i]);
+ }
+
+ /* Set oscclk before powering off a domain*/
+ if (!power_on) {
+ for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ if (IS_ERR(pd->clk[i]))
+ break;
+ pd->pclk[i] = clk_get_parent(pd->clk[i]);
+ if (clk_set_parent(pd->clk[i], pd->oscclk))
+ pr_err("%s: error setting oscclk as parent to clock %d\n",
+ pd->name, i);
+ }
+ }
+
+ pwr = power_on ? pd->local_pwr_cfg : 0;
+ __raw_writel(pwr, base);
+
+ /* Wait max 1ms */
+ timeout = 10;
+
+ while ((__raw_readl(base + 0x4) & pd->local_pwr_cfg) != pwr) {
+ if (!timeout) {
+ op = (power_on) ? "enable" : "disable";
+ pr_err("Power domain %s %s failed\n", domain->name, op);
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ cpu_relax();
+ usleep_range(80, 100);
+ }
+
+ /* Restore clocks after powering on a domain*/
+ if (power_on) {
+ for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ if (IS_ERR(pd->clk[i]))
+ break;
+
+ if (IS_ERR(pd->pclk[i]))
+ continue; /* Skip on first power up */
+ if (clk_set_parent(pd->clk[i], pd->pclk[i]))
+ pr_err("%s: error setting parent to clock%d\n",
+ pd->name, i);
+ }
+ }
+
+ for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ if (IS_ERR(pd->asb_clk[i]))
+ break;
+ clk_disable_unprepare(pd->asb_clk[i]);
+ }
+
+ return 0;
+}
+
+static int exynos_pd_power_on(struct generic_pm_domain *domain)
+{
+ return exynos_pd_power(domain, true);
+}
+
+static int exynos_pd_power_off(struct generic_pm_domain *domain)
+{
+ return exynos_pd_power(domain, false);
+}
+
+static const struct exynos_pm_domain_config exynos4210_cfg __initconst = {
+ .local_pwr_cfg = 0x7,
+};
+
+static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
+ {
+ .compatible = "samsung,exynos4210-pd",
+ .data = &exynos4210_cfg,
+ },
+ { },
+};
+
+static __init int exynos4_pm_init_power_domain(void)
+{
+ struct device_node *np;
+ const struct of_device_id *match;
+
+ for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) {
+ const struct exynos_pm_domain_config *pm_domain_cfg;
+ struct exynos_pm_domain *pd;
+ int on, i;
+
+ pm_domain_cfg = match->data;
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ pr_err("%s: failed to allocate memory for domain\n",
+ __func__);
+ of_node_put(np);
+ return -ENOMEM;
+ }
+ pd->pd.name = kstrdup_const(strrchr(np->full_name, '/') + 1,
+ GFP_KERNEL);
+ if (!pd->pd.name) {
+ kfree(pd);
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ pd->name = pd->pd.name;
+ pd->base = of_iomap(np, 0);
+ if (!pd->base) {
+ pr_warn("%s: failed to map memory\n", __func__);
+ kfree_const(pd->pd.name);
+ kfree(pd);
+ continue;
+ }
+
+ pd->pd.power_off = exynos_pd_power_off;
+ pd->pd.power_on = exynos_pd_power_on;
+ pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg;
+
+ for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ char clk_name[8];
+
+ snprintf(clk_name, sizeof(clk_name), "asb%d", i);
+ pd->asb_clk[i] = of_clk_get_by_name(np, clk_name);
+ if (IS_ERR(pd->asb_clk[i]))
+ break;
+ }
+
+ pd->oscclk = of_clk_get_by_name(np, "oscclk");
+ if (IS_ERR(pd->oscclk))
+ goto no_clk;
+
+ for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ char clk_name[8];
+
+ snprintf(clk_name, sizeof(clk_name), "clk%d", i);
+ pd->clk[i] = of_clk_get_by_name(np, clk_name);
+ if (IS_ERR(pd->clk[i]))
+ break;
+ /*
+ * Skip setting parent on first power up.
+ * The parent at this time may not be useful at all.
+ */
+ pd->pclk[i] = ERR_PTR(-EINVAL);
+ }
+
+ if (IS_ERR(pd->clk[0]))
+ clk_put(pd->oscclk);
+
+no_clk:
+ on = __raw_readl(pd->base + 0x4) & pd->local_pwr_cfg;
+
+ pm_genpd_init(&pd->pd, NULL, !on);
+ of_genpd_add_provider_simple(np, &pd->pd);
+ }
+
+ /* Assign the child power domains to their parents */
+ for_each_matching_node(np, exynos_pm_domain_of_match) {
+ struct generic_pm_domain *child_domain, *parent_domain;
+ struct of_phandle_args args;
+
+ args.np = np;
+ args.args_count = 0;
+ child_domain = of_genpd_get_from_provider(&args);
+ if (IS_ERR(child_domain))
+ continue;
+
+ if (of_parse_phandle_with_args(np, "power-domains",
+ "#power-domain-cells", 0, &args) != 0)
+ continue;
+
+ parent_domain = of_genpd_get_from_provider(&args);
+ if (IS_ERR(parent_domain))
+ continue;
+
+ if (pm_genpd_add_subdomain(parent_domain, child_domain))
+ pr_warn("%s failed to add subdomain: %s\n",
+ parent_domain->name, child_domain->name);
+ else
+ pr_info("%s has as child subdomain: %s.\n",
+ parent_domain->name, child_domain->name);
+ }
+
+ return 0;
+}
+core_initcall(exynos4_pm_init_power_domain);