From 119fc9b4ac190e17cd53d280c68241cf975a4bcc Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 22 Apr 2015 22:23:50 +0900 Subject: [PATCH] soc: samsung: Add the support of power domain for Exynos SoC This patch moves the power domain driver of Exynos SoC to support both 32-bit Exynos and 64-bit Exynos. Signed-off-by: Chanwoo Choi --- arch/arm/mach-exynos/Makefile | 1 - drivers/soc/samsung/Makefile | 1 + .../soc/samsung}/pm_domains.c | 75 ++++++++++------------ 3 files changed, 36 insertions(+), 41 deletions(-) rename {arch/arm/mach-exynos => drivers/soc/samsung}/pm_domains.c (76%) diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index bcefb54..d5fafa9 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o obj-$(CONFIG_PM_SLEEP) += suspend.o -obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index acaae9f..65da306 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o obj-$(CONFIG_EXYNOS5433_PMU) += exynos5433-pmu.o obj-$(CONFIG_EXYNOS_PM) += exynos-pm.o obj-$(CONFIG_EXYNOS5433_PM) += exynos5433-pm.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o diff --git a/arch/arm/mach-exynos/pm_domains.c b/drivers/soc/samsung/pm_domains.c similarity index 76% rename from arch/arm/mach-exynos/pm_domains.c rename to drivers/soc/samsung/pm_domains.c index 6864178..623c422 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -23,21 +23,22 @@ #include #include -#define INT_LOCAL_PWR_EN 0x7 -#define MAX_CLK_PER_DOMAIN 4 +#define INT_LOCAL_PWR_EN 0xF /* * Exynos specific wrapper around the generic power domain */ struct exynos_pm_domain { + struct generic_pm_domain pd; void __iomem *base; char const *name; bool is_off; - struct generic_pm_domain pd; + int nr_reparent_clks; 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]; + struct clk **clk; + struct clk **pclk; + int nr_asb_clks; + struct clk **asb_clk; }; static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) @@ -51,7 +52,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) pd = container_of(domain, struct exynos_pm_domain, pd); base = pd->base; - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { + for (i = 0; i < pd->nr_asb_clks; i++) { if (IS_ERR(pd->asb_clk[i])) break; clk_prepare_enable(pd->asb_clk[i]); @@ -59,7 +60,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) /* Set oscclk before powering off a domain*/ if (!power_on) { - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { + for (i = 0; i < pd->nr_reparent_clks; i++) { if (IS_ERR(pd->clk[i])) break; if (clk_set_parent(pd->clk[i], pd->oscclk)) @@ -72,7 +73,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) __raw_writel(pwr, base); /* Wait max 1ms */ - timeout = 10; + timeout = 100; while ((__raw_readl(base + 0x4) & INT_LOCAL_PWR_EN) != pwr) { if (!timeout) { @@ -87,7 +88,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) /* Restore clocks after powering on a domain*/ if (power_on) { - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { + for (i = 0; i < pd->nr_reparent_clks; i++) { if (IS_ERR(pd->clk[i])) break; if (clk_set_parent(pd->clk[i], pd->pclk[i])) @@ -96,7 +97,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) } } - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { + for (i = 0; i < pd->nr_asb_clks; i++) { if (IS_ERR(pd->asb_clk[i])) break; clk_disable_unprepare(pd->asb_clk[i]); @@ -118,6 +119,7 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) static __init int exynos4_pm_init_power_domain(void) { struct device_node *np; + int nr_clks; for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { struct exynos_pm_domain *pd; @@ -130,46 +132,39 @@ static __init int exynos4_pm_init_power_domain(void) return -ENOMEM; } - pd->pd.name = kstrdup_const(strrchr(np->full_name, '/') + 1, - GFP_KERNEL); + pd->pd.name = kstrdup(np->name, GFP_KERNEL); pd->name = pd->pd.name; pd->base = of_iomap(np, 0); pd->pd.power_off = exynos_pd_power_off; pd->pd.power_on = exynos_pd_power_on; - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - char clk_name[8]; + nr_clks = of_count_phandle_with_args(np, "clocks","#clock-cells"); + if (nr_clks > 0 && !(nr_clks % 2)) { + nr_clks /= 2; - 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])) + pd->oscclk = clk_get(NULL, "xxti"); + if (IS_ERR(pd->oscclk)) 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; - snprintf(clk_name, sizeof(clk_name), "pclk%d", i); - pd->pclk[i] = of_clk_get_by_name(np, clk_name); - if (IS_ERR(pd->pclk[i])) { - clk_put(pd->clk[i]); - pd->clk[i] = ERR_PTR(-EINVAL); - break; + pd->clk = kcalloc(sizeof(struct clk *), + nr_clks, GFP_KERNEL); + pd->pclk = kcalloc(sizeof(struct clk *), + nr_clks, GFP_KERNEL); + for (i = 0; i < nr_clks; i++) { + pd->clk[i] = of_clk_get(np, i); + if (IS_ERR(pd->clk[i])) + break; + pd->pclk[i] = of_clk_get(np, i + 1); + if (IS_ERR(pd->pclk[i])) { + clk_put(pd->clk[i]); + pd->clk[i] = ERR_PTR(-EINVAL); + break; + } } - } - if (IS_ERR(pd->clk[0])) - clk_put(pd->oscclk); + pd->nr_reparent_clks = nr_clks; + } -no_clk: on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN; pm_genpd_init(&pd->pd, NULL, !on); -- 2.7.4