diff options
Diffstat (limited to 'arch/arm/mach-rockchip')
-rw-r--r-- | arch/arm/mach-rockchip/platsmp.c | 104 |
1 files changed, 78 insertions, 26 deletions
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 189684f..4c36fbf 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -19,6 +19,8 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> #include <asm/cacheflush.h> #include <asm/cp15.h> @@ -37,23 +39,42 @@ static int ncores; #define PMU_PWRDN_SCU 4 -static void __iomem *pmu_base_addr; +static struct regmap *pmu; -static inline bool pmu_power_domain_is_on(int pd) +static int pmu_power_domain_is_on(int pd) { - return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd)); + u32 val; + int ret; + + ret = regmap_read(pmu, PMU_PWRDN_ST, &val); + if (ret < 0) + return ret; + + return !(val & BIT(pd)); } -static void pmu_set_power_domain(int pd, bool on) +static int pmu_set_power_domain(int pd, bool on) { - u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON); - if (on) - val &= ~BIT(pd); - else - val |= BIT(pd); - writel(val, pmu_base_addr + PMU_PWRDN_CON); - - while (pmu_power_domain_is_on(pd) != on) { } + u32 val = (on) ? 0 : BIT(pd); + int ret; + + ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); + if (ret < 0) { + pr_err("%s: could not update power domain\n", __func__); + return ret; + } + + ret = -1; + while (ret != on) { + ret = pmu_power_domain_is_on(pd); + if (ret < 0) { + pr_err("%s: could not read power domain state\n", + __func__); + return ret; + } + } + + return 0; } /* @@ -63,7 +84,7 @@ static void pmu_set_power_domain(int pd, bool on) static int __cpuinit rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle) { - if (!sram_base_addr || !pmu_base_addr) { + if (!sram_base_addr || !pmu) { pr_err("%s: sram or pmu missing for cpu boot\n", __func__); return -ENXIO; } @@ -75,9 +96,7 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, } /* start the core */ - pmu_set_power_domain(0 + cpu, true); - - return 0; + return pmu_set_power_domain(0 + cpu, true); } /** @@ -125,6 +144,48 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) return 0; } +static struct regmap_config rockchip_pmu_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int __init rockchip_smp_prepare_pmu(void) +{ + struct device_node *node; + void __iomem *pmu_base; + + pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu"); + if (!IS_ERR(pmu)) + return 0; + + /* fallback, create our own regmap for the pmu area */ + pmu = NULL; + node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); + if (!node) { + pr_err("%s: could not find pmu dt node\n", __func__); + return -ENODEV; + } + + pmu_base = of_iomap(node, 0); + if (!pmu_base) { + pr_err("%s: could not map pmu registers\n", __func__); + return -ENOMEM; + } + + pmu = regmap_init_mmio(NULL, pmu_base, &rockchip_pmu_regmap_config); + if (IS_ERR(pmu)) { + int ret = PTR_ERR(pmu); + + iounmap(pmu_base); + pmu = NULL; + pr_err("%s: regmap init failed\n", __func__); + return ret; + } + + return 0; +} + static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) { struct device_node *node; @@ -151,17 +212,8 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) if (rockchip_smp_prepare_sram(node)) return; - node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); - if (!node) { - pr_err("%s: could not find pmu dt node\n", __func__); + if (rockchip_smp_prepare_pmu()) return; - } - - pmu_base_addr = of_iomap(node, 0); - if (!pmu_base_addr) { - pr_err("%s: could not map pmu registers\n", __func__); - return; - } /* enable the SCU power domain */ pmu_set_power_domain(PMU_PWRDN_SCU, true); |