Skip to contentSkip to conversation

enable HiP04 SoC

PATCH Superseded Haojian Zhuang 4 participants 21 messages Aug 4, 2014 – Aug 24, 2014

Subsystems (7)

v16 of 17 Superseded Latest is v17 →

lore
Share & tools
lore
#0 lore raw

v16 cover enable HiP04 SoC

Changelog:
v16:
* Create new hip04 interrupt controller driver.
* Drop both hip04_defconfig & multi_v7_lpae_defconfig. Use hisi_defconfig & multi_v7_defconfig instead.
* Rename hi3xxx_defconfig to hisi_defconfig. Since we need follow the rule of each vendor only using one defconfig.
* Fix parsing memory issue in FDT when 64-bit address is enabled without CONFIG_ARM_LPAE.
* Drop bootwrapper parameters from DTS file. Use command line instead.
* Declare clock node in DTS file since all these clocks are only fixed rate clocks.
* Drop vgic patch.

v15:
* Add p04 debug uart back.
* Refresh since hix5hd2 code updated.

v14:
* Mount function pointers to different implementation on standard GICv2 and Hisilicon HiP04 GIC.

v13:
* Restore power down operation in MCPM.
* Fix disabling snoop filter issue in MCPM.

v12:
* Use wfi as power down state in MCPM.
* Remove wait_for_powerdown() in MCPM because wfi is used now.

v11:
* Fix the protection issue on mcpm power down.
* Clean assembly code in mcpm power up.

v10:
* Move snoop filter code to be executed on secondary cores. And change it to assembly code since MMU isn't enabled at that time.
* Rebase irq gic patch on latest gic patch.
* Use global variable in irq gic patch.
* Use global variable in vgic patch.
* Drop debug uart patch since it's in another patch set.
* Remove some ARCHs from multi_v7_lpae_defconfig.

v9:
* Remove delay workaround in mcpm implementation.
* Clean in gic.
* Rename vgic_cpu_nr_lr to vgic_cpu_hw_cfg in vgic driver.
* Always use high word of vgic_cpu_hw_cfg for GICH_APR offset. So the implementation of arm64 is also updated.
* Drop "irq: gic: use mask field in GICC_IAR" patch since it's merged.

v7:
* Remove hip04_smp_init_ops().
* Remove CONFIG_ARCH_HIP04 in hisilicn.c since hip04_smp_init_ops() is removed.

v6:
* Split HiP04 enabling patch into patches on document, mcpm & hiP04.
* Move reset operation in HiP04 MCPM implementation.
* Remove ARCH_MULTI_V7_NONLPAE & ARCH_MULTI_V7_LPAE according to olof's comment.

v5:
* Add ARCH_MULTI_V7_NONLPAE to avoid change too much things in Kconfig.
* Use memreserve in DTS.
* Remove L2 reset operation in mcpm implementation.
* Re-use nr_lr field to cover HIP04 GICH_APR implementation.
* Add more comments.

v4:
* Add multi_v7_lpae_defconfig.
* Select CONFIG_ARCH_MULTI_V7_LPAE if CONFIG_ARCH_MULTI_V7 is selected.
* Only ARMADA_XP is ARCH_MULTI_V7_LPAE, other ARMADA chips are ARCH_MULTI_V7.
* Remove gich_lr0 variable since we can calculate offset of GICH_LR0 from GICH_APR.
* Cleanup GIC driver to support HiP04 GIC.
* Cleanup HiP04 mcpm implementation.

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 (9):
ARM: mcpm: support 4 clusters
ARM: hisi: enable MCPM implementation
ARM: hisi: enable HiP04
document: dt: add the binding on HiP04
ARM: dts: add hip04 dts
ARM: config: enable hisilicon hip04
ARM: debug: add HiP04 debug uart
irq: enable hip04 irq chip
of: fdt: fix memory address be truncated

 .../bindings/arm/hisilicon/hisilicon.txt           |  12 +
 arch/arm/Kconfig                                   |   9 +
 arch/arm/Kconfig.debug                             |  10 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/hip04-d01.dts                    |  32 ++
 arch/arm/boot/dts/hip04.dtsi                       | 262 +++++++++++++
 arch/arm/configs/hi3xxx_defconfig                  |  58 ---
 arch/arm/configs/hisi_defconfig                    |  72 ++++
 arch/arm/configs/multi_v7_defconfig                |   2 +
 arch/arm/include/asm/mcpm.h                        |   5 +
 arch/arm/mach-hisi/Kconfig                         |   9 +
 arch/arm/mach-hisi/Makefile                        |   1 +
 arch/arm/mach-hisi/hisilicon.c                     |   9 +
 arch/arm/mach-hisi/platmcpm.c                      | 374 ++++++++++++++++++
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-hip04.c                        | 429 +++++++++++++++++++++
 drivers/of/fdt.c                                   |  10 +
 17 files changed, 1238 insertions(+), 58 deletions(-)
 create mode 100644 arch/arm/boot/dts/hip04-d01.dts
 create mode 100644 arch/arm/boot/dts/hip04.dtsi
 delete mode 100644 arch/arm/configs/hi3xxx_defconfig
 create mode 100644 arch/arm/configs/hisi_defconfig
 create mode 100644 arch/arm/mach-hisi/platmcpm.c
 create mode 100644 drivers/irqchip/irq-hip04.c
Signature · 1 line
1.9.1
#1 lore raw

PATCH v16 1/9 ARM: mcpm: support 4 clusters

Add the CONFIG_MCPM_QUAD_CLUSTER configuration to enlarge cluster number from 2 to 4.

---
 arch/arm/Kconfig            | 9 +++++++++
 arch/arm/include/asm/mcpm.h | 5 +++++
 2 files changed, 14 insertions(+)
arch/arm/Kconfig +9 -0
index 87b63fd..10cc6ec 100644
@@ -1490,6 +1490,15 @@ config MCPM
 	  for (multi-)cluster based systems, such as big.LITTLE based
 	  systems.
 
+config MCPM_QUAD_CLUSTER
+	bool
+	depends on MCPM
+	help
+	  To avoid wasting resources unnecessarily, MCPM only supports up
+	  to 2 clusters by default.
+	  Platforms with 3 or 4 clusters that use MCPM must select this
+	  option to allow the additional clusters to be managed.
+
 config BIG_LITTLE
 	bool "big.LITTLE support (Experimental)"
 	depends on CPU_V7 && SMP
arch/arm/include/asm/mcpm.h +5 -0
index d9702eb..a4fbacc 100644
@@ -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__
 
Signature · 1 line
1.9.1
#2 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

In reply to Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.
v13:
* Restore power down operation in MCPM.
* Fix disabling snoop filter issue in MCPM.
v12:
* Use wfi as power down state in MCPM.
* Remove wait_for_powerdown() in MCPM because wfi is used now.

---
 arch/arm/mach-hisi/Makefile   |   1 +
 arch/arm/mach-hisi/platmcpm.c | 374 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 375 insertions(+)
 create mode 100644 arch/arm/mach-hisi/platmcpm.c
arch/arm/mach-hisi/Makefile +1 -0
index ee2506b..d64831e 100644
@@ -3,4 +3,5 @@
 #
 
 obj-y	+= hisilicon.o
+obj-$(CONFIG_MCPM)		+= platmcpm.o
 obj-$(CONFIG_SMP)		+= platsmp.o hotplug.o headsmp.o
arch/arm/mach-hisi/platmcpm.c new file +374 -0

374 lines not on this page · raw message

Signature · 1 line
1.9.1
#3 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Quoted 8 lines

v13:
* Restore power down operation in MCPM.
* Fix disabling snoop filter issue in MCPM.
v12:
* Use wfi as power down state in MCPM.
* Remove wait_for_powerdown() in MCPM because wfi is used now.

More comments below.

Quoted 96 lines
---
 arch/arm/mach-hisi/Makefile   |   1 +
 arch/arm/mach-hisi/platmcpm.c | 374 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 375 insertions(+)
 create mode 100644 arch/arm/mach-hisi/platmcpm.c
arch/arm/mach-hisi/Makefile +1 -0
index ee2506b..d64831e 100644
@@ -3,4 +3,5 @@
 #
 
 obj-y	+= hisilicon.o
+obj-$(CONFIG_MCPM)		+= platmcpm.o
 obj-$(CONFIG_SMP)		+= platsmp.o hotplug.o headsmp.o
