Skip to content

Commit

Permalink
Merge tag 'power-exynos' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/kgene/linux-samsung into next/soc

Merge "Samsung power management related updates for v3.17" from Kukjin Kim

- support cluster power off on exynos5420 and exynos5800
  to save power.
- use PMU address via DT to remove PMU static mapping
- remove exynos_cpuidle_init() and exynos_cpufreq_init()

* Note that this is including tags/samsung-cleanup and
tags/exynos-cpuidle are already merged into arm-soc.

* tag 'power-exynos' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
  ARM: EXYNOS: Move cpufreq and cpuidle device registration to init_machine
  ARM: EXYNOS: Refactored code for using PMU address via DT
  ARM: EXYNOS: Support cluster power off on exynos5420/5800

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Arnd Bergmann committed Jul 26, 2014
2 parents f169f40 + 6887d9e commit 8e5655c
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 388 deletions.
14 changes: 12 additions & 2 deletions arch/arm/mach-exynos/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ extern void exynos_cpu_die(unsigned int cpu);

/* PMU(Power Management Unit) support */

#define PMU_TABLE_END NULL
#define PMU_TABLE_END (-1U)

enum sys_powerdown {
SYS_AFTR,
Expand All @@ -144,7 +144,7 @@ enum sys_powerdown {
};

struct exynos_pmu_conf {
void __iomem *reg;
unsigned int offset;
unsigned int val[NUM_SYS_POWERDOWN];
};

Expand All @@ -160,4 +160,14 @@ extern void exynos_enter_aftr(void);
extern void s5p_init_cpu(void __iomem *cpuid_addr);
extern unsigned int samsung_rev(void);

static inline void pmu_raw_writel(u32 val, u32 offset)
{
__raw_writel(val, pmu_base_addr + offset);
}

static inline u32 pmu_raw_readl(u32 offset)
{
return __raw_readl(pmu_base_addr + offset);
}

#endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
30 changes: 5 additions & 25 deletions arch/arm/mach-exynos/exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ static struct map_desc exynos4_iodesc[] __initdata = {
.pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_PMU,
.pfn = __phys_to_pfn(EXYNOS4_PA_PMU),
.length = SZ_64K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_COMBINER_BASE,
.pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER),
Expand Down Expand Up @@ -139,19 +134,14 @@ static struct map_desc exynos5_iodesc[] __initdata = {
.pfn = __phys_to_pfn(EXYNOS5_PA_CMU),
.length = 144 * SZ_1K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_PMU,
.pfn = __phys_to_pfn(EXYNOS5_PA_PMU),
.length = SZ_64K,
.type = MT_DEVICE,
},
};

static void exynos_restart(enum reboot_mode mode, const char *cmd)
{
struct device_node *np;
u32 val = 0x1;
void __iomem *addr = EXYNOS_SWRESET;
void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET;

if (of_machine_is_compatible("samsung,exynos5440")) {
u32 status;
Expand All @@ -175,17 +165,6 @@ static struct platform_device exynos_cpuidle = {
.id = -1,
};

void __init exynos_cpuidle_init(void)
{
if (soc_is_exynos4210() || soc_is_exynos5250())
platform_device_register(&exynos_cpuidle);
}

void __init exynos_cpufreq_init(void)
{
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
}

void __iomem *sysram_base_addr;
void __iomem *sysram_ns_base_addr;

Expand Down Expand Up @@ -335,10 +314,11 @@ static void __init exynos_dt_machine_init(void)
if (!IS_ENABLED(CONFIG_SMP))
exynos_sysram_init();

if (!of_machine_is_compatible("samsung,exynos5420"))
exynos_cpuidle_init();
if (of_machine_is_compatible("samsung,exynos4210") ||
of_machine_is_compatible("samsung,exynos5250"))
platform_device_register(&exynos_cpuidle);

exynos_cpufreq_init();
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);

of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
Expand Down
3 changes: 0 additions & 3 deletions arch/arm/mach-exynos/include/mach/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@
#define EXYNOS4_PA_SYSCON 0x10010000
#define EXYNOS5_PA_SYSCON 0x10050100

#define EXYNOS4_PA_PMU 0x10020000
#define EXYNOS5_PA_PMU 0x10040000

#define EXYNOS4_PA_CMU 0x10030000
#define EXYNOS5_PA_CMU 0x10010000

Expand Down
70 changes: 33 additions & 37 deletions arch/arm/mach-exynos/mcpm-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#define EXYNOS5420_CPUS_PER_CLUSTER 4
#define EXYNOS5420_NR_CLUSTERS 2

#define EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN BIT(9)
#define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29)
#define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30)

/*
* The common v7_exit_coherency_flush API could not be used because of the
* Erratum 799270 workaround. This macro is the same as the common one (in
Expand All @@ -51,7 +55,7 @@
"dsb\n\t" \
"ldmfd sp!, {fp, ip}" \
: \
: "Ir" (S5P_INFORM0) \
: "Ir" (pmu_base_addr + S5P_INFORM0) \
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
"r9", "r10", "lr", "memory")

Expand All @@ -73,36 +77,9 @@ cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];

#define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster)

static int exynos_cluster_power_control(unsigned int cluster, int enable)
{
unsigned int tries = 100;
unsigned int val;

if (enable) {
exynos_cluster_power_up(cluster);
val = S5P_CORE_LOCAL_PWR_EN;
} else {
exynos_cluster_power_down(cluster);
val = 0;
}

/* Wait until cluster power control is applied */
while (tries--) {
if (exynos_cluster_power_state(cluster) == val)
return 0;

cpu_relax();
}
pr_debug("timed out waiting for cluster %u to power %s\n", cluster,
enable ? "on" : "off");

return -ETIMEDOUT;
}

