Skip to content

Commit

Permalink
microblaze_v8: Cpuinfo handling
Browse files Browse the repository at this point in the history
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Acked-by: John Linn <john.linn@xilinx.com>
Acked-by: John Williams <john.williams@petalogix.com>
Signed-off-by: Michal Simek <monstr@monstr.eu>
  • Loading branch information
Michal Simek committed Mar 27, 2009
1 parent 8e0ee43 commit 406107d
Show file tree
Hide file tree
Showing 4 changed files with 433 additions and 0 deletions.
102 changes: 102 additions & 0 deletions arch/microblaze/include/asm/cpuinfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Generic support for queying CPU info
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <jwilliams@itee.uq.edu.au>
*
* 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_MICROBLAZE_CPUINFO_H
#define _ASM_MICROBLAZE_CPUINFO_H

#include <asm/prom.h>

/* CPU Version and FPGA Family code conversion table type */
struct cpu_ver_key {
const char *s;
const unsigned k;
};

extern const struct cpu_ver_key cpu_ver_lookup[];

struct family_string_key {
const char *s;
const unsigned k;
};

extern const struct family_string_key family_string_lookup[];

struct cpuinfo {
/* Core CPU configuration */
u32 use_instr;
u32 use_mult;
u32 use_fpu;
u32 use_exc;
u32 ver_code;
u32 mmu;

/* CPU caches */
u32 use_icache;
u32 icache_tagbits;
u32 icache_write;
u32 icache_line;
u32 icache_size;
unsigned long icache_base;
unsigned long icache_high;

u32 use_dcache;
u32 dcache_tagbits;
u32 dcache_write;
u32 dcache_line;
u32 dcache_size;
unsigned long dcache_base;
unsigned long dcache_high;

/* Bus connections */
u32 use_dopb;
u32 use_iopb;
u32 use_dlmb;
u32 use_ilmb;
u32 num_fsl;

/* CPU interrupt line info */
u32 irq_edge;
u32 irq_positive;

u32 area_optimised;

/* HW debug support */
u32 hw_debug;
u32 num_pc_brk;
u32 num_rd_brk;
u32 num_wr_brk;
u32 cpu_clock_freq; /* store real freq of cpu */
u32 freq_div_hz; /* store freq/HZ */

/* FPGA family */
u32 fpga_family_code;

/* User define */
u32 pvr_user1;
u32 pvr_user2;
};

extern struct cpuinfo cpuinfo;

/* 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_full(struct cpuinfo *ci, struct device_node *cpu);

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_MICROBLAZE_CPUINFO_H */
101 changes: 101 additions & 0 deletions arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Support for MicroBlaze PVR (processor version register)
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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 <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); }
#define err_printk(x) \
early_printk("ERROR: Microblaze " x " - different for PVR and DTS\n");

void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
{
struct pvr_s pvr;
int temp; /* for saving temp value */
get_pvr(&pvr);

temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |\
PVR_USE_PCMP_INSTR(pvr) | PVR_USE_DIV(pvr);
if (ci->use_instr != temp)
err_printk("BARREL, MSR, PCMP or DIV");
ci->use_instr = temp;

temp = PVR_USE_HW_MUL(pvr) | PVR_USE_MUL64(pvr);
if (ci->use_mult != temp)
err_printk("HW_MUL");
ci->use_mult = temp;

temp = PVR_USE_FPU(pvr) | PVR_USE_FPU2(pvr);
if (ci->use_fpu != temp)
err_printk("HW_FPU");
ci->use_fpu = temp;

ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) |\
PVR_UNALIGNED_EXCEPTION(pvr) |\
PVR_ILL_OPCODE_EXCEPTION(pvr) |\
PVR_IOPB_BUS_EXCEPTION(pvr) |\
PVR_DOPB_BUS_EXCEPTION(pvr) |\
PVR_DIV_ZERO_EXCEPTION(pvr) |\
PVR_FPU_EXCEPTION(pvr) |\
PVR_FSL_EXCEPTION(pvr);

CI(pvr_user1, USER1);
CI(pvr_user2, USER2);

CI(mmu, USE_MMU);

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(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);

/* take timebase-frequency from DTS */
ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
}
144 changes: 144 additions & 0 deletions arch/microblaze/kernel/cpu/cpuinfo-static.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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 <asm/cpuinfo.h>
#include <asm/pvr.h>

const static char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
const static char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;