arch/arm/mach-hisi/platmcpm.c new file +74 -0
new file mode 100644
index 0000000..fc17973
@@ -0,0 +1,374 @@
+/*
+ * 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 u32 fabric_phys_addr;
+
+static int __init hip04_parse_bootwrapper(char *p)
+{
+	int data[4];

arch/arm/mach-hisi/platmcpm.c line 84

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+
+	get_options(p, ARRAY_SIZE(data), &data[0]);
+	if (!data[0] || (data[0] < 3)) {
+		pr_err("fail to parse bootwrapper parameters\n");
+		return -EINVAL;
+	}
+	hip04_boot.bootwrapper_phys = data[1];
+	hip04_boot.bootwrapper_size = data[2];
+	hip04_boot.bootwrapper_magic = data[3];
+	memblock_reserve(data[1], data[2]);

What if memblock_reserve() fails? You should at least avoid initializing hip04_boot in that case.

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+	return 0;
+}
+early_param("bootwrapper", hip04_parse_bootwrapper);
+
+static int __init hip04_parse_relocation(char *p)
+{
+	int data[3];
+
+	get_options(p, ARRAY_SIZE(data), &data[0]);
+	if (!data[0] || (data[0] < 2)) {

arch/arm/mach-hisi/platmcpm.c line 104

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+		pr_err("fail to parse relocation parameters\n");
+		return -EINVAL;
+	}
+	hip04_boot.relocation_entry = data[1];
+	hip04_boot.relocation_size = data[2];
+	return 0;
+}
+early_param("relocation", hip04_parse_relocation);
+
+static bool hip04_cluster_down(unsigned int cluster)

I'd suggest renaming this into hip04_cluster_is_down() as it only returns a state and performs no action.

Quoted 42 lines
arch/arm/mach-hisi/platmcpm.c new file +42 -0
+{
+	int i;
+
+	for (i = 0; i < HIP04_MAX_CPUS_PER_CLUSTER; i++)
+		if (hip04_cpu_table[cluster][i])
+			return false;
+	return true;
+}
+
+static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
+{
+	unsigned long data;
+
+	if (!fabric)
+		BUG();
+	data = readl_relaxed(fabric + FAB_SF_MODE);
+	if (on)
+		data |= 1 << cluster;
+	else
+		data &= ~(1 << cluster);
+	writel_relaxed(data, fabric + FAB_SF_MODE);
+	while (1) {
+		if (data == readl_relaxed(fabric + FAB_SF_MODE))
+			break;
+	}
+	return;
+}
+
+static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
+{
+	unsigned long data, mask;
+
+	if (!relocation || !sysctrl)
+		return -ENODEV;
+	if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
+		return -EINVAL;
+
+	spin_lock_irq(&boot_lock);
+
+	if (hip04_cpu_table[cluster][cpu])
+		goto out;
+

arch/arm/mach-hisi/platmcpm.c line 156

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+	/* Make secondary core out of reset. */
+	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_DEBUG_RESET_BIT;
+		writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+		do {

Inserting a cpu_relax() right here wouldn't hurt.

Quoted 30 lines
arch/arm/mach-hisi/platmcpm.c new file +30 -0
+			mask = CLUSTER_DEBUG_RESET_STATUS;
+			data = readl_relaxed(sysctrl + \
+					     SC_CPU_RESET_STATUS(cluster));
+		} while (data & mask);
+	}
+
+	data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+	       CORE_DEBUG_RESET_BIT(cpu);
+	writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+out:
+	hip04_cpu_table[cluster][cpu]++;
+	spin_unlock_irq(&boot_lock);
+
+	return 0;
+}
+
+static void hip04_mcpm_power_down(void)
+{
+	unsigned int mpidr, cpu, cluster;
+	bool skip_wfi = false;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	__mcpm_cpu_going_down(cpu, cluster);
+
+	spin_lock(&boot_lock);
+	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+	hip04_cpu_table[cluster][cpu]--;

arch/arm/mach-hisi/platmcpm.c line 196

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+	if (hip04_cpu_table[cluster][cpu] == 1) {
+		/* A power_up request went ahead of us. */
+		skip_wfi = true;
+	} else if (hip04_cpu_table[cluster][cpu] > 1) {
+		pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu);
+		BUG();
+	}
+	spin_unlock(&boot_lock);
+
+	v7_exit_coherency_flush(louis);

If this is the last man, the whole cache must be flushed with v7_exit_coherency_flush(all).

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+
+	__mcpm_cpu_down(cpu, cluster);
+
+	if (!skip_wfi)
+		wfi();
+}
+
+static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int data, tries, count;

arch/arm/mach-hisi/platmcpm.c line 216

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+
+	BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
+	       cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
+
+	count = TIMEOUT_MSEC / POLL_MSEC;
+	spin_lock(&boot_lock);
+	for (tries = 0; tries < count; tries++) {
+		data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
+		if (!(data & CORE_WFI_STATUS(cpu))) {
+			msleep(POLL_MSEC);

You can't sleep while holding a lock.

arch/arm/mach-hisi/platmcpm.c line 228

Quoted 12 lines
arch/arm/mach-hisi/platmcpm.c new file +12 -0
+			continue;
+		}
+	}
+	if (tries >= count)
+		goto err;
+	data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+	       CORE_DEBUG_RESET_BIT(cpu);
+	writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
+	for (tries = 0; tries < count; tries++) {
+		data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
+		if (!(data & CORE_RESET_STATUS(cpu))) {
+			msleep(POLL_MSEC);

Same here.

Also I don't really like the way this MCPM method is abused to shut down a CPU because the target CPU can't do it on its own. We're getting back to this again and I suppose this is because the hardware is not able to do otherwise. However this mysterious CORE_WFI_STATUS bit made its apparition lately, so one may speculate that the hardware might be able to do more than it may seem. The lack of (english) documentation is really making a more optimal implementation impossible at this point. So I'll give in and let this pass but not without a sufficiently comprehensive comment in the code to that effect.

Now... around msleep calls you have to drop and reacquire the lock. And when the lock is reacquired you should check that the CPU count is still 0 and bail out otherwise so not to mess up with a concurrent cpu_up(). This won't be enough to prevent a race against asynchronous wake-ups though, but you are not doing any of that yet. That too would need to be documented in that comment.

arch/arm/mach-hisi/platmcpm.c line 236

Quoted 8 lines
arch/arm/mach-hisi/platmcpm.c new file +8 -0
+			continue;
+		}
+	}
+	if (tries >= count)
+		goto err;
+	if (hip04_cluster_down(cluster))
+		hip04_set_snoop_filter(cluster, 0);
+	spin_unlock(&boot_lock);

Oh, and that ought to be spin_lock_irq()/spin_unlock_irq() here.

Quoted 61 lines
arch/arm/mach-hisi/platmcpm.c new file +61 -0
+	return 0;
+err:
+	spin_unlock(&boot_lock);
+	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 void __naked hip04_mcpm_power_up_setup(unsigned int affinity_level)
+{
+	asm volatile ("			\n"
+"	cmp	r0, #0			\n"
+"	bxeq	lr			\n"
+	/* calculate fabric phys address */
+"	adr	r2, 2f			\n"
+"	ldmia	r2, {r1, r3}		\n"
+"	sub	r0, r2, r1		\n"
+"	ldr	r2, [r0, r3]		\n"
+	/* get cluster id from MPIDR */
+"	mrc	p15, 0, r0, c0, c0, 5	\n"
+"	ubfx	r1, r0, #8, #8		\n"
+	/* 1 << cluster id */
+"	mov	r0, #1			\n"
+"	mov	r3, r0, lsl r1		\n"
+"	ldr	r0, [r2, #"__stringify(FAB_SF_MODE)"]	\n"
+"	tst	r0, r3			\n"
+"	bxne	lr			\n"
+"	orr	r1, r0, r3		\n"
+"	str	r1, [r2, #"__stringify(FAB_SF_MODE)"]	\n"
+"1:	ldr	r0, [r2, #"__stringify(FAB_SF_MODE)"]	\n"
+"	tst	r0, r3			\n"
+"	beq	1b			\n"
+"	bx	lr			\n"
+
+"	.align	2			\n"
+"2:	.word	.			\n"
+"	.word	fabric_phys_addr	\n"
+	);
+}
+
+static const struct mcpm_platform_ops hip04_mcpm_ops = {
+	.power_up		= hip04_mcpm_power_up,
+	.power_down		= hip04_mcpm_power_down,
+	.wait_for_powerdown	= hip04_mcpm_wait_for_powerdown,
+	.powered_up		= hip04_mcpm_powered_up,
+};
+
+static bool __init hip04_cpu_table_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+

arch/arm/mach-hisi/platmcpm.c line 307

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+	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(0, 1);

This should be hip04_set_snoop_filter(cluster, 1).

Quoted 48 lines
arch/arm/mach-hisi/platmcpm.c new file +48 -0
+	hip04_cpu_table[cluster][cpu] = 1;
+	return true;
+}
+
+static int __init hip04_mcpm_init(void)
+{
+	struct device_node *np, *np_fab;
+	struct resource fab_res;
+	int ret = -ENODEV;
+
+	if (!hip04_boot.bootwrapper_phys || !hip04_boot.relocation_entry) {
+		pr_err("fail to find bootwrapper or relocation param\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	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;
+
+	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;
+	}
+	ret = of_address_to_resource(np_fab, 0, &fab_res);
+	if (ret) {
+		pr_err("failed to get fabric base phys\n");
+		goto err_fabric;
+	}
+	fabric_phys_addr = fab_res.start;
+	sync_cache_w(&fabric_phys_addr);
+	fabric = of_iomap(np_fab, 0);
+	if (!fabric) {
+		pr_err("failed to get fabric base\n");
+		ret = -ENOMEM;
+		goto err_fabric;

arch/arm/mach-hisi/platmcpm.c line 365

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+	}
+
+	if (!hip04_cpu_table_init())
+		return -EINVAL;
+	ret = mcpm_platform_register(&hip04_mcpm_ops);
+	if (!ret) {
+		mcpm_sync_init(hip04_mcpm_power_up_setup);
+		pr_info("HiP04 MCPM initialized\n");
+	}
+	mcpm_smp_set_ops();

This mcpm_smp_set_ops() should be called only if MCPM registration is successful i.e. right after mcpm_sync_init inside the if conditional above.

Quoted 13 lines
arch/arm/mach-hisi/platmcpm.c new file +9 -0
+	return ret;
+err_fabric:
+	iounmap(sysctrl);
+err_sysctrl:
+	iounmap(relocation);
+err:
+	return ret;
+}
+early_initcall(hip04_mcpm_init);
Signature · 1 line
1.9.1
#4 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 7 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 3 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Quoted 9 lines
Quoted 3 lines

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Others don't agree put them into DTS file. So I move them into command line.

Quoted 112 lines
Quoted 8 lines

v13:
* Restore power down operation in MCPM.
* Fix disabling snoop filter issue in MCPM.
v12:
* Use wfi as power down state in MCPM.
* Remove wait_for_powerdown() in MCPM because wfi is used now.

More comments below.

Quoted 101 lines
---
 arch/arm/mach-hisi/Makefile   |   1 +
 arch/arm/mach-hisi/platmcpm.c | 374 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 375 insertions(+)
 create mode 100644 arch/arm/mach-hisi/platmcpm.c
arch/arm/mach-hisi/Makefile +1 -0
index ee2506b..d64831e 100644
@@ -3,4 +3,5 @@
 #
 
 obj-y        += hisilicon.o
+obj-$(CONFIG_MCPM)           += platmcpm.o
 obj-$(CONFIG_SMP)            += platsmp.o hotplug.o headsmp.o
arch/arm/mach-hisi/platmcpm.c new file +79 -0
new file mode 100644
index 0000000..fc17973
@@ -0,0 +1,374 @@
+/*
+ * 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 u32 fabric_phys_addr;
+
+static int __init hip04_parse_bootwrapper(char *p)
+{
+     int data[4];
+
+     get_options(p, ARRAY_SIZE(data), &data[0]);
+     if (!data[0] || (data[0] < 3)) {
+             pr_err("fail to parse bootwrapper parameters\n");
+             return -EINVAL;
Quoted 9 lines

arch/arm/mach-hisi/platmcpm.c line 84

Quoted 5 lines
arch/arm/mach-hisi/platmcpm.c new file +5 -0
+     }
+     hip04_boot.bootwrapper_phys = data[1];
+     hip04_boot.bootwrapper_size = data[2];
+     hip04_boot.bootwrapper_magic = data[3];
+     memblock_reserve(data[1], data[2]);

What if memblock_reserve() fails? You should at least avoid initializing hip04_boot in that case.

OK. I'll check the return value.

Quoted 15 lines
Quoted 15 lines
arch/arm/mach-hisi/platmcpm.c new file +15 -0
+     return 0;
+}
+early_param("bootwrapper", hip04_parse_bootwrapper);
+
+static int __init hip04_parse_relocation(char *p)
+{
+     int data[3];
+
+     get_options(p, ARRAY_SIZE(data), &data[0]);
+     if (!data[0] || (data[0] < 2)) {
+             pr_err("fail to parse relocation parameters\n");
+             return -EINVAL;
+     }
+     hip04_boot.relocation_entry = data[1];
+     hip04_boot.relocation_size = data[2];
Quoted 9 lines

arch/arm/mach-hisi/platmcpm.c line 104

Quoted 5 lines
arch/arm/mach-hisi/platmcpm.c new file +5 -0
+     return 0;
+}
+early_param("relocation", hip04_parse_relocation);
+
+static bool hip04_cluster_down(unsigned int cluster)

I'd suggest renaming this into hip04_cluster_is_down() as it only returns a state and performs no action.

OK.

Quoted 46 lines
Quoted 46 lines
arch/arm/mach-hisi/platmcpm.c new file +46 -0
+{
+     int i;
+
+     for (i = 0; i < HIP04_MAX_CPUS_PER_CLUSTER; i++)
+             if (hip04_cpu_table[cluster][i])
+                     return false;
+     return true;
+}
+
+static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
+{
+     unsigned long data;
+
+     if (!fabric)
+             BUG();
+     data = readl_relaxed(fabric + FAB_SF_MODE);
+     if (on)
+             data |= 1 << cluster;
+     else
+             data &= ~(1 << cluster);
+     writel_relaxed(data, fabric + FAB_SF_MODE);
+     while (1) {
+             if (data == readl_relaxed(fabric + FAB_SF_MODE))
+                     break;
+     }
+     return;
+}
+
+static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
+{
+     unsigned long data, mask;
+
+     if (!relocation || !sysctrl)
+             return -ENODEV;
+     if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
+             return -EINVAL;
+
+     spin_lock_irq(&boot_lock);
+
+     if (hip04_cpu_table[cluster][cpu])
+             goto out;
+
+     /* Make secondary core out of reset. */
+     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);
Quoted 9 lines

arch/arm/mach-hisi/platmcpm.c line 156

Quoted 6 lines
arch/arm/mach-hisi/platmcpm.c new file +6 -0
+     writel_relaxed(0, relocation + 12);
+
+     if (hip04_cluster_down(cluster)) {
+             data = CLUSTER_DEBUG_RESET_BIT;
+             writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+             do {

Inserting a cpu_relax() right here wouldn't hurt.

OK

Quoted 35 lines
Quoted 35 lines
arch/arm/mach-hisi/platmcpm.c new file +35 -0
+                     mask = CLUSTER_DEBUG_RESET_STATUS;
+                     data = readl_relaxed(sysctrl + \
+                                          SC_CPU_RESET_STATUS(cluster));
+             } while (data & mask);
+     }
+
+     data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+            CORE_DEBUG_RESET_BIT(cpu);
+     writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+out:
+     hip04_cpu_table[cluster][cpu]++;
+     spin_unlock_irq(&boot_lock);
+
+     return 0;
+}
+
+static void hip04_mcpm_power_down(void)
+{
+     unsigned int mpidr, cpu, cluster;
+     bool skip_wfi = false;
+
+     mpidr = read_cpuid_mpidr();
+     cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+     cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+     __mcpm_cpu_going_down(cpu, cluster);
+
+     spin_lock(&boot_lock);
+     BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+     hip04_cpu_table[cluster][cpu]--;
+     if (hip04_cpu_table[cluster][cpu] == 1) {
+             /* A power_up request went ahead of us. */
+             skip_wfi = true;
+     } else if (hip04_cpu_table[cluster][cpu] > 1) {
+             pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu);
Quoted 9 lines

arch/arm/mach-hisi/platmcpm.c line 196

Quoted 5 lines
arch/arm/mach-hisi/platmcpm.c new file +5 -0
+             BUG();
+     }
+     spin_unlock(&boot_lock);
+
+     v7_exit_coherency_flush(louis);

If this is the last man, the whole cache must be flushed with v7_exit_coherency_flush(all).

OK

Quoted 14 lines
Quoted 14 lines
arch/arm/mach-hisi/platmcpm.c new file +14 -0
+
+     __mcpm_cpu_down(cpu, cluster);
+
+     if (!skip_wfi)
+             wfi();
+}
+
+static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
+{
+     unsigned int data, tries, count;
+
+     BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
+            cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
+
Quoted 9 lines

arch/arm/mach-hisi/platmcpm.c line 216

Quoted 6 lines
arch/arm/mach-hisi/platmcpm.c new file +6 -0
+     count = TIMEOUT_MSEC / POLL_MSEC;
+     spin_lock(&boot_lock);
+     for (tries = 0; tries < count; tries++) {
+             data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
+             if (!(data & CORE_WFI_STATUS(cpu))) {
+                     msleep(POLL_MSEC);

You can't sleep while holding a lock.

Yes, I'll fix it.

Quoted 171 lines

arch/arm/mach-hisi/platmcpm.c line 228

Quoted 12 lines
arch/arm/mach-hisi/platmcpm.c new file +12 -0
+                     continue;
+             }
+     }
+     if (tries >= count)
+             goto err;
+     data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+            CORE_DEBUG_RESET_BIT(cpu);
+     writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
+     for (tries = 0; tries < count; tries++) {
+             data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
+             if (!(data & CORE_RESET_STATUS(cpu))) {
+                     msleep(POLL_MSEC);

Same here.

Also I don't really like the way this MCPM method is abused to shut down a CPU because the target CPU can't do it on its own. We're getting back to this again and I suppose this is because the hardware is not able to do otherwise. However this mysterious CORE_WFI_STATUS bit made its apparition lately, so one may speculate that the hardware might be able to do more than it may seem. The lack of (english) documentation is really making a more optimal implementation impossible at this point. So I'll give in and let this pass but not without a sufficiently comprehensive comment in the code to that effect.

Now... around msleep calls you have to drop and reacquire the lock. And when the lock is reacquired you should check that the CPU count is still 0 and bail out otherwise so not to mess up with a concurrent cpu_up(). This won't be enough to prevent a race against asynchronous wake-ups though, but you are not doing any of that yet. That too would need to be documented in that comment.

arch/arm/mach-hisi/platmcpm.c line 236

Quoted 8 lines
arch/arm/mach-hisi/platmcpm.c new file +8 -0
+                     continue;
+             }
+     }
+     if (tries >= count)
+             goto err;
+     if (hip04_cluster_down(cluster))
+             hip04_set_snoop_filter(cluster, 0);
+     spin_unlock(&boot_lock);

Oh, and that ought to be spin_lock_irq()/spin_unlock_irq() here.

Quoted 61 lines
arch/arm/mach-hisi/platmcpm.c new file +61 -0
+     return 0;
+err:
+     spin_unlock(&boot_lock);
+     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 void __naked hip04_mcpm_power_up_setup(unsigned int affinity_level)
+{
+     asm volatile ("                 \n"
+"    cmp     r0, #0                  \n"
+"    bxeq    lr                      \n"
+     /* calculate fabric phys address */
+"    adr     r2, 2f                  \n"
+"    ldmia   r2, {r1, r3}            \n"
+"    sub     r0, r2, r1              \n"
+"    ldr     r2, [r0, r3]            \n"
+     /* get cluster id from MPIDR */
+"    mrc     p15, 0, r0, c0, c0, 5   \n"
+"    ubfx    r1, r0, #8, #8          \n"
+     /* 1 << cluster id */
+"    mov     r0, #1                  \n"
+"    mov     r3, r0, lsl r1          \n"
+"    ldr     r0, [r2, #"__stringify(FAB_SF_MODE)"]   \n"
+"    tst     r0, r3                  \n"
+"    bxne    lr                      \n"
+"    orr     r1, r0, r3              \n"
+"    str     r1, [r2, #"__stringify(FAB_SF_MODE)"]   \n"
+"1:  ldr     r0, [r2, #"__stringify(FAB_SF_MODE)"]   \n"
+"    tst     r0, r3                  \n"
+"    beq     1b                      \n"
+"    bx      lr                      \n"
+
+"    .align  2                       \n"
+"2:  .word   .                       \n"
+"    .word   fabric_phys_addr        \n"
+     );
+}
+
+static const struct mcpm_platform_ops hip04_mcpm_ops = {
+     .power_up               = hip04_mcpm_power_up,
+     .power_down             = hip04_mcpm_power_down,
+     .wait_for_powerdown     = hip04_mcpm_wait_for_powerdown,
+     .powered_up             = hip04_mcpm_powered_up,
+};
+
+static bool __init hip04_cpu_table_init(void)
+{
+     unsigned int mpidr, cpu, cluster;
+

arch/arm/mach-hisi/platmcpm.c line 307

Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10 -0
+     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(0, 1);

This should be hip04_set_snoop_filter(cluster, 1).

Quoted 54 lines
arch/arm/mach-hisi/platmcpm.c new file +54 -0
+     hip04_cpu_table[cluster][cpu] = 1;
+     return true;
+}
+
+static int __init hip04_mcpm_init(void)
+{
+     struct device_node *np, *np_fab;
+     struct resource fab_res;
+     int ret = -ENODEV;
+
+     if (!hip04_boot.bootwrapper_phys || !hip04_boot.relocation_entry) {
+             pr_err("fail to find bootwrapper or relocation param\n");
+             ret = -EINVAL;
+             goto err;
+     }
+
+     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;
+
+     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;
+     }
+     ret = of_address_to_resource(np_fab, 0, &fab_res);
+     if (ret) {
+             pr_err("failed to get fabric base phys\n");
+             goto err_fabric;
+     }
+     fabric_phys_addr = fab_res.start;
+     sync_cache_w(&fabric_phys_addr);
+     fabric = of_iomap(np_fab, 0);
+     if (!fabric) {
+             pr_err("failed to get fabric base\n");
+             ret = -ENOMEM;
+             goto err_fabric;
+     }
+
+     if (!hip04_cpu_table_init())
+             return -EINVAL;
+     ret = mcpm_platform_register(&hip04_mcpm_ops);
+     if (!ret) {
Quoted 9 lines

arch/arm/mach-hisi/platmcpm.c line 365

Quoted 4 lines
arch/arm/mach-hisi/platmcpm.c new file +4 -0
+             mcpm_sync_init(hip04_mcpm_power_up_setup);
+             pr_info("HiP04 MCPM initialized\n");
+     }
+     mcpm_smp_set_ops();

This mcpm_smp_set_ops() should be called only if MCPM registration is successful i.e. right after mcpm_sync_init inside the if conditional above.

OK

Quoted 13 lines
Quoted 13 lines
arch/arm/mach-hisi/platmcpm.c new file +9 -1
+     return ret;
+err_fabric:
+     iounmap(sysctrl);
+err_sysctrl:
+     iounmap(relocation);
+err:
+     return ret;
+}
+early_initcall(hip04_mcpm_init);
--

1.9.1

#5 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 12 lines · Haojian Zhuang
Quoted 11 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

Quoted 7 lines
Quoted 5 lines

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Others don't agree put them into DTS file. So I move them into command line.

Could you give me a pointer to the discussion around that please?

Nicolas

#6 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 20 lines · Nicolas Pitre
Quoted 18 lines · Haojian Zhuang
Quoted 16 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Quoted 6 lines
Quoted 1 line

Others don't agree put them into DTS file. So I move them into command line.

Could you give me a pointer to the discussion around that please?

Nicolas

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/275944.html

Mark challenged what's relationship between bootwrapper address and system controller. Actually code in bootwrapper is like trampoline. And it's a software protocol, not hardware description. So I moved them into command line instead.

Regards
Haojian

#7 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 26 lines · Haojian Zhuang
Quoted 25 lines · Nicolas Pitre
Quoted 12 lines · Haojian Zhuang
Quoted 11 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

