diff options
author | Haojian Zhuang <haojian.zhuang@linaro.org> | 2014-08-07 20:32:58 +0800 |
---|---|---|
committer | Haojian Zhuang <haojian.zhuang@linaro.org> | 2014-08-12 10:29:18 +0800 |
commit | e17111dba3e95c258b6c40e39d33e54484b6b457 (patch) | |
tree | 11fb5c57ebd23a833cd500d0801ecaa1d6095199 | |
parent | 730ca5bddfcdb1018a18c287341a778a69bc8ac0 (diff) |
ARM: hisi: fix hotplug issuetesting/hotplug-0812
1. fix hotplug issue.
2. move bootwrapper param into new node.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
-rw-r--r-- | arch/arm/boot/dts/hip04.dtsi | 10 | ||||
-rw-r--r-- | arch/arm/mach-hisi/platmcpm.c | 253 |
2 files changed, 164 insertions, 99 deletions
diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi index e140c0ffd449..3887d9b6f916 100644 --- a/arch/arm/boot/dts/hip04.dtsi +++ b/arch/arm/boot/dts/hip04.dtsi @@ -20,6 +20,11 @@ serial0 = &uart0; }; + bootwrapper { + compatible = "hisilicon,hip04-bootwrapper"; + boot-method = <0x10c00000 0x10000>, <0xe0000100 0x1000>; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -208,11 +213,6 @@ sysctrl: sysctrl { compatible = "hisilicon,sysctrl"; reg = <0x3e00000 0x00100000>; - relocation-entry = <0xe0000100>; - relocation-size = <0x1000>; - bootwrapper-phys = <0x10c00000>; - bootwrapper-size = <0x10000>; - bootwrapper-magic = <0xa5a5a5a5>; }; fabric: fabric { diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c index 2bda12b936f9..ceeb913f9581 100644 --- a/arch/arm/mach-hisi/platmcpm.c +++ b/arch/arm/mach-hisi/platmcpm.c @@ -8,6 +8,7 @@ */ #include <linux/delay.h> #include <linux/io.h> +#include <linux/memblock.h> #include <linux/of_address.h> #include <asm/cputype.h> @@ -52,22 +53,21 @@ #define HIP04_MAX_CPUS_PER_CLUSTER 4 #define POLL_MSEC 10 -#define TIMEOUT_MSEC 1000 - -struct hip04_secondary_cpu_data { - u32 bootwrapper_phys; - u32 bootwrapper_size; - u32 bootwrapper_magic; - u32 relocation_entry; - u32 relocation_size; -}; +#define TIMEOUT_MSEC 100 -static void __iomem *relocation, *sysctrl, *fabric; +static void __iomem *sysctrl, *fabric; static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER]; static DEFINE_SPINLOCK(boot_lock); -static struct hip04_secondary_cpu_data hip04_boot; +static u32 fabric_phys_addr; +/* + * [0]: bootwrapper physical address + * [1]: bootwrapper size + * [2]: relocation address + * [3]: relocation size + */ +static u32 hip04_boot_method[4]; -static bool hip04_cluster_down(unsigned int cluster) +static bool hip04_cluster_is_down(unsigned int cluster) { int i; @@ -93,46 +93,45 @@ static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on) if (data == readl_relaxed(fabric + FAB_SF_MODE)) break; } + return; } static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) { unsigned long data, mask; + void __iomem *sys_dreq, *sys_status; - if (!relocation || !sysctrl) + if (!sysctrl) return -ENODEV; if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER) return -EINVAL; spin_lock_irq(&boot_lock); - if (hip04_cpu_table[cluster][cpu]) { - hip04_cpu_table[cluster][cpu]++; - spin_unlock_irq(&boot_lock); - return 0; - } + if (hip04_cpu_table[cluster][cpu]) + goto out; - writel_relaxed(hip04_boot.bootwrapper_phys, relocation); - writel_relaxed(hip04_boot.bootwrapper_magic, relocation + 4); - writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8); - writel_relaxed(0, relocation + 12); - - if (hip04_cluster_down(cluster)) { + sys_dreq = sysctrl + SC_CPU_RESET_DREQ(cluster); + sys_status = sysctrl + SC_CPU_RESET_STATUS(cluster); + if (hip04_cluster_is_down(cluster)) { data = CLUSTER_DEBUG_RESET_BIT; - writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster)); + writel_relaxed(data, sys_dreq); do { + cpu_relax(); mask = CLUSTER_DEBUG_RESET_STATUS; - data = readl_relaxed(sysctrl + \ - SC_CPU_RESET_STATUS(cluster)); + data = readl_relaxed(sys_status); } while (data & mask); - hip04_set_snoop_filter(cluster, 1); } - hip04_cpu_table[cluster][cpu]++; - data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \ CORE_DEBUG_RESET_BIT(cpu); - writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster)); + writel_relaxed(data, sys_dreq); + do { + cpu_relax(); + } while (data == readl_relaxed(sys_status)); + udelay(20); +out: + hip04_cpu_table[cluster][cpu]++; spin_unlock_irq(&boot_lock); return 0; @@ -140,8 +139,8 @@ static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) static void hip04_mcpm_power_down(void) { - unsigned int mpidr, cpu, cluster, data = 0; - bool skip_reset = false; + unsigned int mpidr, cpu, cluster; + bool skip_wfi = false, last_man = false; mpidr = read_cpuid_mpidr(); cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); @@ -149,59 +148,122 @@ static void hip04_mcpm_power_down(void) __mcpm_cpu_going_down(cpu, cluster); - spin_lock(&boot_lock); + spin_lock_irq(&boot_lock); BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); hip04_cpu_table[cluster][cpu]--; if (hip04_cpu_table[cluster][cpu] == 1) { /* A power_up request went ahead of us. */ - skip_reset = true; + skip_wfi = true; } else if (hip04_cpu_table[cluster][cpu] > 1) { pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu); BUG(); } - spin_unlock(&boot_lock); - v7_exit_coherency_flush(louis); + last_man = hip04_cluster_is_down(cluster); + if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) { + spin_unlock(&boot_lock); + v7_exit_coherency_flush(all); + __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); + } else { + spin_unlock(&boot_lock); + v7_exit_coherency_flush(louis); + } __mcpm_cpu_down(cpu, cluster); - if (!skip_reset) { - data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \ - CORE_DEBUG_RESET_BIT(cpu); - writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster)); - } + if (!skip_wfi) + wfi(); } static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) { - unsigned int data, tries; + unsigned int data, tries, count; BUG_ON(cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER); - for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; tries++) { + count = TIMEOUT_MSEC / POLL_MSEC; + spin_lock_irq(&boot_lock); + for (tries = 0; tries < count; tries++) { + cpu_relax(); + udelay(50); data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster)); - if (!(data & CORE_RESET_STATUS(cpu))) { - msleep(POLL_MSEC); - continue; + if (!hip04_cpu_table[cluster][cpu] || \ + (data & CORE_WFI_STATUS(cpu))) { + break; } - return 0; } + if (tries >= count) + goto err; + data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \ + CORE_DEBUG_RESET_BIT(cpu); + writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster)); + for (tries = 0; tries < count; tries++) { + cpu_relax(); + udelay(50); + data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster)); + if (!hip04_cpu_table[cluster][cpu] || \ + (data & CORE_RESET_STATUS(cpu))) { + break; + } + } + if (tries >= count) + goto err; + if (hip04_cluster_is_down(cluster)) + hip04_set_snoop_filter(cluster, 0); + spin_unlock_irq(&boot_lock); + return 0; +err: + spin_unlock_irq(&boot_lock); return -ETIMEDOUT; } static void hip04_mcpm_powered_up(void) { - if (!relocation) - return; + unsigned int mpidr, cpu, cluster; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + spin_lock(&boot_lock); - writel_relaxed(0, relocation); - writel_relaxed(0, relocation + 4); - writel_relaxed(0, relocation + 8); - writel_relaxed(0, relocation + 12); + if (!hip04_cpu_table[cluster][cpu]) + hip04_cpu_table[cluster][cpu] = 1; spin_unlock(&boot_lock); } +static void __naked hip04_mcpm_power_up_setup(unsigned int affinity_level) +{ + asm volatile (" \n" +" cmp r0, #0 \n" +" bxeq lr \n" + /* calculate fabric phys address */ +" adr r2, 2f \n" +" ldmia r2, {r1, r3} \n" +" sub r0, r2, r1 \n" +" ldr r2, [r0, r3] \n" + /* get cluster id from MPIDR */ +" mrc p15, 0, r0, c0, c0, 5 \n" +" ubfx r1, r0, #8, #8 \n" + /* 1 << cluster id */ +" mov r0, #1 \n" +" mov r3, r0, lsl r1 \n" +" ldr r0, [r2, #"__stringify(FAB_SF_MODE)"] \n" +" tst r0, r3 \n" +" bxne lr \n" +" orr r1, r0, r3 \n" +" str r1, [r2, #"__stringify(FAB_SF_MODE)"] \n" +"1: ldr r0, [r2, #"__stringify(FAB_SF_MODE)"] \n" +" tst r0, r3 \n" +" beq 1b \n" +" bx lr \n" + +" .align 2 \n" +"2: .word . \n" +" .word fabric_phys_addr \n" + ); +} + static const struct mcpm_platform_ops hip04_mcpm_ops = { .power_up = hip04_mcpm_power_up, .power_down = hip04_mcpm_power_down, @@ -229,60 +291,48 @@ static bool __init hip04_cpu_table_init(void) static int __init hip04_mcpm_init(void) { - struct device_node *np, *np_fab; + struct device_node *np, *np_sctl, *np_fab; + struct resource fab_res; + void __iomem *relocation; int ret = -ENODEV; - np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); + np = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-bootwrapper"); if (!np) goto err; + ret = of_property_read_u32_array(np, "boot-method", + &hip04_boot_method[0], 4); + if (ret) + goto err; + np_sctl = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); + if (!np_sctl) + goto err; np_fab = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-fabric"); if (!np_fab) goto err; - if (of_property_read_u32(np, "bootwrapper-phys", - &hip04_boot.bootwrapper_phys)) { - pr_err("failed to get bootwrapper-phys\n"); - ret = -EINVAL; + ret = memblock_reserve(hip04_boot_method[0], hip04_boot_method[1]); + if (ret) goto err; - } - if (of_property_read_u32(np, "bootwrapper-size", - &hip04_boot.bootwrapper_size)) { - pr_err("failed to get bootwrapper-size\n"); - ret = -EINVAL; - goto err; - } - if (of_property_read_u32(np, "bootwrapper-magic", - &hip04_boot.bootwrapper_magic)) { - pr_err("failed to get bootwrapper-magic\n"); - ret = -EINVAL; - goto err; - } - if (of_property_read_u32(np, "relocation-entry", - &hip04_boot.relocation_entry)) { - pr_err("failed to get relocation-entry\n"); - ret = -EINVAL; - goto err; - } - if (of_property_read_u32(np, "relocation-size", - &hip04_boot.relocation_size)) { - pr_err("failed to get relocation-size\n"); - ret = -EINVAL; - goto err; - } - relocation = ioremap(hip04_boot.relocation_entry, - hip04_boot.relocation_size); + relocation = ioremap(hip04_boot_method[2], hip04_boot_method[3]); if (!relocation) { pr_err("failed to map relocation space\n"); ret = -ENOMEM; - goto err; + goto err_reloc; } - sysctrl = of_iomap(np, 0); + sysctrl = of_iomap(np_sctl, 0); if (!sysctrl) { pr_err("failed to get sysctrl base\n"); ret = -ENOMEM; goto err_sysctrl; } + ret = of_address_to_resource(np_fab, 0, &fab_res); + if (ret) { + pr_err("failed to get fabric base phys\n"); + goto err_fabric; + } + fabric_phys_addr = fab_res.start; + sync_cache_w(&fabric_phys_addr); fabric = of_iomap(np_fab, 0); if (!fabric) { pr_err("failed to get fabric base\n"); @@ -290,19 +340,34 @@ static int __init hip04_mcpm_init(void) goto err_fabric; } - if (!hip04_cpu_table_init()) - return -EINVAL; + if (!hip04_cpu_table_init()) { + ret = -EINVAL; + goto err_table; + } ret = mcpm_platform_register(&hip04_mcpm_ops); - if (!ret) { - mcpm_sync_init(NULL); - pr_info("HiP04 MCPM initialized\n"); + if (ret) { + goto err_table; } + + /* Make secondary core out of reset. */ + writel_relaxed(hip04_boot_method[0], relocation); + writel_relaxed(0xa5a5a5a5, relocation + 4); /* magic number */ + writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8); + writel_relaxed(0, relocation + 12); + iounmap(relocation); + + mcpm_sync_init(hip04_mcpm_power_up_setup); mcpm_smp_set_ops(); + pr_info("HiP04 MCPM initialized\n"); return ret; +err_table: + iounmap(fabric); err_fabric: iounmap(sysctrl); err_sysctrl: iounmap(relocation); +err_reloc: + memblock_free(hip04_boot_method[0], hip04_boot_method[1]); err: return ret; } |