#define err_printk(x) \
early_printk("ERROR: Microblaze " x "- different for kernel and DTS\n");

void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
{
int i = 0;

ci->use_instr =
(fcpu(cpu, "xlnx,use-barrel") ? PVR0_USE_BARREL_MASK : 0) |
(fcpu(cpu, "xlnx,use-msr-instr") ? PVR2_USE_MSR_INSTR : 0) |
(fcpu(cpu, "xlnx,use-pcmp-instr") ? PVR2_USE_PCMP_INSTR : 0) |
(fcpu(cpu, "xlnx,use-div") ? PVR0_USE_DIV_MASK : 0);
if (CONFIG_XILINX_MICROBLAZE0_USE_BARREL)
i |= PVR0_USE_BARREL_MASK;
if (CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR)
i |= PVR2_USE_MSR_INSTR;
if (CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR)
i |= PVR2_USE_PCMP_INSTR;
if (CONFIG_XILINX_MICROBLAZE0_USE_DIV)
i |= PVR0_USE_DIV_MASK;
if (ci->use_instr != i)
err_printk("BARREL, MSR, PCMP or DIV");

ci->use_mult = fcpu(cpu, "xlnx,use-hw-mul");
if (ci->use_mult != CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL)
err_printk("HW_MUL");
ci->use_mult =
(ci->use_mult > 1 ?
(PVR2_USE_MUL64_MASK | PVR0_USE_HW_MUL_MASK) :
(ci->use_mult == 1 ? PVR0_USE_HW_MUL_MASK : 0));

ci->use_fpu = fcpu(cpu, "xlnx,use-fpu");
if (ci->use_fpu != CONFIG_XILINX_MICROBLAZE0_USE_FPU)
err_printk("HW_FPU");
ci->use_fpu = (ci->use_fpu > 1 ?
(PVR2_USE_FPU2_MASK | PVR0_USE_FPU_MASK) :
(ci->use_fpu == 1 ? PVR0_USE_FPU_MASK : 0));

ci->use_exc =
(fcpu(cpu, "xlnx,unaligned-exceptions") ?
PVR2_UNALIGNED_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,ill-opcode-exception") ?
PVR2_ILL_OPCODE_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,iopb-bus-exception") ?
PVR2_IOPB_BUS_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,dopb-bus-exception") ?
PVR2_DOPB_BUS_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,div-zero-exception") ?
PVR2_DIV_ZERO_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,fpu-exception") ? PVR2_FPU_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,fsl-exception") ? PVR2_USE_EXTEND_FSL : 0);

ci->use_icache = fcpu(cpu, "xlnx,use-icache");
ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
if (!ci->icache_line) {
if (fcpu(cpu, "xlnx,icache-use-fsl"))
ci->icache_line = 4 << 2;
else
ci->icache_line = 1 << 2;
}
ci->icache_size = fcpu(cpu, "i-cache-size");
ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
ci->icache_high = fcpu(cpu, "i-cache-highaddr");

ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
if (!ci->dcache_line) {
if (fcpu(cpu, "xlnx,dcache-use-fsl"))
ci->dcache_line = 4 << 2;
else
ci->dcache_line = 1 << 2;
}
ci->dcache_size = fcpu(cpu, "d-cache-size");
ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
ci->dcache_high = fcpu(cpu, "d-cache-highaddr");

ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
ci->use_iopb = fcpu(cpu, "xlnx,i-opb");
ci->use_dlmb = fcpu(cpu, "xlnx,d-lmb");
ci->use_ilmb = fcpu(cpu, "xlnx,i-lmb");

ci->num_fsl = fcpu(cpu, "xlnx,fsl-links");
ci->irq_edge = fcpu(cpu, "xlnx,interrupt-is-edge");
ci->irq_positive = fcpu(cpu, "xlnx,edge-is-positive");
ci->area_optimised = 0;

ci->hw_debug = fcpu(cpu, "xlnx,debug-enabled");
ci->num_pc_brk = fcpu(cpu, "xlnx,number-of-pc-brk");
ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");
ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk");

ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");

ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1");
ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");

ci->mmu = fcpu(cpu, "xlnx,use-mmu");

ci->ver_code = 0;
ci->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)
ci->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)
ci->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 (ci->ver_code == 0x20 && ci->fpga_family_code != 0xf0)
/* Hardware Multiplier in use */
ci->use_mult = 1;
}
Loading

0 comments on commit 406107d

Please sign in to comment.