Quoted 7 lines
Quoted 5 lines

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Others don't agree put them into DTS file. So I move them into command line.

Could you give me a pointer to the discussion around that please?

Quoted 6 lines
Quoted 1 line

Nicolas

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/275944.html

Mark challenged what's relationship between bootwrapper address and system controller.

There is no relation, obviously. Hence this doesn't belong in the system controller node. That doesn't mean it should not be in DT at all.

Quoted 3 lines

Actually code in bootwrapper is like trampoline. And it's a software protocol, not hardware description. So I moved them into command line instead.

There are many examples for software protocols being specified in DT already. The first that comes to my mind is the "boot method = spin table" which has nothing to do with hardware. PSCI bindings are about another software-only thing.

Nicolas

#8 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 43 lines · Nicolas Pitre
Quoted 26 lines · Haojian Zhuang
Quoted 25 lines · Nicolas Pitre
Quoted 12 lines · Haojian Zhuang
Quoted 11 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

Quoted 7 lines
Quoted 5 lines

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Others don't agree put them into DTS file. So I move them into command line.

Could you give me a pointer to the discussion around that please?

Quoted 6 lines
Quoted 1 line

Nicolas

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/275944.html

Mark challenged what's relationship between bootwrapper address and system controller.

There is no relation, obviously. Hence this doesn't belong in the system controller node. That doesn't mean it should not be in DT at all.

Quoted 3 lines

Actually code in bootwrapper is like trampoline. And it's a software protocol, not hardware description. So I moved them into command line instead.

Quoted 7 lines

There are many examples for software protocols being specified in DT already. The first that comes to my mind is the "boot method = spin table" which has nothing to do with hardware. PSCI bindings are about another software-only thing.

Nicolas

bootwrapper {
        compatible = "hisilicon,hip04-bootwrapper";
        boot-method = <0x10c00000, 0x10000, 0xa5a5a5a5, 0xe0000100, 0x1000>;
};

I changed them into this format. Could you help to review?

Regards
Haojian

#9 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 50 lines · Haojian Zhuang
Quoted 49 lines · Nicolas Pitre
Quoted 26 lines · Haojian Zhuang
Quoted 25 lines · Nicolas Pitre
Quoted 12 lines · Haojian Zhuang
Quoted 11 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

Quoted 7 lines
Quoted 5 lines

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Others don't agree put them into DTS file. So I move them into command line.

Could you give me a pointer to the discussion around that please?

Quoted 6 lines
Quoted 1 line

Nicolas

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/275944.html

Mark challenged what's relationship between bootwrapper address and system controller.

There is no relation, obviously. Hence this doesn't belong in the system controller node. That doesn't mean it should not be in DT at all.

Quoted 3 lines

Actually code in bootwrapper is like trampoline. And it's a software protocol, not hardware description. So I moved them into command line instead.

There are many examples for software protocols being specified in DT already. The first that comes to my mind is the "boot method = spin table" which has nothing to do with hardware. PSCI bindings are about another software-only thing.

Quoted 8 lines
Quoted 1 line

Nicolas

bootwrapper {
        compatible = "hisilicon,hip04-bootwrapper";
        boot-method = <0x10c00000, 0x10000, 0xa5a5a5a5, 0xe0000100, 0x1000>;
};

I changed them into this format. Could you help to review?

Unfortunately I'm not really knowledgeable about best device tree syntax and practices. You'll have to nag someone else for reviewing this.

One thing though, do you really need to put some magic number there? Is it likely to change? If not this could be hardcoded in the code and only describe the special memory region in DT.

Nicolas

#10 lore raw

PATCH v16 2/9 ARM: hisi: enable MCPM implementation

Quoted 64 lines · Nicolas Pitre
Quoted 50 lines · Haojian Zhuang
Quoted 49 lines · Nicolas Pitre
Quoted 26 lines · Haojian Zhuang
Quoted 25 lines · Nicolas Pitre
Quoted 12 lines · Haojian Zhuang
Quoted 11 lines · Nicolas Pitre

Sorry for the delay -- I was on vacation.

Quoted 6 lines · Haojian Zhuang

Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM framework to manage power on HiP04 SoC.

Changelog:
v16:
* Parse bootwrapper parameters in command line instead.

Quoted 7 lines
Quoted 5 lines

What is that about? I don't particularly like to see bootloader handshake details passed to the kernel via the kernel command line mechanism. Given this looks like special memory regions, can't they be specified via the device tree instead?

Others don't agree put them into DTS file. So I move them into command line.

Could you give me a pointer to the discussion around that please?

Quoted 6 lines
Quoted 1 line

Nicolas

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/275944.html

Mark challenged what's relationship between bootwrapper address and system controller.

There is no relation, obviously. Hence this doesn't belong in the system controller node. That doesn't mean it should not be in DT at all.

Quoted 3 lines

Actually code in bootwrapper is like trampoline. And it's a software protocol, not hardware description. So I moved them into command line instead.

There are many examples for software protocols being specified in DT already. The first that comes to my mind is the "boot method = spin table" which has nothing to do with hardware. PSCI bindings are about another software-only thing.

Quoted 8 lines
Quoted 1 line

Nicolas

bootwrapper {
        compatible = "hisilicon,hip04-bootwrapper";
        boot-method = <0x10c00000, 0x10000, 0xa5a5a5a5, 0xe0000100, 0x1000>;
};

I changed them into this format. Could you help to review?

Unfortunately I'm not really knowledgeable about best device tree syntax and practices. You'll have to nag someone else for reviewing this.

Quoted 6 lines

One thing though, do you really need to put some magic number there? Is it likely to change? If not this could be hardcoded in the code and only describe the special memory region in DT.

Nicolas

Sure. I can define the magic number as hardcode.

Regards
Haojian

#11 lore raw

PATCH v16 3/9 ARM: hisi: enable HiP04

In reply to Haojian Zhuang

Support HiP04 SoC what supports 16 cores. And it relies on MCPM framework.

---
 arch/arm/mach-hisi/Kconfig     | 9 +++++++++
 arch/arm/mach-hisi/hisilicon.c | 9 +++++++++
 2 files changed, 18 insertions(+)
arch/arm/mach-hisi/Kconfig +9 -0
index 9848829..075772b 100644
@@ -22,6 +22,15 @@ config ARCH_HI3xxx
 	help
 	  Support for Hisilicon Hi36xx SoC family
 
+config ARCH_HIP04
+	bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7
+	select ARM_ERRATA_798181 if SMP
+	select HAVE_ARM_ARCH_TIMER
+	select MCPM if SMP
+	select MCPM_QUAD_CLUSTER if SMP
+	help
+	  Support for Hisilicon HiP04 SoC family
+
 config ARCH_HIX5HD2
 	bool "Hisilicon X5HD2 family" if ARCH_MULTI_V7
 	select CACHE_L2X0
arch/arm/mach-hisi/hisilicon.c +9 -0
index f37fb65..5b8c11f 100644
@@ -65,3 +65,12 @@ static const char *hix5hd2_compat[] __initconst = {
 DT_MACHINE_START(HIX5HD2_DT, "Hisilicon HIX5HD2 (Flattened Device Tree)")
 	.dt_compat	= hix5hd2_compat,
 MACHINE_END
+
+static const char *hip04_compat[] __initconst = {
+	"hisilicon,hip04-d01",
+	NULL,
+};
+
+DT_MACHINE_START(HIP04, "Hisilicon HiP04 (Flattened Device Tree)")
+	.dt_compat	= hip04_compat,
+MACHINE_END
Signature · 1 line
1.9.1
#12 lore raw

PATCH v16 4/9 document: dt: add the binding on HiP04

In reply to Haojian Zhuang

Add Hisilicon HiP04 SoC platform & Fabric controller.

Fabric controller could be used to configure snoop filter among multiple clusters.

---
 .../devicetree/bindings/arm/hisilicon/hisilicon.txt          | 12 ++++++++++++
 1 file changed, 12 insertions(+)
Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +12 -0
index 934f000..fd8a759 100644
@@ -5,6 +5,11 @@ Hi4511 Board
 Required root node properties:
 	- compatible = "hisilicon,hi3620-hi4511";
 
+HiP04 D01 Board
+Required root node properties:
+	- compatible = "hisilicon,hip04-d01";
+
+
 Hisilicon system controller
 
 Required properties:
@@ -55,3 +60,10 @@ Example:
 		compatible = "hisilicon,pctrl";
 		reg = <0xfca09000 0x1000>;
 	};
