@@ -5,4 +5,5 @@ obj-$(CONFIG_ARM_32) += midway.o
obj-$(CONFIG_ARM_32) += omap5.o
obj-$(CONFIG_ARM_32) += sunxi.o
obj-$(CONFIG_ARM_64) += seattle.o
+obj-$(CONFIG_ARM_32) += hip04.o
obj-$(CONFIG_ARM_64) += xgene-storm.o
new file mode 100644
@@ -0,0 +1,308 @@
+/*
+ * xen/arch/arm/platforms/hip04.c
+ *
+ * HiSilicon HIP-04 D01 board
+ *
+ * Copyright (c) 2012-2013 Hisilicon Ltd.
+ * Copyright (c) 2012-2013 Linaro Ltd.
+ * Copyright (c) 2014 Huawei Tech. Co., Ltd.
+ *
+ * Author: Frediano Ziglio <frediano.ziglio@huawei.com>
+ *
+ * Original code from Linux kernel arch/arm/mach-hisi/hisilicon.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/platform.h>
+#include <xen/mm.h>
+#include <xen/vmap.h>
+#include <asm/io.h>
+#include <asm/gic.h>
+#include <xen/delay.h>
+
+#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)
+
+#define CLUSTER_L2_RESET_STATUS (1 << 8)
+#define CLUSTER_DEBUG_RESET_STATUS (1 << 13)
+
+#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 HIP04_MAX_CLUSTERS 4
+#define HIP04_MAX_CPUS_PER_CLUSTER 4
+
+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, *gb2;
+static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER];
+static struct hip04_secondary_cpu_data hip04_boot;
+
+static void hip04_reset(void)
+{
+ unsigned long data;
+
+ if ( !gb2 )
+ return;
+
+ data = readl_relaxed(gb2);
+ writel_relaxed(data & ~0x4000000u, gb2);
+
+ mdelay(10);
+}
+
+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 bool __init hip04_cpu_table_init(void)
+{
+ unsigned int mpidr, cpu, cluster;
+
+ mpidr = cpu_logical_map(smp_processor_id());
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+ if ( cluster >= HIP04_MAX_CLUSTERS ||
+ cpu >= HIP04_MAX_CPUS_PER_CLUSTER )
+ {
+ printk(XENLOG_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 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_cluster_up(unsigned int cluster)
+{
+ unsigned long data, mask;
+
+ if ( !hip04_cluster_down(cluster) )
+ return;
+
+ 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);
+}
+
+static void __init hip04_iounmap(void __iomem **p)
+{
+ if ( *p )
+ {
+ iounmap(*p);
+ *p = NULL;
+ }
+}
+
+static int __init hip04_smp_init(void)
+{
+ const struct dt_device_node *np, *np_fab, *bw;
+ const char *msg;
+ u64 addr, size;
+
+ np = dt_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+ msg = "hisilicon,sysctrl missing in DT\n";
+ if ( !np )
+ goto err;
+
+ np_fab = dt_find_compatible_node(NULL, NULL, "hisilicon,hip04-fabric");
+ msg = "hisilicon,hip04-fabric missing in DT\n";
+ if ( !np_fab )
+ goto err;
+
+ if ( !dt_property_read_u32(np, "bootwrapper-phys",
+ &hip04_boot.bootwrapper_phys) ) {
+ u32 boot_method[4];
+ bw = dt_find_compatible_node(NULL, NULL, "hisilicon,hip04-bootwrapper");
+ msg = "hisilicon,hip04-bootwrapper missing in DT\n";
+ if ( !bw )
+ goto err;
+
+ msg = "failed to get boot-method\n";
+ if ( !dt_property_read_u32_array(bw, "boot-method", boot_method, 4) )
+ goto err;
+ hip04_boot.bootwrapper_phys = boot_method[0];
+ hip04_boot.bootwrapper_size = boot_method[1];
+ hip04_boot.bootwrapper_magic = 0xa5a5a5a5;
+ hip04_boot.relocation_entry = boot_method[2];
+ hip04_boot.relocation_size = boot_method[3];
+ }
+ else
+ {
+ msg = "failed to get bootwrapper-size\n";
+ if ( !dt_property_read_u32(np, "bootwrapper-size",
+ &hip04_boot.bootwrapper_size) )
+ goto err;
+
+ msg = "failed to get bootwrapper-magic\n";
+ if ( !dt_property_read_u32(np, "bootwrapper-magic",
+ &hip04_boot.bootwrapper_magic) )
+ goto err;
+
+ msg = "failed to get relocation-entry\n";
+ if ( !dt_property_read_u32(np, "relocation-entry",
+ &hip04_boot.relocation_entry) )
+ goto err;
+
+ msg = "failed to get relocation-size\n";
+ if ( !dt_property_read_u32(np, "relocation-size",
+ &hip04_boot.relocation_size) )
+ goto err;
+ }
+
+ relocation = ioremap_nocache(hip04_boot.relocation_entry,
+ hip04_boot.relocation_size);
+ msg = "failed to map relocation space\n";
+ if ( !relocation )
+ goto err;
+
+ msg = "Error in \"hisilicon,sysctrl\"\n";
+ if ( dt_device_get_address(np, 0, &addr, &size) )
+ goto err;
+ sysctrl = ioremap_nocache(addr, size);
+ if ( !sysctrl )
+ goto err;
+
+ msg = "Error in \"hisilicon,hip04-fabric\"\n";
+ if ( dt_device_get_address(np_fab, 0, &addr, &size) )
+ goto err;
+ fabric = ioremap_nocache(addr, size);
+ if ( !fabric )
+ goto err;
+
+ msg = "Error mapping GB2\n";
+ gb2 = ioremap_nocache(0xe4002000, 0x1000);
+ if ( !gb2 )
+ goto err;
+
+ msg = "Error initializing SMP table\n";
+ if ( !hip04_cpu_table_init() )
+ goto err;
+
+ writel_relaxed(hip04_boot.bootwrapper_phys, relocation);
+ writel_relaxed(hip04_boot.bootwrapper_magic, relocation + 4);
+ writel_relaxed(__pa(init_secondary), relocation + 8);
+ writel_relaxed(0, relocation + 12);
+
+ return 0;
+
+err:
+ hip04_iounmap(&relocation);
+ hip04_iounmap(&sysctrl);
+ hip04_iounmap(&fabric);
+ hip04_iounmap(&gb2);
+
+ printk("%s", msg);
+ return -ENXIO;
+}
+
+static int hip04_cpu_up(int cpu)
+{
+ unsigned int cluster;
+ unsigned long data;
+
+ cluster = cpu / HIP04_MAX_CPUS_PER_CLUSTER;
+ cpu %= HIP04_MAX_CPUS_PER_CLUSTER;
+
+ writel_relaxed(hip04_boot.bootwrapper_phys, relocation);
+ writel_relaxed(hip04_boot.bootwrapper_magic, relocation + 4);
+ writel_relaxed(__pa(init_secondary), relocation + 8);
+ writel_relaxed(0, relocation + 12);
+
+ hip04_cluster_up(cluster);
+
+ 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));
+
+ return cpu_up_send_sgi(cpu);
+}
+
+
+static const char * const hip04_dt_compat[] __initconst =
+{
+ "hisilicon,hip04-d01",
+ NULL
+};
+
+static const struct dt_device_match hip04_blacklist_dev[] __initconst =
+{
+ /* Hardware power management */
+ DT_MATCH_COMPATIBLE("hisilicon,sysctrl"),
+ DT_MATCH_COMPATIBLE("hisilicon,hip04-fabric"),
+ { /* sentinel */ },
+};
+
+
+PLATFORM_START(hip04, "HISILICON HIP04")
+ .compatible = hip04_dt_compat,
+ .smp_init = hip04_smp_init,
+ .cpu_up = hip04_cpu_up,
+ .reset = hip04_reset,
+ .blacklist_dev = hip04_blacklist_dev,
+PLATFORM_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */