summaryrefslogtreecommitdiff
path: root/arch/arc/plat-arcfpga
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-08-05 17:04:01 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-08-05 17:04:01 -0300
commit57f0f512b273f60d52568b8c6b77e17f5636edc0 (patch)
tree5e910f0e82173f4ef4f51111366a3f1299037a7b /arch/arc/plat-arcfpga
Initial import
Diffstat (limited to 'arch/arc/plat-arcfpga')
-rw-r--r--arch/arc/plat-arcfpga/Kconfig33
-rw-r--r--arch/arc/plat-arcfpga/Makefile12
-rw-r--r--arch/arc/plat-arcfpga/include/plat/smp.h118
-rw-r--r--arch/arc/plat-arcfpga/platform.c45
-rw-r--r--arch/arc/plat-arcfpga/smp.c186
5 files changed, 394 insertions, 0 deletions
diff --git a/arch/arc/plat-arcfpga/Kconfig b/arch/arc/plat-arcfpga/Kconfig
new file mode 100644
index 000000000..217593a70
--- /dev/null
+++ b/arch/arc/plat-arcfpga/Kconfig
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+#
+# 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.
+#
+
+menuconfig ARC_PLAT_FPGA_LEGACY
+ bool "\"Legacy\" ARC FPGA dev Boards"
+ select ARC_HAS_COH_CACHES if SMP
+ help
+ Support for ARC development boards, provided by Synopsys.
+ These are based on FPGA or ISS. e.g.
+ - ARCAngel4
+ - ML509
+ - MetaWare ISS
+
+if ARC_PLAT_FPGA_LEGACY
+
+config ISS_SMP_EXTN
+ bool "ARC SMP Extensions (ISS Models only)"
+ default n
+ depends on SMP
+ help
+ SMP Extensions to ARC700, in a "simulation only" Model, supported in
+ ARC ISS (Instruction Set Simulator).
+ The SMP extensions include:
+ -IDU (Interrupt Distribution Unit)
+ -XTL (To enable CPU start/stop/set-PC for another CPU)
+ It doesn't provide coherent Caches and/or Atomic Ops (LLOCK/SCOND)
+
+endif
diff --git a/arch/arc/plat-arcfpga/Makefile b/arch/arc/plat-arcfpga/Makefile
new file mode 100644
index 000000000..66fd0ecd6
--- /dev/null
+++ b/arch/arc/plat-arcfpga/Makefile
@@ -0,0 +1,12 @@
+#
+# Copyright (C) 2011-2012 Synopsys, Inc. (www.synopsys.com)
+#
+# 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.
+#
+
+KBUILD_CFLAGS += -Iarch/arc/plat-arcfpga/include
+
+obj-y := platform.o
+obj-$(CONFIG_ISS_SMP_EXTN) += smp.o
diff --git a/arch/arc/plat-arcfpga/include/plat/smp.h b/arch/arc/plat-arcfpga/include/plat/smp.h
new file mode 100644
index 000000000..c09eb4cfc
--- /dev/null
+++ b/arch/arc/plat-arcfpga/include/plat/smp.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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.
+ *
+ * Rajeshwar Ranga: Interrupt Distribution Unit API's
+ */
+
+#ifndef __PLAT_ARCFPGA_SMP_H
+#define __PLAT_ARCFPGA_SMP_H
+
+#ifdef CONFIG_SMP
+
+#include <linux/types.h>
+#include <asm/arcregs.h>
+
+#define ARC_AUX_IDU_REG_CMD 0x2000
+#define ARC_AUX_IDU_REG_PARAM 0x2001
+
+#define ARC_AUX_XTL_REG_CMD 0x2002
+#define ARC_AUX_XTL_REG_PARAM 0x2003
+
+#define ARC_REG_MP_BCR 0x2021
+
+#define ARC_XTL_CMD_WRITE_PC 0x04
+#define ARC_XTL_CMD_CLEAR_HALT 0x02
+
+/*
+ * Build Configuration Register which identifies the sub-components
+ */
+struct bcr_mp {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int mp_arch:16, pad:5, sdu:1, idu:1, scu:1, ver:8;
+#else
+ unsigned int ver:8, scu:1, idu:1, sdu:1, pad:5, mp_arch:16;
+#endif
+};
+
+/* IDU supports 256 common interrupts */
+#define NR_IDU_IRQS 256
+
+/*
+ * The Aux Regs layout is same bit-by-bit in both BE/LE modes.
+ * However when casted as a bitfield encoded "C" struct, gcc treats it as
+ * memory, generating different code for BE/LE, requiring strcture adj (see
+ * include/asm/arcregs.h)
+ *
+ * However when manually "carving" the value for a Aux, no special handling
+ * of BE is needed because of the property discribed above
+ */
+#define IDU_SET_COMMAND(irq, cmd) \
+do { \
+ uint32_t __val; \
+ __val = (((irq & 0xFF) << 8) | (cmd & 0xFF)); \
+ write_aux_reg(ARC_AUX_IDU_REG_CMD, __val); \
+} while (0)
+
+#define IDU_SET_PARAM(par) write_aux_reg(ARC_AUX_IDU_REG_PARAM, par)
+#define IDU_GET_PARAM() read_aux_reg(ARC_AUX_IDU_REG_PARAM)
+
+/* IDU Commands */
+#define IDU_DISABLE 0x00
+#define IDU_ENABLE 0x01
+#define IDU_IRQ_CLEAR 0x02
+#define IDU_IRQ_ASSERT 0x03
+#define IDU_IRQ_WMODE 0x04
+#define IDU_IRQ_STATUS 0x05
+#define IDU_IRQ_ACK 0x06
+#define IDU_IRQ_PEND 0x07
+#define IDU_IRQ_RMODE 0x08
+#define IDU_IRQ_WBITMASK 0x09
+#define IDU_IRQ_RBITMASK 0x0A
+
+#define idu_enable() IDU_SET_COMMAND(0, IDU_ENABLE)
+#define idu_disable() IDU_SET_COMMAND(0, IDU_DISABLE)
+
+#define idu_irq_assert(irq) IDU_SET_COMMAND((irq), IDU_IRQ_ASSERT)
+#define idu_irq_clear(irq) IDU_SET_COMMAND((irq), IDU_IRQ_CLEAR)
+
+/* IDU Interrupt Mode - Destination Encoding */
+#define IDU_IRQ_MOD_DISABLE 0x00
+#define IDU_IRQ_MOD_ROUND_RECP 0x01
+#define IDU_IRQ_MOD_TCPU_FIRSTRECP 0x02
+#define IDU_IRQ_MOD_TCPU_ALLRECP 0x03
+
+/* IDU Interrupt Mode - Triggering Mode */
+#define IDU_IRQ_MODE_LEVEL_TRIG 0x00
+#define IDU_IRQ_MODE_PULSE_TRIG 0x01
+
+#define IDU_IRQ_MODE_PARAM(dest_mode, trig_mode) \
+ (((trig_mode & 0x01) << 15) | (dest_mode & 0xFF))
+
+struct idu_irq_config {
+ uint8_t irq;
+ uint8_t dest_mode;
+ uint8_t trig_mode;
+};
+
+struct idu_irq_status {
+ uint8_t irq;
+ bool enabled;
+ bool status;
+ bool ack;
+ bool pend;
+ uint8_t next_rr;
+};
+
+extern void idu_irq_set_tgtcpu(uint8_t irq, uint32_t mask);
+extern void idu_irq_set_mode(uint8_t irq, uint8_t dest_mode, uint8_t trig_mode);
+
+extern void iss_model_init_smp(unsigned int cpu);
+extern void iss_model_init_early_smp(void);
+
+#endif /* CONFIG_SMP */
+
+#endif
diff --git a/arch/arc/plat-arcfpga/platform.c b/arch/arc/plat-arcfpga/platform.c
new file mode 100644
index 000000000..afc88254a
--- /dev/null
+++ b/arch/arc/plat-arcfpga/platform.c
@@ -0,0 +1,45 @@
+/*
+ * ARC FPGA Platform support code
+ *
+ * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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/init.h>
+#include <asm/mach_desc.h>
+#include <plat/smp.h>
+
+/*----------------------- Machine Descriptions ------------------------------
+ *
+ * Machine description is simply a set of platform/board specific callbacks
+ * This is not directly related to DeviceTree based dynamic device creation,
+ * however as part of early device tree scan, we also select the right
+ * callback set, by matching the DT compatible name.
+ */
+
+static const char *legacy_fpga_compat[] __initconst = {
+ "snps,arc-angel4",
+ "snps,arc-ml509",
+ NULL,
+};
+
+MACHINE_START(LEGACY_FPGA, "legacy_fpga")
+ .dt_compat = legacy_fpga_compat,
+#ifdef CONFIG_ISS_SMP_EXTN
+ .init_early = iss_model_init_early_smp,
+ .init_smp = iss_model_init_smp,
+#endif
+MACHINE_END
+
+static const char *simulation_compat[] __initconst = {
+ "snps,nsim",
+ "snps,nsimosci",
+ NULL,
+};
+
+MACHINE_START(SIMULATION, "simulation")
+ .dt_compat = simulation_compat,
+MACHINE_END
diff --git a/arch/arc/plat-arcfpga/smp.c b/arch/arc/plat-arcfpga/smp.c
new file mode 100644
index 000000000..64797ba3b
--- /dev/null
+++ b/arch/arc/plat-arcfpga/smp.c
@@ -0,0 +1,186 @@
+/*
+ * ARC700 Simulation-only Extensions for SMP
+ *
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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.
+ *
+ * Vineet Gupta - 2012 : split off arch common and plat specific SMP
+ * Rajeshwar Ranga - 2007 : Interrupt Distribution Unit API's
+ */
+
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <plat/smp.h>
+
+#define IDU_INTERRUPT_0 16
+
+static char smp_cpuinfo_buf[128];
+
+/*
+ *-------------------------------------------------------------------
+ * Platform specific callbacks expected by arch SMP code
+ *-------------------------------------------------------------------
+ */
+
+/*
+ * Master kick starting another CPU
+ */
+static void iss_model_smp_wakeup_cpu(int cpu, unsigned long pc)
+{
+ /* setup the start PC */
+ write_aux_reg(ARC_AUX_XTL_REG_PARAM, pc);
+
+ /* Trigger WRITE_PC cmd for this cpu */
+ write_aux_reg(ARC_AUX_XTL_REG_CMD,
+ (ARC_XTL_CMD_WRITE_PC | (cpu << 8)));
+
+ /* Take the cpu out of Halt */
+ write_aux_reg(ARC_AUX_XTL_REG_CMD,
+ (ARC_XTL_CMD_CLEAR_HALT | (cpu << 8)));
+
+}
+
+static inline int get_hw_config_num_irq(void)
+{
+ uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR);
+
+ switch (val & 0x03) {
+ case 0:
+ return 16;
+ case 1:
+ return 32;
+ case 2:
+ return 8;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Any SMP specific init any CPU does when it comes up.
+ * Here we setup the CPU to enable Inter-Processor-Interrupts
+ * Called for each CPU
+ * -Master : init_IRQ()
+ * -Other(s) : start_kernel_secondary()
+ */
+void iss_model_init_smp(unsigned int cpu)
+{
+ /* Check if CPU is configured for more than 16 interrupts */
+ if (NR_IRQS <= 16 || get_hw_config_num_irq() <= 16)
+ panic("[arcfpga] IRQ system can't support IDU IPI\n");
+
+ idu_disable();
+
+ /****************************************************************
+ * IDU provides a set of Common IRQs, each of which can be dynamically
+ * attached to (1|many|all) CPUs.
+ * The Common IRQs [0-15] are mapped as CPU pvt [16-31]
+ *
+ * Here we use a simple 1:1 mapping:
+ * A CPU 'x' is wired to Common IRQ 'x'.
+ * So an IDU ASSERT on IRQ 'x' will trigger Interupt on CPU 'x', which
+ * makes up for our simple IPI plumbing.
+ *
+ * TBD: Have a dedicated multicast IRQ for sending IPIs to all CPUs
+ * w/o having to do one-at-a-time
+ ******************************************************************/
+
+ /*
+ * Claim an IRQ which would trigger IPI on this CPU.
+ * In IDU parlance it involves setting up a cpu bitmask for the IRQ
+ * The bitmap here contains only 1 CPU (self).
+ */
+ idu_irq_set_tgtcpu(cpu, 0x1 << cpu);
+
+ /* Set the IRQ destination to use the bitmask above */
+ idu_irq_set_mode(cpu, 7, /* XXX: IDU_IRQ_MOD_TCPU_ALLRECP: ISS bug */
+ IDU_IRQ_MODE_PULSE_TRIG);
+
+ idu_enable();
+
+ /* Attach the arch-common IPI ISR to our IDU IRQ */
+ smp_ipi_irq_setup(cpu, IDU_INTERRUPT_0 + cpu);
+}
+
+static void iss_model_ipi_send(int cpu)
+{
+ idu_irq_assert(cpu);
+}
+
+static void iss_model_ipi_clear(int irq)
+{
+ idu_irq_clear(IDU_INTERRUPT_0 + smp_processor_id());
+}
+
+void iss_model_init_early_smp(void)
+{
+#define IS_AVAIL1(var, str) ((var) ? str : "")
+
+ struct bcr_mp mp;
+
+ READ_BCR(ARC_REG_MP_BCR, mp);
+
+ sprintf(smp_cpuinfo_buf, "Extn [ISS-SMP]: v%d, arch(%d) %s %s %s\n",
+ mp.ver, mp.mp_arch, IS_AVAIL1(mp.scu, "SCU"),
+ IS_AVAIL1(mp.idu, "IDU"), IS_AVAIL1(mp.sdu, "SDU"));
+
+ plat_smp_ops.info = smp_cpuinfo_buf;
+
+ plat_smp_ops.cpu_kick = iss_model_smp_wakeup_cpu;
+ plat_smp_ops.ipi_send = iss_model_ipi_send;
+ plat_smp_ops.ipi_clear = iss_model_ipi_clear;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * Low level Platform IPI Providers
+ *-------------------------------------------------------------------
+ */
+
+/* Set the Mode for the Common IRQ */
+void idu_irq_set_mode(uint8_t irq, uint8_t dest_mode, uint8_t trig_mode)
+{
+ uint32_t par = IDU_IRQ_MODE_PARAM(dest_mode, trig_mode);
+
+ IDU_SET_PARAM(par);
+ IDU_SET_COMMAND(irq, IDU_IRQ_WMODE);
+}
+
+/* Set the target cpu Bitmask for Common IRQ */
+void idu_irq_set_tgtcpu(uint8_t irq, uint32_t mask)
+{
+ IDU_SET_PARAM(mask);
+ IDU_SET_COMMAND(irq, IDU_IRQ_WBITMASK);
+}
+
+/* Get the Interrupt Acknowledged status for IRQ (as CPU Bitmask) */
+bool idu_irq_get_ack(uint8_t irq)
+{
+ uint32_t val;
+
+ IDU_SET_COMMAND(irq, IDU_IRQ_ACK);
+ val = IDU_GET_PARAM();
+
+ return val & (1 << irq);
+}
+
+/*
+ * Get the Interrupt Pending status for IRQ (as CPU Bitmask)
+ * -Pending means CPU has not yet noticed the IRQ (e.g. disabled)
+ * -After Interrupt has been taken, the IPI expcitily needs to be
+ * cleared, to be acknowledged.
+ */
+bool idu_irq_get_pend(uint8_t irq)
+{
+ uint32_t val;
+
+ IDU_SET_COMMAND(irq, IDU_IRQ_PEND);
+ val = IDU_GET_PARAM();
+
+ return val & (1 << irq);
+}