+
+-----------------------------------------------------------------------
+Fabric:
+
+Required Properties:
+- compatible: "hisilicon,hip04-fabric";
+- reg: Address and size of Fabric
Signature · 1 line
1.9.1
#13 lore raw

PATCH v16 5/9 ARM: dts: add hip04 dts

In reply to Haojian Zhuang

Add hip04-d01.dts & hip04.dtsi for hip04 SoC platform.

---
 arch/arm/boot/dts/Makefile      |   1 +
 arch/arm/boot/dts/hip04-d01.dts |  32 +++++
 arch/arm/boot/dts/hip04.dtsi    | 262 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 295 insertions(+)
 create mode 100644 arch/arm/boot/dts/hip04-d01.dts
 create mode 100644 arch/arm/boot/dts/hip04.dtsi
arch/arm/boot/dts/Makefile +1 -0
index 721525e..6587bbf 100644
@@ -86,6 +86,7 @@ dtb-$(CONFIG_ARCH_HI3xxx) += hi3620-hi4511.dtb
 dtb-$(CONFIG_ARCH_HIX5HD2) += hix5hd2-dkb.dtb
 dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
 	ecx-2000.dtb
+dtb-$(CONFIG_ARCH_HIP04) += hip04-d01.dtb
 dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \
 	integratorcp.dtb
 dtb-$(CONFIG_ARCH_KEYSTONE) += k2hk-evm.dtb \
arch/arm/boot/dts/hip04-d01.dts new file +32 -0
new file mode 100644
index 0000000..40a9e33
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (C) 2013-2014 Linaro Ltd.
+ *  Author: Haojian Zhuang <[email protected]>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+
+#include "hip04.dtsi"
+
+/ {
+	/* memory bus is 64-bit */
+	#address-cells = <2>;
+	#size-cells = <2>;
+	model = "Hisilicon D01 Development Board";
+	compatible = "hisilicon,hip04-d01";
+
+	memory at 00000000,10000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000 0x00000000 0xc0000000>,
+		      <0x00000004 0xc0000000 0x00000003 0x40000000>;
+	};
+
+	soc {
+		uart0: uart at 4007000 {
+			status = "ok";
+		};
+	};
+};
arch/arm/boot/dts/hip04.dtsi new file +262 -0

262 lines not on this page · raw message

Signature · 1 line
1.9.1
#14 lore raw

PATCH v16 6/9 ARM: config: enable hisilicon hip04

In reply to Haojian Zhuang

Enable CONFIG_ARCH_HIP04 in both hi3xxx_defconfig & multi_v7_defconfig.

Since CONFIG_ARM_LPAE is disabled by default, only 3GB memory could be support by this defconfig. User should enable CONFIG_ARM_LPAE locally to support 16GB memory on hip04 platform.

Since hip04 doesn't belong to hi3xxx series, rename hi3xxx_defconfig to hisi_defconfig.

---
 arch/arm/configs/hi3xxx_defconfig   | 58 ------------------------------
 arch/arm/configs/hisi_defconfig     | 72 +++++++++++++++++++++++++++++++++++++
 arch/arm/configs/multi_v7_defconfig |  2 ++
 3 files changed, 74 insertions(+), 58 deletions(-)
 delete mode 100644 arch/arm/configs/hi3xxx_defconfig
 create mode 100644 arch/arm/configs/hisi_defconfig
arch/arm/configs/hi3xxx_defconfig deleted +0 -58
deleted file mode 100644
index 9630687..0000000
@@ -1,58 +0,0 @@
-CONFIG_IRQ_DOMAIN_DEBUG=y
-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_ARCH_HIX5HD2=y
-CONFIG_SMP=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ARM_APPENDED_DTB=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_SD=y
-CONFIG_ATA=y
-CONFIG_SATA_AHCI_PLATFORM=y
-CONFIG_NETDEVICES=y
-CONFIG_SERIAL_AMBA_PL011=y
-CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_I2C_DESIGNWARE_PLATFORM=y
-CONFIG_SPI=y
-CONFIG_SPI_PL022=y
-CONFIG_PINCTRL_SINGLE=y
-CONFIG_GPIO_GENERIC_PLATFORM=y
-CONFIG_REGULATOR_GPIO=y
-CONFIG_DRM=y
-CONFIG_FB_SIMPLE=y
-CONFIG_USB=y
-CONFIG_USB_XHCI_HCD=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_MXC=y
-CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_STORAGE=y
-CONFIG_NOP_USB_XCEIV=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_PL031=y
-CONFIG_DMADEVICES=y
-CONFIG_DW_DMAC=y
-CONFIG_PL330_DMA=y
-CONFIG_PWM=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_LOCKUP_DETECTOR=y
arch/arm/configs/hisi_defconfig new file +72 -0

72 lines not on this page · raw message

arch/arm/configs/multi_v7_defconfig +2 -0
index d34ab30..fd8694d 100644
@@ -24,8 +24,10 @@ CONFIG_MACH_BERLIN_BG2=y
 CONFIG_MACH_BERLIN_BG2CD=y
 CONFIG_MACH_BERLIN_BG2Q=y
 CONFIG_ARCH_HIGHBANK=y
+CONFIG_ARCH_HISI=y
 CONFIG_ARCH_HI3xxx=y
 CONFIG_ARCH_HIX5HD2=y
+CONFIG_ARCH_HIP04=y
 CONFIG_ARCH_KEYSTONE=y
 CONFIG_ARCH_MXC=y
 CONFIG_MACH_IMX51_DT=y
Signature · 1 line
1.9.1
#15 lore raw

PATCH v16 7/9 ARM: debug: add HiP04 debug uart

In reply to Haojian Zhuang

Add the support of Hisilicon HiP04 debug uart.

---
 arch/arm/Kconfig.debug | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/arm/Kconfig.debug +10 -0
index d061de0..c6499cc 100644
@@ -231,6 +231,14 @@ choice
 		  Say Y here if you want kernel low-level debugging support
 		  on Hix5hd2 UART.
 
+	config DEBUG_HIP04_UART
+		bool "Hisilicon HiP04 Debug UART"
+		depends on ARCH_HIP04
+		select DEBUG_UART_8250
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on HIP04 UART.
+
 	config DEBUG_HIGHBANK_UART
 		bool "Kernel low-level debugging messages via Highbank UART"
 		depends on ARCH_HIGHBANK
@@ -1095,6 +1103,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 || \
@@ -1136,6 +1145,7 @@ config DEBUG_UART_VIRT
 	default 0xf7008000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART2 || \
 				DEBUG_S3C2410_UART2)
 	default 0xf7fc9000 if DEBUG_BERLIN_UART
+	default 0xf8007000 if DEBUG_HIP04_UART
 	default 0xf8009000 if DEBUG_VEXPRESS_UART0_CA9
 	default 0xf8090000 if DEBUG_VEXPRESS_UART0_RS1
 	default 0xfa71e000 if DEBUG_QCOM_UARTDM
Signature · 1 line
1.9.1
#16 lore raw

PATCH v16 8/9 irq: enable hip04 irq chip

In reply to Haojian Zhuang

HiP04 GIC is the variate of ARM GICv2.

ARM GICv2 supports 8 cores. HiP04 GIC extends to support 16 cores. It results that bit fields in GIC_DIST_TARGET & GIC_DIST_SOFTINT are different from ARM GICv2. And the maximium IRQ is downgrade from 1020 to 510.

Since different register offset & bitfields definitation breaks compartible with ARM GICv2, create a new hip04 irq driver.

---
 drivers/irqchip/Makefile    |   1 +
 drivers/irqchip/irq-hip04.c | 429 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 430 insertions(+)
 create mode 100644 drivers/irqchip/irq-hip04.c
drivers/irqchip/Makefile +1 -0
index c57e642..23dcf45 100644
@@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP)			+= irqchip.o
 
 obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2835.o
 obj-$(CONFIG_ARCH_EXYNOS)		+= exynos-combiner.o
+obj-$(CONFIG_ARCH_HIP04)		+= irq-hip04.o
 obj-$(CONFIG_ARCH_MMP)			+= irq-mmp.o
 obj-$(CONFIG_ARCH_MVEBU)		+= irq-armada-370-xp.o
 obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o