static int exynos_power_up(unsigned int cpu, unsigned int cluster)
{
unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
int err = 0;

pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
Expand All @@ -126,12 +103,9 @@ static int exynos_power_up(unsigned int cpu, unsigned int cluster)
* cores.
*/
if (was_cluster_down)
err = exynos_cluster_power_control(cluster, 1);
exynos_cluster_power_up(cluster);

if (!err)
exynos_cpu_power_up(cpunr);
else
exynos_cluster_power_control(cluster, 0);
exynos_cpu_power_up(cpunr);
} else if (cpu_use_count[cpu][cluster] != 2) {
/*
* The only possible values are:
Expand All @@ -147,7 +121,7 @@ static int exynos_power_up(unsigned int cpu, unsigned int cluster)
arch_spin_unlock(&exynos_mcpm_lock);
local_irq_enable();

return err;
return 0;
}

/*
Expand Down Expand Up @@ -178,9 +152,10 @@ static void exynos_power_down(void)
if (cpu_use_count[cpu][cluster] == 0) {
exynos_cpu_power_down(cpunr);

if (exynos_cluster_unused(cluster))
/* TODO: Turn off the cluster here to save power. */
if (exynos_cluster_unused(cluster)) {
exynos_cluster_power_down(cluster);
last_man = true;
}
} else if (cpu_use_count[cpu][cluster] == 1) {
/*
* A power_up request went ahead of us.
Expand Down Expand Up @@ -335,6 +310,7 @@ static int __init exynos_mcpm_init(void)
{
struct device_node *node;
void __iomem *ns_sram_base_addr;
unsigned int value, i;
int ret;

node = of_find_matching_node(NULL, exynos_dt_mcpm_match);
Expand All @@ -361,7 +337,7 @@ static int __init exynos_mcpm_init(void)
* To increase the stability of KFC reset we need to program
* the PMU SPARE3 register
*/
__raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
pmu_raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);

exynos_mcpm_usage_count_init();

Expand All @@ -377,6 +353,26 @@ static int __init exynos_mcpm_init(void)

pr_info("Exynos MCPM support installed\n");

/*
* On Exynos5420/5800 for the A15 and A7 clusters:
*
* EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN ensures that all the cores
* in a cluster are turned off before turning off the cluster L2.
*
* EXYNOS5420_USE_ARM_CORE_DOWN_STATE ensures that a cores is powered
* off before waking it up.
*
* EXYNOS5420_USE_L2_COMMON_UP_STATE ensures that cluster L2 will be
* turned on before the first man is powered up.
*/
for (i = 0; i < EXYNOS5420_NR_CLUSTERS; i++) {
value = pmu_raw_readl(EXYNOS_COMMON_OPTION(i));
value |= EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN |
EXYNOS5420_USE_ARM_CORE_DOWN_STATE |
EXYNOS5420_USE_L2_COMMON_UP_STATE;
pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
}

/*
* U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
* as part of secondary_cpu_start(). Let's redirect it to the
Expand Down
4 changes: 3 additions & 1 deletion arch/arm/mach-exynos/platsmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include <asm/smp_scu.h>
#include <asm/firmware.h>

#include <mach/map.h>

#include "common.h"
#include "regs-pmu.h"

Expand All @@ -34,7 +36,7 @@ extern void exynos4_secondary_startup(void);
static inline void __iomem *cpu_boot_reg_base(void)
{
if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1)
return S5P_INFORM5;
return pmu_base_addr + S5P_INFORM5;
return sysram_base_addr;
}

Expand Down
Loading

0 comments on commit 8e5655c

Please sign in to comment.