diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index e65aa7d11b20..58b334f5f1d6 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -19,6 +19,7 @@ menuconfig ARCH_EXYNOS select EXYNOS_THERMAL select EXYNOS_PMU select EXYNOS_SROM + select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS select HAVE_ARM_SCU if SMP select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 34d29df3e006..838249d4ff5c 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.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/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/arch/arm/mach-exynos/pm_domains.c b/drivers/soc/samsung/pm_domains.c similarity index 85% rename from arch/arm/mach-exynos/pm_domains.c rename to drivers/soc/samsung/pm_domains.c index 875a2bab64f6..f60515eefb66 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -23,9 +23,13 @@ #include #include -#define INT_LOCAL_PWR_EN 0x7 #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 */ @@ -38,6 +42,7 @@ struct exynos_pm_domain { 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) @@ -69,13 +74,13 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) } } - pwr = power_on ? INT_LOCAL_PWR_EN : 0; + pwr = power_on ? pd->local_pwr_cfg : 0; __raw_writel(pwr, base); /* Wait max 1ms */ timeout = 10; - while ((__raw_readl(base + 0x4) & INT_LOCAL_PWR_EN) != pwr) { + 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); @@ -119,14 +124,30 @@ 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_compatible_node(np, NULL, "samsung,exynos4210-pd") { + 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", @@ -153,6 +174,7 @@ static __init int exynos4_pm_init_power_domain(void) 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]; @@ -185,14 +207,14 @@ static __init int exynos4_pm_init_power_domain(void) clk_put(pd->oscclk); no_clk: - on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN; + 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_compatible_node(np, NULL, "samsung,exynos4210-pd") { + for_each_matching_node(np, exynos_pm_domain_of_match) { struct generic_pm_domain *child_domain, *parent_domain; struct of_phandle_args args;