[PATCH 03/52] [microblaze] Cpuinfo handling

From: monstr
Date: Sat Jan 26 2008 - 11:12:46 EST


From: microblaze <microblaze@xxxxxxxxxxxxxxxxxxxxx>


Signed-off-by: Michal Simek <monstr@xxxxxxxxx>
---
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c | 83 +++++++++++++++++
arch/microblaze/kernel/cpu/cpuinfo-static.c | 123 +++++++++++++++++++++++++
arch/microblaze/kernel/cpu/cpuinfo.c | 93 +++++++++++++++++++
include/asm-microblaze/cpuinfo.h | 114 +++++++++++++++++++++++
4 files changed, 413 insertions(+), 0 deletions(-)
create mode 100644 arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
create mode 100644 arch/microblaze/kernel/cpu/cpuinfo-static.c
create mode 100644 arch/microblaze/kernel/cpu/cpuinfo.c
create mode 100644 include/asm-microblaze/cpuinfo.h

diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
new file mode 100644
index 0000000..ea5f958
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
@@ -0,0 +1,83 @@
+/*
+ * arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
+ *
+ * Support for MicroBlaze PVR (processor version register)
+ *
+ * (c) 2007 John Williams <john.williams@xxxxxxxxxxxxx>
+ * (c) 2007 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/autoconf.h>
+#include <asm/pvr.h>
+#include <asm/cpuinfo.h>
+
+/*
+ * Helper macro to map between fields in our struct cpuinfo, and
+ * the PVR macros in pvr.h.
+ */
+
+#define CI(c, p) ci->c = PVR_##p(pvr)
+
+void set_cpuinfo_pvr_full(struct cpuinfo *ci)
+{
+ struct pvr_s pvr;
+ get_pvr(&pvr);
+
+ CI(use_barrel, USE_BARREL);
+ CI(use_divider, USE_DIV);
+ CI(use_mult, USE_HW_MUL);
+ CI(use_fpu, USE_FPU);
+
+ CI(use_mul_64, USE_MUL64);
+ CI(use_msr_instr, USE_MSR_INSTR);
+ CI(use_pcmp_instr, USE_PCMP_INSTR);
+ CI(ver_code, VERSION);
+
+ CI(use_icache, USE_ICACHE);
+ CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
+ CI(icache_write, ICACHE_ALLOW_WR);
+ CI(icache_line, ICACHE_LINE_LEN);
+ CI(icache_size, ICACHE_BYTE_SIZE);
+ CI(icache_base, ICACHE_BASEADDR);
+ CI(icache_high, ICACHE_HIGHADDR);
+
+ CI(use_dcache, USE_DCACHE);
+ CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
+ CI(dcache_write, DCACHE_ALLOW_WR);
+ CI(dcache_line, DCACHE_LINE_LEN);
+ CI(dcache_size, DCACHE_BYTE_SIZE);
+ CI(dcache_base, DCACHE_BASEADDR);
+ CI(dcache_high, DCACHE_HIGHADDR);
+
+ CI(use_dopb, D_OPB);
+ CI(use_iopb, I_OPB);
+ CI(use_dlmb, D_LMB);
+ CI(use_ilmb, I_LMB);
+ CI(num_fsl, FSL_LINKS);
+
+ CI(irq_edge, INTERRUPT_IS_EDGE);
+ CI(irq_positive, EDGE_IS_POSITIVE);
+
+ CI(area_optimised, AREA_OPTIMISED);
+ CI(opcode_0_illegal, OPCODE_0x0_ILLEGAL);
+ CI(exc_unaligned, UNALIGNED_EXCEPTION);
+ CI(exc_ill_opcode, ILL_OPCODE_EXCEPTION);
+ CI(exc_iopb, IOPB_BUS_EXCEPTION);
+ CI(exc_dopb, DOPB_BUS_EXCEPTION);
+ CI(exc_div_zero, DIV_ZERO_EXCEPTION);
+ CI(exc_fpu, FPU_EXCEPTION);
+
+ CI(hw_debug, DEBUG_ENABLED);
+ CI(num_pc_brk, NUMBER_OF_PC_BRK);
+ CI(num_rd_brk, NUMBER_OF_RD_ADDR_BRK);
+ CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK);
+
+ CI(fpga_family_code, TARGET_FAMILY);
+}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c
new file mode 100644
index 0000000..2d35ff5
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c
@@ -0,0 +1,123 @@
+/*
+ * arch/microblaze/kernel/cpu/cpuinfo-static.c
+ *
+ * (c) 2007 Michal Simek <monstr@xxxxxxxxx>
+ * (c) 2007 John Williams <john.williams@xxxxxxxxxxxxx>
+ * (c) 2007 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/autoconf.h>
+#include <asm/cpuinfo.h>
+
+static char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
+static char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;
+
+void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
+{
+ int i;
+ struct cpuinfo cs;
+
+ memset(&cs, 0, sizeof(struct cpuinfo));
+
+ cs.use_barrel = fcpu(cpu, "xlnx,use-barrel");
+ cs.use_divider = fcpu(cpu, "xlnx,use-div");
+ cs.use_mult = fcpu(cpu, "xlnx,use-hw-mul");
+ cs.use_fpu = fcpu(cpu, "xlnx,use-fpu");
+ cs.use_mul_64 = (cs.use_mult == 2 ? 1 : 0);
+ cs.use_msr_instr = fcpu(cpu, "xlnx,use-msr-instr");
+ cs.use_pcmp_instr = fcpu(cpu, "xlnx,use-pcmp-instr");
+
+ cs.use_exception = fcpu(cpu, "xlnx,unaligned-exceptions") ||
+ fcpu(cpu, "xlnx,ill-opcode-exception") ||
+ fcpu(cpu, "xlnx,iopb-bus-exception") ||
+ fcpu(cpu, "xlnx,dopb-bus-exception") ||
+ fcpu(cpu, "xlnx,div-zero-exception") ||
+ fcpu(cpu, "xlnx,fpu-exception");
+
+ cs.exc_unaligned = fcpu(cpu, "xlnx,unaligned-exceptions");
+ cs.exc_unaligned = fcpu(cpu, "xlnx,ill-opcode-exception");
+ cs.exc_iopb = fcpu(cpu, "xlnx,iopb-bus-exception");
+ cs.exc_dopb = fcpu(cpu, "xlnx,dopb-bus-exception");
+ cs.exc_fpu = fcpu(cpu, "xlnx,fpu-exception");
+ cs.exc_div_zero = fcpu(cpu, "xlnx,div-zero-exception");
+ cs.opcode_0_illegal = fcpu(cpu, "xlnx,opcode-0x0-illegal");
+
+ cs.use_icache = fcpu(cpu, "xlnx,use-icache");
+ cs.icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
+ cs.icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
+ cs.icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
+ if (!cs.icache_line) {
+ if (fcpu(cpu, "xlnx,icache-use-fsl"))
+ cs.icache_line = 4 << 2;
+ else
+ cs.icache_line = 1 << 2;
+ }
+ cs.icache_size = fcpu(cpu, "i-cache-size");
+ cs.icache_base = fcpu(cpu, "i-cache-baseaddr");
+ cs.icache_high = fcpu(cpu, "i-cache-highaddr");
+
+ cs.use_dcache = fcpu(cpu, "xlnx,use-dcache");
+ cs.dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
+ cs.dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
+ cs.dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
+ if (!cs.dcache_line) {
+ if (fcpu(cpu, "xlnx,dcache-use-fsl"))
+ cs.dcache_line = 4 << 2;
+ else
+ cs.dcache_line = 1 << 2;
+ }
+ cs.dcache_size = fcpu(cpu, "d-cache-size");
+ cs.dcache_base = fcpu(cpu, "d-cache-baseaddr");
+ cs.dcache_high = fcpu(cpu, "d-cache-highaddr");
+
+ cs.use_dopb = fcpu(cpu, "xlnx,d-opb");
+ cs.use_iopb = fcpu(cpu, "xlnx,i-opb");
+ cs.use_dlmb = fcpu(cpu, "xlnx,d-lmb");
+ cs.use_ilmb = fcpu(cpu, "xlnx,i-lmb");
+
+ cs.num_fsl = fcpu(cpu, "xlnx,fsl-links");
+ cs.irq_edge = fcpu(cpu, "xlnx,interrupt-is-edge");
+ cs.irq_positive = fcpu(cpu, "xlnx,edge-is-positive");
+ cs.area_optimised = 0;
+
+ cs.hw_debug = fcpu(cpu, "xlnx,debug-enabled");
+ cs.num_pc_brk = fcpu(cpu, "xlnx,number-of-pc-brk");
+ cs.num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");
+ cs.num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk");
+
+ cs.cpu_clock_freq = fcpu(cpu, "timebase-frequency");
+
+ cs.ver_code = 0;
+ cs.fpga_family_code = 0;
+
+ /* Do various fixups based on CPU version and FPGA family strings */
+
+ /* Resolved the CPU version code */
+ for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
+ if (strcmp(cpu_ver_lookup[i].s, cpu_ver_string) == 0)
+ cs.ver_code = cpu_ver_lookup[i].k;
+ }
+
+ /* Resolved the fpga family code */
+ for (i = 0; family_string_lookup[i].s != NULL; i++) {
+ if (strcmp(family_string_lookup[i].s, family_string) == 0)
+ cs.fpga_family_code = family_string_lookup[i].k;
+ }
+
+ /* FIXME - mb3 and spartan2 do not exist in PVR */
+ /* This is mb3 and on a non Spartan2 */
+ if (cs.ver_code == 0x20 && cs.fpga_family_code != 0xf0)
+ /* Hardware Multiplier in use */
+ cs.use_mult = 1;
+
+ /* Copy our static CPUINFO descriptor into place */
+ memcpy(ci, &cs, sizeof(struct cpuinfo));
+}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
new file mode 100644
index 0000000..97c3294
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -0,0 +1,93 @@
+/*
+ * arch/microblaze/kernel/cpu/cpuinfo.c
+ *
+ * (c) 2007 Michal Simek <monstr@xxxxxxxxx>
+ * (c) 2007 John Williams <john.williams@xxxxxxxxxxxxx>
+ * (c) 2007 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/autoconf.h>
+#include <asm/cpuinfo.h>
+#include <asm/pvr.h>
+
+static struct cpuinfo the_cpuinfo;
+struct cpuinfo *cpuinfo = &the_cpuinfo;
+
+static struct cpu_ver_key the_cpu_ver_lookup[] = {
+ /* These key value are as per MBV field in PVR0 */
+ {"5.00.a", 0x01},
+ {"5.00.b", 0x02},
+ {"5.00.c", 0x03},
+ {"6.00.a", 0x04},
+ {"6.00.b", 0x06},
+ {"7.00.a", 0x05},
+ /* FIXME There is no keycode defined in MBV for these versions */
+ {"2.10.a", 0x10},
+ {"3.00.a", 0x20},
+ {"4.00.a", 0x30},
+ {"4.00.b", 0x40},
+ {NULL, 0},
+};
+struct cpu_ver_key *cpu_ver_lookup =
+ (struct cpu_ver_key *) the_cpu_ver_lookup;
+
+/*
+ * FIXME Not sure if the actual key is defined by Xilinx in the PVR
+ */
+static struct family_string_key the_family_string_lookup[] = {
+ {"virtex2", 0x4},
+ {"virtex2pro", 0x5},
+ {"spartan3", 0x6},
+ {"virtex4", 0x7},
+ {"virtex5", 0x8},
+ {"spartan3e", 0x9},
+ {"spartan3a", 0xa},
+ {"spartan3an", 0xb},
+ /* FIXME There is no key code defined for spartan2 */
+ {"spartan2", 0xf0},
+ {NULL, 0},
+};
+struct family_string_key *family_string_lookup =
+ (struct family_string_key *) the_family_string_lookup;
+
+void __init setup_cpuinfo(void)
+{
+ struct device_node *cpu = NULL;
+ int pvr_level = cpu_has_pvr();
+
+ cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu");
+ if (!cpu)
+ printk(KERN_ERR "You don't have cpu!!!\n");
+
+ printk(KERN_INFO "%s: initialising\n", __FUNCTION__);
+
+ switch (pvr_level) {
+ case 0:
+ printk(KERN_WARNING
+ "%s: No PVR support. Using static CPU info from FDT\n",
+ __FUNCTION__);
+ set_cpuinfo_static(cpuinfo, cpu);
+ break;
+#if 0
+ case 1:
+ set_cpuinfo_pvr_partial(cpuinfo);
+ break;
+#endif
+ case 2:
+ printk(KERN_INFO "%s: Using full CPU PVR support\n",
+ __FUNCTION__);
+ set_cpuinfo_pvr_full(cpuinfo);
+ cpuinfo->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
+ break;
+ default:
+ WARN_ON(1);
+ set_cpuinfo_static(cpuinfo, cpu);
+ }
+}
diff --git a/include/asm-microblaze/cpuinfo.h b/include/asm-microblaze/cpuinfo.h
new file mode 100644
index 0000000..0e1621b
--- /dev/null
+++ b/include/asm-microblaze/cpuinfo.h
@@ -0,0 +1,114 @@
+/*
+ * include/asm-microblaze/cpuinfo.h
+ *
+ * Generic support for queying CPU info
+ *
+ * Copyright (C) 2007 John Williams <john.williams@xxxxxxxxxxxxx>
+ * Copyright (C) 2007 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+
+#ifndef _ASM_CPUINFO_H
+#define _ASM_CPUINFO_H
+
+#include <asm/prom.h>
+
+extern unsigned long loops_per_jiffy;
+
+/* CPU Version and FPGA Family code conversion table type */
+struct cpu_ver_key {
+ char *s;
+ unsigned k;
+};
+
+struct family_string_key {
+ char *s;
+ unsigned k;
+};
+
+struct cpuinfo {
+ /* Core CPU configuration */
+ int use_barrel;
+ int use_divider;
+ int use_mult;
+ int use_fpu;
+ int use_exception;
+ int use_mul_64;
+ int use_msr_instr;
+ int use_pcmp_instr;
+
+ int ver_code;
+
+ /* CPU caches */
+ int use_icache;
+ int icache_tagbits;
+ int icache_write;
+ int icache_line;
+ int icache_size;
+ unsigned long icache_base;
+ unsigned long icache_high;
+
+ int use_dcache;
+ int dcache_tagbits;
+ int dcache_write;
+ int dcache_line;
+ int dcache_size;
+ unsigned long dcache_base;
+ unsigned long dcache_high;
+
+ /* Bus connections */
+ int use_dopb;
+ int use_iopb;
+ int use_dlmb;
+ int use_ilmb;
+ int num_fsl;
+
+ /* CPU interrupt line info */
+ int irq_edge;
+ int irq_positive;
+
+ int area_optimised;
+
+ /* HW support for CPU exceptions */
+ int opcode_0_illegal;
+ int exc_unaligned;
+ int exc_ill_opcode;
+ int exc_iopb;
+ int exc_dopb;
+ int exc_div_zero;
+ int exc_fpu;
+
+ /* HW debug support */
+ int hw_debug;
+ int num_pc_brk;
+ int num_rd_brk;
+ int num_wr_brk;
+ int cpu_clock_freq;
+
+ /* FPGA family */
+ int fpga_family_code;
+};
+
+/* Declare a global instance of the cpuinfo_ops */
+extern struct cpuinfo *cpuinfo;
+extern struct cpu_ver_key *cpu_ver_lookup;
+extern struct family_string_key *family_string_lookup;
+
+/* fwd declarations of the various CPUinfo populators */
+void setup_cpuinfo(void);
+
+void set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu);
+void set_cpuinfo_pvr_partial(struct cpuinfo *ci);
+void set_cpuinfo_pvr_full(struct cpuinfo *ci);
+
+static inline unsigned int fcpu(struct device_node *cpu, char *n)
+{
+ int *val;
+ return ((val = (int *) of_get_property(cpu, n, NULL)) ? *val : 0);
+}
+
+#endif /* _ASM_CPUINFO_H */
--
1.5.4.rc4.14.g6fc74

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/