* [PATCH v3 00/13] enable Hisilicon HiP04 SoC
@ 2014-04-18 6:05 Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 01/13] ARM: debug: add HiP04 debug uart Haojian Zhuang
` (12 more replies)
0 siblings, 13 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Changelog:
v3:
* Replace CONFIG_ARCH_MULTI_V7 by CONFIG_ARCH_MULTI_V7_LPAE in some SoC.
* Update MCPM code based on Dave's patch.
* Remove MCPM node in DTS file. Use sysctrl & fabric node instead.
* Move hardcoding on bootwrapper into DTS file.
* Append the CONFIG_MCPM_QUAD_CLUSTER for HiP04.
* Fix the return value from gic_get_cpumask() if it's used in standard gic.
* Add the vgic support on HiP04 GIC.
* Add virtualization support in HiP04 defconfig.
v2:
* Append ARCH_MULTI_V7_LPAE configuration. Define ARCH_MULTI_V7 to only
support non-LPAE platform.
* Append document of DT supporting.
* Append ARCH_HISI in hi3xxx_defconfig.
* Enable errata 798181 for HiP04 SoC.
* Add PMU support.
Haojian Zhuang (11):
ARM: debug: add HiP04 debug uart
ARM: append ARCH_MULTI_V7_LPAE
ARM: hisi: add ARCH_HISI
irq: gic: use mask field in GICC_IAR
irq: gic: support hip04 gic
ARM: mcpm: support 4 clusters in HiP04
ARM: hisi: add hip04 SoC support
ARM: dts: add hip04-d01 dts file
ARM: config: append hip04_defconfig
ARM: config: select ARCH_HISI in hi3xxx_defconfig
virt: arm: support hip04 gic
Kefeng Wang (2):
ARM: hisi: enable erratum 798181 of A15 on HiP04
ARM: dts: Add PMU support in HiP04
Documentation/devicetree/bindings/arm/gic.txt | 1 +
.../bindings/arm/hisilicon/hisilicon.txt | 10 +
.../devicetree/bindings/clock/hip04-clock.txt | 20 ++
arch/arm/Kconfig | 19 +-
arch/arm/Kconfig.debug | 10 +
arch/arm/Makefile | 2 +-
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/hip04-d01.dts | 74 +++++
arch/arm/boot/dts/hip04.dtsi | 259 ++++++++++++++++
arch/arm/configs/hi3xxx_defconfig | 1 +
arch/arm/configs/hip04_defconfig | 74 +++++
arch/arm/include/asm/mcpm.h | 5 +
arch/arm/kvm/interrupts_head.S | 23 +-
arch/arm/mach-berlin/Kconfig | 2 +-
arch/arm/mach-highbank/Kconfig | 2 +-
arch/arm/mach-hisi/Kconfig | 26 +-
arch/arm/mach-hisi/Makefile | 1 +
arch/arm/mach-hisi/core.h | 2 +
arch/arm/mach-hisi/hisilicon.c | 12 +
arch/arm/mach-hisi/platmcpm.c | 334 +++++++++++++++++++++
arch/arm/mach-mvebu/Kconfig | 6 +-
arch/arm/mach-omap2/Kconfig | 4 +-
arch/arm/mach-qcom/Kconfig | 2 +-
arch/arm/mach-shmobile/Kconfig | 2 +-
arch/arm/mach-tegra/Kconfig | 2 +-
arch/arm/mach-vexpress/Kconfig | 2 +-
drivers/irqchip/irq-gic.c | 155 +++++++---
include/linux/irqchip/arm-gic.h | 5 +
virt/kvm/arm/vgic.c | 10 +-
29 files changed, 998 insertions(+), 68 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/hip04-clock.txt
create mode 100644 arch/arm/boot/dts/hip04-d01.dts
create mode 100644 arch/arm/boot/dts/hip04.dtsi
create mode 100644 arch/arm/configs/hip04_defconfig
create mode 100644 arch/arm/mach-hisi/platmcpm.c
--
1.8.3.2
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 01/13] ARM: debug: add HiP04 debug uart
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE Haojian Zhuang
` (11 subsequent siblings)
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Add the support of Hisilicon HiP04 debug uart.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/Kconfig.debug | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 4a2fc0b..5a311af 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -223,6 +223,14 @@ choice
Say Y here if you want kernel low-level debugging support
on HI3716 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
@@ -1044,6 +1052,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_KIRKWOOD || ARCH_MV78XX0 || \
@@ -1076,6 +1085,7 @@ config DEBUG_UART_VIRT
default 0xf4090000 if ARCH_LPC32XX
default 0xf4200000 if ARCH_GEMINI
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 0xfb009000 if DEBUG_REALVIEW_STD_PORT
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 01/13] ARM: debug: add HiP04 debug uart Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:56 ` Gregory CLEMENT
2014-04-18 6:05 ` [PATCH v3 03/13] ARM: hisi: add ARCH_HISI Haojian Zhuang
` (10 subsequent siblings)
12 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Add new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both
ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
ARCH_MULTI_V7 means non-LPAE platform.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/Kconfig | 9 ++++++++-
arch/arm/mach-berlin/Kconfig | 2 +-
arch/arm/mach-highbank/Kconfig | 2 +-
arch/arm/mach-mvebu/Kconfig | 6 +++---
arch/arm/mach-omap2/Kconfig | 4 ++--
arch/arm/mach-qcom/Kconfig | 2 +-
arch/arm/mach-shmobile/Kconfig | 2 +-
arch/arm/mach-tegra/Kconfig | 2 +-
arch/arm/mach-vexpress/Kconfig | 2 +-
9 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ab438cb..9a2214e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -918,12 +918,19 @@ config ARCH_MULTI_V6
select CPU_V6K
config ARCH_MULTI_V7
- bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
+ bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
default y
select ARCH_MULTI_V6_V7
select CPU_V7
select HAVE_SMP
+config ARCH_MULTI_V7_LPAE
+ bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
+ select ARCH_MULTI_V6_V7
+ select CPU_V7
+ select HAVE_SMP
+ select ARM_LPAE if !(ARCH_MULTI_V6 || ARCH_MULTI_V7)
+
config ARCH_MULTI_V6_V7
bool
select MIGHT_HAVE_CACHE_L2X0
diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig
index b0cb072..be0512d 100644
--- a/arch/arm/mach-berlin/Kconfig
+++ b/arch/arm/mach-berlin/Kconfig
@@ -1,5 +1,5 @@
config ARCH_BERLIN
- bool "Marvell Berlin SoCs" if ARCH_MULTI_V7
+ bool "Marvell Berlin SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE)
select ARM_GIC
select GENERIC_IRQ_CHIP
select DW_APB_ICTL
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 830b76e..9b6b3f8 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,5 @@
config ARCH_HIGHBANK
- bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+ bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7_LPAE
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_HAS_CPUFREQ
select ARCH_HAS_HOLES_MEMORYMODEL
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 3f73eec..16f69ae 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -1,5 +1,5 @@
config ARCH_MVEBU
- bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V5)
+ bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE || ARCH_MULTI_V5)
select ARCH_SUPPORTS_BIG_ENDIAN
select CLKSRC_MMIO
select GENERIC_IRQ_CHIP
@@ -23,7 +23,7 @@ config MACH_MVEBU_V7
select CACHE_L2X0
config MACH_ARMADA_370
- bool "Marvell Armada 370 boards" if ARCH_MULTI_V7
+ bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAE
select ARMADA_370_CLK
select CPU_PJ4B
select MACH_MVEBU_V7
@@ -59,7 +59,7 @@ config MACH_ARMADA_38X
on the Marvell Armada 380/385 SoC with device tree.
config MACH_ARMADA_XP
- bool "Marvell Armada XP boards" if ARCH_MULTI_V7
+ bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE
select ARMADA_XP_CLK
select CPU_PJ4B
select MACH_MVEBU_V7
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index cb31d43..1958791 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -41,7 +41,7 @@ config ARCH_OMAP4
config SOC_OMAP5
bool "TI OMAP5"
- depends on ARCH_MULTI_V7
+ depends on ARCH_MULTI_V7_LPAE
select ARCH_OMAP2PLUS
select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
@@ -68,7 +68,7 @@ config SOC_AM43XX
config SOC_DRA7XX
bool "TI DRA7XX"
- depends on ARCH_MULTI_V7
+ depends on ARCH_MULTI_V7_LPAE
select ARCH_OMAP2PLUS
select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index a028be2..0da77d2 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -1,5 +1,5 @@
config ARCH_QCOM
- bool "Qualcomm Support" if ARCH_MULTI_V7
+ bool "Qualcomm Support" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE)
select ARCH_REQUIRE_GPIOLIB
select ARM_GIC
select CLKSRC_OF
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 0f92ba8..c2a1fce 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -2,7 +2,7 @@ config ARCH_SHMOBILE
bool
config ARCH_SHMOBILE_MULTI
- bool "Renesas ARM SoCs" if ARCH_MULTI_V7
+ bool "Renesas ARM SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE)
depends on MMU
select ARCH_SHMOBILE
select HAVE_ARM_SCU if SMP
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 92d660f..12e1b49 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -1,5 +1,5 @@
config ARCH_TEGRA
- bool "NVIDIA Tegra" if ARCH_MULTI_V7
+ bool "NVIDIA Tegra" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE)
select ARCH_HAS_CPUFREQ
select ARCH_REQUIRE_GPIOLIB
select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 657d52d..a1d69d1 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -1,5 +1,5 @@
config ARCH_VEXPRESS
- bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7
+ bool "ARM Ltd. Versatile Express family" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE)
select ARCH_REQUIRE_GPIOLIB
select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 03/13] ARM: hisi: add ARCH_HISI
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 01/13] ARM: debug: add HiP04 debug uart Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 04/13] irq: gic: use mask field in GICC_IAR Haojian Zhuang
` (9 subsequent siblings)
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Since multiple ARCH configuration will be appended into mach-hisi
directory, add ARCH_HISI as common configuration for different ARCH in
mach-hisi.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/Makefile | 2 +-
arch/arm/mach-hisi/Kconfig | 16 ++++++++++++++--
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 41c1931..4c2798a 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -154,7 +154,7 @@ machine-$(CONFIG_ARCH_EP93XX) += ep93xx
machine-$(CONFIG_ARCH_EXYNOS) += exynos
machine-$(CONFIG_ARCH_GEMINI) += gemini
machine-$(CONFIG_ARCH_HIGHBANK) += highbank
-machine-$(CONFIG_ARCH_HI3xxx) += hisi
+machine-$(CONFIG_ARCH_HISI) += hisi
machine-$(CONFIG_ARCH_INTEGRATOR) += integrator
machine-$(CONFIG_ARCH_IOP13XX) += iop13xx
machine-$(CONFIG_ARCH_IOP32X) += iop32x
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index feee4db..da16efd 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -1,8 +1,16 @@
-config ARCH_HI3xxx
- bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7
+config ARCH_HISI
+ bool "Hisilicon SoC Support"
+ depends on ARCH_MULTIPLATFORM
select ARM_AMBA
select ARM_GIC
select ARM_TIMER_SP804
+
+if ARCH_HISI
+
+menu "Hisilicon platform type"
+
+config ARCH_HI3xxx
+ bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7
select CACHE_L2X0
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
@@ -10,3 +18,7 @@ config ARCH_HI3xxx
select PINCTRL_SINGLE
help
Support for Hisilicon Hi36xx/Hi37xx processor family
+
+endmenu
+
+endif
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 04/13] irq: gic: use mask field in GICC_IAR
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (2 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 03/13] ARM: hisi: add ARCH_HISI Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 05/13] irq: gic: support hip04 gic Haojian Zhuang
` (8 subsequent siblings)
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Bit[9:0] is interrupt ID field in GICC_IAR. Bit[12:10] is CPU ID field,
and others are reserved.
So we should use GICC_IAR_INTID to get interrupt ID. It's not a good way
to use ~0x1c00 (CPU ID field) to get interrupt ID.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
drivers/irqchip/irq-gic.c | 2 +-
include/linux/irqchip/arm-gic.h | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4300b66..8fd27bf 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -287,7 +287,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
do {
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
- irqnr = irqstat & ~0x1c00;
+ irqnr = irqstat & GICC_IAR_INTID;
if (likely(irqnr > 15 && irqnr < 1021)) {
irqnr = irq_find_mapping(gic->domain, irqnr);
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..55933aa 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -21,6 +21,8 @@
#define GIC_CPU_ACTIVEPRIO 0xd0
#define GIC_CPU_IDENT 0xfc
+#define GICC_IAR_INTID 0x3ff
+
#define GIC_DIST_CTRL 0x000
#define GIC_DIST_CTR 0x004
#define GIC_DIST_IGROUP 0x080
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 05/13] irq: gic: support hip04 gic
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (3 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 04/13] irq: gic: use mask field in GICC_IAR Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-22 10:47 ` Marc Zyngier
2014-04-18 6:05 ` [PATCH v3 06/13] ARM: mcpm: support 4 clusters in HiP04 Haojian Zhuang
` (7 subsequent siblings)
12 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
There's a little difference between ARM GIC and HiP04 GIC.
* HiP04 GIC could support 16 cores at most, and ARM GIC could support
8 cores at most. So the difination on GIC_DIST_SGIR,
GIC_DIST_SGI_PENDING_SET, GIC_DIST_SGI_PENDING_CLEAR
& GIC_DIST_TARGET registers are different since CPU interfaces are
increased from 8-bit to 16-bit.
* HiP04 GIC could support 510 interrupts at most, and ARM GIC could
support 1020 interrupts at most.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
drivers/irqchip/irq-gic.c | 153 +++++++++++++++++++++++++++++++++-------------
1 file changed, 109 insertions(+), 44 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 8fd27bf..18f3d56 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -68,6 +68,8 @@ struct gic_chip_data {
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
#endif
+ u32 nr_cpu_if;
+ u32 nr_if_per_reg;
};
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -76,9 +78,14 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
* The GIC mapping of CPU interfaces does not necessarily match
* the logical CPU numbering. Let's use a mapping as returned
* by the GIC itself.
+ *
+ * Hisilicon HiP04 extends the number of CPU interface from 8 to 16.
*/
-#define NR_GIC_CPU_IF 8
-static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
+#define NR_GIC_CPU_IF 16
+static u16 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
+
+/* GIC register is always 32-bit long whatever it's in ARM64 or ARM32 */
+#define GIC_REG_BITS 32
/*
* Supported arch specific GIC irq extension.
@@ -242,19 +249,50 @@ static int gic_retrigger(struct irq_data *d)
}
#ifdef CONFIG_SMP
+static inline u32 irq_to_core_offset(u32 i, u32 nr_cpu_if)
+{
+ if (nr_cpu_if == 8) {
+ /* ARM GIC, i / 4 * 4 */
+ return ((i >> 2) << 2);
+ }
+ /* HiP04 GIC (nr_cpu_if == 16), i / 2 * 4 */
+ return ((i >> 1) << 2);
+}
+
+static inline u32 irq_to_core_shift(u32 i, u32 nr_cpu_if)
+{
+ if (nr_cpu_if == 8) {
+ /* ARM GIC, i % 4 * 8 */
+ return ((i % 4) << 3);
+ }
+ /* HiP04 GIC (nr_cpu_if == 16), i % 2 * 16 */
+ return ((i % 2) << 4);
+}
+
+static inline u32 irq_to_core_mask(u32 i, u32 nr_cpu_if)
+{
+ u32 mask;
+ /* ARM GIC, nr_cpu_if == 8; HiP04 GIC, nr_cpu_if == 16 */
+ mask = (1 << nr_cpu_if) - 1;
+ return (mask << irq_to_core_shift(i, nr_cpu_if));
+}
+
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force)
{
- void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
- unsigned int shift = (gic_irq(d) % 4) * 8;
+ void __iomem *reg;
+ unsigned int i = gic_irq(d);
+ unsigned int shift = irq_to_core_shift(i, gic_data[0].nr_cpu_if);
unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
u32 val, mask, bit;
-
- if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
+ if (cpu >= gic_data[0].nr_cpu_if || cpu >= nr_cpu_ids)
return -EINVAL;
+ reg = gic_dist_base(d) + GIC_DIST_TARGET +
+ irq_to_core_offset(i, gic_data[0].nr_cpu_if);
+
raw_spin_lock(&irq_controller_lock);
- mask = 0xff << shift;
+ mask = irq_to_core_mask(i, gic_data[0].nr_cpu_if);
bit = gic_cpu_map[cpu] << shift;
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
@@ -354,15 +392,16 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
-static u8 gic_get_cpumask(struct gic_chip_data *gic)
+static u16 gic_get_cpumask(struct gic_chip_data *gic)
{
void __iomem *base = gic_data_dist_base(gic);
- u32 mask, i;
+ u32 mask, i, j, nr_if = gic->nr_if_per_reg;
- for (i = mask = 0; i < 32; i += 4) {
- mask = readl_relaxed(base + GIC_DIST_TARGET + i);
- mask |= mask >> 16;
- mask |= mask >> 8;
+ /* get the number of CPU fields in GIC_DIST_TARGET register */
+ for (i = mask = 0; i < DIV_ROUND_UP(32, nr_if); i++) {
+ mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
+ for (j = GIC_REG_BITS >> 1; j >= gic->nr_cpu_if; j >>= 1)
+ mask |= mask >> j;
if (mask)
break;
}
@@ -370,12 +409,16 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
if (!mask)
pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
+ /* ARM GIC needs 8-bit cpu mask, HiP04 GIC needs 16-bit cpu mask. */
+ if (gic->nr_cpu_if == 8)
+ mask &= 0xff;
+
return mask;
}
static void __init gic_dist_init(struct gic_chip_data *gic)
{
- unsigned int i;
+ unsigned int i, nr_if = gic->nr_if_per_reg;
u32 cpumask;
unsigned int gic_irqs = gic->gic_irqs;
void __iomem *base = gic_data_dist_base(gic);
@@ -392,23 +435,25 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
* Set all global interrupts to this CPU only.
*/
cpumask = gic_get_cpumask(gic);
- cpumask |= cpumask << 8;
- cpumask |= cpumask << 16;
- for (i = 32; i < gic_irqs; i += 4)
- writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
+ for (i = gic->nr_cpu_if; i < GIC_REG_BITS; i <<= 1)
+ cpumask |= cpumask << i;
+ for (i = 32 / nr_if; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
+ writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4);
/*
* Set priority on all global interrupts.
*/
- for (i = 32; i < gic_irqs; i += 4)
- writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
+ for (i = 32 / nr_if; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
- for (i = 32; i < gic_irqs; i += 32)
- writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+ i = 32 / GIC_REG_BITS;
+ for (; i < DIV_ROUND_UP(gic_irqs, GIC_REG_BITS); i++)
+ writel_relaxed(0xffffffff,
+ base + GIC_DIST_ENABLE_CLEAR + i * 4);
writel_relaxed(1, base + GIC_DIST_CTRL);
}
@@ -423,7 +468,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
/*
* Get what the GIC says our CPU mask is.
*/
- BUG_ON(cpu >= NR_GIC_CPU_IF);
+ BUG_ON(cpu >= gic->nr_cpu_if);
cpu_mask = gic_get_cpumask(gic);
gic_cpu_map[cpu] = cpu_mask;
@@ -431,7 +476,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
* Clear our mask from the other map entries in case they're
* still undefined.
*/
- for (i = 0; i < NR_GIC_CPU_IF; i++)
+ for (i = 0; i < gic->nr_cpu_if; i++)
if (i != cpu)
gic_cpu_map[i] &= ~cpu_mask;
@@ -445,8 +490,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)
/*
* Set priority on PPI and SGI interrupts
*/
- for (i = 0; i < 32; i += 4)
- writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+ for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
+ writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
writel_relaxed(1, base + GIC_CPU_CTRL);
@@ -467,7 +512,7 @@ void gic_cpu_if_down(void)
*/
static void gic_dist_save(unsigned int gic_nr)
{
- unsigned int gic_irqs;
+ unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;
void __iomem *dist_base;
int i;
@@ -484,7 +529,7 @@ static void gic_dist_save(unsigned int gic_nr)
gic_data[gic_nr].saved_spi_conf[i] =
readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
- for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
gic_data[gic_nr].saved_spi_target[i] =
readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
@@ -502,7 +547,7 @@ static void gic_dist_save(unsigned int gic_nr)
*/
static void gic_dist_restore(unsigned int gic_nr)
{
- unsigned int gic_irqs;
+ unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;
unsigned int i;
void __iomem *dist_base;
@@ -525,7 +570,7 @@ static void gic_dist_restore(unsigned int gic_nr)
writel_relaxed(0xa0a0a0a0,
dist_base + GIC_DIST_PRI + i * 4);
- for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
dist_base + GIC_DIST_TARGET + i * 4);
@@ -665,9 +710,15 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
*/
dmb(ishst);
- /* this always happens on GIC0 */
- writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
+ /*
+ * CPUTargetList -- bit[23:16] in GIC_DIST_SOFTINT in ARM GIC.
+ * bit[23:8] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC.
+ * NSATT -- bit[15] in GIC_DIST_SOFTINT in ARM GIC.
+ * bit[7] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC.
+ * this always happens on GIC0
+ */
+ writel_relaxed(map << (16 + 8 - gic_data[0].nr_cpu_if) | irq,
+ gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
#endif
@@ -681,10 +732,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
*/
void gic_send_sgi(unsigned int cpu_id, unsigned int irq)
{
- BUG_ON(cpu_id >= NR_GIC_CPU_IF);
+ BUG_ON(cpu_id >= gic_data[0].nr_cpu_if);
cpu_id = 1 << cpu_id;
/* this always happens on GIC0 */
- writel_relaxed((cpu_id << 16) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+ writel_relaxed((cpu_id << (16 + 8 - gic_data[0].nr_cpu_if)) | irq,
+ gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
}
/*
@@ -700,7 +752,7 @@ int gic_get_cpu_id(unsigned int cpu)
{
unsigned int cpu_bit;
- if (cpu >= NR_GIC_CPU_IF)
+ if (cpu >= gic_data[0].nr_cpu_if)
return -1;
cpu_bit = gic_cpu_map[cpu];
if (cpu_bit & (cpu_bit - 1))
@@ -771,10 +823,10 @@ void gic_migrate_target(unsigned int new_cpu_id)
*/
for (i = 0; i < 16; i += 4) {
int j;
- val = readl_relaxed(dist_base + GIC_DIST_SGI_PENDING_SET + i);
+ val = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i);
if (!val)
continue;
- writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i);
+ writel_relaxed(val, dist_base + GIC_DIST_PENDING_CLEAR + i);
for (j = i; j < i + 4; j++) {
if (val & 0xff)
writel_relaxed((1 << (new_cpu_id + 16)) | j,
@@ -931,7 +983,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
irq_hw_number_t hwirq_base;
struct gic_chip_data *gic;
int gic_irqs, irq_base, i;
- int nr_routable_irqs;
+ int nr_routable_irqs, max_nr_irq;
BUG_ON(gic_nr >= MAX_GIC_NR);
@@ -967,12 +1019,23 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
gic_set_base_accessor(gic, gic_get_common_base);
}
+ if (of_device_is_compatible(node, "hisilicon,hip04-gic")) {
+ /* HiP04 GIC supports 16 CPUs at most */
+ gic->nr_cpu_if = 16;
+ max_nr_irq = 510;
+ } else {
+ /* ARM/Qualcomm GIC supports 8 CPUs at most */
+ gic->nr_cpu_if = 8;
+ max_nr_irq = 1020;
+ }
+ gic->nr_if_per_reg = GIC_REG_BITS / gic->nr_cpu_if;
+
/*
* Initialize the CPU interface map to all CPUs.
* It will be refined as each CPU probes its ID.
*/
- for (i = 0; i < NR_GIC_CPU_IF; i++)
- gic_cpu_map[i] = 0xff;
+ for (i = 0; i < gic->nr_cpu_if; i++)
+ gic_cpu_map[i] = (1 << gic->nr_cpu_if) - 1;
/*
* For primary GICs, skip over SGIs.
@@ -988,12 +1051,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
/*
* Find out how many interrupts are supported.
- * The GIC only supports up to 1020 interrupt sources.
+ * The ARM/Qualcomm GIC only supports up to 1020 interrupt sources.
+ * The HiP04 GIC only supports up to 510 interrupt sources.
*/
gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
gic_irqs = (gic_irqs + 1) * 32;
- if (gic_irqs > 1020)
- gic_irqs = 1020;
+ if (gic_irqs > max_nr_irq)
+ gic_irqs = max_nr_irq;
gic->gic_irqs = gic_irqs;
gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
@@ -1069,6 +1133,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
}
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
+IRQCHIP_DECLARE(hip04_gic, "hisilicon,hip04-gic", gic_of_init);
IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 06/13] ARM: mcpm: support 4 clusters in HiP04
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (4 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 05/13] irq: gic: support hip04 gic Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-22 3:09 ` Nicolas Pitre
2014-04-18 6:05 ` [PATCH v3 07/13] ARM: hisi: add hip04 SoC support Haojian Zhuang
` (6 subsequent siblings)
12 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Since 16 Cortex-A15 cores are used in HiP04 SoC, enlarge the maximum
clusters from 2 to 4 if HiP04 SoC is built without CONFIG_BIG_LITTLE.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/Kconfig | 8 ++++++++
arch/arm/include/asm/mcpm.h | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9a2214e..f2a25be 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1571,6 +1571,14 @@ config MCPM
for (multi-)cluster based systems, such as big.LITTLE based
systems.
+config MCPM_QUAD_CLUSTER
+ bool "Enable Quad clusters in MPCM"
+ depends on MCPM
+ default n
+ help
+ This option enables quad clusters in MCPM. Quad clusters exist
+ in HiP04 SoC.
+
config BIG_LITTLE
bool "big.LITTLE support (Experimental)"
depends on CPU_V7 && SMP
diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h
index 608516e..fc8d70d 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__
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 07/13] ARM: hisi: add hip04 SoC support
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (5 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 06/13] ARM: mcpm: support 4 clusters in HiP04 Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-22 4:08 ` Nicolas Pitre
2014-04-18 6:05 ` [PATCH v3 08/13] ARM: dts: add hip04-d01 dts file Haojian Zhuang
` (5 subsequent siblings)
12 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on
Cortex A15 Core. Since multiple clusters is used in HiP04 SoC, it could
be based on MCPM.
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 | 9 +-
arch/arm/mach-hisi/Makefile | 1 +
arch/arm/mach-hisi/core.h | 2 +
arch/arm/mach-hisi/hisilicon.c | 12 ++
arch/arm/mach-hisi/platmcpm.c | 334 +++++++++++++++++++++++++++++++++++++++++
6 files changed, 358 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/mach-hisi/platmcpm.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f2a25be..2961627 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1113,7 +1113,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..0bfd739 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -17,7 +17,14 @@ config ARCH_HI3xxx
select PINCTRL
select PINCTRL_SINGLE
help
- Support for Hisilicon Hi36xx/Hi37xx processor family
+ Support for Hisilicon Hi36xx/Hi37xx SoC family
+
+config ARCH_HIP04
+ bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7_LPAE
+ select HAVE_ARM_ARCH_TIMER
+ select MCPM if SMP
+ help
+ Support for Hisilicon HiP04 SoC family
endmenu
diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile
index 2ae1b59..e7a8640 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
diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h
index af23ec2..1e60795 100644
--- a/arch/arm/mach-hisi/core.h
+++ b/arch/arm/mach-hisi/core.h
@@ -12,4 +12,6 @@ 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);
+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..6489e57 100644
--- a/arch/arm/mach-hisi/hisilicon.c
+++ b/arch/arm/mach-hisi/hisilicon.c
@@ -88,3 +88,15 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)")
.smp = smp_ops(hi3xxx_smp_ops),
.restart = hi3xxx_restart,
MACHINE_END
+
+#ifdef CONFIG_ARCH_HIP04
+static const char *hip04_compat[] __initconst = {
+ "hisilicon,hip04-d01",
+ NULL,
+};
+
+DT_MACHINE_START(HIP04, "Hisilicon HiP04 (Flattened Device Tree)")
+ .dt_compat = hip04_compat,
+ .smp_init = smp_init_ops(hip04_smp_init_ops),
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c
new file mode 100644
index 0000000..4ac8d4b
--- /dev/null
+++ b/arch/arm/mach-hisi/platmcpm.c
@@ -0,0 +1,334 @@
+/*
+ * 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
+
+struct hip04_secondary_cpu_data {
+ u32 bootwrapper_phys;
+ u32 bootwrapper_size;
+ u32 bootwrapper_magic;
+ u32 relocation_entry;
+ u32 relocation_size;
+};
+
+static void __iomem *relocation, *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 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_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)) {
+ 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);
+ msleep(POLL_MSEC);
+
+ return 0;
+}
+
+static void hip04_mcpm_power_down(void)
+{
+ unsigned int mpidr, cpu, cluster;
+ unsigned int v;
+
+ mpidr = read_cpuid_mpidr();
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+ 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;
+ }
+
+ __mcpm_cpu_down(cpu, cluster);
+ spin_unlock(&boot_lock);
+
+ 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)
+ :);
+
+ flush_cache_louis();
+
+ asm volatile(
+ /* Turn off coherency, disable SMP bit in ACTLR */
+ " 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)
+ :);
+
+ isb();
+ dsb();
+
+ while (true)
+ wfi();
+ return;
+out:
+ spin_unlock(&boot_lock);
+}
+
+static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
+{
+ unsigned int data, tries;
+
+ BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
+ cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
+
+ for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; tries++) {
+ data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
+ if (!(data & CORE_WFI_STATUS(cpu))) {
+ msleep(POLL_MSEC);
+ continue;
+ }
+ data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+ CORE_DEBUG_RESET_BIT(cpu);
+ writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+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,
+ .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_fab;
+ int ret = -ENODEV;
+
+ np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+ if (!np)
+ 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;
+ 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);
+ if (!relocation) {
+ pr_err("failed to map relocation space\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ sysctrl = of_iomap(np, 0);
+ if (!sysctrl) {
+ pr_err("failed to get sysctrl base\n");
+ ret = -ENOMEM;
+ goto err_sysctrl;
+ }
+ fabric = of_iomap(np_fab, 0);
+ if (!fabric) {
+ pr_err("failed to get fabric base\n");
+ ret = -ENOMEM;
+ goto err_fabric;
+ }
+
+ memblock_reserve(hip04_boot.bootwrapper_phys,
+ hip04_boot.bootwrapper_size);
+
+ 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;
+}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 08/13] ARM: dts: add hip04-d01 dts file
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (6 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 07/13] ARM: hisi: add hip04 SoC support Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 09/13] ARM: config: append hip04_defconfig Haojian Zhuang
` (4 subsequent siblings)
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Add hip04.dtsi & hip04-d01.dts file to support HiP04 SoC platform.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
Documentation/devicetree/bindings/arm/gic.txt | 1 +
.../bindings/arm/hisilicon/hisilicon.txt | 10 +
.../devicetree/bindings/clock/hip04-clock.txt | 20 ++
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/hip04-d01.dts | 74 +++++++
arch/arm/boot/dts/hip04.dtsi | 239 +++++++++++++++++++++
6 files changed, 345 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/hip04-clock.txt
create mode 100644 arch/arm/boot/dts/hip04-d01.dts
create mode 100644 arch/arm/boot/dts/hip04.dtsi
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 5573c08..150f7d6 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -16,6 +16,7 @@ Main node required properties:
"arm,cortex-a9-gic"
"arm,cortex-a7-gic"
"arm,arm11mp-gic"
+ "hisilicon,hip04-gic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The type shall be a <u32> and the value shall be 3.
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index df0a452..4681f15 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -4,6 +4,10 @@ Hisilicon Platforms Device Tree Bindings
Hi4511 Board
Required root node properties:
- compatible = "hisilicon,hi3620-hi4511";
+HiP04 D01 Board
+Required root node properties:
+ - compatible = "hisilicon,hip04-d01";
+
Hisilicon system controller
@@ -19,6 +23,11 @@ Optional properties:
If reg value is not zero, cpun exit wfi and go
- resume-offset : offset in sysctrl for notifying cpu0 when resume
- reboot-offset : offset in sysctrl for system reboot
+- relocation-entry : relocation address of secondary cpu boot code
+- relocation-size : relocation size of secondary cpu boot code
+- bootwrapper-phys : physical address of boot wrapper
+- bootwrapper-size : size of boot wrapper
+- bootwrapper-magic : magic number for secondary cpu in boot wrapper
Example:
@@ -31,6 +40,7 @@ Example:
reboot-offset = <0x4>;
};
+
PCTRL: Peripheral misc control register
Required Properties:
diff --git a/Documentation/devicetree/bindings/clock/hip04-clock.txt b/Documentation/devicetree/bindings/clock/hip04-clock.txt
new file mode 100644
index 0000000..4d31ae3
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/hip04-clock.txt
@@ -0,0 +1,20 @@
+* Hisilicon HiP04 Clock Controller
+
+The HiP04 clock controller generates and supplies clock to various
+controllers within the HiP04 SoC.
+
+Required Properties:
+
+- compatible: should be one of the following.
+ - "hisilicon,hip04-clock" - controller compatible with HiP04 SoC.
+
+- reg: physical base address of the controller and length of memory mapped
+ region.
+
+- #clock-cells: should be 1.
+
+
+Each clock is assigned an identifier and client nodes use this identifier
+to specify the clock which they consume.
+
+All these identifier could be found in <dt-bindings/clock/hip04-clock.h>.
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 35c146f..7119bca 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -80,6 +80,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
dtb-$(CONFIG_ARCH_HI3xxx) += hi3620-hi4511.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 0000000..a10dcf3
--- /dev/null
+++ b/arch/arm/boot/dts/hip04-d01.dts
@@ -0,0 +1,74 @@
+/*
+ * 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 = <1>;
+ model = "Hisilicon D01 Development Board";
+ compatible = "hisilicon,hip04-d01";
+
+ memory at 0 {
+ device_type = "memory";
+ /*
+ * Bootloader loads kernel image into 0x1000_0000 region,
+ * so disables the region between [0000_0000 - 1000_0000]
+ * temporarily.
+ * Because the PHYS_TO_VIRT_OFFSET is calculated based on
+ * the original region that kenrel is loaded.
+ * This workaround will be removed only after UEFI updated.
+ */
+ reg = <0x00000000 0x10000000 0xc0000000>;
+ };
+
+ memory at 00000004c0000000 {
+ device_type = "memory";
+ reg = <0x00000004 0xc0000000 0x40000000>;
+ };
+
+ memory at 0000000500000000 {
+ device_type = "memory";
+ reg = <0x00000005 0x00000000 0x80000000>;
+ };
+
+ memory at 0000000580000000 {
+ device_type = "memory";
+ reg = <0x00000005 0x80000000 0x80000000>;
+ };
+
+ memory at 0000000600000000 {
+ device_type = "memory";
+ reg = <0x00000006 0x00000000 0x80000000>;
+ };
+
+ memory at 0000000680000000 {
+ device_type = "memory";
+ reg = <0x00000006 0x80000000 0x80000000>;
+ };
+
+ memory at 0000000700000000 {
+ device_type = "memory";
+ reg = <0x00000007 0x00000000 0x80000000>;
+ };
+
+ memory at 0000000780000000 {
+ device_type = "memory";
+ reg = <0x00000007 0x80000000 0x80000000>;
+ };
+
+ soc {
+ uart0: uart at 4007000 {
+ status = "ok";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi
new file mode 100644
index 0000000..7e909ee
--- /dev/null
+++ b/arch/arm/boot/dts/hip04.dtsi
@@ -0,0 +1,239 @@
+/*
+ * Hisilicon Ltd. HiP01 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
+ * publishhed by the Free Software Foundation.
+ */
+
+#include <dt-bindings/clock/hip04-clock.h>
+
+/ {
+ /* memory bus is 64-bit */
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ 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 at 0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0>;
+ };
+ CPU1: cpu at 1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <1>;
+ };
+ CPU2: cpu at 2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <2>;
+ };
+ CPU3: cpu at 3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <3>;
+ };
+ CPU4: cpu at 100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x100>;
+ };
+ CPU5: cpu at 101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x101>;
+ };
+ CPU6: cpu at 102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x102>;
+ };
+ CPU7: cpu at 103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x103>;
+ };
+ CPU8: cpu at 200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x200>;
+ };
+ CPU9: cpu at 201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x201>;
+ };
+ CPU10: cpu at 202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x202>;
+ };
+ CPU11: cpu at 203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x203>;
+ };
+ CPU12: cpu at 300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x300>;
+ };
+ CPU13: cpu at 301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x301>;
+ };
+ CPU14: cpu at 302 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x302>;
+ };
+ CPU15: cpu at 303 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x303>;
+ };
+ };
+
+ soc {
+ /* It's a 32-bit SoC. */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,amba-bus", "simple-bus";
+ device_type = "soc";
+ interrupt-parent = <&gic>;
+ ranges = <0 0 0xe0000000 0x10000000>;
+
+ gic: interrupt-controller at c01000 {
+ compatible = "hisilicon,hip04-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ interrupts = <1 9 0xf04>;
+
+ /* gic dist base, gic cpu base */
+ reg = <0xc01000 0x1000>, <0xc02000 0x1000>,
+ <0xc04000 0x2000>, <0xc06000 0x2000>;
+ };
+
+ 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 {
+ compatible = "hisilicon,hip04-fabric";
+ reg = <0x302a000 0x1000>;
+ };
+
+ clock: clock {
+ compatible = "hisilicon,hip04-clock";
+ /* dummy register */
+ reg = <0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ dual_timer0: dual_timer at 3000000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x3000000 0x1000>;
+ interrupts = <0 224 4>;
+ clocks = <&clock HIP04_CLK_50M>;
+ clock-names = "apb_pclk";
+ status = "ok";
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
+ };
+
+ uart0: uart at 4007000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x4007000 0x1000>;
+ interrupts = <0 381 4>;
+ clocks = <&clock HIP04_CLK_168M>;
+ clock-names = "uartclk";
+ reg-shift = <2>;
+ status = "disabled";
+ };
+ };
+};
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 09/13] ARM: config: append hip04_defconfig
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (7 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 08/13] ARM: dts: add hip04-d01 dts file Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 10/13] ARM: config: select ARCH_HISI in hi3xxx_defconfig Haojian Zhuang
` (3 subsequent siblings)
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Select HiP04 SoC configuration by hip04_defconfig.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/configs/hip04_defconfig | 74 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 arch/arm/configs/hip04_defconfig
diff --git a/arch/arm/configs/hip04_defconfig b/arch/arm/configs/hip04_defconfig
new file mode 100644
index 0000000..3e674f7
--- /dev/null
+++ b/arch/arm/configs/hip04_defconfig
@@ -0,0 +1,74 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_GZIP=y
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
+CONFIG_ARCH_MULTI_V7_LPAE=y
+CONFIG_ARCH_HISI=y
+CONFIG_ARCH_HIP04=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_MCPM=y
+CONFIG_MCPM_QUAD_CLUSTER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_HIGHMEM=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_8250=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_OF_PLATFORM=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_DRM=y
+CONFIG_FB_SIMPLE=y
+CONFIG_RTC_CLASS=y
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_UART_8250=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_DEBUG_USER=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=y
+CONFIG_KVM_ARM_HOST=y
+CONFIG_KVM_ARM_MAX_VCPUS=4
+CONFIG_KVM_ARM_VGIC=y
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 10/13] ARM: config: select ARCH_HISI in hi3xxx_defconfig
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (8 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 09/13] ARM: config: append hip04_defconfig Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 11/13] ARM: hisi: enable erratum 798181 of A15 on HiP04 Haojian Zhuang
` (2 subsequent siblings)
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
Since ARCH_HISI is added as common configuration of both ARCH_HI3xxx and
ARCH_HIP04, update it into hi3xxx_defconfig.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/configs/hi3xxx_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/hi3xxx_defconfig b/arch/arm/configs/hi3xxx_defconfig
index f186bdf..f8c78ac 100644
--- a/arch/arm/configs/hi3xxx_defconfig
+++ b/arch/arm/configs/hi3xxx_defconfig
@@ -3,6 +3,7 @@ CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_LZMA=y
+CONFIG_ARCH_HISI=y
CONFIG_ARCH_HI3xxx=y
CONFIG_SMP=y
CONFIG_PREEMPT=y
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 11/13] ARM: hisi: enable erratum 798181 of A15 on HiP04
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (9 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 10/13] ARM: config: select ARCH_HISI in hi3xxx_defconfig Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 12/13] ARM: dts: Add PMU support in HiP04 Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 13/13] virt: arm: support hip04 gic Haojian Zhuang
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
From: Kefeng Wang <kefeng.wang@linaro.org>
The commit 93dc688 (ARM: 7684/1: errata: Workaround for Cortex-A15
erratum 798181 (TLBI/DSB operations)) introduced a workaround for
Cortex-A15 erratum 798181. Enable it for HIP04(Cortex-a15 r3p2).
Signed-off-by: Kefeng Wang <kefeng.wang@linaro.org>
Singed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/mach-hisi/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index 0bfd739..82e85717 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -21,6 +21,7 @@ config ARCH_HI3xxx
config ARCH_HIP04
bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7_LPAE
+ select ARM_ERRATA_798181 if SMP
select HAVE_ARM_ARCH_TIMER
select MCPM if SMP
help
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 12/13] ARM: dts: Add PMU support in HiP04
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (10 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 11/13] ARM: hisi: enable erratum 798181 of A15 on HiP04 Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 13/13] virt: arm: support hip04 gic Haojian Zhuang
12 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
From: Kefeng Wang <kefeng.wang@linaro.org>
ARM Performance Monitor Units are available on the HiP04.
So add the support in the dtsi.
Simply tested with perf.
Signed-off-by: Kefeng Wang <kefeng.wang@linaro.org>
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/boot/dts/hip04.dtsi | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi
index 7e909ee..98aa9fd 100644
--- a/arch/arm/boot/dts/hip04.dtsi
+++ b/arch/arm/boot/dts/hip04.dtsi
@@ -218,6 +218,26 @@
status = "ok";
};
+ 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>;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 13 0xf08>,
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 13/13] virt: arm: support hip04 gic
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
` (11 preceding siblings ...)
2014-04-18 6:05 ` [PATCH v3 12/13] ARM: dts: Add PMU support in HiP04 Haojian Zhuang
@ 2014-04-18 6:05 ` Haojian Zhuang
2014-04-22 12:15 ` Marc Zyngier
12 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 6:05 UTC (permalink / raw)
To: linux-arm-kernel
In HiP04 SoC, the address of GICH_APR & GICH_LR0 registers are different
from ARM standard SoC. So add the support of HiP04 SoC in VGIC.
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++----
include/linux/irqchip/arm-gic.h | 3 +++
virt/kvm/arm/vgic.c | 10 ++++++++--
3 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 76af9302..13e4144 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0
ldr r7, [r2, #GICH_EISR1]
ldr r8, [r2, #GICH_ELRSR0]
ldr r9, [r2, #GICH_ELRSR1]
- ldr r10, [r2, #GICH_APR]
+ ldr r10, =gich_apr
+ ldr r10, [r10]
+ ldr r10, [r2, r10]
str r3, [r11, #VGIC_CPU_HCR]
str r4, [r11, #VGIC_CPU_VMCR]
@@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0
str r5, [r2, #GICH_HCR]
/* Save list registers */
- add r2, r2, #GICH_LR0
+ ldr r10, =gich_lr0
+ ldr r10, [r10]
+ add r2, r2, r10
add r3, r11, #VGIC_CPU_LR
ldr r4, [r11, #VGIC_CPU_NR_LR]
1: ldr r6, [r2], #4
@@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0
str r3, [r2, #GICH_HCR]
str r4, [r2, #GICH_VMCR]
- str r8, [r2, #GICH_APR]
+ ldr r6, =gich_apr
+ ldr r6, [r6]
+ str r8, [r2, r6]
/* Restore list registers */
- add r2, r2, #GICH_LR0
+ ldr r6, =gich_lr0
+ ldr r6, [r6]
+ add r2, r2, r6
add r3, r11, #VGIC_CPU_LR
ldr r4, [r11, #VGIC_CPU_NR_LR]
1: ldr r6, [r3], #4
@@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0
.macro load_vcpu
mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR
.endm
+
+ .global gich_apr
+gich_apr:
+ .long GICH_APR
+ .global gich_lr0
+gich_lr0:
+ .long GICH_LR0
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 55933aa..653525b 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -49,6 +49,8 @@
#define GICH_ELRSR1 0x34
#define GICH_APR 0xf0
#define GICH_LR0 0x100
+#define HIP04_GICH_APR 0x70
+#define HIP04_GICH_LR0 0x80
#define GICH_HCR_EN (1 << 0)
#define GICH_HCR_UIE (1 << 1)
@@ -78,6 +80,7 @@
struct device_node;
extern struct irq_chip gic_arch_extn;
+extern unsigned int gich_apr, gich_lr0;
void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
u32 offset, struct device_node *);
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 47b2983..010e491 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void)
vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic");
if (!vgic_node) {
- kvm_err("error: no compatible vgic node in DT\n");
- return -ENODEV;
+ vgic_node = of_find_compatible_node(NULL, NULL,
+ "hisilicon,hip04-gic");
+ if (!vgic_node) {
+ kvm_err("error: no compatible vgic node in DT\n");
+ return -ENODEV;
+ }
+ gich_apr = HIP04_GICH_APR;
+ gich_lr0 = HIP04_GICH_LR0;
}
vgic_maint_irq = irq_of_parse_and_map(vgic_node, 0);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE
2014-04-18 6:05 ` [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE Haojian Zhuang
@ 2014-04-18 6:56 ` Gregory CLEMENT
2014-04-18 7:08 ` Haojian Zhuang
0 siblings, 1 reply; 26+ messages in thread
From: Gregory CLEMENT @ 2014-04-18 6:56 UTC (permalink / raw)
To: linux-arm-kernel
Hi Haojian,
On 18/04/2014 08:05, Haojian Zhuang wrote:
> Add new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both
> ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
>
> ARCH_MULTI_V7 means non-LPAE platform.
>
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
> ---
> arch/arm/Kconfig | 9 ++++++++-
> arch/arm/mach-berlin/Kconfig | 2 +-
> arch/arm/mach-highbank/Kconfig | 2 +-
> arch/arm/mach-mvebu/Kconfig | 6 +++---
> arch/arm/mach-omap2/Kconfig | 4 ++--
> arch/arm/mach-qcom/Kconfig | 2 +-
> arch/arm/mach-shmobile/Kconfig | 2 +-
> arch/arm/mach-tegra/Kconfig | 2 +-
> arch/arm/mach-vexpress/Kconfig | 2 +-
> 9 files changed, 19 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index ab438cb..9a2214e 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -918,12 +918,19 @@ config ARCH_MULTI_V6
> select CPU_V6K
>
> config ARCH_MULTI_V7
> - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
> + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
Actually some PJ4B are also non LPAE capable
> default y
> select ARCH_MULTI_V6_V7
> select CPU_V7
> select HAVE_SMP
>
> +config ARCH_MULTI_V7_LPAE
> + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B
but a PJ4B-MP
> + select ARCH_MULTI_V6_V7
> + select CPU_V7
> + select HAVE_SMP
> + select ARM_LPAE if !(ARCH_MULTI_V6 || ARCH_MULTI_V7)
> +
> config ARCH_MULTI_V6_V7
> bool
> select MIGHT_HAVE_CACHE_L2X0
> diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig
> index b0cb072..be0512d 100644
> --- a/arch/arm/mach-berlin/Kconfig
> +++ b/arch/arm/mach-berlin/Kconfig
> @@ -1,5 +1,5 @@
> config ARCH_BERLIN
> - bool "Marvell Berlin SoCs" if ARCH_MULTI_V7
> + bool "Marvell Berlin SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE)
> select ARM_GIC
> select GENERIC_IRQ_CHIP
> select DW_APB_ICTL
> diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
> index 830b76e..9b6b3f8 100644
> --- a/arch/arm/mach-highbank/Kconfig
> +++ b/arch/arm/mach-highbank/Kconfig
> @@ -1,5 +1,5 @@
> config ARCH_HIGHBANK
> - bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
> + bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7_LPAE
> select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
> select ARCH_HAS_CPUFREQ
> select ARCH_HAS_HOLES_MEMORYMODEL
> diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
> index 3f73eec..16f69ae 100644
> --- a/arch/arm/mach-mvebu/Kconfig
> +++ b/arch/arm/mach-mvebu/Kconfig
> @@ -1,5 +1,5 @@
> config ARCH_MVEBU
> - bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V5)
> + bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE || ARCH_MULTI_V5)
> select ARCH_SUPPORTS_BIG_ENDIAN
> select CLKSRC_MMIO
> select GENERIC_IRQ_CHIP
> @@ -23,7 +23,7 @@ config MACH_MVEBU_V7
> select CACHE_L2X0
>
> config MACH_ARMADA_370
> - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7
> + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAE
Armada 370 is not LPAE capable
> select ARMADA_370_CLK
> select CPU_PJ4B
> select MACH_MVEBU_V7
> @@ -59,7 +59,7 @@ config MACH_ARMADA_38X
> on the Marvell Armada 380/385 SoC with device tree.
>
> config MACH_ARMADA_XP
> - bool "Marvell Armada XP boards" if ARCH_MULTI_V7
> + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE
> select ARMADA_XP_CLK
> select CPU_PJ4B
> select MACH_MVEBU_V7
Thanks,
Gregory
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE
2014-04-18 6:56 ` Gregory CLEMENT
@ 2014-04-18 7:08 ` Haojian Zhuang
2014-04-18 7:18 ` Gregory CLEMENT
0 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 7:08 UTC (permalink / raw)
To: linux-arm-kernel
On 18 April 2014 14:56, Gregory CLEMENT
<gregory.clement@free-electrons.com> wrote:
> Hi Haojian,
>
> On 18/04/2014 08:05, Haojian Zhuang wrote:
>> Add new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both
>> ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
>>
>> ARCH_MULTI_V7 means non-LPAE platform.
>>
>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>> ---
>> arch/arm/Kconfig | 9 ++++++++-
>> arch/arm/mach-berlin/Kconfig | 2 +-
>> arch/arm/mach-highbank/Kconfig | 2 +-
>> arch/arm/mach-mvebu/Kconfig | 6 +++---
>> arch/arm/mach-omap2/Kconfig | 4 ++--
>> arch/arm/mach-qcom/Kconfig | 2 +-
>> arch/arm/mach-shmobile/Kconfig | 2 +-
>> arch/arm/mach-tegra/Kconfig | 2 +-
>> arch/arm/mach-vexpress/Kconfig | 2 +-
>> 9 files changed, 19 insertions(+), 12 deletions(-)
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index ab438cb..9a2214e 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -918,12 +918,19 @@ config ARCH_MULTI_V6
>> select CPU_V6K
>>
>> config ARCH_MULTI_V7
>> - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
>> + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
> Actually some PJ4B are also non LPAE capable
>
>
>> default y
>> select ARCH_MULTI_V6_V7
>> select CPU_V7
>> select HAVE_SMP
>>
>> +config ARCH_MULTI_V7_LPAE
>> + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
> Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B
> but a PJ4B-MP
Do you mind that I append CPU_PJ4B_MP?
>>
>> config MACH_ARMADA_370
>> - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7
>> + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAE
> Armada 370 is not LPAE capable
>
>> select ARMADA_370_CLK
>> select CPU_PJ4B
>> select MACH_MVEBU_V7
>> @@ -59,7 +59,7 @@ config MACH_ARMADA_38X
>> on the Marvell Armada 380/385 SoC with device tree.
>>
>> config MACH_ARMADA_XP
>> - bool "Marvell Armada XP boards" if ARCH_MULTI_V7
>> + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE
>> select ARMADA_XP_CLK
>> select CPU_PJ4B
>> select MACH_MVEBU_V7
>
>
> Thanks,
>
> Gregory
>
>
> --
> Gregory Clement, Free Electrons
> Kernel, drivers, real-time and embedded Linux
> development, consulting, training and support.
> http://free-electrons.com
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE
2014-04-18 7:08 ` Haojian Zhuang
@ 2014-04-18 7:18 ` Gregory CLEMENT
2014-04-18 7:40 ` Haojian Zhuang
0 siblings, 1 reply; 26+ messages in thread
From: Gregory CLEMENT @ 2014-04-18 7:18 UTC (permalink / raw)
To: linux-arm-kernel
On 18/04/2014 09:08, Haojian Zhuang wrote:
> On 18 April 2014 14:56, Gregory CLEMENT
> <gregory.clement@free-electrons.com> wrote:
>> Hi Haojian,
>>
>> On 18/04/2014 08:05, Haojian Zhuang wrote:
>>> Add new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both
>>> ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
>>>
>>> ARCH_MULTI_V7 means non-LPAE platform.
>>>
>>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>>> ---
>>> arch/arm/Kconfig | 9 ++++++++-
>>> arch/arm/mach-berlin/Kconfig | 2 +-
>>> arch/arm/mach-highbank/Kconfig | 2 +-
>>> arch/arm/mach-mvebu/Kconfig | 6 +++---
>>> arch/arm/mach-omap2/Kconfig | 4 ++--
>>> arch/arm/mach-qcom/Kconfig | 2 +-
>>> arch/arm/mach-shmobile/Kconfig | 2 +-
>>> arch/arm/mach-tegra/Kconfig | 2 +-
>>> arch/arm/mach-vexpress/Kconfig | 2 +-
>>> 9 files changed, 19 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>> index ab438cb..9a2214e 100644
>>> --- a/arch/arm/Kconfig
>>> +++ b/arch/arm/Kconfig
>>> @@ -918,12 +918,19 @@ config ARCH_MULTI_V6
>>> select CPU_V6K
>>>
>>> config ARCH_MULTI_V7
>>> - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
>>> + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
>> Actually some PJ4B are also non LPAE capable
>>
>>
>>> default y
>>> select ARCH_MULTI_V6_V7
>>> select CPU_V7
>>> select HAVE_SMP
>>>
>>> +config ARCH_MULTI_V7_LPAE
>>> + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
>> Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B
>> but a PJ4B-MP
>
> Do you mind that I append CPU_PJ4B_MP?
Currently we make no difference in the code between PJ4B and PJ4B-MP.
Moreover the ARCH_MULTI_V7_LPAE vs ARCH_MULTI_V7 si done by SoC not by
CPU.
Maybe I missed something, what is your proposal?
>
>>>
>>> config MACH_ARMADA_370
>>> - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7
>>> + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAE
>> Armada 370 is not LPAE capable
>>
>>> select ARMADA_370_CLK
>>> select CPU_PJ4B
>>> select MACH_MVEBU_V7
>>> @@ -59,7 +59,7 @@ config MACH_ARMADA_38X
>>> on the Marvell Armada 380/385 SoC with device tree.
>>>
>>> config MACH_ARMADA_XP
>>> - bool "Marvell Armada XP boards" if ARCH_MULTI_V7
>>> + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE
>>> select ARMADA_XP_CLK
>>> select CPU_PJ4B
>>> select MACH_MVEBU_V7
>>
>>
>> Thanks,
>>
>> Gregory
>>
>>
>> --
>> Gregory Clement, Free Electrons
>> Kernel, drivers, real-time and embedded Linux
>> development, consulting, training and support.
>> http://free-electrons.com
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE
2014-04-18 7:18 ` Gregory CLEMENT
@ 2014-04-18 7:40 ` Haojian Zhuang
2014-04-18 7:44 ` Gregory CLEMENT
0 siblings, 1 reply; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-18 7:40 UTC (permalink / raw)
To: linux-arm-kernel
On 18 April 2014 15:18, Gregory CLEMENT
<gregory.clement@free-electrons.com> wrote:
> On 18/04/2014 09:08, Haojian Zhuang wrote:
>> On 18 April 2014 14:56, Gregory CLEMENT
>> <gregory.clement@free-electrons.com> wrote:
>>> Hi Haojian,
>>>
>>> On 18/04/2014 08:05, Haojian Zhuang wrote:
>>>> Add new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both
>>>> ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
>>>>
>>>> ARCH_MULTI_V7 means non-LPAE platform.
>>>>
>>>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>>>> ---
>>>> arch/arm/Kconfig | 9 ++++++++-
>>>> arch/arm/mach-berlin/Kconfig | 2 +-
>>>> arch/arm/mach-highbank/Kconfig | 2 +-
>>>> arch/arm/mach-mvebu/Kconfig | 6 +++---
>>>> arch/arm/mach-omap2/Kconfig | 4 ++--
>>>> arch/arm/mach-qcom/Kconfig | 2 +-
>>>> arch/arm/mach-shmobile/Kconfig | 2 +-
>>>> arch/arm/mach-tegra/Kconfig | 2 +-
>>>> arch/arm/mach-vexpress/Kconfig | 2 +-
>>>> 9 files changed, 19 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>>> index ab438cb..9a2214e 100644
>>>> --- a/arch/arm/Kconfig
>>>> +++ b/arch/arm/Kconfig
>>>> @@ -918,12 +918,19 @@ config ARCH_MULTI_V6
>>>> select CPU_V6K
>>>>
>>>> config ARCH_MULTI_V7
>>>> - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
>>>> + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
>>> Actually some PJ4B are also non LPAE capable
>>>
>>>
>>>> default y
>>>> select ARCH_MULTI_V6_V7
>>>> select CPU_V7
>>>> select HAVE_SMP
>>>>
>>>> +config ARCH_MULTI_V7_LPAE
>>>> + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
>>> Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B
>>> but a PJ4B-MP
>>
>> Do you mind that I append CPU_PJ4B_MP?
>
> Currently we make no difference in the code between PJ4B and PJ4B-MP.
> Moreover the ARCH_MULTI_V7_LPAE vs ARCH_MULTI_V7 si done by SoC not by
> CPU.
>
> Maybe I missed something, what is your proposal?
>
Since they're same between PJ4B & PJ4B-MP, I shouldn't append a new PJ4B_MP.
I'll only use both ARCH_MULTI_V7 & ARCH_MULTI_V7_LPAE as the
precondition on ARMADA_XP. I'll keep ARCH_MULTI_V7 as the precondition
on other armada chips in mach-berlin directory.
So when multi_v7_lpae_defconfig is appended, only ARMADA_XP is built
from mach-berlin directory. Is it OK?
Regards
Haojian
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE
2014-04-18 7:40 ` Haojian Zhuang
@ 2014-04-18 7:44 ` Gregory CLEMENT
0 siblings, 0 replies; 26+ messages in thread
From: Gregory CLEMENT @ 2014-04-18 7:44 UTC (permalink / raw)
To: linux-arm-kernel
On 18/04/2014 09:40, Haojian Zhuang wrote:
> On 18 April 2014 15:18, Gregory CLEMENT
> <gregory.clement@free-electrons.com> wrote:
>> On 18/04/2014 09:08, Haojian Zhuang wrote:
>>> On 18 April 2014 14:56, Gregory CLEMENT
>>> <gregory.clement@free-electrons.com> wrote:
>>>> Hi Haojian,
>>>>
>>>> On 18/04/2014 08:05, Haojian Zhuang wrote:
>>>>> Add new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both
>>>>> ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
>>>>>
>>>>> ARCH_MULTI_V7 means non-LPAE platform.
>>>>>
>>>>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>>>>> ---
>>>>> arch/arm/Kconfig | 9 ++++++++-
>>>>> arch/arm/mach-berlin/Kconfig | 2 +-
>>>>> arch/arm/mach-highbank/Kconfig | 2 +-
>>>>> arch/arm/mach-mvebu/Kconfig | 6 +++---
>>>>> arch/arm/mach-omap2/Kconfig | 4 ++--
>>>>> arch/arm/mach-qcom/Kconfig | 2 +-
>>>>> arch/arm/mach-shmobile/Kconfig | 2 +-
>>>>> arch/arm/mach-tegra/Kconfig | 2 +-
>>>>> arch/arm/mach-vexpress/Kconfig | 2 +-
>>>>> 9 files changed, 19 insertions(+), 12 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>>>> index ab438cb..9a2214e 100644
>>>>> --- a/arch/arm/Kconfig
>>>>> +++ b/arch/arm/Kconfig
>>>>> @@ -918,12 +918,19 @@ config ARCH_MULTI_V6
>>>>> select CPU_V6K
>>>>>
>>>>> config ARCH_MULTI_V7
>>>>> - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
>>>>> + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
>>>> Actually some PJ4B are also non LPAE capable
>>>>
>>>>
>>>>> default y
>>>>> select ARCH_MULTI_V6_V7
>>>>> select CPU_V7
>>>>> select HAVE_SMP
>>>>>
>>>>> +config ARCH_MULTI_V7_LPAE
>>>>> + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
>>>> Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B
>>>> but a PJ4B-MP
>>>
>>> Do you mind that I append CPU_PJ4B_MP?
>>
>> Currently we make no difference in the code between PJ4B and PJ4B-MP.
>> Moreover the ARCH_MULTI_V7_LPAE vs ARCH_MULTI_V7 si done by SoC not by
>> CPU.
>>
>> Maybe I missed something, what is your proposal?
>>
>
> Since they're same between PJ4B & PJ4B-MP, I shouldn't append a new PJ4B_MP.
>
> I'll only use both ARCH_MULTI_V7 & ARCH_MULTI_V7_LPAE as the
> precondition on ARMADA_XP. I'll keep ARCH_MULTI_V7 as the precondition
> on other armada chips in mach-berlin directory.
In mach-mvebu actually
>
> So when multi_v7_lpae_defconfig is appended, only ARMADA_XP is built
> from mach-berlin directory. Is it OK?
ARMADA_XP is in mach-mvebu directory, but beside this typo I am OK :)
By the way I am really happy to have the possibility to build now a
multi_v7_lpae image.
Thanks,
Gregory
>
> Regards
> Haojian
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 06/13] ARM: mcpm: support 4 clusters in HiP04
2014-04-18 6:05 ` [PATCH v3 06/13] ARM: mcpm: support 4 clusters in HiP04 Haojian Zhuang
@ 2014-04-22 3:09 ` Nicolas Pitre
0 siblings, 0 replies; 26+ messages in thread
From: Nicolas Pitre @ 2014-04-22 3:09 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 18 Apr 2014, Haojian Zhuang wrote:
> Since 16 Cortex-A15 cores are used in HiP04 SoC, enlarge the maximum
> clusters from 2 to 4 if HiP04 SoC is built without CONFIG_BIG_LITTLE.
Why "... if HiP04 SoC is built without CONFIG_BIG_LITTLE" ?
That statement makes no sense. As mentioned before, if you have a
multi-platform kernel config with CONFIG_BIG_LITTLE included, there is
no reason for not supporting quad cluster platforms at the same time.
FYI you might want to have a look at patch #8032 in RMK's patch system
that removes a build-time MCPM dependency from the b.L switcher.
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
More comments below.
> ---
> arch/arm/Kconfig | 8 ++++++++
> arch/arm/include/asm/mcpm.h | 5 +++++
> 2 files changed, 13 insertions(+)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 9a2214e..f2a25be 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1571,6 +1571,14 @@ config MCPM
> for (multi-)cluster based systems, such as big.LITTLE based
> systems.
>
> +config MCPM_QUAD_CLUSTER
> + bool "Enable Quad clusters in MPCM"
s/MPCM/MCPM/
Yet you should not provide any prompt text here. This is way too
technical to leave to the user configuring the kernel to decide.
Instead, the actual platform needing this feature should select this
config symbol directly.
> + depends on MCPM
> + default n
The default is already n, so no need to explicitly default to the
default's default.
> + help
> + This option enables quad clusters in MCPM. Quad clusters exist
> + in HiP04 SoC.
Please refrain from listing SoCs here.
> config BIG_LITTLE
> bool "big.LITTLE support (Experimental)"
> depends on CPU_V7 && SMP
> diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h
> index 608516e..fc8d70d 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__
>
> --
> 1.8.3.2
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 07/13] ARM: hisi: add hip04 SoC support
2014-04-18 6:05 ` [PATCH v3 07/13] ARM: hisi: add hip04 SoC support Haojian Zhuang
@ 2014-04-22 4:08 ` Nicolas Pitre
2014-04-25 3:00 ` Haojian Zhuang
0 siblings, 1 reply; 26+ messages in thread
From: Nicolas Pitre @ 2014-04-22 4:08 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, 18 Apr 2014, Haojian Zhuang wrote:
> Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on
> Cortex A15 Core. Since multiple clusters is used in HiP04 SoC, it could
> be based on MCPM.
>
> And HiP04 supports LPAE to support large memory.
>
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
I'm providing review comments on the MCPM parts only.
> ---
> arch/arm/Kconfig | 2 +-
> arch/arm/mach-hisi/Kconfig | 9 +-
> arch/arm/mach-hisi/Makefile | 1 +
> arch/arm/mach-hisi/core.h | 2 +
> arch/arm/mach-hisi/hisilicon.c | 12 ++
> arch/arm/mach-hisi/platmcpm.c | 334 +++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 358 insertions(+), 2 deletions(-)
> create mode 100644 arch/arm/mach-hisi/platmcpm.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index f2a25be..2961627 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1113,7 +1113,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..0bfd739 100644
> --- a/arch/arm/mach-hisi/Kconfig
> +++ b/arch/arm/mach-hisi/Kconfig
> @@ -17,7 +17,14 @@ config ARCH_HI3xxx
> select PINCTRL
> select PINCTRL_SINGLE
> help
> - Support for Hisilicon Hi36xx/Hi37xx processor family
> + Support for Hisilicon Hi36xx/Hi37xx SoC family
> +
> +config ARCH_HIP04
> + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7_LPAE
> + select HAVE_ARM_ARCH_TIMER
> + select MCPM if SMP
This is where you should select MCPM_QUAD_CLUSTER as well.
> + help
> + Support for Hisilicon HiP04 SoC family
>
> endmenu
>
[...]
> diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c
> new file mode 100644
> index 0000000..4ac8d4b
> --- /dev/null
> +++ b/arch/arm/mach-hisi/platmcpm.c
> @@ -0,0 +1,334 @@
> +/*
> + * 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
> +
> +struct hip04_secondary_cpu_data {
> + u32 bootwrapper_phys;
> + u32 bootwrapper_size;
> + u32 bootwrapper_magic;
> + u32 relocation_entry;
> + u32 relocation_size;
> +};
> +
> +static void __iomem *relocation, *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 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);
This is called in interruptible context. Surely you want
spin_lock_irq() here.
> + 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)) {
> + 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));
It might be a good idea to reset and initialize things only if
hip04_cpu_table[cluster][cpu] was zero initially. Please see the
comment in mcpm_cpu_power_down() discussing concurrent up/down
operations, and the way races are handled using dcscb_use_count in
dcscb_power_up() / dcscb_power_down() for example.
> + spin_unlock(&boot_lock);
> + msleep(POLL_MSEC);
You don't have to wait here. The MCPM up method should set things for
the CPU to come up eventually and that CPU to signal itself when it is
finally online.
> + return 0;
> +}
> +
> +static void hip04_mcpm_power_down(void)
> +{
> + unsigned int mpidr, cpu, cluster;
> + unsigned int v;
> +
> + mpidr = read_cpuid_mpidr();
> + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> + 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;
> + }
This is wrong. Please see dcscb_power_down() or tc2_pm_down() for
examples of how to deal with this situation.
> + __mcpm_cpu_down(cpu, cluster);
That call should happen last i.e. after coherency has been disabled and
the CPU is about to call WFI. Again, see the TC2 implementation for
example. You may also read
Documentation/arm/cluster-pm-race-avoidance.txt for more details about
those calls and the algorithm behind them.
> + spin_unlock(&boot_lock);
> +
> + 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)
> + :);
> +
> + flush_cache_louis();
> +
> + asm volatile(
> + /* Turn off coherency, disable SMP bit in ACTLR */
> + " 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)
> + :);
The above code is not safe.
You should use v7_exit_coherency_flush() instead.
> + isb();
> + dsb();
> +
> + while (true)
> + wfi();
This is wrong. By the time execution gets here, it is well possible
that another CPU decided that this CPU should not be down anymore, in
which case wfi() will return. See what's expected in this case by
looking at mcpm_cpu_power_down() and what other backend implementations
do.
> + return;
> +out:
> + spin_unlock(&boot_lock);
> +}
> +
> +static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
> +{
> + unsigned int data, tries;
> +
> + BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
> + cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
> +
> + for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; tries++) {
> + data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
> + if (!(data & CORE_WFI_STATUS(cpu))) {
> + msleep(POLL_MSEC);
> + continue;
> + }
> + data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
> + CORE_DEBUG_RESET_BIT(cpu);
> + writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
Why are you resetting those here?
> + return 0;
> + }
> +
> + return -ETIMEDOUT;
> +}
> +
> +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,
> + .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_fab;
> + int ret = -ENODEV;
> +
> + np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
> + if (!np)
> + 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;
> + 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);
> + if (!relocation) {
> + pr_err("failed to map relocation space\n");
> + ret = -ENOMEM;
> + goto err;
> + }
> + sysctrl = of_iomap(np, 0);
> + if (!sysctrl) {
> + pr_err("failed to get sysctrl base\n");
> + ret = -ENOMEM;
> + goto err_sysctrl;
> + }
> + fabric = of_iomap(np_fab, 0);
> + if (!fabric) {
> + pr_err("failed to get fabric base\n");
> + ret = -ENOMEM;
> + goto err_fabric;
> + }
> +
> + memblock_reserve(hip04_boot.bootwrapper_phys,
> + hip04_boot.bootwrapper_size);
> +
> + 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;
> +}
> --
> 1.8.3.2
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 05/13] irq: gic: support hip04 gic
2014-04-18 6:05 ` [PATCH v3 05/13] irq: gic: support hip04 gic Haojian Zhuang
@ 2014-04-22 10:47 ` Marc Zyngier
2014-04-25 2:52 ` Haojian Zhuang
0 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2014-04-22 10:47 UTC (permalink / raw)
To: linux-arm-kernel
Hi Haojian,
On Fri, Apr 18 2014 at 7:05:48 am BST, Haojian Zhuang <haojian.zhuang@linaro.org> wrote:
> There's a little difference between ARM GIC and HiP04 GIC.
>
> * HiP04 GIC could support 16 cores at most, and ARM GIC could support
> 8 cores at most. So the difination on GIC_DIST_SGIR,
definitions of
> GIC_DIST_SGI_PENDING_SET, GIC_DIST_SGI_PENDING_CLEAR
> & GIC_DIST_TARGET registers are different since CPU interfaces are
> increased from 8-bit to 16-bit.
>
> * HiP04 GIC could support 510 interrupts at most, and ARM GIC could
> support 1020 interrupts at most.
>
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
> ---
> drivers/irqchip/irq-gic.c | 153 +++++++++++++++++++++++++++++++++-------------
> 1 file changed, 109 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 8fd27bf..18f3d56 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -68,6 +68,8 @@ struct gic_chip_data {
> #ifdef CONFIG_GIC_NON_BANKED
> void __iomem *(*get_base)(union gic_base *);
> #endif
> + u32 nr_cpu_if;
> + u32 nr_if_per_reg;
Which register? Surely you can compute that at runtime.
> };
>
> static DEFINE_RAW_SPINLOCK(irq_controller_lock);
> @@ -76,9 +78,14 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
> * The GIC mapping of CPU interfaces does not necessarily match
> * the logical CPU numbering. Let's use a mapping as returned
> * by the GIC itself.
> + *
> + * Hisilicon HiP04 extends the number of CPU interface from 8 to 16.
> */
> -#define NR_GIC_CPU_IF 8
> -static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
> +#define NR_GIC_CPU_IF 16
> +static u16 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
> +
> +/* GIC register is always 32-bit long whatever it's in ARM64 or ARM32 */
> +#define GIC_REG_BITS 32
What doesn this buy us? I'm not sure we gain much from it.
> /*
> * Supported arch specific GIC irq extension.
> @@ -242,19 +249,50 @@ static int gic_retrigger(struct irq_data *d)
> }
>
> #ifdef CONFIG_SMP
> +static inline u32 irq_to_core_offset(u32 i, u32 nr_cpu_if)
> +{
Make this function take an irq_data pointer, and use the accessor to
find out about the number of CPU interfaces.
> + if (nr_cpu_if == 8) {
> + /* ARM GIC, i / 4 * 4 */
> + return ((i >> 2) << 2);
Why does the comment has one expression and the code another? I know
they give the same result, but this is pretty useless.
> + }
> + /* HiP04 GIC (nr_cpu_if == 16), i / 2 * 4 */
> + return ((i >> 1) << 2);
Same here.
> +}
> +
> +static inline u32 irq_to_core_shift(u32 i, u32 nr_cpu_if)
> +{
Same remarks as above.
> + if (nr_cpu_if == 8) {
> + /* ARM GIC, i % 4 * 8 */
> + return ((i % 4) << 3);
> + }
> + /* HiP04 GIC (nr_cpu_if == 16), i % 2 * 16 */
> + return ((i % 2) << 4);
> +}
> +
> +static inline u32 irq_to_core_mask(u32 i, u32 nr_cpu_if)
> +{
And here too.
> + u32 mask;
> + /* ARM GIC, nr_cpu_if == 8; HiP04 GIC, nr_cpu_if == 16 */
> + mask = (1 << nr_cpu_if) - 1;
> + return (mask << irq_to_core_shift(i, nr_cpu_if));
> +}
> +
> static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
> bool force)
> {
> - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
> - unsigned int shift = (gic_irq(d) % 4) * 8;
> + void __iomem *reg;
> + unsigned int i = gic_irq(d);
> + unsigned int shift = irq_to_core_shift(i, gic_data[0].nr_cpu_if);
> unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
> u32 val, mask, bit;
> -
> - if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
> + if (cpu >= gic_data[0].nr_cpu_if || cpu >= nr_cpu_ids)
> return -EINVAL;
>
> + reg = gic_dist_base(d) + GIC_DIST_TARGET +
> + irq_to_core_offset(i, gic_data[0].nr_cpu_if);
> +
> raw_spin_lock(&irq_controller_lock);
> - mask = 0xff << shift;
> + mask = irq_to_core_mask(i, gic_data[0].nr_cpu_if);
> bit = gic_cpu_map[cpu] << shift;
> val = readl_relaxed(reg) & ~mask;
> writel_relaxed(val | bit, reg);
> @@ -354,15 +392,16 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
> irq_set_chained_handler(irq, gic_handle_cascade_irq);
> }
>
> -static u8 gic_get_cpumask(struct gic_chip_data *gic)
> +static u16 gic_get_cpumask(struct gic_chip_data *gic)
> {
> void __iomem *base = gic_data_dist_base(gic);
> - u32 mask, i;
> + u32 mask, i, j, nr_if = gic->nr_if_per_reg;
>
> - for (i = mask = 0; i < 32; i += 4) {
> - mask = readl_relaxed(base + GIC_DIST_TARGET + i);
> - mask |= mask >> 16;
> - mask |= mask >> 8;
> + /* get the number of CPU fields in GIC_DIST_TARGET register */
> + for (i = mask = 0; i < DIV_ROUND_UP(32, nr_if); i++) {
> + mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
> + for (j = GIC_REG_BITS >> 1; j >= gic->nr_cpu_if; j >>= 1)
> + mask |= mask >> j;
> if (mask)
> break;
> }
This looks incredibly convoluted. How about something like the code
below, which is way simpler and doesn't involve changing so much stuff
(completely untested, of course):
int nr_target_regs = 32 / (gic->nr_cpu_if == 8 ? 4 : 2);
for (i = mask = 0; i < nr_target_regs; i++) {
mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
mask |= mask >> 16;
if (gic->nr_cpu_if == 8)
mask |= mask >> 8;
if (mask)
break;
}
> @@ -370,12 +409,16 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
> if (!mask)
> pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
>
> + /* ARM GIC needs 8-bit cpu mask, HiP04 GIC needs 16-bit cpu mask. */
> + if (gic->nr_cpu_if == 8)
> + mask &= 0xff;
> +
> return mask;
> }
>
> static void __init gic_dist_init(struct gic_chip_data *gic)
> {
> - unsigned int i;
> + unsigned int i, nr_if = gic->nr_if_per_reg;
> u32 cpumask;
> unsigned int gic_irqs = gic->gic_irqs;
> void __iomem *base = gic_data_dist_base(gic);
> @@ -392,23 +435,25 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
> * Set all global interrupts to this CPU only.
> */
> cpumask = gic_get_cpumask(gic);
> - cpumask |= cpumask << 8;
> - cpumask |= cpumask << 16;
> - for (i = 32; i < gic_irqs; i += 4)
> - writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
> + for (i = gic->nr_cpu_if; i < GIC_REG_BITS; i <<= 1)
> + cpumask |= cpumask << i;
Really, you should stop adding bit arithmetics all over the
place. You're just making a simple problem way too complex. What is
wrong with:
if (gic->nr_cpu_if == 8)
cpumask |= cpumask << 8;
?
> + for (i = 32 / nr_if; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
> + writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4);
Why do you need to DIV_ROUND_UP? GIC interrupts are always a multiple of
32.
> /*
> * Set priority on all global interrupts.
> */
> - for (i = 32; i < gic_irqs; i += 4)
> - writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
> + for (i = 32 / nr_if; i < DIV_ROUND_UP(gic_irqs, 4); i++)
> + writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4);
>
> /*
> * Disable all interrupts. Leave the PPI and SGIs alone
> * as these enables are banked registers.
> */
> - for (i = 32; i < gic_irqs; i += 32)
> - writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
> + i = 32 / GIC_REG_BITS;
I predict this value to be the grand total of one.
> + for (; i < DIV_ROUND_UP(gic_irqs, GIC_REG_BITS); i++)
> + writel_relaxed(0xffffffff,
> + base + GIC_DIST_ENABLE_CLEAR + i * 4);
>
> writel_relaxed(1, base + GIC_DIST_CTRL);
> }
> @@ -423,7 +468,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
> /*
> * Get what the GIC says our CPU mask is.
> */
> - BUG_ON(cpu >= NR_GIC_CPU_IF);
> + BUG_ON(cpu >= gic->nr_cpu_if);
> cpu_mask = gic_get_cpumask(gic);
> gic_cpu_map[cpu] = cpu_mask;
>
> @@ -431,7 +476,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
> * Clear our mask from the other map entries in case they're
> * still undefined.
> */
> - for (i = 0; i < NR_GIC_CPU_IF; i++)
> + for (i = 0; i < gic->nr_cpu_if; i++)
> if (i != cpu)
> gic_cpu_map[i] &= ~cpu_mask;
>
> @@ -445,8 +490,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)
> /*
> * Set priority on PPI and SGI interrupts
> */
> - for (i = 0; i < 32; i += 4)
> - writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
> + for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
> + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>
> writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
> writel_relaxed(1, base + GIC_CPU_CTRL);
> @@ -467,7 +512,7 @@ void gic_cpu_if_down(void)
> */
> static void gic_dist_save(unsigned int gic_nr)
> {
> - unsigned int gic_irqs;
> + unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;
> void __iomem *dist_base;
> int i;
>
> @@ -484,7 +529,7 @@ static void gic_dist_save(unsigned int gic_nr)
> gic_data[gic_nr].saved_spi_conf[i] =
> readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
>
> - for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
> + for (i = 0; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
> gic_data[gic_nr].saved_spi_target[i] =
> readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
>
> @@ -502,7 +547,7 @@ static void gic_dist_save(unsigned int gic_nr)
> */
> static void gic_dist_restore(unsigned int gic_nr)
> {
> - unsigned int gic_irqs;
> + unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;
> unsigned int i;
> void __iomem *dist_base;
>
> @@ -525,7 +570,7 @@ static void gic_dist_restore(unsigned int gic_nr)
> writel_relaxed(0xa0a0a0a0,
> dist_base + GIC_DIST_PRI + i * 4);
>
> - for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
> + for (i = 0; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
> writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
> dist_base + GIC_DIST_TARGET + i * 4);
>
> @@ -665,9 +710,15 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
> */
> dmb(ishst);
>
> - /* this always happens on GIC0 */
> - writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
> -
> + /*
> + * CPUTargetList -- bit[23:16] in GIC_DIST_SOFTINT in ARM GIC.
> + * bit[23:8] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC.
> + * NSATT -- bit[15] in GIC_DIST_SOFTINT in ARM GIC.
> + * bit[7] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC.
> + * this always happens on GIC0
> + */
> + writel_relaxed(map << (16 + 8 - gic_data[0].nr_cpu_if) | irq,
> + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Make this two cases. This bit arithmetic makes it unreadable. Also, why
does the comment makes the GIC_DIST_SOFTINT/HIP04_GIC_DIST_SOFTINT
distinction, while the code only refers to GIC_DIST_SOFTINT?
> raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
> }
> #endif
> @@ -681,10 +732,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
> */
> void gic_send_sgi(unsigned int cpu_id, unsigned int irq)
> {
> - BUG_ON(cpu_id >= NR_GIC_CPU_IF);
> + BUG_ON(cpu_id >= gic_data[0].nr_cpu_if);
> cpu_id = 1 << cpu_id;
> /* this always happens on GIC0 */
> - writel_relaxed((cpu_id << 16) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
> + writel_relaxed((cpu_id << (16 + 8 - gic_data[0].nr_cpu_if)) | irq,
> + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Same here.
> }
>
> /*
> @@ -700,7 +752,7 @@ int gic_get_cpu_id(unsigned int cpu)
> {
> unsigned int cpu_bit;
>
> - if (cpu >= NR_GIC_CPU_IF)
> + if (cpu >= gic_data[0].nr_cpu_if)
> return -1;
> cpu_bit = gic_cpu_map[cpu];
> if (cpu_bit & (cpu_bit - 1))
> @@ -771,10 +823,10 @@ void gic_migrate_target(unsigned int new_cpu_id)
> */
> for (i = 0; i < 16; i += 4) {
> int j;
> - val = readl_relaxed(dist_base + GIC_DIST_SGI_PENDING_SET + i);
> + val = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i);
> if (!val)
> continue;
> - writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i);
> + writel_relaxed(val, dist_base + GIC_DIST_PENDING_CLEAR + i);
What? Hell no. This is the SGI sources we're dealing with. And I'd
expect your implementation to be quite different.
> for (j = i; j < i + 4; j++) {
> if (val & 0xff)
> writel_relaxed((1 << (new_cpu_id + 16)) | j,
> @@ -931,7 +983,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
> irq_hw_number_t hwirq_base;
> struct gic_chip_data *gic;
> int gic_irqs, irq_base, i;
> - int nr_routable_irqs;
> + int nr_routable_irqs, max_nr_irq;
>
> BUG_ON(gic_nr >= MAX_GIC_NR);
>
> @@ -967,12 +1019,23 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
> gic_set_base_accessor(gic, gic_get_common_base);
> }
>
> + if (of_device_is_compatible(node, "hisilicon,hip04-gic")) {
> + /* HiP04 GIC supports 16 CPUs at most */
> + gic->nr_cpu_if = 16;
> + max_nr_irq = 510;
> + } else {
> + /* ARM/Qualcomm GIC supports 8 CPUs at most */
> + gic->nr_cpu_if = 8;
> + max_nr_irq = 1020;
> + }
> + gic->nr_if_per_reg = GIC_REG_BITS / gic->nr_cpu_if;
> +
Loose this last line, and do the explicit computation. where needed. I
don't this this adds anything.
> /*
> * Initialize the CPU interface map to all CPUs.
> * It will be refined as each CPU probes its ID.
> */
> - for (i = 0; i < NR_GIC_CPU_IF; i++)
> - gic_cpu_map[i] = 0xff;
> + for (i = 0; i < gic->nr_cpu_if; i++)
> + gic_cpu_map[i] = (1 << gic->nr_cpu_if) - 1;
>
> /*
> * For primary GICs, skip over SGIs.
> @@ -988,12 +1051,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>
> /*
> * Find out how many interrupts are supported.
> - * The GIC only supports up to 1020 interrupt sources.
> + * The ARM/Qualcomm GIC only supports up to 1020 interrupt sources.
> + * The HiP04 GIC only supports up to 510 interrupt sources.
> */
> gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
> gic_irqs = (gic_irqs + 1) * 32;
> - if (gic_irqs > 1020)
> - gic_irqs = 1020;
> + if (gic_irqs > max_nr_irq)
> + gic_irqs = max_nr_irq;
> gic->gic_irqs = gic_irqs;
>
> gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
> @@ -1069,6 +1133,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
> }
> IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
> IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
> +IRQCHIP_DECLARE(hip04_gic, "hisilicon,hip04-gic", gic_of_init);
> IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
> IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
Overall, there is still some work required to make this patch
acceptable. The whole change could be much simpler and less
controvertial if you didn't obfuscate the handling of the 16 CPU-IF case
with so much bit arithmetic. Most of this code is on a slow path anyway,
so you're not even optimizing anything that would be performance
critical.
Cheers,
M.
--
Jazz is not dead. It just smells funny.
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 13/13] virt: arm: support hip04 gic
2014-04-18 6:05 ` [PATCH v3 13/13] virt: arm: support hip04 gic Haojian Zhuang
@ 2014-04-22 12:15 ` Marc Zyngier
2014-04-25 1:16 ` Haojian Zhuang
0 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2014-04-22 12:15 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Apr 18 2014 at 7:05:56 am BST, Haojian Zhuang <haojian.zhuang@linaro.org> wrote:
> In HiP04 SoC, the address of GICH_APR & GICH_LR0 registers are different
> from ARM standard SoC. So add the support of HiP04 SoC in VGIC.
Please explain the differences in the commit message.
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
> ---
> arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++----
> include/linux/irqchip/arm-gic.h | 3 +++
> virt/kvm/arm/vgic.c | 10 ++++++++--
> 3 files changed, 30 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
> index 76af9302..13e4144 100644
> --- a/arch/arm/kvm/interrupts_head.S
> +++ b/arch/arm/kvm/interrupts_head.S
> @@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0
> ldr r7, [r2, #GICH_EISR1]
> ldr r8, [r2, #GICH_ELRSR0]
> ldr r9, [r2, #GICH_ELRSR1]
> - ldr r10, [r2, #GICH_APR]
> + ldr r10, =gich_apr
> + ldr r10, [r10]
> + ldr r10, [r2, r10]
>
> str r3, [r11, #VGIC_CPU_HCR]
> str r4, [r11, #VGIC_CPU_VMCR]
> @@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0
> str r5, [r2, #GICH_HCR]
>
> /* Save list registers */
> - add r2, r2, #GICH_LR0
> + ldr r10, =gich_lr0
> + ldr r10, [r10]
> + add r2, r2, r10
> add r3, r11, #VGIC_CPU_LR
> ldr r4, [r11, #VGIC_CPU_NR_LR]
> 1: ldr r6, [r2], #4
> @@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0
>
> str r3, [r2, #GICH_HCR]
> str r4, [r2, #GICH_VMCR]
> - str r8, [r2, #GICH_APR]
> + ldr r6, =gich_apr
> + ldr r6, [r6]
> + str r8, [r2, r6]
>
> /* Restore list registers */
> - add r2, r2, #GICH_LR0
> + ldr r6, =gich_lr0
> + ldr r6, [r6]
> + add r2, r2, r6
> add r3, r11, #VGIC_CPU_LR
> ldr r4, [r11, #VGIC_CPU_NR_LR]
> 1: ldr r6, [r3], #4
So we get four extra memory accesses per world switch, just to find out
about the new fancy memory map. Let's just say that I'm not exactly
pleased.
How about encoding that in the field containing the number of LRs? the
distance between GICH_APR and GICH_LR0 is constant (0x10), so we only
need to encode the offset of GICH_APR. This way, we only have to read
one single word from memory. Not pretty, but I'm not really willing to
impact
> @@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0
> .macro load_vcpu
> mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR
> .endm
> +
> + .global gich_apr
> +gich_apr:
> + .long GICH_APR
> + .global gich_lr0
> +gich_lr0:
> + .long GICH_LR0
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 55933aa..653525b 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -49,6 +49,8 @@
> #define GICH_ELRSR1 0x34
> #define GICH_APR 0xf0
> #define GICH_LR0 0x100
> +#define HIP04_GICH_APR 0x70
> +#define HIP04_GICH_LR0 0x80
>
> #define GICH_HCR_EN (1 << 0)
> #define GICH_HCR_UIE (1 << 1)
> @@ -78,6 +80,7 @@
> struct device_node;
>
> extern struct irq_chip gic_arch_extn;
> +extern unsigned int gich_apr, gich_lr0;
>
> void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
> u32 offset, struct device_node *);
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 47b2983..010e491 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void)
>
> vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic");
> if (!vgic_node) {
> - kvm_err("error: no compatible vgic node in DT\n");
> - return -ENODEV;
> + vgic_node = of_find_compatible_node(NULL, NULL,
> + "hisilicon,hip04-gic");
> + if (!vgic_node) {
> + kvm_err("error: no compatible vgic node in DT\n");
> + return -ENODEV;
> + }
> + gich_apr = HIP04_GICH_APR;
> + gich_lr0 = HIP04_GICH_LR0;
Consider using of_find_matching_node_and_match instead, with a set of
flags for this particular case.
> }
>
> vgic_maint_irq = irq_of_parse_and_map(vgic_node, 0);
Thanks,
M.
--
Jazz is not dead. It just smells funny.
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 13/13] virt: arm: support hip04 gic
2014-04-22 12:15 ` Marc Zyngier
@ 2014-04-25 1:16 ` Haojian Zhuang
0 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-25 1:16 UTC (permalink / raw)
To: linux-arm-kernel
On 22 April 2014 20:15, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On Fri, Apr 18 2014 at 7:05:56 am BST, Haojian Zhuang <haojian.zhuang@linaro.org> wrote:
>> In HiP04 SoC, the address of GICH_APR & GICH_LR0 registers are different
>> from ARM standard SoC. So add the support of HiP04 SoC in VGIC.
>
> Please explain the differences in the commit message.
>
OK. I'll append it.
>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>> ---
>> arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++----
>> include/linux/irqchip/arm-gic.h | 3 +++
>> virt/kvm/arm/vgic.c | 10 ++++++++--
>> 3 files changed, 30 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
>> index 76af9302..13e4144 100644
>> --- a/arch/arm/kvm/interrupts_head.S
>> +++ b/arch/arm/kvm/interrupts_head.S
>> @@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0
>> ldr r7, [r2, #GICH_EISR1]
>> ldr r8, [r2, #GICH_ELRSR0]
>> ldr r9, [r2, #GICH_ELRSR1]
>> - ldr r10, [r2, #GICH_APR]
>> + ldr r10, =gich_apr
>> + ldr r10, [r10]
>> + ldr r10, [r2, r10]
>>
>> str r3, [r11, #VGIC_CPU_HCR]
>> str r4, [r11, #VGIC_CPU_VMCR]
>> @@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0
>> str r5, [r2, #GICH_HCR]
>>
>> /* Save list registers */
>> - add r2, r2, #GICH_LR0
>> + ldr r10, =gich_lr0
>> + ldr r10, [r10]
>> + add r2, r2, r10
>> add r3, r11, #VGIC_CPU_LR
>> ldr r4, [r11, #VGIC_CPU_NR_LR]
>> 1: ldr r6, [r2], #4
>> @@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0
>>
>> str r3, [r2, #GICH_HCR]
>> str r4, [r2, #GICH_VMCR]
>> - str r8, [r2, #GICH_APR]
>> + ldr r6, =gich_apr
>> + ldr r6, [r6]
>> + str r8, [r2, r6]
>>
>> /* Restore list registers */
>> - add r2, r2, #GICH_LR0
>> + ldr r6, =gich_lr0
>> + ldr r6, [r6]
>> + add r2, r2, r6
>> add r3, r11, #VGIC_CPU_LR
>> ldr r4, [r11, #VGIC_CPU_NR_LR]
>> 1: ldr r6, [r3], #4
>
> So we get four extra memory accesses per world switch, just to find out
> about the new fancy memory map. Let's just say that I'm not exactly
> pleased.
>
> How about encoding that in the field containing the number of LRs? the
> distance between GICH_APR and GICH_LR0 is constant (0x10), so we only
> need to encode the offset of GICH_APR. This way, we only have to read
> one single word from memory. Not pretty, but I'm not really willing to
> impact
>
Yes, it's better.
>
>> @@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0
>> .macro load_vcpu
>> mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR
>> .endm
>> +
>> + .global gich_apr
>> +gich_apr:
>> + .long GICH_APR
>> + .global gich_lr0
>> +gich_lr0:
>> + .long GICH_LR0
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 55933aa..653525b 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -49,6 +49,8 @@
>> #define GICH_ELRSR1 0x34
>> #define GICH_APR 0xf0
>> #define GICH_LR0 0x100
>> +#define HIP04_GICH_APR 0x70
>> +#define HIP04_GICH_LR0 0x80
>>
>> #define GICH_HCR_EN (1 << 0)
>> #define GICH_HCR_UIE (1 << 1)
>> @@ -78,6 +80,7 @@
>> struct device_node;
>>
>> extern struct irq_chip gic_arch_extn;
>> +extern unsigned int gich_apr, gich_lr0;
>>
>> void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
>> u32 offset, struct device_node *);
>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>> index 47b2983..010e491 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void)
>>
>> vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic");
>> if (!vgic_node) {
>> - kvm_err("error: no compatible vgic node in DT\n");
>> - return -ENODEV;
>> + vgic_node = of_find_compatible_node(NULL, NULL,
>> + "hisilicon,hip04-gic");
>> + if (!vgic_node) {
>> + kvm_err("error: no compatible vgic node in DT\n");
>> + return -ENODEV;
>> + }
>> + gich_apr = HIP04_GICH_APR;
>> + gich_lr0 = HIP04_GICH_LR0;
>
> Consider using of_find_matching_node_and_match instead, with a set of
> flags for this particular case.
>
OK. I'll use it.
Thanks
Haojian
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 05/13] irq: gic: support hip04 gic
2014-04-22 10:47 ` Marc Zyngier
@ 2014-04-25 2:52 ` Haojian Zhuang
0 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-25 2:52 UTC (permalink / raw)
To: linux-arm-kernel
On 22 April 2014 18:47, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Hi Haojian,
>
> On Fri, Apr 18 2014 at 7:05:48 am BST, Haojian Zhuang <haojian.zhuang@linaro.org> wrote:
>> There's a little difference between ARM GIC and HiP04 GIC.
>>
>> * HiP04 GIC could support 16 cores at most, and ARM GIC could support
>> 8 cores at most. So the difination on GIC_DIST_SGIR,
> definitions of
>> GIC_DIST_SGI_PENDING_SET, GIC_DIST_SGI_PENDING_CLEAR
>> & GIC_DIST_TARGET registers are different since CPU interfaces are
>> increased from 8-bit to 16-bit.
>>
>> * HiP04 GIC could support 510 interrupts at most, and ARM GIC could
>> support 1020 interrupts at most.
>>
>> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
>> ---
>> drivers/irqchip/irq-gic.c | 153 +++++++++++++++++++++++++++++++++-------------
>> 1 file changed, 109 insertions(+), 44 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 8fd27bf..18f3d56 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -68,6 +68,8 @@ struct gic_chip_data {
>> #ifdef CONFIG_GIC_NON_BANKED
>> void __iomem *(*get_base)(union gic_base *);
>> #endif
>> + u32 nr_cpu_if;
>> + u32 nr_if_per_reg;
>
> Which register? Surely you can compute that at runtime.
Yes, I can compute it at runtime. I'll change it.
>
>> };
>>
>> static DEFINE_RAW_SPINLOCK(irq_controller_lock);
>> @@ -76,9 +78,14 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
>> * The GIC mapping of CPU interfaces does not necessarily match
>> * the logical CPU numbering. Let's use a mapping as returned
>> * by the GIC itself.
>> + *
>> + * Hisilicon HiP04 extends the number of CPU interface from 8 to 16.
>> */
>> -#define NR_GIC_CPU_IF 8
>> -static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
>> +#define NR_GIC_CPU_IF 16
>> +static u16 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
>> +
>> +/* GIC register is always 32-bit long whatever it's in ARM64 or ARM32 */
>> +#define GIC_REG_BITS 32
>
> What doesn this buy us? I'm not sure we gain much from it.
OK. I'll remove it.
>
>> /*
>> * Supported arch specific GIC irq extension.
>> @@ -242,19 +249,50 @@ static int gic_retrigger(struct irq_data *d)
>> }
>>
>> #ifdef CONFIG_SMP
>> +static inline u32 irq_to_core_offset(u32 i, u32 nr_cpu_if)
>> +{
>
> Make this function take an irq_data pointer, and use the accessor to
> find out about the number of CPU interfaces.
Oh. No problem.
>
>> + if (nr_cpu_if == 8) {
>> + /* ARM GIC, i / 4 * 4 */
>> + return ((i >> 2) << 2);
>
> Why does the comment has one expression and the code another? I know
> they give the same result, but this is pretty useless.
>
Yes, I'll do.
>
>> + u32 mask;
>> + /* ARM GIC, nr_cpu_if == 8; HiP04 GIC, nr_cpu_if == 16 */
>> + mask = (1 << nr_cpu_if) - 1;
>> + return (mask << irq_to_core_shift(i, nr_cpu_if));
>> +}
>> +
>> static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
>> bool force)
>> {
>> - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
>> - unsigned int shift = (gic_irq(d) % 4) * 8;
>> + void __iomem *reg;
>> + unsigned int i = gic_irq(d);
>> + unsigned int shift = irq_to_core_shift(i, gic_data[0].nr_cpu_if);
>> unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
>> u32 val, mask, bit;
>> -
>> - if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
>> + if (cpu >= gic_data[0].nr_cpu_if || cpu >= nr_cpu_ids)
>> return -EINVAL;
>>
>> + reg = gic_dist_base(d) + GIC_DIST_TARGET +
>> + irq_to_core_offset(i, gic_data[0].nr_cpu_if);
>> +
>> raw_spin_lock(&irq_controller_lock);
>> - mask = 0xff << shift;
>> + mask = irq_to_core_mask(i, gic_data[0].nr_cpu_if);
>> bit = gic_cpu_map[cpu] << shift;
>> val = readl_relaxed(reg) & ~mask;
>> writel_relaxed(val | bit, reg);
>> @@ -354,15 +392,16 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
>> irq_set_chained_handler(irq, gic_handle_cascade_irq);
>> }
>>
>> -static u8 gic_get_cpumask(struct gic_chip_data *gic)
>> +static u16 gic_get_cpumask(struct gic_chip_data *gic)
>> {
>> void __iomem *base = gic_data_dist_base(gic);
>> - u32 mask, i;
>> + u32 mask, i, j, nr_if = gic->nr_if_per_reg;
>>
>> - for (i = mask = 0; i < 32; i += 4) {
>> - mask = readl_relaxed(base + GIC_DIST_TARGET + i);
>> - mask |= mask >> 16;
>> - mask |= mask >> 8;
>> + /* get the number of CPU fields in GIC_DIST_TARGET register */
>> + for (i = mask = 0; i < DIV_ROUND_UP(32, nr_if); i++) {
>> + mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
>> + for (j = GIC_REG_BITS >> 1; j >= gic->nr_cpu_if; j >>= 1)
>> + mask |= mask >> j;
>> if (mask)
>> break;
>> }
>
> This looks incredibly convoluted. How about something like the code
> below, which is way simpler and doesn't involve changing so much stuff
> (completely untested, of course):
>
> int nr_target_regs = 32 / (gic->nr_cpu_if == 8 ? 4 : 2);
> for (i = mask = 0; i < nr_target_regs; i++) {
> mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
> mask |= mask >> 16;
> if (gic->nr_cpu_if == 8)
> mask |= mask >> 8;
>
> if (mask)
> break;
> }
I'll change it.
>
>> @@ -370,12 +409,16 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
>> if (!mask)
>> pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
>>
>> + /* ARM GIC needs 8-bit cpu mask, HiP04 GIC needs 16-bit cpu mask. */
>> + if (gic->nr_cpu_if == 8)
>> + mask &= 0xff;
>> +
>> return mask;
>> }
>>
>> static void __init gic_dist_init(struct gic_chip_data *gic)
>> {
>> - unsigned int i;
>> + unsigned int i, nr_if = gic->nr_if_per_reg;
>> u32 cpumask;
>> unsigned int gic_irqs = gic->gic_irqs;
>> void __iomem *base = gic_data_dist_base(gic);
>> @@ -392,23 +435,25 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
>> * Set all global interrupts to this CPU only.
>> */
>> cpumask = gic_get_cpumask(gic);
>> - cpumask |= cpumask << 8;
>> - cpumask |= cpumask << 16;
>> - for (i = 32; i < gic_irqs; i += 4)
>> - writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
>> + for (i = gic->nr_cpu_if; i < GIC_REG_BITS; i <<= 1)
>> + cpumask |= cpumask << i;
>
> Really, you should stop adding bit arithmetics all over the
> place. You're just making a simple problem way too complex. What is
> wrong with:
>
> if (gic->nr_cpu_if == 8)
> cpumask |= cpumask << 8;
>
> ?
I'll use simple way to express it.
>
>> + for (i = 32 / nr_if; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
>> + writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4);
>
> Why do you need to DIV_ROUND_UP? GIC interrupts are always a multiple of
> 32.
>
OK. I'll remove it.
>> /*
>> * Set priority on all global interrupts.
>> */
>> - for (i = 32; i < gic_irqs; i += 4)
>> - writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
>> + for (i = 32 / nr_if; i < DIV_ROUND_UP(gic_irqs, 4); i++)
>> + writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4);
>>
>> /*
>> * Disable all interrupts. Leave the PPI and SGIs alone
>> * as these enables are banked registers.
>> */
>> - for (i = 32; i < gic_irqs; i += 32)
>> - writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
>> + i = 32 / GIC_REG_BITS;
>
> I predict this value to be the grand total of one.
>
>> + for (; i < DIV_ROUND_UP(gic_irqs, GIC_REG_BITS); i++)
>> + writel_relaxed(0xffffffff,
>> + base + GIC_DIST_ENABLE_CLEAR + i * 4);
>>
>> writel_relaxed(1, base + GIC_DIST_CTRL);
>> }
>> @@ -423,7 +468,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
>> /*
>> * Get what the GIC says our CPU mask is.
>> */
>> - BUG_ON(cpu >= NR_GIC_CPU_IF);
>> + BUG_ON(cpu >= gic->nr_cpu_if);
>> cpu_mask = gic_get_cpumask(gic);
>> gic_cpu_map[cpu] = cpu_mask;
>>
>> @@ -431,7 +476,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
>> * Clear our mask from the other map entries in case they're
>> * still undefined.
>> */
>> - for (i = 0; i < NR_GIC_CPU_IF; i++)
>> + for (i = 0; i < gic->nr_cpu_if; i++)
>> if (i != cpu)
>> gic_cpu_map[i] &= ~cpu_mask;
>>
>> @@ -445,8 +490,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)
>> /*
>> * Set priority on PPI and SGI interrupts
>> */
>> - for (i = 0; i < 32; i += 4)
>> - writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
>> + for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
>> + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>>
>> writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
>> writel_relaxed(1, base + GIC_CPU_CTRL);
>> @@ -467,7 +512,7 @@ void gic_cpu_if_down(void)
>> */
>> static void gic_dist_save(unsigned int gic_nr)
>> {
>> - unsigned int gic_irqs;
>> + unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;
>> void __iomem *dist_base;
>> int i;
>>
>> @@ -484,7 +529,7 @@ static void gic_dist_save(unsigned int gic_nr)
>> gic_data[gic_nr].saved_spi_conf[i] =
>> readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
>>
>> - for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
>> + for (i = 0; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
>> gic_data[gic_nr].saved_spi_target[i] =
>> readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
>>
>> @@ -502,7 +547,7 @@ static void gic_dist_save(unsigned int gic_nr)
>> */
>> static void gic_dist_restore(unsigned int gic_nr)
>> {
>> - unsigned int gic_irqs;
>> + unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;
>> unsigned int i;
>> void __iomem *dist_base;
>>
>> @@ -525,7 +570,7 @@ static void gic_dist_restore(unsigned int gic_nr)
>> writel_relaxed(0xa0a0a0a0,
>> dist_base + GIC_DIST_PRI + i * 4);
>>
>> - for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
>> + for (i = 0; i < DIV_ROUND_UP(gic_irqs, nr_if); i++)
>> writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
>> dist_base + GIC_DIST_TARGET + i * 4);
>>
>> @@ -665,9 +710,15 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>> */
>> dmb(ishst);
>>
>> - /* this always happens on GIC0 */
>> - writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>> -
>> + /*
>> + * CPUTargetList -- bit[23:16] in GIC_DIST_SOFTINT in ARM GIC.
>> + * bit[23:8] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC.
>> + * NSATT -- bit[15] in GIC_DIST_SOFTINT in ARM GIC.
>> + * bit[7] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC.
>> + * this always happens on GIC0
>> + */
>> + writel_relaxed(map << (16 + 8 - gic_data[0].nr_cpu_if) | irq,
>> + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>
> Make this two cases. This bit arithmetic makes it unreadable. Also, why
> does the comment makes the GIC_DIST_SOFTINT/HIP04_GIC_DIST_SOFTINT
> distinction, while the code only refers to GIC_DIST_SOFTINT?
OK. I'll make it simpler.
>
>> raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
>> }
>> #endif
>> @@ -681,10 +732,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>> */
>> void gic_send_sgi(unsigned int cpu_id, unsigned int irq)
>> {
>> - BUG_ON(cpu_id >= NR_GIC_CPU_IF);
>> + BUG_ON(cpu_id >= gic_data[0].nr_cpu_if);
>> cpu_id = 1 << cpu_id;
>> /* this always happens on GIC0 */
>> - writel_relaxed((cpu_id << 16) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>> + writel_relaxed((cpu_id << (16 + 8 - gic_data[0].nr_cpu_if)) | irq,
>> + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>
> Same here.
>
>> }
>>
>> /*
>> @@ -700,7 +752,7 @@ int gic_get_cpu_id(unsigned int cpu)
>> {
>> unsigned int cpu_bit;
>>
>> - if (cpu >= NR_GIC_CPU_IF)
>> + if (cpu >= gic_data[0].nr_cpu_if)
>> return -1;
>> cpu_bit = gic_cpu_map[cpu];
>> if (cpu_bit & (cpu_bit - 1))
>> @@ -771,10 +823,10 @@ void gic_migrate_target(unsigned int new_cpu_id)
>> */
>> for (i = 0; i < 16; i += 4) {
>> int j;
>> - val = readl_relaxed(dist_base + GIC_DIST_SGI_PENDING_SET + i);
>> + val = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i);
>> if (!val)
>> continue;
>> - writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i);
>> + writel_relaxed(val, dist_base + GIC_DIST_PENDING_CLEAR + i);
>
> What? Hell no. This is the SGI sources we're dealing with. And I'd
> expect your implementation to be quite different.
>
>> for (j = i; j < i + 4; j++) {
>> if (val & 0xff)
>> writel_relaxed((1 << (new_cpu_id + 16)) | j,
>> @@ -931,7 +983,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>> irq_hw_number_t hwirq_base;
>> struct gic_chip_data *gic;
>> int gic_irqs, irq_base, i;
>> - int nr_routable_irqs;
>> + int nr_routable_irqs, max_nr_irq;
>>
>> BUG_ON(gic_nr >= MAX_GIC_NR);
>>
>> @@ -967,12 +1019,23 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>> gic_set_base_accessor(gic, gic_get_common_base);
>> }
>>
>> + if (of_device_is_compatible(node, "hisilicon,hip04-gic")) {
>> + /* HiP04 GIC supports 16 CPUs at most */
>> + gic->nr_cpu_if = 16;
>> + max_nr_irq = 510;
>> + } else {
>> + /* ARM/Qualcomm GIC supports 8 CPUs at most */
>> + gic->nr_cpu_if = 8;
>> + max_nr_irq = 1020;
>> + }
>> + gic->nr_if_per_reg = GIC_REG_BITS / gic->nr_cpu_if;
>> +
>
> Loose this last line, and do the explicit computation. where needed. I
> don't this this adds anything.
OK.
>
>> /*
>> * Initialize the CPU interface map to all CPUs.
>> * It will be refined as each CPU probes its ID.
>> */
>> - for (i = 0; i < NR_GIC_CPU_IF; i++)
>> - gic_cpu_map[i] = 0xff;
>> + for (i = 0; i < gic->nr_cpu_if; i++)
>> + gic_cpu_map[i] = (1 << gic->nr_cpu_if) - 1;
>>
>> /*
>> * For primary GICs, skip over SGIs.
>> @@ -988,12 +1051,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>
>> /*
>> * Find out how many interrupts are supported.
>> - * The GIC only supports up to 1020 interrupt sources.
>> + * The ARM/Qualcomm GIC only supports up to 1020 interrupt sources.
>> + * The HiP04 GIC only supports up to 510 interrupt sources.
>> */
>> gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
>> gic_irqs = (gic_irqs + 1) * 32;
>> - if (gic_irqs > 1020)
>> - gic_irqs = 1020;
>> + if (gic_irqs > max_nr_irq)
>> + gic_irqs = max_nr_irq;
>> gic->gic_irqs = gic_irqs;
>>
>> gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
>> @@ -1069,6 +1133,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
>> }
>> IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
>> IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
>> +IRQCHIP_DECLARE(hip04_gic, "hisilicon,hip04-gic", gic_of_init);
>> IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
>> IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
>
> Overall, there is still some work required to make this patch
> acceptable. The whole change could be much simpler and less
> controvertial if you didn't obfuscate the handling of the 16 CPU-IF case
> with so much bit arithmetic. Most of this code is on a slow path anyway,
> so you're not even optimizing anything that would be performance
> critical.
>
> Cheers,
>
> M.
> --
> Jazz is not dead. It just smells funny.
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 07/13] ARM: hisi: add hip04 SoC support
2014-04-22 4:08 ` Nicolas Pitre
@ 2014-04-25 3:00 ` Haojian Zhuang
0 siblings, 0 replies; 26+ messages in thread
From: Haojian Zhuang @ 2014-04-25 3:00 UTC (permalink / raw)
To: linux-arm-kernel
On 22 April 2014 12:08, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> On Fri, 18 Apr 2014, Haojian Zhuang wrote:
>
>> +
>> + data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
>> + CORE_DEBUG_RESET_BIT(cpu);
>> + writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
>
> It might be a good idea to reset and initialize things only if
> hip04_cpu_table[cluster][cpu] was zero initially. Please see the
> comment in mcpm_cpu_power_down() discussing concurrent up/down
> operations, and the way races are handled using dcscb_use_count in
> dcscb_power_up() / dcscb_power_down() for example.
>
I'll use it as reference.
>> + spin_unlock(&boot_lock);
>> + msleep(POLL_MSEC);
>
> You don't have to wait here. The MCPM up method should set things for
> the CPU to come up eventually and that CPU to signal itself when it is
> finally online.
>
I have to wait. Otherwise, I'll meet hang when make the CPU offline &
online continuously.
>> + return 0;
>> +}
>> +
>> +static void hip04_mcpm_power_down(void)
>> +{
>> + unsigned int mpidr, cpu, cluster;
>> + unsigned int v;
>> +
>> + mpidr = read_cpuid_mpidr();
>> + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +
>> + 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;
>> + }
>
> This is wrong. Please see dcscb_power_down() or tc2_pm_down() for
> examples of how to deal with this situation.
>
>> + __mcpm_cpu_down(cpu, cluster);
>
> That call should happen last i.e. after coherency has been disabled and
> the CPU is about to call WFI. Again, see the TC2 implementation for
> example. You may also read
> Documentation/arm/cluster-pm-race-avoidance.txt for more details about
> those calls and the algorithm behind them.
>
>> + spin_unlock(&boot_lock);
>> +
>> + 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)
>> + :);
>> +
>> + flush_cache_louis();
>> +
>> + asm volatile(
>> + /* Turn off coherency, disable SMP bit in ACTLR */
>> + " 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)
>> + :);
>
> The above code is not safe.
>
> You should use v7_exit_coherency_flush() instead.
>
OK.
>> + isb();
>> + dsb();
>> +
>> + while (true)
>> + wfi();
>
> This is wrong. By the time execution gets here, it is well possible
> that another CPU decided that this CPU should not be down anymore, in
> which case wfi() will return. See what's expected in this case by
> looking at mcpm_cpu_power_down() and what other backend implementations
> do.
>
>> + return;
>> +out:
>> + spin_unlock(&boot_lock);
>> +}
>> +
>> +static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
>> +{
>> + unsigned int data, tries;
>> +
>> + BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
>> + cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
>> +
>> + for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; tries++) {
>> + data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
>> + if (!(data & CORE_WFI_STATUS(cpu))) {
>> + msleep(POLL_MSEC);
>> + continue;
>> + }
>> + data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
>> + CORE_DEBUG_RESET_BIT(cpu);
>> + writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
>
> Why are you resetting those here?
>
Do you mean that I should move this reset code into hip04_mcpm_power_down()?
Regards
Haojian
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2014-04-25 3:00 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-18 6:05 [PATCH v3 00/13] enable Hisilicon HiP04 SoC Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 01/13] ARM: debug: add HiP04 debug uart Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 02/13] ARM: append ARCH_MULTI_V7_LPAE Haojian Zhuang
2014-04-18 6:56 ` Gregory CLEMENT
2014-04-18 7:08 ` Haojian Zhuang
2014-04-18 7:18 ` Gregory CLEMENT
2014-04-18 7:40 ` Haojian Zhuang
2014-04-18 7:44 ` Gregory CLEMENT
2014-04-18 6:05 ` [PATCH v3 03/13] ARM: hisi: add ARCH_HISI Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 04/13] irq: gic: use mask field in GICC_IAR Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 05/13] irq: gic: support hip04 gic Haojian Zhuang
2014-04-22 10:47 ` Marc Zyngier
2014-04-25 2:52 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 06/13] ARM: mcpm: support 4 clusters in HiP04 Haojian Zhuang
2014-04-22 3:09 ` Nicolas Pitre
2014-04-18 6:05 ` [PATCH v3 07/13] ARM: hisi: add hip04 SoC support Haojian Zhuang
2014-04-22 4:08 ` Nicolas Pitre
2014-04-25 3:00 ` Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 08/13] ARM: dts: add hip04-d01 dts file Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 09/13] ARM: config: append hip04_defconfig Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 10/13] ARM: config: select ARCH_HISI in hi3xxx_defconfig Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 11/13] ARM: hisi: enable erratum 798181 of A15 on HiP04 Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 12/13] ARM: dts: Add PMU support in HiP04 Haojian Zhuang
2014-04-18 6:05 ` [PATCH v3 13/13] virt: arm: support hip04 gic Haojian Zhuang
2014-04-22 12:15 ` Marc Zyngier
2014-04-25 1:16 ` Haojian Zhuang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).