summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHyungwon Hwang <human.hwang@samsung.com>2014-12-11 07:47:30 (GMT)
committerHyungwon Hwang <human.hwang@samsung.com>2014-12-23 02:09:28 (GMT)
commit8f212af171ccdfee5723d83d52682a8c9a308df6 (patch)
treeea747569acb304fe01716e7dd4c8dd7b47f50f8a
parentabfd8d41fec0be05c23748b8ca90572ca0d17a3c (diff)
downloadlinux-3.10-8f212af171ccdfee5723d83d52682a8c9a308df6.zip
linux-3.10-8f212af171ccdfee5723d83d52682a8c9a308df6.tar.gz
linux-3.10-8f212af171ccdfee5723d83d52682a8c9a308df6.tar.bz2
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 5364d4b..b124366 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 4c97426..44932a8 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 9a8d557..8deffeb 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));
}
}