diff options
author | Olof Johansson <olof@lixom.net> | 2014-09-23 22:20:10 -0700 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2014-09-23 22:21:04 -0700 |
commit | c8bc4dceb798fc18abd45ae7b7d9200009b1b2eb (patch) | |
tree | 0be71a97ffb4850509f94ff609ae2c1c4df30a91 | |
parent | 0501414bd52409464a74d457b576c1666f2eb75c (diff) | |
parent | c9a1df48a97ac9141540f177e4293a9966348f8c (diff) | |
download | talos-op-linux-c8bc4dceb798fc18abd45ae7b7d9200009b1b2eb.tar.gz talos-op-linux-c8bc4dceb798fc18abd45ae7b7d9200009b1b2eb.zip |
Merge tag 'D01-for-3.18' of git://github.com/hisilicon/linux-hisi into next/soc
Merge "pull request for hisilicon hip04 soc and D01 board updates" from Wei Xu:
ARM: mach-hisi: Hisilicon hip04 soc and D01 board updates for 3.18
- Add the CONFIG_MCPM_QUAD_CLUSTER configuration to enlarge cluster number from 2 to 4
- Enable MCPM on HiP04 SoC
- Enable 16 cores on HiP04 SoC
- Add platform & Fabric controller devicetree binding document for HiP04 SoC
- Add hip04.dtsi & hip04-d01.dts for hip04 SoC platform and D01 board
- Enable HiP04 SoC in both hi3xxx_defconfig & multi_v7_defconfig
- Add the support of Hisilicon HiP04 debug uart
* tag 'D01-for-3.18' of git://github.com/hisilicon/linux-hisi:
ARM: debug: add HiP04 debug uart
ARM: config: enable hisilicon hip04
ARM: dts: add hip04 dts
document: dt: add the binding on HiP04
ARM: hisi: enable HiP04
ARM: hisi: enable MCPM implementation
ARM: mcpm: support 4 clusters
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt | 23 | ||||
-rw-r--r-- | arch/arm/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/Kconfig.debug | 10 | ||||
-rw-r--r-- | arch/arm/boot/dts/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/boot/dts/hip04-d01.dts | 32 | ||||
-rw-r--r-- | arch/arm/boot/dts/hip04.dtsi | 267 | ||||
-rw-r--r-- | arch/arm/configs/hisi_defconfig (renamed from arch/arm/configs/hi3xxx_defconfig) | 13 | ||||
-rw-r--r-- | arch/arm/configs/multi_v7_defconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/mcpm.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-hisi/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/mach-hisi/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-hisi/hisilicon.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-hisi/platmcpm.c | 386 |
13 files changed, 766 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt index 934f00025cc4..f717c7b48603 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt @@ -5,6 +5,11 @@ Hi4511 Board Required root node properties: - compatible = "hisilicon,hi3620-hi4511"; +HiP04 D01 Board +Required root node properties: + - compatible = "hisilicon,hip04-d01"; + + Hisilicon system controller Required properties: @@ -55,3 +60,21 @@ Example: compatible = "hisilicon,pctrl"; reg = <0xfca09000 0x1000>; }; + +----------------------------------------------------------------------- +Fabric: + +Required Properties: +- compatible: "hisilicon,hip04-fabric"; +- reg: Address and size of Fabric + +----------------------------------------------------------------------- +Bootwrapper boot method (software protocol on SMP): + +Required Properties: +- compatible: "hisilicon,hip04-bootwrapper"; +- boot-method: Address and size of boot method. + [0]: bootwrapper physical address + [1]: bootwrapper size + [2]: relocation physical address + [3]: relocation size diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 27a5c5b3f409..cf6da5226cef 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1406,6 +1406,15 @@ config MCPM for (multi-)cluster based systems, such as big.LITTLE based systems. +config MCPM_QUAD_CLUSTER + bool + depends on MCPM + help + To avoid wasting resources unnecessarily, MCPM only supports up + to 2 clusters by default. + Platforms with 3 or 4 clusters that use MCPM must select this + option to allow the additional clusters to be managed. + config BIG_LITTLE bool "big.LITTLE support (Experimental)" depends on CPU_V7 && SMP diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index b11ad54f8d17..59a6dabaf28d 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -231,6 +231,14 @@ choice Say Y here if you want kernel low-level debugging support on Hix5hd2 UART. + config DEBUG_HIP04_UART + bool "Hisilicon HiP04 Debug UART" + depends on ARCH_HIP04 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on HIP04 UART. + config DEBUG_HIGHBANK_UART bool "Kernel low-level debugging messages via Highbank UART" depends on ARCH_HIGHBANK @@ -1109,6 +1117,7 @@ config DEBUG_UART_PHYS default 0xd4017000 if DEBUG_MMP_UART2 default 0xd4018000 if DEBUG_MMP_UART3 default 0xe0000000 if ARCH_SPEAR13XX + default 0xe4007000 if DEBUG_HIP04_UART default 0xf0000be0 if ARCH_EBSA110 default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \ @@ -1152,6 +1161,7 @@ config DEBUG_UART_VIRT default 0xf7008000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART2 || \ DEBUG_S3C2410_UART2) default 0xf7fc9000 if DEBUG_BERLIN_UART + default 0xf8007000 if DEBUG_HIP04_UART default 0xf8009000 if DEBUG_VEXPRESS_UART0_CA9 default 0xf8090000 if DEBUG_VEXPRESS_UART0_RS1 default 0xfa71e000 if DEBUG_QCOM_UARTDM diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 2bff594ca7e2..22aba8598ca7 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -90,6 +90,7 @@ dtb-$(CONFIG_ARCH_HI3xxx) += hi3620-hi4511.dtb dtb-$(CONFIG_ARCH_HIX5HD2) += hisi-x5hd2-dkb.dtb dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \ ecx-2000.dtb +dtb-$(CONFIG_ARCH_HIP04) += hip04-d01.dtb dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \ integratorcp.dtb dtb-$(CONFIG_ARCH_KEYSTONE) += k2hk-evm.dtb \ diff --git a/arch/arm/boot/dts/hip04-d01.dts b/arch/arm/boot/dts/hip04-d01.dts new file mode 100644 index 000000000000..40a9e33c2654 --- /dev/null +++ b/arch/arm/boot/dts/hip04-d01.dts @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013-2014 Linaro Ltd. + * Author: Haojian Zhuang <haojian.zhuang@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * publishhed by the Free Software Foundation. + */ + +/dts-v1/; + +#include "hip04.dtsi" + +/ { + /* memory bus is 64-bit */ + #address-cells = <2>; + #size-cells = <2>; + model = "Hisilicon D01 Development Board"; + compatible = "hisilicon,hip04-d01"; + + memory@00000000,10000000 { + device_type = "memory"; + reg = <0x00000000 0x10000000 0x00000000 0xc0000000>, + <0x00000004 0xc0000000 0x00000003 0x40000000>; + }; + + soc { + uart0: uart@4007000 { + status = "ok"; + }; + }; +}; diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi new file mode 100644 index 000000000000..93b6c909e991 --- /dev/null +++ b/arch/arm/boot/dts/hip04.dtsi @@ -0,0 +1,267 @@ +/* + * Hisilicon Ltd. HiP04 SoC + * + * Copyright (C) 2013-2014 Hisilicon Ltd. + * Copyright (C) 2013-2014 Linaro Ltd. + * + * Author: Haojian Zhuang <haojian.zhuang@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/ { + /* memory bus is 64-bit */ + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &uart0; + }; + + bootwrapper { + compatible = "hisilicon,hip04-bootwrapper"; + boot-method = <0x10c00000 0x10000>, <0xe0000100 0x1000>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + cluster1 { + core0 { + cpu = <&CPU4>; + }; + core1 { + cpu = <&CPU5>; + }; + core2 { + cpu = <&CPU6>; + }; + core3 { + cpu = <&CPU7>; + }; + }; + cluster2 { + core0 { + cpu = <&CPU8>; + }; + core1 { + cpu = <&CPU9>; + }; + core2 { + cpu = <&CPU10>; + }; + core3 { + cpu = <&CPU11>; + }; + }; + cluster3 { + core0 { + cpu = <&CPU12>; + }; + core1 { + cpu = <&CPU13>; + }; + core2 { + cpu = <&CPU14>; + }; + core3 { + cpu = <&CPU15>; + }; + }; + }; + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0>; + }; + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <1>; + }; + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <2>; + }; + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <3>; + }; + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x100>; + }; + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x101>; + }; + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x102>; + }; + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x103>; + }; + CPU8: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x200>; + }; + CPU9: cpu@201 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x201>; + }; + CPU10: cpu@202 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x202>; + }; + CPU11: cpu@203 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x203>; + }; + CPU12: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x300>; + }; + CPU13: cpu@301 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x301>; + }; + CPU14: cpu@302 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x302>; + }; + CPU15: cpu@303 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x303>; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupt-parent = <&gic>; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>, + <1 10 0xf08>; + }; + + clk_50m: clk_50m { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; + }; + + clk_168m: clk_168m { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <168000000>; + }; + + soc { + /* It's a 32-bit SoC. */ + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&gic>; + ranges = <0 0 0xe0000000 0x10000000>; + + gic: interrupt-controller@c01000 { + compatible = "hisilicon,hip04-intc"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + interrupts = <1 9 0xf04>; + + reg = <0xc01000 0x1000>, <0xc02000 0x1000>, + <0xc04000 0x2000>, <0xc06000 0x2000>; + }; + + sysctrl: sysctrl { + compatible = "hisilicon,sysctrl"; + reg = <0x3e00000 0x00100000>; + }; + + fabric: fabric { + compatible = "hisilicon,hip04-fabric"; + reg = <0x302a000 0x1000>; + }; + + dual_timer0: dual_timer@3000000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x3000000 0x1000>; + interrupts = <0 224 4>; + clocks = <&clk_50m>, <&clk_50m>; + clock-names = "apb_pclk"; + }; + + arm-pmu { + compatible = "arm,cortex-a15-pmu"; + interrupts = <0 64 4>, + <0 65 4>, + <0 66 4>, + <0 67 4>, + <0 68 4>, + <0 69 4>, + <0 70 4>, + <0 71 4>, + <0 72 4>, + <0 73 4>, + <0 74 4>, + <0 75 4>, + <0 76 4>, + <0 77 4>, + <0 78 4>, + <0 79 4>; + }; + + uart0: uart@4007000 { + compatible = "snps,dw-apb-uart"; + reg = <0x4007000 0x1000>; + interrupts = <0 381 4>; + clocks = <&clk_168m>; + clock-names = "uartclk"; + reg-shift = <2>; + status = "disabled"; + }; + + sata0: sata@a000000 { + compatible = "hisilicon,hisi-ahci"; + reg = <0xa000000 0x1000000>; + interrupts = <0 372 4>; + }; + + }; +}; diff --git a/arch/arm/configs/hi3xxx_defconfig b/arch/arm/configs/hisi_defconfig index 9630687e7d07..1772505caeba 100644 --- a/arch/arm/configs/hi3xxx_defconfig +++ b/arch/arm/configs/hisi_defconfig @@ -6,10 +6,15 @@ CONFIG_RD_LZMA=y CONFIG_ARCH_HISI=y CONFIG_ARCH_HI3xxx=y CONFIG_ARCH_HIX5HD2=y +CONFIG_ARCH_HIP04=y CONFIG_SMP=y +CONFIG_NR_CPUS=16 CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_HIGHMEM=y CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y @@ -21,6 +26,12 @@ CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_SATA_AHCI_PLATFORM=y CONFIG_NETDEVICES=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y @@ -56,3 +67,5 @@ CONFIG_PRINTK_TIME=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_VFP=y +CONFIG_VFPv3=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 5fb95fb758d9..691117bc7e2b 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -28,6 +28,7 @@ CONFIG_ARCH_HIGHBANK=y CONFIG_ARCH_HISI=y CONFIG_ARCH_HI3xxx=y CONFIG_ARCH_HIX5HD2=y +CONFIG_ARCH_HIP04=y CONFIG_ARCH_KEYSTONE=y CONFIG_ARCH_MXC=y CONFIG_SOC_IMX51=y diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h index 57ff7f2a3084..d428e386c88e 100644 --- a/arch/arm/include/asm/mcpm.h +++ b/arch/arm/include/asm/mcpm.h @@ -20,7 +20,12 @@ * to consider dynamic allocation. */ #define MAX_CPUS_PER_CLUSTER 4 + +#ifdef CONFIG_MCPM_QUAD_CLUSTER +#define MAX_NR_CLUSTERS 4 +#else #define MAX_NR_CLUSTERS 2 +#endif #ifndef __ASSEMBLY__ diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig index 984882943f77..075772b34e80 100644 --- a/arch/arm/mach-hisi/Kconfig +++ b/arch/arm/mach-hisi/Kconfig @@ -22,6 +22,15 @@ config ARCH_HI3xxx help Support for Hisilicon Hi36xx SoC family +config ARCH_HIP04 + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7 + select ARM_ERRATA_798181 if SMP + select HAVE_ARM_ARCH_TIMER + select MCPM if SMP + select MCPM_QUAD_CLUSTER if SMP + help + Support for Hisilicon HiP04 SoC family + config ARCH_HIX5HD2 bool "Hisilicon X5HD2 family" if ARCH_MULTI_V7 select CACHE_L2X0 diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile index ee2506b9cde3..d64831e6a782 100644 --- a/arch/arm/mach-hisi/Makefile +++ b/arch/arm/mach-hisi/Makefile @@ -3,4 +3,5 @@ # obj-y += hisilicon.o +obj-$(CONFIG_MCPM) += platmcpm.o obj-$(CONFIG_SMP) += platsmp.o hotplug.o headsmp.o diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c index 7cda6dda3cd0..7744c351bbfd 100644 --- a/arch/arm/mach-hisi/hisilicon.c +++ b/arch/arm/mach-hisi/hisilicon.c @@ -63,3 +63,12 @@ static const char *hix5hd2_compat[] __initconst = { DT_MACHINE_START(HIX5HD2_DT, "Hisilicon HIX5HD2 (Flattened Device Tree)") .dt_compat = hix5hd2_compat, MACHINE_END + +static const char *hip04_compat[] __initconst = { + "hisilicon,hip04-d01", + NULL, +}; + +DT_MACHINE_START(HIP04, "Hisilicon HiP04 (Flattened Device Tree)") + .dt_compat = hip04_compat, +MACHINE_END diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c new file mode 100644 index 000000000000..280f3f14f77c --- /dev/null +++ b/arch/arm/mach-hisi/platmcpm.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2013-2014 Linaro Ltd. + * Copyright (c) 2013-2014 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/memblock.h> +#include <linux/of_address.h> + +#include <asm/cputype.h> +#include <asm/cp15.h> +#include <asm/mcpm.h> + +#include "core.h" + +/* 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 + +#define POLL_MSEC 10 +#define TIMEOUT_MSEC 1000 + +static void __iomem *sysctrl, *fabric; +static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER]; +static DEFINE_SPINLOCK(boot_lock); +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_is_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) + BUG(); + data = readl_relaxed(fabric + FAB_SF_MODE); + if (on) + data |= 1 << cluster; + else + data &= ~(1 << cluster); + writel_relaxed(data, fabric + FAB_SF_MODE); + do { + cpu_relax(); + } while (data != readl_relaxed(fabric + FAB_SF_MODE)); +} + +static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) +{ + unsigned long data; + void __iomem *sys_dreq, *sys_status; + + 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]) + goto out; + + 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, sys_dreq); + do { + cpu_relax(); + data = readl_relaxed(sys_status); + } while (data & CLUSTER_DEBUG_RESET_STATUS); + } + + data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \ + CORE_DEBUG_RESET_BIT(cpu); + writel_relaxed(data, sys_dreq); + do { + cpu_relax(); + } while (data == readl_relaxed(sys_status)); + /* + * We may fail to power up core again without this delay. + * It's not mentioned in document. It's found by test. + */ + udelay(20); +out: + hip04_cpu_table[cluster][cpu]++; + spin_unlock_irq(&boot_lock); + + return 0; +} + +static void hip04_mcpm_power_down(void) +{ + unsigned int mpidr, cpu, cluster; + bool skip_wfi = false, last_man = false; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + + __mcpm_cpu_going_down(cpu, cluster); + + spin_lock(&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_wfi = true; + } else if (hip04_cpu_table[cluster][cpu] > 1) { + pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu); + BUG(); + } + + last_man = hip04_cluster_is_down(cluster); + if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) { + spin_unlock(&boot_lock); + /* Since it's Cortex A15, disable L2 prefetching. */ + asm volatile( + "mcr p15, 1, %0, c15, c0, 3 \n\t" + "isb \n\t" + "dsb " + : : "r" (0x400) ); + v7_exit_coherency_flush(all); + hip04_set_snoop_filter(cluster, 0); + __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); + } else { + spin_unlock(&boot_lock); + v7_exit_coherency_flush(louis); + } + + __mcpm_cpu_down(cpu, cluster); + + if (!skip_wfi) + wfi(); +} + +static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) +{ + unsigned int data, tries, count; + int ret = -ETIMEDOUT; + + BUG_ON(cluster >= HIP04_MAX_CLUSTERS || + cpu >= HIP04_MAX_CPUS_PER_CLUSTER); + + count = TIMEOUT_MSEC / POLL_MSEC; + spin_lock_irq(&boot_lock); + for (tries = 0; tries < count; tries++) { + if (hip04_cpu_table[cluster][cpu]) { + ret = -EBUSY; + goto err; + } + cpu_relax(); + data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster)); + if (data & CORE_WFI_STATUS(cpu)) + break; + spin_unlock_irq(&boot_lock); + /* Wait for clean L2 when the whole cluster is down. */ + msleep(POLL_MSEC); + spin_lock_irq(&boot_lock); + } + 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(); + data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster)); + if (data & CORE_RESET_STATUS(cpu)) + break; + } + if (tries >= count) + goto err; + spin_unlock_irq(&boot_lock); + return 0; +err: + spin_unlock_irq(&boot_lock); + return ret; +} + +static void hip04_mcpm_powered_up(void) +{ + 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); + 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, + .wait_for_powerdown = hip04_mcpm_wait_for_powerdown, + .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, *np_sctl, *np_fab; + struct resource fab_res; + void __iomem *relocation; + int ret = -ENODEV; + + 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; + + ret = memblock_reserve(hip04_boot_method[0], hip04_boot_method[1]); + if (ret) + goto err; + + relocation = ioremap(hip04_boot_method[2], hip04_boot_method[3]); + if (!relocation) { + pr_err("failed to map relocation space\n"); + ret = -ENOMEM; + goto err_reloc; + } + 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"); + ret = -ENOMEM; + goto err_fabric; + } + + if (!hip04_cpu_table_init()) { + ret = -EINVAL; + goto err_table; + } + ret = mcpm_platform_register(&hip04_mcpm_ops); + if (ret) { + goto err_table; + } + + /* + * Fill the instruction address that is used after 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; +} +early_initcall(hip04_mcpm_init); |