aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuodong Xu <guodong.xu@linaro.org>2014-02-27 23:47:43 +0800
committerGuodong Xu <guodong.xu@linaro.org>2014-02-27 23:47:43 +0800
commit6370e9d677b756b790c2fa46868a51babd887cb2 (patch)
tree45f07ee17443c3d57d6e79c7accf3425d6239f11
parent3c30851ceaf0afe879cda5bfe0548657c7345c38 (diff)
parentae2f2e3d38a35829a824d7b23ee24cd12c153351 (diff)
Merge remote-tracking branch 'origin/integration-hilt-d01' into integration-hilt-d01
* origin/integration-hilt-d01: ARM: hisi: reserve bootwrapper space for HiP04 ARM: hisi: add reboot for hip04 ARM: dts: remove skeleton dtsi ARM: config: LTP requires loop block device ARM: hisi: remove L2 cache in P04 config ARM: config: always enable DEBUG_LL & EARLY_PRINTK irq: gic: support HiP04 registers ARM: config: support 16CPUs in HiP04 ARM: dts: enable SMP for HiP04 ARM: mcpm: change max clusters to 4 irq: gic: extends the cpu interface to 16 irq: gic: use mask field in GICC_IAR ARM: hisi: move hip04 out of hisilicon driver
-rw-r--r--arch/arm/boot/dts/hip04.dtsi42
-rw-r--r--arch/arm/configs/hip04_defconfig6
-rw-r--r--arch/arm/include/asm/mcpm.h2
-rw-r--r--arch/arm/kvm/interrupts_head.S12
-rw-r--r--arch/arm/mach-hisi/Kconfig2
-rw-r--r--arch/arm/mach-hisi/Makefile3
-rw-r--r--arch/arm/mach-hisi/hip04.c382
-rw-r--r--arch/arm/mach-hisi/hisilicon.c37
-rw-r--r--drivers/irqchip/irq-gic.c84
-rw-r--r--include/linux/irqchip/arm-gic.h2
-rw-r--r--include/linux/irqchip/hip04-gic.h32
-rw-r--r--virt/kvm/arm/vgic.c5
12 files changed, 531 insertions, 78 deletions
diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi
index c7d3bc59047f..834dde46df41 100644
--- a/arch/arm/boot/dts/hip04.dtsi
+++ b/arch/arm/boot/dts/hip04.dtsi
@@ -11,7 +11,6 @@
* publishhed by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
#include <dt-bindings/clock/hip04-clock.h>
/ {
@@ -27,11 +26,42 @@
#address-cells = <1>;
#size-cells = <0>;
- cpu@0 {
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+ CPU0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0>;
};
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <1>;
+ };
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <2>;
+ };
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <3>;
+ };
};
soc {
@@ -44,7 +74,7 @@
ranges = <0 0 0xe0000000 0x10000000>;
gic: interrupt-controller@c01000 {
- compatible = "arm,cortex-a15-gic";
+ compatible = "hisilicon,hip04-gic";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
@@ -53,6 +83,12 @@
reg = <0xc01000 0x1000>, <0xc02000 0x1000>;
};
+ mcpm: mcpm {
+ compatible = "hisilicon,hip04-mcpm";
+ reg = <0x100 0x1000>, <0x3e00000 0x00100000>,
+ <0x302a000 0x1000>;
+ };
+
clock: clock {
compatible = "hisilicon,hip04-clock";
/* FIXME: the base of clock controller */
diff --git a/arch/arm/configs/hip04_defconfig b/arch/arm/configs/hip04_defconfig
index aadb31736cab..473dc5bcaae8 100644
--- a/arch/arm/configs/hip04_defconfig
+++ b/arch/arm/configs/hip04_defconfig
@@ -8,6 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_GZIP=y
CONFIG_ARCH_HIP04=y
CONFIG_SMP=y
+CONFIG_NR_CPUS=16
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
@@ -25,6 +26,9 @@ 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_SD=y
CONFIG_ATA=y
CONFIG_SATA_AHCI_PLATFORM=y
@@ -52,5 +56,7 @@ CONFIG_ROOT_NFS=y
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
CONFIG_LOCKUP_DETECTOR=y
CONFIG_DEBUG_USER=y
diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h
index 608516ebabfe..68f82cf323d2 100644
--- a/arch/arm/include/asm/mcpm.h
+++ b/arch/arm/include/asm/mcpm.h
@@ -20,7 +20,7 @@
* to consider dynamic allocation.
*/
#define MAX_CPUS_PER_CLUSTER 4
-#define MAX_NR_CLUSTERS 2
+#define MAX_NR_CLUSTERS 4
#ifndef __ASSEMBLY__
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 6f18695a09cb..5b86191121a8 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -1,4 +1,5 @@
#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/hip04-gic.h>
#define VCPU_USR_REG(_reg_nr) (VCPU_USR_REGS + (_reg_nr * 4))
#define VCPU_USR_SP (VCPU_USR_REG(13))
@@ -411,7 +412,11 @@ 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]
+ /* The GICH_APR offset is different between ARM_GIC and HIP04_GIC */
+ ldr r10, =BSYM(arm_gic_im)
+ tst r10, #ARM_GIC_IMPLEMENTATION
+ ldreq r10, [r2, #GICH_APR]
+ ldrne r10, [r2, #HIP04_GICH_APR]
str r3, [r11, #VGIC_CPU_HCR]
str r4, [r11, #VGIC_CPU_VMCR]
@@ -427,7 +432,10 @@ vcpu .req r0 @ vcpu pointer always in r0
str r5, [r2, #GICH_HCR]
/* Save list registers */
- add r2, r2, #GICH_LR0
+ ldr r10, =BSYM(arm_gic_im)
+ tst r10, #ARM_GIC_IMPLEMENTATION
+ addeq r2, r2, #GICH_LR0
+ addne r2, r2, #HIP04_GICH_LR0
add r3, r11, #VGIC_CPU_LR
ldr r4, [r11, #VGIC_CPU_NR_LR]
1: ldr r6, [r2], #4
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index 33852ca2dd61..2468678fe406 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -25,11 +25,11 @@ config ARCH_HIP04
select ARM_GIC
select ARM_LPAE
select ARM_TIMER_SP804
- select CACHE_L2X0
select CLKSRC_OF
select GENERIC_CLOCKEVENTS
select HAVE_ARM_ARCH_TIMER
select HAVE_SMP
+ select MCPM
select SMP
help
Support for Hisilicon HiP0x processor family
diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile
index 6870058d0a48..31a5511f7cc7 100644
--- a/arch/arm/mach-hisi/Makefile
+++ b/arch/arm/mach-hisi/Makefile
@@ -2,6 +2,7 @@
# Makefile for Hisilicon processors family
#
-obj-y += hisilicon.o
+obj-$(CONFIG_ARCH_HI3xxx) += hisilicon.o
+obj-$(CONFIG_ARCH_HIP04) += hip04.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-hisi/hip04.c b/arch/arm/mach-hisi/hip04.c
new file mode 100644
index 000000000000..3997db38fcb4
--- /dev/null
+++ b/arch/arm/mach-hisi/hip04.c
@@ -0,0 +1,382 @@
+/*
+ * (Hisilicon's HiP04 SoC) flattened device tree enabled machine
+ *
+ * Copyright (c) 2013-2014 Hisilicon Ltd.
+ * Copyright (c) 2013-2014 Linaro Ltd.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/ahci_platform.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/memblock.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+
+#include <asm/cp15.h>
+#include <asm/cputype.h>
+#include <asm/mcpm.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "ahci_vsemiphy.c"
+
+#define BOOTWRAPPER_PHYS 0x10c00000
+#define BOOTWRAPPER_MAGIC 0xa5a5a5a5
+#define BOOTWRAPPER_SIZE 0x00010000
+
+/* bits definition in SC_CPU_RESET_REQ[x]/SC_CPU_RESET_DREQ[x]
+ * 1 -- unreset; 0 -- reset
+ */
+#define CORE_RESET_BIT(x) (1 << x)
+#define NEON_RESET_BIT(x) (1 << (x + 4))
+#define CORE_DEBUG_RESET_BIT(x) (1 << (x + 9))
+#define CLUSTER_L2_RESET_BIT (1 << 8)
+#define CLUSTER_DEBUG_RESET_BIT (1 << 13)
+
+/*
+ * bits definition in SC_CPU_RESET_STATUS[x]
+ * 1 -- reset status; 0 -- unreset status
+ */
+#define CORE_RESET_STATUS(x) (1 << x)
+#define NEON_RESET_STATUS(x) (1 << (x + 4))
+#define CORE_DEBUG_RESET_STATUS(x) (1 << (x + 9))
+#define CLUSTER_L2_RESET_STATUS (1 << 8)
+#define CLUSTER_DEBUG_RESET_STATUS (1 << 13)
+#define CORE_WFI_STATUS(x) (1 << (x + 16))
+#define CORE_WFE_STATUS(x) (1 << (x + 20))
+#define CORE_DEBUG_ACK(x) (1 << (x + 24))
+
+#define SC_CPU_RESET_REQ(x) (0x520 + (x << 3)) /* reset */
+#define SC_CPU_RESET_DREQ(x) (0x524 + (x << 3)) /* unreset */
+#define SC_CPU_RESET_STATUS(x) (0x1520 + (x << 3))
+
+#define FAB_SF_MODE 0x0c
+#define FAB_SF_INVLD 0x10
+
+/* bits definition in FB_SF_INVLD */
+#define FB_SF_INVLD_START (1 << 8)
+
+#define HIP04_MAX_CLUSTERS 4
+#define HIP04_MAX_CPUS_PER_CLUSTER 4
+
+static void __iomem *relocation = NULL, *sysctrl = NULL, *fabric = NULL;
+static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER];
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __iomem *gb3 = NULL; /* gpio bank3 to control watchdog */
+
+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(BOOTWRAPPER_PHYS, relocation);
+ writel_relaxed(BOOTWRAPPER_MAGIC, relocation + 4);
+ writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8);
+ writel_relaxed(0, relocation + 12);
+
+ if (hip04_cluster_down(cluster)) {
+ data = CLUSTER_L2_RESET_BIT | CLUSTER_DEBUG_RESET_BIT;
+ writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+ do {
+ mask = CLUSTER_L2_RESET_STATUS | \
+ CLUSTER_DEBUG_RESET_STATUS;
+ data = readl_relaxed(sysctrl + \
+ SC_CPU_RESET_STATUS(cluster));
+ } while (data & mask);
+ hip04_set_snoop_filter(cluster, 1);
+ }
+
+ hip04_cpu_table[cluster][cpu]++;
+
+ data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+ CORE_DEBUG_RESET_BIT(cpu);
+ writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+ spin_unlock(&boot_lock);
+
+ return 0;
+}
+
+static void hip04_mcpm_power_down(void)
+{
+ unsigned int mpidr, cpu, cluster;
+ unsigned int v;
+
+ spin_lock(&boot_lock);
+ spin_unlock(&boot_lock);
+
+ mpidr = read_cpuid_mpidr();
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+ local_irq_disable();
+ gic_cpu_if_down();
+
+ __mcpm_cpu_down(cpu, cluster);
+
+ asm volatile(
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "Ir" (CR_C)
+ : "cc");
+
+ flush_cache_louis();
+
+ asm volatile(
+ /*
+ * Turn off coherency
+ */
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (0x40)
+ : "cc");
+
+ isb();
+ dsb();
+
+#if 0
+ /* system hang when writing to SC_CPU_RESET_REQ(cluster) register */
+ data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu);
+ writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
+#endif
+}
+
+static int hip04_mcpm_power_down_finish(unsigned int cpu, unsigned int cluster)
+{
+ int ret = -EBUSY;
+
+ spin_lock(&boot_lock);
+ BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+ __mcpm_cpu_going_down(cpu, cluster);
+
+ hip04_cpu_table[cluster][cpu]--;
+ if (hip04_cpu_table[cluster][cpu]) {
+ pr_err("Cluster %d CPU%d is still running\n", cluster, cpu);
+ goto out;
+ }
+ ret = 0;
+out:
+ spin_unlock(&boot_lock);
+ return ret;
+}
+
+static void hip04_mcpm_powered_up(void)
+{
+ if (!relocation)
+ return;
+ spin_lock(&boot_lock);
+ writel_relaxed(0, relocation);
+ writel_relaxed(0, relocation + 4);
+ writel_relaxed(0, relocation + 8);
+ writel_relaxed(0, relocation + 12);
+ spin_unlock(&boot_lock);
+}
+
+static const struct mcpm_platform_ops hip04_mcpm_ops = {
+ .power_up = hip04_mcpm_power_up,
+ .power_down = hip04_mcpm_power_down,
+ .power_down_finish = hip04_mcpm_power_down_finish,
+ .powered_up = hip04_mcpm_powered_up,
+};
+
+static bool __init hip04_cpu_table_init(void)
+{
+ unsigned int mpidr, cpu, cluster;
+
+ mpidr = read_cpuid_mpidr();
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+ if (cluster >= HIP04_MAX_CLUSTERS ||
+ cpu >= HIP04_MAX_CPUS_PER_CLUSTER) {
+ pr_err("%s: boot CPU is out of bound!\n", __func__);
+ return false;
+ }
+ hip04_set_snoop_filter(cluster, 1);
+ hip04_cpu_table[cluster][cpu] = 1;
+ return true;
+}
+
+static int __init hip04_mcpm_init(void)
+{
+ struct device_node *np;
+ int ret = -ENODEV;
+
+ np = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-mcpm");
+ if (!np) {
+ pr_err("failed to find hisilicon,hip04-mcpm node\n");
+ goto err;
+ }
+ relocation = of_iomap(np, 0);
+ if (!relocation) {
+ pr_err("failed to get relocation space\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ sysctrl = of_iomap(np, 1);
+ if (!sysctrl) {
+ pr_err("failed to get sysctrl base\n");
+ ret = -ENOMEM;
+ goto err_sysctrl;
+ }
+ fabric = of_iomap(np, 2);
+ if (!fabric) {
+ pr_err("failed to get fabric base\n");
+ ret = -ENOMEM;
+ goto err_fabric;
+ }
+ if (!hip04_cpu_table_init())
+ return -EINVAL;
+ ret = mcpm_platform_register(&hip04_mcpm_ops);
+ if (!ret) {
+ mcpm_sync_init(NULL);
+ pr_info("HiP04 MCPM initialized\n");
+ }
+ return ret;
+err_fabric:
+ iounmap(sysctrl);
+err_sysctrl:
+ iounmap(relocation);
+err:
+ return ret;
+}
+early_initcall(hip04_mcpm_init);
+
+bool __init hip04_smp_init_ops(void)
+{
+ mcpm_smp_set_ops();
+ return true;
+}
+
+static const char *hip04_compat[] __initconst = {
+ "hisilicon,hip04-d01",
+ NULL,
+};
+
+#define HIP04_SATA_BASE (0xea000000)
+
+static int sata_vsemiphy_init(struct device *dev, void __iomem *addr)
+{
+ hi_vsemi_init(addr);
+ return 0;
+}
+
+static struct ahci_platform_data hip04_sata_pdata = {
+ .init = sata_vsemiphy_init,
+};
+
+static struct of_dev_auxdata hip04_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("hisilicon,hisi-ahci", HIP04_SATA_BASE,
+ NULL, &hip04_sata_pdata),
+ {},
+};
+
+static void __init hip04_init_machine(void)
+{
+ unsigned int data, mask;
+ of_platform_populate(NULL, of_default_bus_match_table,
+ hip04_auxdata_lookup, NULL);
+
+ gb3 = ioremap(0xe4003000, 0x1000);
+ if (!gb3) {
+ pr_err("failed to map GB3\n");
+ return;
+ }
+ mask = 0xffdfffff;
+ /* read GPIO3_SWPORT_DDR */
+ data = readl_relaxed(gb3 + 4);
+ if (!(data & ~mask)) {
+ /* switch GPIO direction from IN to OUT */
+ writel_relaxed(data | ~mask, gb3 + 4);
+ }
+ data = readl_relaxed(gb3);
+ /* write high to GPIO117 to disable watchdog */
+ writel_relaxed(data | ~mask, gb3);
+}
+
+static void hip04_restart(enum reboot_mode mode, const char *cmd)
+{
+ unsigned int data, mask;
+
+ if (!gb3) {
+ pr_err("GB3 isn't initialized\n");
+ return;
+ }
+ mask = 0xffdfffff;
+ /* read GPIO3_SWPORT_DDR */
+ data = readl_relaxed(gb3 + 4);
+ if (!(data & ~mask)) {
+ /* switch GPIO direction from IN to OUT */
+ writel_relaxed(data | ~mask, gb3 + 4);
+ }
+ data = readl_relaxed(gb3);
+ /* write low to GPIO117 */
+ writel_relaxed(data & mask, gb3);
+ udelay(100);
+ /* write high to GPIO117 to disable watchdog */
+ writel_relaxed(data | ~mask, gb3);
+ udelay(100);
+ /* write low to GPIO117 */
+ writel_relaxed(data & mask, gb3);
+ udelay(100);
+}
+
+static void __init hip04_reserve(void)
+{
+ memblock_reserve(BOOTWRAPPER_PHYS, BOOTWRAPPER_SIZE);
+}
+
+DT_MACHINE_START(HIP01, "Hisilicon HiP04 (Flattened Device Tree)")
+ .dt_compat = hip04_compat,
+ .smp_init = smp_init_ops(hip04_smp_init_ops),
+ .init_machine = hip04_init_machine,
+ .restart = hip04_restart,
+ .reserve = hip04_reserve,
+MACHINE_END
diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c
index bf36cf42ab00..741faf3e7100 100644
--- a/arch/arm/mach-hisi/hisilicon.c
+++ b/arch/arm/mach-hisi/hisilicon.c
@@ -16,7 +16,6 @@
#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <linux/ahci_platform.h>
#include <asm/proc-fns.h>
@@ -24,7 +23,6 @@
#include <asm/mach/map.h>
#include "core.h"
-#include "ahci_vsemiphy.c"
#define HI3620_SYSCTRL_PHYS_BASE 0xfc802000
#define HI3620_SYSCTRL_VIRT_BASE 0xfe802000
@@ -90,38 +88,3 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)")
.smp = smp_ops(hi3xxx_smp_ops),
.restart = hi3xxx_restart,
MACHINE_END
-
-
-#define HIP04_SATA_BASE (0xea000000)
-
-static int sata_vsemiphy_init(struct device *dev, void __iomem *addr)
-{
- hi_vsemi_init(addr);
- return 0;
-}
-
-static struct ahci_platform_data hip04_sata_pdata = {
- .init = sata_vsemiphy_init,
-};
-
-static struct of_dev_auxdata hip04_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("hisilicon,hisi-ahci", HIP04_SATA_BASE,
- NULL, &hip04_sata_pdata),
- {},
-};
-
-static void __init hip04_init_machine(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table,
- hip04_auxdata_lookup, NULL);
-}
-
-static const char *hip04_compat[] __initconst = {
- "hisilicon,hip04-d01",
- NULL,
-};
-
-DT_MACHINE_START(HIP01, "Hisilicon HiP04 (Flattened Device Tree)")
- .dt_compat = hip04_compat,
- .init_machine = hip04_init_machine,
-MACHINE_END
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 9031171c141b..f2cc7eb4c3a8 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,7 @@
#include <linux/slab.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/hip04-gic.h>
#include <asm/irq.h>
#include <asm/exception.h>
@@ -76,9 +77,13 @@ 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 MAX_NR_GIC_CPU_IF 16
+static u16 gic_cpu_map[MAX_NR_GIC_CPU_IF] __read_mostly;
+static int nr_gic_cpu_if = 8; /* The standard GIC supports 8 CPUs */
+unsigned long arm_gic_im = ARM_GIC_IMPLEMENTATION;
/*
* Supported arch specific GIC irq extension.
@@ -245,16 +250,19 @@ static int gic_retrigger(struct irq_data *d)
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 shift, step;
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 >= nr_gic_cpu_if || cpu >= nr_cpu_ids)
return -EINVAL;
+ step = BITS_PER_LONG / nr_gic_cpu_if;
+ shift = (gic_irq(d) % step) * nr_gic_cpu_if;
+ reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) / step * 4);
+
raw_spin_lock(&irq_controller_lock);
- mask = 0xff << shift;
+ mask = ((1 << nr_gic_cpu_if) - 1) << shift;
bit = gic_cpu_map[cpu] << shift;
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
@@ -287,7 +295,7 @@ static asmlinkage 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);
@@ -354,15 +362,17 @@ 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;
-
- for (i = mask = 0; i < 32; i += 4) {
- mask = readl_relaxed(base + GIC_DIST_TARGET + i);
- mask |= mask >> 16;
- mask |= mask >> 8;
+ u32 mask, i, j, step, nr;
+
+ /* get the number of CPU fields in GIC_DIST_TARGET register */
+ step = BITS_PER_LONG / nr_gic_cpu_if;
+ for (i = mask = 0; i < 32; i += step) {
+ mask = readl_relaxed(base + GIC_DIST_TARGET + i / step * 4);
+ for (j = BITS_PER_LONG >> 1; j >= nr_gic_cpu_if; j >>= 1)
+ mask |= mask >> j;
if (mask)
break;
}
@@ -375,7 +385,7 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
static void __init gic_dist_init(struct gic_chip_data *gic)
{
- unsigned int i;
+ unsigned int i, step;
u32 cpumask;
unsigned int gic_irqs = gic->gic_irqs;
void __iomem *base = gic_data_dist_base(gic);
@@ -392,10 +402,11 @@ 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 = nr_gic_cpu_if; i < BITS_PER_LONG; i <<= 1)
+ cpumask |= cpumask << i;
+ step = BITS_PER_LONG / nr_gic_cpu_if;
+ for (i = 32; i < gic_irqs; i += step)
+ writel_relaxed(cpumask, base + GIC_DIST_TARGET + i / step * 4);
/*
* Set priority on all global interrupts.
@@ -423,7 +434,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 >= nr_gic_cpu_if);
cpu_mask = gic_get_cpumask(gic);
gic_cpu_map[cpu] = cpu_mask;
@@ -431,7 +442,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 < nr_gic_cpu_if; i++)
if (i != cpu)
gic_cpu_map[i] &= ~cpu_mask;
@@ -469,7 +480,7 @@ static void gic_dist_save(unsigned int gic_nr)
{
unsigned int gic_irqs;
void __iomem *dist_base;
- int i;
+ int i, step;
if (gic_nr >= MAX_GIC_NR)
BUG();
@@ -484,7 +495,8 @@ 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++)
+ step = BITS_PER_LONG / nr_gic_cpu_if;
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, step); i++)
gic_data[gic_nr].saved_spi_target[i] =
readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
@@ -503,7 +515,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 i;
+ unsigned int i, step;
void __iomem *dist_base;
if (gic_nr >= MAX_GIC_NR)
@@ -525,7 +537,8 @@ 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++)
+ step = BITS_PER_LONG / nr_gic_cpu_if;
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, step); i++)
writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
dist_base + GIC_DIST_TARGET + i * 4);
@@ -666,8 +679,8 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
dsb();
/* this always happens on GIC0 */
- writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
+ writel_relaxed(map << (8 + 16 - nr_gic_cpu_if) | irq,
+ gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
#endif
@@ -681,7 +694,7 @@ 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 >= nr_gic_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);
@@ -700,7 +713,7 @@ int gic_get_cpu_id(unsigned int cpu)
{
unsigned int cpu_bit;
- if (cpu >= NR_GIC_CPU_IF)
+ if (cpu >= nr_gic_cpu_if)
return -1;
cpu_bit = gic_cpu_map[cpu];
if (cpu_bit & (cpu_bit - 1))
@@ -920,8 +933,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
* 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 < nr_gic_cpu_if; i++)
+ gic_cpu_map[i] = (1 << MAX_NR_GIC_CPU_IF) - 1;
/*
* For primary GICs, skip over SGIs.
@@ -983,6 +996,12 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
if (WARN_ON(!node))
return -ENODEV;
+ /* HiP04 supports 16 CPUs at most */
+ if (of_device_is_compatible(node, "hisilicon,hip04-gic")) {
+ nr_gic_cpu_if = 16;
+ arm_gic_im = HIP04_GIC_IMPLEMENTATION;
+ }
+
dist_base = of_iomap(node, 0);
WARN(!dist_base, "unable to map gic dist registers\n");
@@ -1005,6 +1024,7 @@ int __init 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);
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index cac496b1e279..287fe1852727 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -18,6 +18,8 @@
#define GIC_CPU_RUNNINGPRI 0x14
#define GIC_CPU_HIGHPRI 0x18
+#define GICC_IAR_INTID 0x3ff
+
#define GIC_DIST_CTRL 0x000
#define GIC_DIST_CTR 0x004
#define GIC_DIST_IGROUP 0x080
diff --git a/include/linux/irqchip/hip04-gic.h b/include/linux/irqchip/hip04-gic.h
new file mode 100644
index 000000000000..7f9f06f1e0db
--- /dev/null
+++ b/include/linux/irqchip/hip04-gic.h
@@ -0,0 +1,32 @@
+/*
+ * include/linux/irqchip/hip04-gic.h
+ *
+ * Copyright (C) 2013-2014 Hisilicon Limited, All Rights Reserved.
+ * Copyright (C) 2013-2014 Linaro Limited, All Rights Reserved.
+ *
+ * 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.
+ */
+#ifndef __LINUX_IRQCHIP_HIP04_GIC_H
+#define __LINUX_IRQCHIP_HIP04_GIC_H
+
+/* GIC Implementation */
+#define ARM_GIC_IMPLEMENTATION (1 << 0)
+#define HIP04_GIC_IMPLEMENTATION (1 << 1)
+
+#define HIP04_GIC_DIST_TARGET 0x800
+
+#define HIP04_GIC_DIST_SGI_PENDING_CLEAR 0xf40
+#define HIP04_GIC_DIST_SGI_PENDING_SET 0xf80
+
+#define HIP04_GICH_APR 0x70
+#define HIP04_GICH_LR0 0x80
+
+#define HIP04_GICH_LR_PHYSID_CPUID (0xf << GICH_LR_PHYSID_CPUID_SHIFT)
+
+#ifndef __ASSEMBLY__
+extern unsigned long arm_gic_im;
+#endif
+
+#endif /* __LINUX_IRQCHIP_HIP04_GIC_H */
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 685fc72fc751..51a5821f576a 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -26,6 +26,7 @@
#include <linux/of_irq.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/hip04-gic.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_arm.h>
@@ -825,7 +826,9 @@ static void vgic_update_state(struct kvm *kvm)
}
#define LR_CPUID(lr) \
- (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
+ ((arm_gic_im & ARM_GIC_IMPLEMENTATION) ? \
+ ((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT : \
+ ((lr) & HIP04_GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
#define MK_LR_PEND(src, irq) \
(GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq))