aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze/kernel/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/microblaze/kernel/cpu')
-rw-r--r--arch/microblaze/kernel/cpu/Makefile8
-rw-r--r--arch/microblaze/kernel/cpu/cache.c255
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c106
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-static.c144
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c86
-rw-r--r--arch/microblaze/kernel/cpu/mb.c148
-rw-r--r--arch/microblaze/kernel/cpu/pvr.c81
7 files changed, 828 insertions, 0 deletions
diff --git a/arch/microblaze/kernel/cpu/Makefile b/arch/microblaze/kernel/cpu/Makefile
new file mode 100644
index 000000000000..20646e549271
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/Makefile
@@ -0,0 +1,8 @@
1#
2# Build the appropriate CPU version support
3#
4
5EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
6 -DCPU_REV=$(CPU_REV)
7
8obj-y += cache.o cpuinfo.o cpuinfo-pvr-full.o cpuinfo-static.o mb.o pvr.o
diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c
new file mode 100644
index 000000000000..af866a450125
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cache.c
@@ -0,0 +1,255 @@
1/*
2 * Cache control for MicroBlaze cache memories
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of this
10 * archive for more details.
11 */
12
13#include <asm/cacheflush.h>
14#include <linux/cache.h>
15#include <asm/cpuinfo.h>
16
17/* Exported functions */
18
19void _enable_icache(void)
20{
21 if (cpuinfo.use_icache) {
22#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
23 __asm__ __volatile__ (" \
24 msrset r0, %0; \
25 nop; " \
26 : \
27 : "i" (MSR_ICE) \
28 : "memory");
29#else
30 __asm__ __volatile__ (" \
31 mfs r12, rmsr; \
32 nop; \
33 ori r12, r12, %0; \
34 mts rmsr, r12; \
35 nop; " \
36 : \
37 : "i" (MSR_ICE) \
38 : "memory", "r12");
39#endif
40 }
41}
42
43void _disable_icache(void)
44{
45 if (cpuinfo.use_icache) {
46#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
47 __asm__ __volatile__ (" \
48 msrclr r0, %0; \
49 nop; " \
50 : \
51 : "i" (MSR_ICE) \
52 : "memory");
53#else
54 __asm__ __volatile__ (" \
55 mfs r12, rmsr; \
56 nop; \
57 andi r12, r12, ~%0; \
58 mts rmsr, r12; \
59 nop; " \
60 : \
61 : "i" (MSR_ICE) \
62 : "memory", "r12");
63#endif
64 }
65}
66
67void _invalidate_icache(unsigned int addr)
68{
69 if (cpuinfo.use_icache) {
70 __asm__ __volatile__ (" \
71 wic %0, r0" \
72 : \
73 : "r" (addr));
74 }
75}
76
77void _enable_dcache(void)
78{
79 if (cpuinfo.use_dcache) {
80#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
81 __asm__ __volatile__ (" \
82 msrset r0, %0; \
83 nop; " \
84 : \
85 : "i" (MSR_DCE) \
86 : "memory");
87#else
88 __asm__ __volatile__ (" \
89 mfs r12, rmsr; \
90 nop; \
91 ori r12, r12, %0; \
92 mts rmsr, r12; \
93 nop; " \
94 : \
95 : "i" (MSR_DCE) \
96 : "memory", "r12");
97#endif
98 }
99}
100
101void _disable_dcache(void)
102{
103#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
104 __asm__ __volatile__ (" \
105 msrclr r0, %0; \
106 nop; " \
107 : \
108 : "i" (MSR_DCE) \
109 : "memory");
110#else
111 __asm__ __volatile__ (" \
112 mfs r12, rmsr; \
113 nop; \
114 andi r12, r12, ~%0; \
115 mts rmsr, r12; \
116 nop; " \
117 : \
118 : "i" (MSR_DCE) \
119 : "memory", "r12");
120#endif
121}
122
123void _invalidate_dcache(unsigned int addr)
124{
125 __asm__ __volatile__ (" \
126 wdc %0, r0" \
127 : \
128 : "r" (addr));
129}
130
131void __invalidate_icache_all(void)
132{
133 unsigned int i;
134 unsigned flags;
135
136 if (cpuinfo.use_icache) {
137 local_irq_save(flags);
138 __disable_icache();
139
140 /* Just loop through cache size and invalidate, no need to add
141 CACHE_BASE address */
142 for (i = 0; i < cpuinfo.icache_size;
143 i += cpuinfo.icache_line)
144 __invalidate_icache(i);
145
146 __enable_icache();
147 local_irq_restore(flags);
148 }
149}
150
151void __invalidate_icache_range(unsigned long start, unsigned long end)
152{
153 unsigned int i;
154 unsigned flags;
155 unsigned int align;
156
157 if (cpuinfo.use_icache) {
158 /*
159 * No need to cover entire cache range,
160 * just cover cache footprint
161 */
162 end = min(start + cpuinfo.icache_size, end);
163 align = ~(cpuinfo.icache_line - 1);
164 start &= align; /* Make sure we are aligned */
165 /* Push end up to the next cache line */
166 end = ((end & align) + cpuinfo.icache_line);
167
168 local_irq_save(flags);
169 __disable_icache();
170
171 for (i = start; i < end; i += cpuinfo.icache_line)
172 __invalidate_icache(i);
173
174 __enable_icache();
175 local_irq_restore(flags);
176 }
177}
178
179void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
180{
181 __invalidate_icache_all();
182}
183
184void __invalidate_icache_user_range(struct vm_area_struct *vma,
185 struct page *page, unsigned long adr,
186 int len)
187{
188 __invalidate_icache_all();
189}
190
191void __invalidate_cache_sigtramp(unsigned long addr)
192{
193 __invalidate_icache_range(addr, addr + 8);
194}
195
196void __invalidate_dcache_all(void)
197{
198 unsigned int i;
199 unsigned flags;
200
201 if (cpuinfo.use_dcache) {
202 local_irq_save(flags);
203 __disable_dcache();
204
205 /*
206 * Just loop through cache size and invalidate,
207 * no need to add CACHE_BASE address
208 */
209 for (i = 0; i < cpuinfo.dcache_size;
210 i += cpuinfo.dcache_line)
211 __invalidate_dcache(i);
212
213 __enable_dcache();
214 local_irq_restore(flags);
215 }
216}
217
218void __invalidate_dcache_range(unsigned long start, unsigned long end)
219{
220 unsigned int i;
221 unsigned flags;
222 unsigned int align;
223
224 if (cpuinfo.use_dcache) {
225 /*
226 * No need to cover entire cache range,
227 * just cover cache footprint
228 */
229 end = min(start + cpuinfo.dcache_size, end);
230 align = ~(cpuinfo.dcache_line - 1);
231 start &= align; /* Make sure we are aligned */
232 /* Push end up to the next cache line */
233 end = ((end & align) + cpuinfo.dcache_line);
234 local_irq_save(flags);
235 __disable_dcache();
236
237 for (i = start; i < end; i += cpuinfo.dcache_line)
238 __invalidate_dcache(i);
239
240 __enable_dcache();
241 local_irq_restore(flags);
242 }
243}
244
245void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
246{
247 __invalidate_dcache_all();
248}
249
250void __invalidate_dcache_user_range(struct vm_area_struct *vma,
251 struct page *page, unsigned long adr,
252 int len)
253{
254 __invalidate_dcache_all();
255}
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 000000000000..153f57c57b6d
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
@@ -0,0 +1,106 @@
1/*
2 * Support for MicroBlaze PVR (processor version register)
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/string.h>
15#include <asm/pvr.h>
16#include <asm/cpuinfo.h>
17
18/*
19 * Helper macro to map between fields in our struct cpuinfo, and
20 * the PVR macros in pvr.h.
21 */
22
23#define CI(c, p) { ci->c = PVR_##p(pvr); }
24#define err_printk(x) \
25 early_printk("ERROR: Microblaze " x " - different for PVR and DTS\n");
26
27void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
28{
29 struct pvr_s pvr;
30 int temp; /* for saving temp value */
31 get_pvr(&pvr);
32
33 CI(ver_code, VERSION);
34 if (!ci->ver_code) {
35 printk(KERN_ERR "ERROR: MB has broken PVR regs "
36 "-> use DTS setting\n");
37 return;
38 }
39
40 temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |\
41 PVR_USE_PCMP_INSTR(pvr) | PVR_USE_DIV(pvr);
42 if (ci->use_instr != temp)
43 err_printk("BARREL, MSR, PCMP or DIV");
44 ci->use_instr = temp;
45
46 temp = PVR_USE_HW_MUL(pvr) | PVR_USE_MUL64(pvr);
47 if (ci->use_mult != temp)
48 err_printk("HW_MUL");
49 ci->use_mult = temp;
50
51 temp = PVR_USE_FPU(pvr) | PVR_USE_FPU2(pvr);
52 if (ci->use_fpu != temp)
53 err_printk("HW_FPU");
54 ci->use_fpu = temp;
55
56 ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) |\
57 PVR_UNALIGNED_EXCEPTION(pvr) |\
58 PVR_ILL_OPCODE_EXCEPTION(pvr) |\
59 PVR_IOPB_BUS_EXCEPTION(pvr) |\
60 PVR_DOPB_BUS_EXCEPTION(pvr) |\
61 PVR_DIV_ZERO_EXCEPTION(pvr) |\
62 PVR_FPU_EXCEPTION(pvr) |\
63 PVR_FSL_EXCEPTION(pvr);
64
65 CI(pvr_user1, USER1);
66 CI(pvr_user2, USER2);
67
68 CI(mmu, USE_MMU);
69
70 CI(use_icache, USE_ICACHE);
71 CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
72 CI(icache_write, ICACHE_ALLOW_WR);
73 CI(icache_line, ICACHE_LINE_LEN);
74 CI(icache_size, ICACHE_BYTE_SIZE);
75 CI(icache_base, ICACHE_BASEADDR);
76 CI(icache_high, ICACHE_HIGHADDR);
77
78 CI(use_dcache, USE_DCACHE);
79 CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
80 CI(dcache_write, DCACHE_ALLOW_WR);
81 CI(dcache_line, DCACHE_LINE_LEN);
82 CI(dcache_size, DCACHE_BYTE_SIZE);
83 CI(dcache_base, DCACHE_BASEADDR);
84 CI(dcache_high, DCACHE_HIGHADDR);
85
86 CI(use_dopb, D_OPB);
87 CI(use_iopb, I_OPB);
88 CI(use_dlmb, D_LMB);
89 CI(use_ilmb, I_LMB);
90 CI(num_fsl, FSL_LINKS);
91
92 CI(irq_edge, INTERRUPT_IS_EDGE);
93 CI(irq_positive, EDGE_IS_POSITIVE);
94
95 CI(area_optimised, AREA_OPTIMISED);
96
97 CI(hw_debug, DEBUG_ENABLED);
98 CI(num_pc_brk, NUMBER_OF_PC_BRK);
99 CI(num_rd_brk, NUMBER_OF_RD_ADDR_BRK);
100 CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK);
101
102 CI(fpga_family_code, TARGET_FAMILY);
103
104 /* take timebase-frequency from DTS */
105 ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
106}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c
new file mode 100644
index 000000000000..450ca6bb828d
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c
@@ -0,0 +1,144 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/string.h>
14#include <asm/cpuinfo.h>
15#include <asm/pvr.h>
16
17static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
18static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;
19
20#define err_printk(x) \
21 early_printk("ERROR: Microblaze " x "- different for kernel and DTS\n");
22
23void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
24{
25 int i = 0;
26
27 ci->use_instr =
28 (fcpu(cpu, "xlnx,use-barrel") ? PVR0_USE_BARREL_MASK : 0) |
29 (fcpu(cpu, "xlnx,use-msr-instr") ? PVR2_USE_MSR_INSTR : 0) |
30 (fcpu(cpu, "xlnx,use-pcmp-instr") ? PVR2_USE_PCMP_INSTR : 0) |
31 (fcpu(cpu, "xlnx,use-div") ? PVR0_USE_DIV_MASK : 0);
32 if (CONFIG_XILINX_MICROBLAZE0_USE_BARREL)
33 i |= PVR0_USE_BARREL_MASK;
34 if (CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR)
35 i |= PVR2_USE_MSR_INSTR;
36 if (CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR)
37 i |= PVR2_USE_PCMP_INSTR;
38 if (CONFIG_XILINX_MICROBLAZE0_USE_DIV)
39 i |= PVR0_USE_DIV_MASK;
40 if (ci->use_instr != i)
41 err_printk("BARREL, MSR, PCMP or DIV");
42
43 ci->use_mult = fcpu(cpu, "xlnx,use-hw-mul");
44 if (ci->use_mult != CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL)
45 err_printk("HW_MUL");
46 ci->use_mult =
47 (ci->use_mult > 1 ?
48 (PVR2_USE_MUL64_MASK | PVR0_USE_HW_MUL_MASK) :
49 (ci->use_mult == 1 ? PVR0_USE_HW_MUL_MASK : 0));
50
51 ci->use_fpu = fcpu(cpu, "xlnx,use-fpu");
52 if (ci->use_fpu != CONFIG_XILINX_MICROBLAZE0_USE_FPU)
53 err_printk("HW_FPU");
54 ci->use_fpu = (ci->use_fpu > 1 ?
55 (PVR2_USE_FPU2_MASK | PVR0_USE_FPU_MASK) :
56 (ci->use_fpu == 1 ? PVR0_USE_FPU_MASK : 0));
57
58 ci->use_exc =
59 (fcpu(cpu, "xlnx,unaligned-exceptions") ?
60 PVR2_UNALIGNED_EXC_MASK : 0) |
61 (fcpu(cpu, "xlnx,ill-opcode-exception") ?
62 PVR2_ILL_OPCODE_EXC_MASK : 0) |
63 (fcpu(cpu, "xlnx,iopb-bus-exception") ?
64 PVR2_IOPB_BUS_EXC_MASK : 0) |
65 (fcpu(cpu, "xlnx,dopb-bus-exception") ?
66 PVR2_DOPB_BUS_EXC_MASK : 0) |
67 (fcpu(cpu, "xlnx,div-zero-exception") ?
68 PVR2_DIV_ZERO_EXC_MASK : 0) |
69 (fcpu(cpu, "xlnx,fpu-exception") ? PVR2_FPU_EXC_MASK : 0) |
70 (fcpu(cpu, "xlnx,fsl-exception") ? PVR2_USE_EXTEND_FSL : 0);
71
72 ci->use_icache = fcpu(cpu, "xlnx,use-icache");
73 ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
74 ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
75 ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
76 if (!ci->icache_line) {
77 if (fcpu(cpu, "xlnx,icache-use-fsl"))
78 ci->icache_line = 4 << 2;
79 else
80 ci->icache_line = 1 << 2;
81 }
82 ci->icache_size = fcpu(cpu, "i-cache-size");
83 ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
84 ci->icache_high = fcpu(cpu, "i-cache-highaddr");
85
86 ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
87 ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
88 ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
89 ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
90 if (!ci->dcache_line) {
91 if (fcpu(cpu, "xlnx,dcache-use-fsl"))
92 ci->dcache_line = 4 << 2;
93 else
94 ci->dcache_line = 1 << 2;
95 }
96 ci->dcache_size = fcpu(cpu, "d-cache-size");
97 ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
98 ci->dcache_high = fcpu(cpu, "d-cache-highaddr");
99
100 ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
101 ci->use_iopb = fcpu(cpu, "xlnx,i-opb");
102 ci->use_dlmb = fcpu(cpu, "xlnx,d-lmb");
103 ci->use_ilmb = fcpu(cpu, "xlnx,i-lmb");
104
105 ci->num_fsl = fcpu(cpu, "xlnx,fsl-links");
106 ci->irq_edge = fcpu(cpu, "xlnx,interrupt-is-edge");
107 ci->irq_positive = fcpu(cpu, "xlnx,edge-is-positive");
108 ci->area_optimised = 0;
109
110 ci->hw_debug = fcpu(cpu, "xlnx,debug-enabled");
111 ci->num_pc_brk = fcpu(cpu, "xlnx,number-of-pc-brk");
112 ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");
113 ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk");
114
115 ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
116
117 ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1");
118 ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
119
120 ci->mmu = fcpu(cpu, "xlnx,use-mmu");
121
122 ci->ver_code = 0;
123 ci->fpga_family_code = 0;
124
125 /* Do various fixups based on CPU version and FPGA family strings */
126
127 /* Resolved the CPU version code */
128 for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
129 if (strcmp(cpu_ver_lookup[i].s, cpu_ver_string) == 0)
130 ci->ver_code = cpu_ver_lookup[i].k;
131 }
132
133 /* Resolved the fpga family code */
134 for (i = 0; family_string_lookup[i].s != NULL; i++) {
135 if (strcmp(family_string_lookup[i].s, family_string) == 0)
136 ci->fpga_family_code = family_string_lookup[i].k;
137 }
138
139 /* FIXME - mb3 and spartan2 do not exist in PVR */
140 /* This is mb3 and on a non Spartan2 */
141 if (ci->ver_code == 0x20 && ci->fpga_family_code != 0xf0)
142 /* Hardware Multiplier in use */
143 ci->use_mult = 1;
144}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
new file mode 100644
index 000000000000..a10bea119b94
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/init.h>
12#include <linux/slab.h>
13#include <asm/cpuinfo.h>
14#include <asm/pvr.h>
15
16const struct cpu_ver_key cpu_ver_lookup[] = {
17 /* These key value are as per MBV field in PVR0 */
18 {"5.00.a", 0x01},
19 {"5.00.b", 0x02},
20 {"5.00.c", 0x03},
21 {"6.00.a", 0x04},
22 {"6.00.b", 0x06},
23 {"7.00.a", 0x05},
24 {"7.00.b", 0x07},
25 {"7.10.a", 0x08},
26 {"7.10.b", 0x09},
27 {"7.10.c", 0x0a},
28 {"7.10.d", 0x0b},
29 /* FIXME There is no keycode defined in MBV for these versions */
30 {"2.10.a", 0x10},
31 {"3.00.a", 0x20},
32 {"4.00.a", 0x30},
33 {"4.00.b", 0x40},
34 {NULL, 0},
35};
36
37/*
38 * FIXME Not sure if the actual key is defined by Xilinx in the PVR
39 */
40const struct family_string_key family_string_lookup[] = {
41 {"virtex2", 0x4},
42 {"virtex2pro", 0x5},
43 {"spartan3", 0x6},
44 {"virtex4", 0x7},
45 {"virtex5", 0x8},
46 {"spartan3e", 0x9},
47 {"spartan3a", 0xa},
48 {"spartan3an", 0xb},
49 {"spartan3adsp", 0xc},
50 /* FIXME There is no key code defined for spartan2 */
51 {"spartan2", 0xf0},
52 {NULL, 0},
53};
54
55struct cpuinfo cpuinfo;
56
57void __init setup_cpuinfo(void)
58{
59 struct device_node *cpu = NULL;
60
61 cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu");
62 if (!cpu)
63 printk(KERN_ERR "You don't have cpu!!!\n");
64
65 printk(KERN_INFO "%s: initialising\n", __func__);
66
67 switch (cpu_has_pvr()) {
68 case 0:
69 printk(KERN_WARNING
70 "%s: No PVR support. Using static CPU info from FDT\n",
71 __func__);
72 set_cpuinfo_static(&cpuinfo, cpu);
73 break;
74/* FIXME I found weird behavior with MB 7.00.a/b 7.10.a
75 * please do not use FULL PVR with MMU */
76 case 1:
77 printk(KERN_INFO "%s: Using full CPU PVR support\n",
78 __func__);
79 set_cpuinfo_static(&cpuinfo, cpu);
80 set_cpuinfo_pvr_full(&cpuinfo, cpu);
81 break;
82 default:
83 printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__);
84 set_cpuinfo_static(&cpuinfo, cpu);
85 }
86}
diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c
new file mode 100644
index 000000000000..4dcfccdbc364
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/mb.c
@@ -0,0 +1,148 @@
1/*
2 * CPU-version specific code
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2006-2009 PetaLogix
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11
12#include <linux/init.h>
13#include <linux/string.h>
14#include <linux/seq_file.h>
15#include <linux/cpu.h>
16#include <linux/initrd.h>
17
18#include <linux/bug.h>
19#include <asm/cpuinfo.h>
20#include <linux/delay.h>
21#include <linux/io.h>
22#include <asm/page.h>
23#include <linux/param.h>
24#include <asm/pvr.h>
25#include <asm/sections.h>
26#include <asm/setup.h>
27
28static int show_cpuinfo(struct seq_file *m, void *v)
29{
30 int count = 0;
31 char *fpga_family = "Unknown";
32 char *cpu_ver = "Unknown";
33 int i;
34
35 /* Denormalised to get the fpga family string */
36 for (i = 0; family_string_lookup[i].s != NULL; i++) {
37 if (cpuinfo.fpga_family_code == family_string_lookup[i].k) {
38 fpga_family = (char *)family_string_lookup[i].s;
39 break;
40 }
41 }
42
43 /* Denormalised to get the hw version string */
44 for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
45 if (cpuinfo.ver_code == cpu_ver_lookup[i].k) {
46 cpu_ver = (char *)cpu_ver_lookup[i].s;
47 break;
48 }
49 }
50
51 count = seq_printf(m,
52 "CPU-Family: MicroBlaze\n"
53 "FPGA-Arch: %s\n"
54 "CPU-Ver: %s\n"
55 "CPU-MHz: %d.%02d\n"
56 "BogoMips: %lu.%02lu\n",
57 fpga_family,
58 cpu_ver,
59 cpuinfo.cpu_clock_freq /
60 1000000,
61 cpuinfo.cpu_clock_freq %
62 1000000,
63 loops_per_jiffy / (500000 / HZ),
64 (loops_per_jiffy / (5000 / HZ)) % 100);
65
66 count += seq_printf(m,
67 "HW:\n Shift:\t\t%s\n"
68 " MSR:\t\t%s\n"
69 " PCMP:\t\t%s\n"
70 " DIV:\t\t%s\n",
71 (cpuinfo.use_instr & PVR0_USE_BARREL_MASK) ? "yes" : "no",
72 (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) ? "yes" : "no",
73 (cpuinfo.use_instr & PVR2_USE_PCMP_INSTR) ? "yes" : "no",
74 (cpuinfo.use_instr & PVR0_USE_DIV_MASK) ? "yes" : "no");
75
76 count += seq_printf(m,
77 " MMU:\t\t%x\n",
78 cpuinfo.mmu);
79
80 count += seq_printf(m,
81 " MUL:\t\t%s\n"
82 " FPU:\t\t%s\n",
83 (cpuinfo.use_mult & PVR2_USE_MUL64_MASK) ? "v2" :
84 (cpuinfo.use_mult & PVR0_USE_HW_MUL_MASK) ? "v1" : "no",
85 (cpuinfo.use_fpu & PVR2_USE_FPU2_MASK) ? "v2" :
86 (cpuinfo.use_fpu & PVR0_USE_FPU_MASK) ? "v1" : "no");
87
88 count += seq_printf(m,
89 " Exc:\t\t%s%s%s%s%s%s%s%s\n",
90 (cpuinfo.use_exc & PVR2_OPCODE_0x0_ILL_MASK) ? "op0x0 " : "",
91 (cpuinfo.use_exc & PVR2_UNALIGNED_EXC_MASK) ? "unal " : "",
92 (cpuinfo.use_exc & PVR2_ILL_OPCODE_EXC_MASK) ? "ill " : "",
93 (cpuinfo.use_exc & PVR2_IOPB_BUS_EXC_MASK) ? "iopb " : "",
94 (cpuinfo.use_exc & PVR2_DOPB_BUS_EXC_MASK) ? "dopb " : "",
95 (cpuinfo.use_exc & PVR2_DIV_ZERO_EXC_MASK) ? "zero " : "",
96 (cpuinfo.use_exc & PVR2_FPU_EXC_MASK) ? "fpu " : "",
97 (cpuinfo.use_exc & PVR2_USE_FSL_EXC) ? "fsl " : "");
98
99 if (cpuinfo.use_icache)
100 count += seq_printf(m,
101 "Icache:\t\t%ukB\n",
102 cpuinfo.icache_size >> 10);
103 else
104 count += seq_printf(m, "Icache:\t\tno\n");
105
106 if (cpuinfo.use_dcache)
107 count += seq_printf(m,
108 "Dcache:\t\t%ukB\n",
109 cpuinfo.dcache_size >> 10);
110 else
111 count += seq_printf(m, "Dcache:\t\tno\n");
112
113 count += seq_printf(m,
114 "HW-Debug:\t%s\n",
115 cpuinfo.hw_debug ? "yes" : "no");
116
117 count += seq_printf(m,
118 "PVR-USR1:\t%02x\n"
119 "PVR-USR2:\t%08x\n",
120 cpuinfo.pvr_user1,
121 cpuinfo.pvr_user2);
122
123 return 0;
124}
125
126static void *c_start(struct seq_file *m, loff_t *pos)
127{
128 int i = *pos;
129
130 return i < NR_CPUS ? (void *) (i + 1) : NULL;
131}
132
133static void *c_next(struct seq_file *m, void *v, loff_t *pos)
134{
135 ++*pos;
136 return c_start(m, pos);
137}
138
139static void c_stop(struct seq_file *m, void *v)
140{
141}
142
143const struct seq_operations cpuinfo_op = {
144 .start = c_start,
145 .next = c_next,
146 .stop = c_stop,
147 .show = show_cpuinfo,
148};
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c
new file mode 100644
index 000000000000..c9a4340ddd53
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/pvr.c
@@ -0,0 +1,81 @@
1/*
2 * Support for MicroBlaze PVR (processor version register)
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/compiler.h>
15#include <asm/system.h>
16#include <asm/exceptions.h>
17#include <asm/pvr.h>
18
19/*
20 * Until we get an assembler that knows about the pvr registers,
21 * this horrible cruft will have to do.
22 * That hardcoded opcode is mfs r3, rpvrNN
23 */
24
25#define get_single_pvr(pvrid, val) \
26{ \
27 register unsigned tmp __asm__("r3"); \
28 tmp = 0x0; /* Prevent warning about unused */ \
29 __asm__ __volatile__ ( \
30 ".byte 0x94,0x60,0xa0, " #pvrid "\n\t" \
31 : "=r" (tmp) : : "memory"); \
32 val = tmp; \
33}
34
35/*
36 * Does the CPU support the PVR register?
37 * return value:
38 * 0: no PVR
39 * 1: simple PVR
40 * 2: full PVR
41 *
42 * This must work on all CPU versions, including those before the
43 * PVR was even an option.
44 */
45
46int cpu_has_pvr(void)
47{
48 unsigned flags;
49 unsigned pvr0;
50
51 local_save_flags(flags);
52
53 /* PVR bit in MSR tells us if there is any support */
54 if (!(flags & PVR_MSR_BIT))
55 return 0;
56
57 get_single_pvr(0x00, pvr0);
58 pr_debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);
59
60 if (pvr0 & PVR0_PVR_FULL_MASK)
61 return 1;
62
63 /* for partial PVR use static cpuinfo */
64 return 2;
65}
66
67void get_pvr(struct pvr_s *p)
68{
69 get_single_pvr(0, p->pvr[0]);
70 get_single_pvr(1, p->pvr[1]);
71 get_single_pvr(2, p->pvr[2]);
72 get_single_pvr(3, p->pvr[3]);
73 get_single_pvr(4, p->pvr[4]);
74 get_single_pvr(5, p->pvr[5]);
75 get_single_pvr(6, p->pvr[6]);
76 get_single_pvr(7, p->pvr[7]);
77 get_single_pvr(8, p->pvr[8]);
78 get_single_pvr(9, p->pvr[9]);
79 get_single_pvr(10, p->pvr[10]);
80 get_single_pvr(11, p->pvr[11]);
81}