drivers/irqchip/irq-hip04.c new file +429 -0

429 lines not on this page · raw message

Signature · 1 line
1.9.1
#17 lore raw

PATCH v16 8/9 irq: enable hip04 irq chip

Hi,

to me this looks much better than the version integrated into irq-gic.c and is reasonably small and self-contained.

See for comments below...

Quoted 50 lines · Haojian Zhuang

HiP04 GIC is the variate of ARM GICv2.

ARM GICv2 supports 8 cores. HiP04 GIC extends to support 16 cores. It results that bit fields in GIC_DIST_TARGET & GIC_DIST_SOFTINT are different from ARM GICv2. And the maximium IRQ is downgrade from 1020 to 510.

Since different register offset & bitfields definitation breaks compartible with ARM GICv2, create a new hip04 irq driver.

---
 drivers/irqchip/Makefile    |   1 +
 drivers/irqchip/irq-hip04.c | 429 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 430 insertions(+)
 create mode 100644 drivers/irqchip/irq-hip04.c
drivers/irqchip/Makefile +1 -0
index c57e642..23dcf45 100644
@@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP)			+= irqchip.o
 
 obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2835.o
 obj-$(CONFIG_ARCH_EXYNOS)		+= exynos-combiner.o
+obj-$(CONFIG_ARCH_HIP04)		+= irq-hip04.o
 obj-$(CONFIG_ARCH_MMP)			+= irq-mmp.o
 obj-$(CONFIG_ARCH_MVEBU)		+= irq-armada-370-xp.o
 obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o
drivers/irqchip/irq-hip04.c new file +16 -0
new file mode 100644
index 0000000..751a7ee
@@ -0,0 +1,429 @@
+/*
+ * Hisilicon HiP04 INTC
+ *
+ * Copyright (C) 2002-2014 ARM Limited.
+ * Copyright (c) 2013-2014 Hisilicon Ltd.
+ * Copyright (c) 2013-2014 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Interrupt architecture for the HIP04 INTC:
+ *
+ * o There is one Interrupt Distributor, which receives interrupts
+ *   from system devices and sends them to the Interrupt Controllers.
+ *

drivers/irqchip/irq-hip04.c line 26

Quoted 10 lines
drivers/irqchip/irq-hip04.c new file +10 -0
+ * o There is one CPU Interface per CPU, which sends interrupts sent
+ *   by the Distributor, and interrupts generated locally, to the
+ *   associated CPU. The base address of the CPU interface is usually
+ *   aliased so that the same address points to different chips depending
+ *   on the CPU it is accessed from.
+ *
+ * Note that IRQs 0-31 are special - they are local to each CPU.
+ * As such, the enable set/clear, pending set/clear and active bit
+ * registers are banked per-cpu for these sources.
+ */

I'd find it more useful to have a reference to the GIC code here and only list the delta of the two drivers.
Since you removed (almost) any references to GIC, to an uninitiated reader it's not obvious that this is in fact a stripped and tweaked GIC.

So you could copy some of the rationale from the commit message into here, something along the lines of:
---------
This is derived from irq-gic.c to support the HiSilicon HiP04 interrupt controller, which is similar to the GIC, but deviates at some points. Support for power management, non-banked registers, cascaded GICs (and multiple controllers in general) and bigLittle support has been removed from the GIC driver.
Affinity related functions have been adjusted to match the HiSilicon hardware implementation.
---------

By the way, you removed CONFIG_CPU_PM support, is there any reason for that? I don't see an issue code-wise with keeping this in.

[...]

drivers/irqchip/irq-hip04.c line 276

Quoted 5 lines
drivers/irqchip/irq-hip04.c new file +5 -0
+
+void hip04_cpu_if_down(void)
+{
+	writel_relaxed(0, hip04_data.cpu_base + GIC_CPU_CTRL);
+}

Where is this used? The GIC counterpart is only called by some VExpress code, does your platform need a similar call? Otherwise (and since you don't seem to provide a public prototype) this function can be removed.

drivers/irqchip/irq-hip04.c line 288

Quoted 12 lines
drivers/irqchip/irq-hip04.c new file +12 -0
+
+#ifdef CONFIG_SMP
+static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq)
+{
+	int cpu;
+	unsigned long flags, map = 0;
+
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+
+	/* Convert our logical CPU mask into a physical one. */
+	for_each_cpu(cpu, mask)
+		map |= hip04_cpu_map[cpu];

Are we sure that mask does not contain any CPU number higher than NR_HIP04_CPU_IF?

Regards,
Andre.

Quoted 142 lines
drivers/irqchip/irq-hip04.c new file +141 -0
+
+	/*
+	 * Ensure that stores to Normal memory are visible to the
+	 * other CPUs before they observe us issuing the IPI.
+	 */
+	dmb(ishst);
+
+	/* this always happens on GIC0 */
+	writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT);
+
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+#endif
+
+static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq,
+				irq_hw_number_t hw)
+{
+	if (hw < 32) {
+		irq_set_percpu_devid(irq);
+		irq_set_chip_and_handler(irq, &hip04_irq_chip,
+					 handle_percpu_devid_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+	} else {
+		irq_set_chip_and_handler(irq, &hip04_irq_chip,
+					 handle_fasteoi_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+	}
+	irq_set_chip_data(irq, d->host_data);
+	return 0;
+}
+
+static int hip04_irq_domain_xlate(struct irq_domain *d,
+				  struct device_node *controller,
+				  const u32 *intspec, unsigned int intsize,
+				  unsigned long *out_hwirq,
+				  unsigned int *out_type)
+{
+	unsigned long ret = 0;
+
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 3)
+		return -EINVAL;
+
+	/* Get the interrupt number and add 16 to skip over SGIs */
+	*out_hwirq = intspec[1] + 16;
+
+	/* For SPIs, we need to add 16 more to get the irq ID number */
+	if (!intspec[0])
+		*out_hwirq += 16;
+
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+
+	return ret;
+}
+
+#ifdef CONFIG_SMP
+static int hip04_irq_secondary_init(struct notifier_block *nfb,
+				    unsigned long action,
+				    void *hcpu)
+{
+	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+		hip04_irq_cpu_init(&hip04_data);
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier for enabling the INTC CPU interface. Set an arbitrarily high
+ * priority because the GIC needs to be up before the ARM generic timers.
+ */
+static struct notifier_block hip04_irq_cpu_notifier = {
+	.notifier_call	= hip04_irq_secondary_init,
+	.priority	= 100,
+};
+#endif
+
+static const struct irq_domain_ops hip04_irq_domain_ops = {
+	.map	= hip04_irq_domain_map,
+	.xlate	= hip04_irq_domain_xlate,
+};
+
+static int __init
+hip04_of_init(struct device_node *node, struct device_node *parent)
+{
+	irq_hw_number_t hwirq_base = 16;
+	int nr_irqs, irq_base, i;
+
+	if (WARN_ON(!node))
+		return -ENODEV;
+
+	hip04_data.dist_base = of_iomap(node, 0);
+	WARN(!hip04_data.dist_base, "fail to map hip04 intc dist registers\n");
+
+	hip04_data.cpu_base = of_iomap(node, 1);
+	WARN(!hip04_data.cpu_base, "unable to map hip04 intc cpu registers\n");
+
+	/*
+	 * Initialize the CPU interface map to all CPUs.
+	 * It will be refined as each CPU probes its ID.
+	 */
+	for (i = 0; i < NR_HIP04_CPU_IF; i++)
+		hip04_cpu_map[i] = 0xff;
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The HIP04 INTC only supports up to 510 interrupt sources.
+	 */
+	nr_irqs = readl_relaxed(hip04_data.dist_base + GIC_DIST_CTR) & 0x1f;
+	nr_irqs = (nr_irqs + 1) * 32;
+	if (nr_irqs > HIP04_MAX_IRQS)
+		nr_irqs = HIP04_MAX_IRQS;
+	hip04_data.nr_irqs = nr_irqs;
+
+	nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+
+	irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id());
+	if (IS_ERR_VALUE(irq_base)) {
+		pr_err("failed to allocate IRQ numbers\n");
+		return -EINVAL;
+	}
+
+	hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base,
+						  hwirq_base,
+						  &hip04_irq_domain_ops,
+						  &hip04_data);
+
+	if (WARN_ON(!hip04_data.domain))
+		return -EINVAL;
+
+#ifdef CONFIG_SMP
+	set_smp_cross_call(hip04_raise_softirq);
+	register_cpu_notifier(&hip04_irq_cpu_notifier);
+#endif
+	set_handle_irq(hip04_handle_irq);
+
+	hip04_irq_dist_init(&hip04_data);
+	hip04_irq_cpu_init(&hip04_data);
+
+	return 0;
+}
+IRQCHIP_DECLARE(hip04_intc, "hisilicon,hip04-intc", hip04_of_init);
#18 lore raw

