summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHyungwon Hwang <human.hwang@samsung.com>2014-12-11 16:47:30 +0900
committerHyungwon Hwang <human.hwang@samsung.com>2014-12-24 11:20:19 +0900
commitc25aae8a02c0e3132df581d1d12be1d6738a08d6 (patch)
tree849e5fe850909bbfd55bb7beb028e79915bac129
parent996ac4b387722b1c9214a33bc424f793c30dd67f (diff)
downloadlinux-3.10-c25aae8a02c0e3132df581d1d12be1d6738a08d6.tar.gz
linux-3.10-c25aae8a02c0e3132df581d1d12be1d6738a08d6.tar.bz2
linux-3.10-c25aae8a02c0e3132df581d1d12be1d6738a08d6.zip
ARM: exynos: add support secondary core bootup in big.LITTLE processor.
This patch adds support secondary core bootup in big.LITTLE processor for platsmp. Just core id cannot be used for identification, because there is a pair of the cores which have same core id. Cluster id have to be included for their identification. This patch makes cpu index using cluster id and core id for the calculation of their register address and the identification. But there is a problem to use cluster id for core index creation. That is, cluster id does not start from 0 in old processors which do not have more than one cluster. For example, Exynos4412's cluster id for its 4 core is 0xa. So I makes all cluster id to 0 when they are bigger than 1. Normally big.LITTLE processor does not use platsmp. But at this moment, just for the minimal functionality of big.LITTLE, this patch adds support for it. This patch can be reverted after another CPU management method is adopted. Change-Id: Ifa2d62545dd4174998f962c9608fd6d9b6034c16 Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
-rw-r--r--arch/arm/mach-exynos/headsmp.S2
-rw-r--r--arch/arm/mach-exynos/hotplug.c7
-rw-r--r--arch/arm/mach-exynos/platsmp.c32
3 files changed, 26 insertions, 15 deletions
diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S
index 5364d4bfa8b..b1243664999 100644
--- a/arch/arm/mach-exynos/headsmp.S
+++ b/arch/arm/mach-exynos/headsmp.S
@@ -22,7 +22,7 @@
*/
ENTRY(exynos4_secondary_startup)
mrc p15, 0, r0, c0, c0, 5
- and r0, r0, #15
+ and r0, r0, #0xFFFFFF
adr r4, 1f
ldmia r4, {r5, r6}
sub r4, r4, r5
diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c
index 4c974267852..44932a8ae7b 100644
--- a/arch/arm/mach-exynos/hotplug.c
+++ b/arch/arm/mach-exynos/hotplug.c
@@ -94,10 +94,13 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
{
u32 mpidr = cpu_logical_map(cpu);
u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ u32 cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ cluster_id = cluster_id > 1 ? 0 : cluster_id;
+ u32 cpu_idx = (cluster_id * 4) + core_id;
for (;;) {
/* Turn the CPU off on next WFI instruction. */
- exynos_cpu_power_down(core_id);
+ exynos_cpu_power_down(cpu_idx);
/*
* here's the WFI
@@ -107,7 +110,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
:
: "memory", "cc");
- if (pen_release == core_id) {
+ if (pen_release == cpu_idx) {
/*
* OK, proper wakeup, we're done
*/
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 9a8d557054c..8deffebd3f5 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -95,6 +95,9 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct
unsigned long timeout;
u32 mpidr = cpu_logical_map(cpu);
u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ u32 cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ cluster_id = cluster_id > 1 ? 0 : cluster_id;
+ u32 cpu_idx = (cluster_id * 4) + core_id;
/*
* Set synchronisation state between this boot processor
@@ -110,21 +113,21 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct
* Note that "pen_release" is the hardware CPU core ID, whereas
* "cpu" is Linux's internal ID.
*/
- write_pen_release(core_id);
+ write_pen_release(mpidr);
- if (!(__raw_readl(S5P_ARM_CORE_STATUS(core_id))
+ if (!(__raw_readl(S5P_ARM_CORE_STATUS(cpu_idx))
& S5P_CORE_LOCAL_PWR_EN)) {
u32 core_conf = 0;
core_conf |= S5P_CORE_LOCAL_PWR_EN;
if (soc_is_exynos3250())
core_conf |= S5P_CORE_AUTOWAKEUP_EN;
- __raw_writel(core_conf, S5P_ARM_CORE_CONFIGURATION(core_id));
+ __raw_writel(core_conf, S5P_ARM_CORE_CONFIGURATION(cpu_idx));
timeout = 10;
/* wait max 10 ms until cpu1 is on */
- while ((__raw_readl(S5P_ARM_CORE_STATUS(core_id))
+ while ((__raw_readl(S5P_ARM_CORE_STATUS(cpu_idx))
& S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
if (timeout-- == 0)
break;
@@ -148,13 +151,13 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct
udelay(10);
udelay(10);
- tmp = __raw_readl(S5P_ARM_CORE_STATUS(core_id));
+ tmp = __raw_readl(S5P_ARM_CORE_STATUS(cpu_idx));
tmp |= (S5P_CORE_LOCAL_PWR_EN << 8);
- __raw_writel(tmp, S5P_ARM_CORE_STATUS(core_id));
+ __raw_writel(tmp, S5P_ARM_CORE_STATUS(cpu_idx));
}
if (soc_is_exynos3250())
- __raw_writel(EXYNOS3_COREPORESET(core_id), EXYNOS_SWRESET);
+ __raw_writel(EXYNOS3_COREPORESET(cpu_idx), EXYNOS_SWRESET);
/*
* Send the secondary CPU a soft interrupt, thereby causing
@@ -174,10 +177,10 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct
* Try to set boot address using firmware first
* and fall back to boot register if it fails.
*/
- if (call_firmware_op(set_cpu_boot_addr, core_id, boot_addr))
- __raw_writel(boot_addr, cpu_boot_reg(core_id));
+ if (call_firmware_op(set_cpu_boot_addr, cpu_idx, boot_addr))
+ __raw_writel(boot_addr, cpu_boot_reg(cpu_idx));
- call_firmware_op(cpu_boot, core_id);
+ call_firmware_op(cpu_boot, cpu_idx);
if (soc_is_exynos3250())
dsb_sev();
@@ -245,13 +248,18 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
unsigned long boot_addr;
u32 mpidr;
u32 core_id;
+ u32 cluster_id;
+ u32 cpu_idx;
mpidr = cpu_logical_map(i);
core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ cluster_id = cluster_id > 1 ? 0 : cluster_id;
+ cpu_idx = (cluster_id * 4) + core_id;
boot_addr = virt_to_phys(exynos4_secondary_startup);
- if (call_firmware_op(set_cpu_boot_addr, core_id, boot_addr))
- __raw_writel(boot_addr, cpu_boot_reg(core_id));
+ if (call_firmware_op(set_cpu_boot_addr, cpu_idx, boot_addr))
+ __raw_writel(boot_addr, cpu_boot_reg(cpu_idx));
}
}