Message ID | 1396339430-21084-7-git-send-email-haojian.zhuang@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Haojian Zhuang <haojian.zhuang@linaro.org> writes: > Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on > Cortex A15 Core. And HiP04 supports LPAE to support large memory. > > Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> [...] > diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig > index da16efd..707abfe 100644 > --- a/arch/arm/mach-hisi/Kconfig > +++ b/arch/arm/mach-hisi/Kconfig > @@ -19,6 +19,16 @@ config ARCH_HI3xxx > help > Support for Hisilicon Hi36xx/Hi37xx processor family > > +config ARCH_HIP04 > + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7 > + select ARM_LPAE Presumably this SoC can support non-LPAE also, correct? If so, LPAE should't be selected here, or else it will force LPAE on in a multi_v7 build also. Also, please run this patch through scripts/checkpatch.pl and fix the issues reported there. Kevin
On Friday 04 April 2014 07:57:36 Kevin Hilman wrote: > Haojian Zhuang <haojian.zhuang@linaro.org> writes: > > > Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on > > Cortex A15 Core. And HiP04 supports LPAE to support large memory. > > > > Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> > > [...] > > > diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig > > index da16efd..707abfe 100644 > > --- a/arch/arm/mach-hisi/Kconfig > > +++ b/arch/arm/mach-hisi/Kconfig > > @@ -19,6 +19,16 @@ config ARCH_HI3xxx > > help > > Support for Hisilicon Hi36xx/Hi37xx processor family > > > > +config ARCH_HIP04 > > + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7 > > + select ARM_LPAE > > Presumably this SoC can support non-LPAE also, correct? If so, LPAE > should't be selected here, or else it will force LPAE on in a multi_v7 > build also. Actually even if it doesn't support non-LPAE, using "select" is still wrong for the same reason. I think we should actually extend the CPU selection phase for multiplatform, so we have separate symbols for ARCH_MULTI_V7 (non-LPAE) and ARCH_MULTI_V7_LPAE. These would still be selectable at the same time, but you should only be able to turn on CONFIG_LPAE if ARCH_MULTI_V7 is disabled. A platform that cannot run without LPAE conversely would have to depend on (ARCH_MULTI_V7_LPAE && !ARCH_MULTI_V7 && !ARCH_MULTI_V6). Once it does this, it can 'select LPAE' without breaking other platforms. Arnd
On Fri, Apr 4, 2014 at 8:43 AM, Arnd Bergmann <arnd@arndb.de> wrote: > On Friday 04 April 2014 07:57:36 Kevin Hilman wrote: >> Haojian Zhuang <haojian.zhuang@linaro.org> writes: >> >> > Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on >> > Cortex A15 Core. And HiP04 supports LPAE to support large memory. >> > >> > Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> >> >> [...] >> >> > diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig >> > index da16efd..707abfe 100644 >> > --- a/arch/arm/mach-hisi/Kconfig >> > +++ b/arch/arm/mach-hisi/Kconfig >> > @@ -19,6 +19,16 @@ config ARCH_HI3xxx >> > help >> > Support for Hisilicon Hi36xx/Hi37xx processor family >> > >> > +config ARCH_HIP04 >> > + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7 >> > + select ARM_LPAE >> >> Presumably this SoC can support non-LPAE also, correct? If so, LPAE >> should't be selected here, or else it will force LPAE on in a multi_v7 >> build also. > > Actually even if it doesn't support non-LPAE, using "select" is still > wrong for the same reason. > > I think we should actually extend the CPU selection phase for multiplatform, > so we have separate symbols for ARCH_MULTI_V7 (non-LPAE) and > ARCH_MULTI_V7_LPAE. These would still be selectable at the same time, > but you should only be able to turn on CONFIG_LPAE if ARCH_MULTI_V7 > is disabled. > > A platform that cannot run without LPAE conversely would have to depend > on (ARCH_MULTI_V7_LPAE && !ARCH_MULTI_V7 && !ARCH_MULTI_V6). Once it > does this, it can 'select LPAE' without breaking other platforms. Why not just have it depend on ARCH_MULTI_V7 && LPAE? LPAE shouldn't be possible to enable if MULTI_V6 is enabled. So, you'd have: MULTI_V6 MULTI_V6 + V7 MULTI_V7 + LPAE as valid options. We'd need to annotate existing non-LPAE platforms with depends on !LPAE, but that shouldn't be a big deal. And, we should probably change the multi defconfigs to be: multi_v6_v7_defconfig which contains what v7_defconfig does today, plus the v6 platforms multi_lpae_defconfig which contains only v7+lpae platforms (and would enable kvm, etc). -Olof
On Saturday 05 April 2014 19:01:16 Olof Johansson wrote: > On Fri, Apr 4, 2014 at 8:43 AM, Arnd Bergmann <arnd@arndb.de> wrote: > > I think we should actually extend the CPU selection phase for multiplatform, > > so we have separate symbols for ARCH_MULTI_V7 (non-LPAE) and > > ARCH_MULTI_V7_LPAE. These would still be selectable at the same time, > > but you should only be able to turn on CONFIG_LPAE if ARCH_MULTI_V7 > > is disabled. > > > > A platform that cannot run without LPAE conversely would have to depend > > on (ARCH_MULTI_V7_LPAE && !ARCH_MULTI_V7 && !ARCH_MULTI_V6). Once it > > does this, it can 'select LPAE' without breaking other platforms. > > Why not just have it depend on ARCH_MULTI_V7 && LPAE? LPAE shouldn't > be possible to enable if MULTI_V6 is enabled. > > So, you'd have: > > MULTI_V6 > MULTI_V6 + V7 > MULTI_V7 + LPAE > > as valid options. > > We'd need to annotate existing non-LPAE platforms with depends on > !LPAE, but that shouldn't be a big deal. That would work, too. It really depends on how we treat global options like MMU, SMP, LPAE, SPARSEMEM, etc in combination with multiplatform kernels. At the moment we are rather inconsistent, and so far I have always thought we should have them ordered in the Kconfig menu in the same way as the dependency flow: 1. Pick a platform type (normally ARCH_MULTIPLATFORM) 2. (if ARCH_MULTIPLATFORM), pick architecture level(s): V4, V4T, V5, V6, V6K, V6K+SMP, V7, V7+LPAE, V7-M. We may decide to skip some of these. 3. Pick global features that are allowed based on 1. and 2.: MMU, SMP, LPAE, SPARSEMEM 4. (again, if MULTIPLATFORM) Pick SoC families, based on 1. and 2. 5. (if necessary) Pick boards. I'd like to keep steps 3 and 4 independent of one another, possibly doing them in the opposite order. An idea I just had was to essentially always imply compatibility to later architectures where possible, e.g. selecting v4 would always enable v4t and v5, and selecting v6k would always enable support for v6+smp, v7 and v7+lpae, but not to v6. If we do this, the matrix of possible combinations becomes much simpler, and for all I can tell we only lose the ones that are not interesting anyway. The cost of enabling support for a later architecture level is usually much lower than the cost for enabling an earlier level. The architecture level selection at that point becomes a simple 'choice' statement, rather than the complex logic I introduced for multiplatform initially. It would also simplify adding new levels for v7-m and v7-r. > And, we should probably change the multi defconfigs to be: > > multi_v6_v7_defconfig which contains what v7_defconfig does today, > plus the v6 platforms > multi_lpae_defconfig which contains only v7+lpae platforms (and would > enable kvm, etc). I like this part. Arnd
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a48712e..3f2e973 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1107,7 +1107,7 @@ source arch/arm/mm/Kconfig config ARM_NR_BANKS int - default 16 if ARCH_EP93XX + default 16 if ARCH_EP93XX || ARCH_HIP04 default 8 config IWMMXT diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig index da16efd..707abfe 100644 --- a/arch/arm/mach-hisi/Kconfig +++ b/arch/arm/mach-hisi/Kconfig @@ -19,6 +19,16 @@ config ARCH_HI3xxx help Support for Hisilicon Hi36xx/Hi37xx processor family +config ARCH_HIP04 + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7 + select ARM_LPAE + select HAVE_ARM_ARCH_TIMER + select HAVE_SMP + select MCPM + select SMP + help + Support for Hisilicon HiP04 processor family + endmenu endif diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h index af23ec2..e008c7a 100644 --- a/arch/arm/mach-hisi/core.h +++ b/arch/arm/mach-hisi/core.h @@ -12,4 +12,10 @@ extern void hi3xxx_cpu_die(unsigned int cpu); extern int hi3xxx_cpu_kill(unsigned int cpu); extern void hi3xxx_set_cpu(int cpu, bool enable); +#define HIP04_BOOTWRAPPER_PHYS 0x10c00000 +#define HIP04_BOOTWRAPPER_MAGIC 0xa5a5a5a5 +#define HIP04_BOOTWRAPPER_SIZE 0x00010000 + +extern bool __init hip04_smp_init_ops(void); + #endif diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c index 741faf3..ca277de 100644 --- a/arch/arm/mach-hisi/hisilicon.c +++ b/arch/arm/mach-hisi/hisilicon.c @@ -14,6 +14,7 @@ #include <linux/clk-provider.h> #include <linux/clocksource.h> #include <linux/irqchip.h> +#include <linux/memblock.h> #include <linux/of_address.h> #include <linux/of_platform.h> @@ -88,3 +89,19 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") .smp = smp_ops(hi3xxx_smp_ops), .restart = hi3xxx_restart, MACHINE_END + +static const char *hip04_compat[] __initconst = { + "hisilicon,hip04-d01", + NULL, +}; + +static void __init hip04_reserve(void) +{ + memblock_reserve(HIP04_BOOTWRAPPER_PHYS, HIP04_BOOTWRAPPER_SIZE); +} + +DT_MACHINE_START(HIP04, "Hisilicon HiP04 (Flattened Device Tree)") + .dt_compat = hip04_compat, + .smp_init = smp_init_ops(hip04_smp_init_ops), + .reserve = hip04_reserve, +MACHINE_END diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c index 471f1ee..a0082d7 100644 --- a/arch/arm/mach-hisi/platsmp.c +++ b/arch/arm/mach-hisi/platsmp.c @@ -9,9 +9,13 @@ */ #include <linux/smp.h> #include <linux/io.h> +#include <linux/irqchip/arm-gic.h> #include <linux/of_address.h> #include <asm/cacheflush.h> +#include <asm/cp15.h> +#include <asm/cputype.h> +#include <asm/mcpm.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> @@ -87,3 +91,256 @@ struct smp_operations hi3xxx_smp_ops __initdata = { .cpu_kill = hi3xxx_cpu_kill, #endif }; + +/* bits definition in SC_CPU_RESET_REQ[x]/SC_CPU_RESET_DREQ[x] + * 1 -- unreset; 0 -- reset + */ +#define CORE_RESET_BIT(x) (1 << x) +#define NEON_RESET_BIT(x) (1 << (x + 4)) +#define CORE_DEBUG_RESET_BIT(x) (1 << (x + 9)) +#define CLUSTER_L2_RESET_BIT (1 << 8) +#define CLUSTER_DEBUG_RESET_BIT (1 << 13) + +/* + * bits definition in SC_CPU_RESET_STATUS[x] + * 1 -- reset status; 0 -- unreset status + */ +#define CORE_RESET_STATUS(x) (1 << x) +#define NEON_RESET_STATUS(x) (1 << (x + 4)) +#define CORE_DEBUG_RESET_STATUS(x) (1 << (x + 9)) +#define CLUSTER_L2_RESET_STATUS (1 << 8) +#define CLUSTER_DEBUG_RESET_STATUS (1 << 13) +#define CORE_WFI_STATUS(x) (1 << (x + 16)) +#define CORE_WFE_STATUS(x) (1 << (x + 20)) +#define CORE_DEBUG_ACK(x) (1 << (x + 24)) + +#define SC_CPU_RESET_REQ(x) (0x520 + (x << 3)) /* reset */ +#define SC_CPU_RESET_DREQ(x) (0x524 + (x << 3)) /* unreset */ +#define SC_CPU_RESET_STATUS(x) (0x1520 + (x << 3)) + +#define FAB_SF_MODE 0x0c +#define FAB_SF_INVLD 0x10 + +/* bits definition in FB_SF_INVLD */ +#define FB_SF_INVLD_START (1 << 8) + +#define HIP04_MAX_CLUSTERS 4 +#define HIP04_MAX_CPUS_PER_CLUSTER 4 + +static void __iomem *relocation = NULL, *sysctrl = NULL, *fabric = NULL; +static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER]; +static DEFINE_SPINLOCK(boot_lock); + +static bool hip04_cluster_down(unsigned int cluster) +{ + int i; + + for (i = 0; i < HIP04_MAX_CPUS_PER_CLUSTER; i++) + if (hip04_cpu_table[cluster][i]) + return false; + return true; +} + +static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on) +{ + unsigned long data; + + if (!fabric) + return; + data = readl_relaxed(fabric + FAB_SF_MODE); + if (on) + data |= 1 << cluster; + else + data &= ~(1 << cluster); + writel_relaxed(data, fabric + FAB_SF_MODE); + while (1) { + if (data == readl_relaxed(fabric + FAB_SF_MODE)) + break; + } +} + +static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) +{ + unsigned long data, mask; + + if (!relocation || !sysctrl) + return -ENODEV; + if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER) + return -EINVAL; + + spin_lock(&boot_lock); + writel_relaxed(HIP04_BOOTWRAPPER_PHYS, relocation); + writel_relaxed(HIP04_BOOTWRAPPER_MAGIC, relocation + 4); + writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8); + writel_relaxed(0, relocation + 12); + + if (hip04_cluster_down(cluster)) { + data = CLUSTER_L2_RESET_BIT | CLUSTER_DEBUG_RESET_BIT; + writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster)); + do { + mask = CLUSTER_L2_RESET_STATUS | \ + CLUSTER_DEBUG_RESET_STATUS; + data = readl_relaxed(sysctrl + \ + SC_CPU_RESET_STATUS(cluster)); + } 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)); + spin_unlock(&boot_lock); + + return 0; +} + +static void hip04_mcpm_power_down(void) +{ + unsigned int mpidr, cpu, cluster; + unsigned int v; + + spin_lock(&boot_lock); + spin_unlock(&boot_lock); + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + + local_irq_disable(); + gic_cpu_if_down(); + + __mcpm_cpu_down(cpu, cluster); + + asm volatile( + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "Ir" (CR_C) + : "cc"); + + flush_cache_louis(); + + asm volatile( + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (0x40) + : "cc"); + + isb(); + dsb(); +} + +static int hip04_mcpm_power_down_finish(unsigned int cpu, unsigned int cluster) +{ + int ret = -EBUSY; + + spin_lock(&boot_lock); + BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); + __mcpm_cpu_going_down(cpu, cluster); + + hip04_cpu_table[cluster][cpu]--; + if (hip04_cpu_table[cluster][cpu]) { + pr_err("Cluster %d CPU%d is still running\n", cluster, cpu); + goto out; + } + ret = 0; +out: + spin_unlock(&boot_lock); + return ret; +} + +static void hip04_mcpm_powered_up(void) +{ + if (!relocation) + return; + spin_lock(&boot_lock); + writel_relaxed(0, relocation); + writel_relaxed(0, relocation + 4); + writel_relaxed(0, relocation + 8); + writel_relaxed(0, relocation + 12); + spin_unlock(&boot_lock); +} + +static const struct mcpm_platform_ops hip04_mcpm_ops = { + .power_up = hip04_mcpm_power_up, + .power_down = hip04_mcpm_power_down, + .power_down_finish = hip04_mcpm_power_down_finish, + .powered_up = hip04_mcpm_powered_up, +}; + +static bool __init hip04_cpu_table_init(void) +{ + unsigned int mpidr, cpu, cluster; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + + if (cluster >= HIP04_MAX_CLUSTERS || + cpu >= HIP04_MAX_CPUS_PER_CLUSTER) { + pr_err("%s: boot CPU is out of bound!\n", __func__); + return false; + } + hip04_set_snoop_filter(cluster, 1); + hip04_cpu_table[cluster][cpu] = 1; + return true; +} + +static int __init hip04_mcpm_init(void) +{ + struct device_node *np; + int ret = -ENODEV; + + np = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-mcpm"); + if (!np) { + pr_err("failed to find hisilicon,hip04-mcpm node\n"); + goto err; + } + relocation = of_iomap(np, 0); + if (!relocation) { + pr_err("failed to get relocation space\n"); + ret = -ENOMEM; + goto err; + } + sysctrl = of_iomap(np, 1); + if (!sysctrl) { + pr_err("failed to get sysctrl base\n"); + ret = -ENOMEM; + goto err_sysctrl; + } + fabric = of_iomap(np, 2); + if (!fabric) { + pr_err("failed to get fabric base\n"); + ret = -ENOMEM; + goto err_fabric; + } + if (!hip04_cpu_table_init()) + return -EINVAL; + ret = mcpm_platform_register(&hip04_mcpm_ops); + if (!ret) { + mcpm_sync_init(NULL); + pr_info("HiP04 MCPM initialized\n"); + } + return ret; +err_fabric: + iounmap(sysctrl); +err_sysctrl: + iounmap(relocation); +err: + return ret; +} +early_initcall(hip04_mcpm_init); + +bool __init hip04_smp_init_ops(void) +{ + mcpm_smp_set_ops(); + return true; +}
Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on Cortex A15 Core. And HiP04 supports LPAE to support large memory. Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> --- arch/arm/Kconfig | 2 +- arch/arm/mach-hisi/Kconfig | 10 ++ arch/arm/mach-hisi/core.h | 6 + arch/arm/mach-hisi/hisilicon.c | 17 +++ arch/arm/mach-hisi/platsmp.c | 257 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 291 insertions(+), 1 deletion(-)