PATCH v16 8/9 irq: enable hip04 irq chip

Quoted 86 lines · Andre Przywara

Hi,

to me this looks much better than the version integrated into irq-gic.c and is reasonably small and self-contained.

See for comments below...

Quoted 50 lines · Haojian Zhuang

HiP04 GIC is the variate of ARM GICv2.

ARM GICv2 supports 8 cores. HiP04 GIC extends to support 16 cores. It results that bit fields in GIC_DIST_TARGET & GIC_DIST_SOFTINT are different from ARM GICv2. And the maximium IRQ is downgrade from 1020 to 510.

Since different register offset & bitfields definitation breaks compartible with ARM GICv2, create a new hip04 irq driver.

---
 drivers/irqchip/Makefile    |   1 +
 drivers/irqchip/irq-hip04.c | 429 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 430 insertions(+)
 create mode 100644 drivers/irqchip/irq-hip04.c
drivers/irqchip/Makefile +1 -0
index c57e642..23dcf45 100644
@@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP)                 += irqchip.o
 
 obj-$(CONFIG_ARCH_BCM2835)           += irq-bcm2835.o
 obj-$(CONFIG_ARCH_EXYNOS)            += exynos-combiner.o
+obj-$(CONFIG_ARCH_HIP04)             += irq-hip04.o
 obj-$(CONFIG_ARCH_MMP)                       += irq-mmp.o
 obj-$(CONFIG_ARCH_MVEBU)             += irq-armada-370-xp.o
 obj-$(CONFIG_ARCH_MXS)                       += irq-mxs.o
drivers/irqchip/irq-hip04.c new file +16 -0
new file mode 100644
index 0000000..751a7ee
@@ -0,0 +1,429 @@
+/*
+ * Hisilicon HiP04 INTC
+ *
+ * Copyright (C) 2002-2014 ARM Limited.
+ * Copyright (c) 2013-2014 Hisilicon Ltd.
+ * Copyright (c) 2013-2014 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Interrupt architecture for the HIP04 INTC:
+ *
+ * o There is one Interrupt Distributor, which receives interrupts
+ *   from system devices and sends them to the Interrupt Controllers.
+ *

drivers/irqchip/irq-hip04.c line 26

Quoted 10 lines
drivers/irqchip/irq-hip04.c new file +10 -0
+ * o There is one CPU Interface per CPU, which sends interrupts sent
+ *   by the Distributor, and interrupts generated locally, to the
+ *   associated CPU. The base address of the CPU interface is usually
+ *   aliased so that the same address points to different chips depending
+ *   on the CPU it is accessed from.
+ *
+ * Note that IRQs 0-31 are special - they are local to each CPU.
+ * As such, the enable set/clear, pending set/clear and active bit
+ * registers are banked per-cpu for these sources.
+ */

I'd find it more useful to have a reference to the GIC code here and only list the delta of the two drivers.
Since you removed (almost) any references to GIC, to an uninitiated reader it's not obvious that this is in fact a stripped and tweaked GIC.

So you could copy some of the rationale from the commit message into here, something along the lines of:
---------
This is derived from irq-gic.c to support the HiSilicon HiP04 interrupt controller, which is similar to the GIC, but deviates at some points. Support for power management, non-banked registers, cascaded GICs (and multiple controllers in general) and bigLittle support has been removed from the GIC driver.
Affinity related functions have been adjusted to match the HiSilicon hardware implementation.
---------

Quoted 3 lines

By the way, you removed CONFIG_CPU_PM support, is there any reason for that? I don't see an issue code-wise with keeping this in.

Since we didn't enable power management on HiP04 yet, I removed them. If we enable power management later, I could append them again.

Quoted 11 lines

drivers/irqchip/irq-hip04.c line 276

Quoted 6 lines
drivers/irqchip/irq-hip04.c new file +5 -0
+
+void hip04_cpu_if_down(void)
+{
+     writel_relaxed(0, hip04_data.cpu_base + GIC_CPU_CTRL);
+}

Where is this used? The GIC counterpart is only called by some VExpress code, does your platform need a similar call? Otherwise (and since you don't seem to provide a public prototype) this function can be removed.

I should remove it. It doesn't help me.

Quoted 17 lines

drivers/irqchip/irq-hip04.c line 288

Quoted 13 lines
drivers/irqchip/irq-hip04.c new file +12 -0
+
+#ifdef CONFIG_SMP
+static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq)
+{
+     int cpu;
+     unsigned long flags, map = 0;
+
+     raw_spin_lock_irqsave(&irq_controller_lock, flags);
+
+     /* Convert our logical CPU mask into a physical one. */
+     for_each_cpu(cpu, mask)
+             map |= hip04_cpu_map[cpu];

Are we sure that mask does not contain any CPU number higher than NR_HIP04_CPU_IF?

Yes, the maximum CPU number is 16. We shouldn't configure higher CPU numbers in HiP04.

Regards
Haojian

#19 lore raw

PATCH v16 9/9 of: fdt: fix memory address be truncated

In reply to Haojian Zhuang

early_init_dt_add_memory_arch() accepts base & size parameters as u64 type. memblock_add() accepts base & size parameters as phys_addr_t type. But phys_addr_t isn't equal to u64. In 32-bit system, phys_addr_t is 32-bit long. If 64-bit memory address is specified in DTS file, it'll be truncated into 32-bit address.

So create two values to store base & size first as phys_addr_t type. Then compare them with u64 base & u64 size. If they don't match, discard them.

---
 drivers/of/fdt.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/of/fdt.c +10 -0
index c4cddf0..10d5382 100644
@@ -878,6 +878,8 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 {
 	const u64 phys_offset = __pa(PAGE_OFFSET);
+	phys_addr_t mbase, msize;
+
 	base &= PAGE_MASK;
 	size &= PAGE_MASK;
 	if (base + size < phys_offset) {
@@ -885,6 +887,14 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 			   base, base + size);
 		return;
 	}
+	/* phys_addr_t may not be equal to u64 */
+	mbase = base;
+	msize = size;
+	if ((mbase != base) || (msize != size)) {
+		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
+			   base, base + size);
+		return;
+	}
 	if (base < phys_offset) {
 		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
 			   base, phys_offset);
Signature · 1 line
1.9.1
#20 lore raw

PATCH v16 9/9 of: fdt: fix memory address be truncated

Quoted 29 lines · Haojian Zhuang

early_init_dt_add_memory_arch() accepts base & size parameters as u64 type. memblock_add() accepts base & size parameters as phys_addr_t type. But phys_addr_t isn't equal to u64. In 32-bit system, phys_addr_t is 32-bit long. If 64-bit memory address is specified in DTS file, it'll be truncated into 32-bit address.

So create two values to store base & size first as phys_addr_t type. Then compare them with u64 base & u64 size. If they don't match, discard them.

---
 drivers/of/fdt.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/of/fdt.c +2 -0
index c4cddf0..10d5382 100644
@@ -878,6 +878,8 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 {
 	const u64 phys_offset = __pa(PAGE_OFFSET);
+	phys_addr_t mbase, msize;
+
 	base &= PAGE_MASK;
 	size &= PAGE_MASK;
 	if (base + size < phys_offset) {

drivers/of/fdt.c void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) · line 896

Quoted 10 lines
drivers/of/fdt.c +7 -0
@@ -885,6 +887,14 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 			   base, base + size);
 		return;
 	}
+	/* phys_addr_t may not be equal to u64 */
+	mbase = base;
+	msize = size;
+	if ((mbase != base) || (msize != size)) {
+		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
+			   base, base + size);
+		return;

Actually, you can do better than this -- you can still use the part that fits in 32 bits even if not all of it does.

-Olof