diff options
author | Ley Foon Tan <lftan@altera.com> | 2014-11-06 02:20:06 -0500 |
---|---|---|
committer | Ley Foon Tan <lftan@altera.com> | 2014-12-07 23:56:02 -0500 |
commit | 2612b87959db46ab9339b395e0ae2a8c9a2a49f6 (patch) | |
tree | 49686c0bd18a411278226a2db579576fc6c4a598 /arch/nios2 | |
parent | 4182de9e6356c0ac567c072241f014476ffd9ce0 (diff) |
nios2: Cpuinfo handling
Signed-off-by: Ley Foon Tan <lftan@altera.com>
Diffstat (limited to 'arch/nios2')
-rw-r--r-- | arch/nios2/include/asm/cpuinfo.h | 57 | ||||
-rw-r--r-- | arch/nios2/kernel/cpuinfo.c | 201 |
2 files changed, 258 insertions, 0 deletions
diff --git a/arch/nios2/include/asm/cpuinfo.h b/arch/nios2/include/asm/cpuinfo.h new file mode 100644 index 000000000000..e88fcae464d9 --- /dev/null +++ b/arch/nios2/include/asm/cpuinfo.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef _ASM_NIOS2_CPUINFO_H | ||
20 | #define _ASM_NIOS2_CPUINFO_H | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | |||
24 | struct cpuinfo { | ||
25 | /* Core CPU configuration */ | ||
26 | char cpu_impl[12]; | ||
27 | u32 cpu_clock_freq; | ||
28 | u32 mmu; | ||
29 | u32 has_div; | ||
30 | u32 has_mul; | ||
31 | u32 has_mulx; | ||
32 | |||
33 | /* CPU caches */ | ||
34 | u32 icache_line_size; | ||
35 | u32 icache_size; | ||
36 | u32 dcache_line_size; | ||
37 | u32 dcache_size; | ||
38 | |||
39 | /* TLB */ | ||
40 | u32 tlb_pid_num_bits; /* number of bits used for the PID in TLBMISC */ | ||
41 | u32 tlb_num_ways; | ||
42 | u32 tlb_num_ways_log2; | ||
43 | u32 tlb_num_entries; | ||
44 | u32 tlb_num_lines; | ||
45 | u32 tlb_ptr_sz; | ||
46 | |||
47 | /* Addresses */ | ||
48 | u32 reset_addr; | ||
49 | u32 exception_addr; | ||
50 | u32 fast_tlb_miss_exc_addr; | ||
51 | }; | ||
52 | |||
53 | extern struct cpuinfo cpuinfo; | ||
54 | |||
55 | extern void setup_cpuinfo(void); | ||
56 | |||
57 | #endif /* _ASM_NIOS2_CPUINFO_H */ | ||
diff --git a/arch/nios2/kernel/cpuinfo.c b/arch/nios2/kernel/cpuinfo.c new file mode 100644 index 000000000000..b8081c5f50a1 --- /dev/null +++ b/arch/nios2/kernel/cpuinfo.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Altera Corporation | ||
3 | * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> | ||
4 | * | ||
5 | * Based on cpuinfo.c from microblaze | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/of.h> | ||
28 | #include <asm/cpuinfo.h> | ||
29 | |||
30 | struct cpuinfo cpuinfo; | ||
31 | |||
32 | #define err_cpu(x) \ | ||
33 | pr_err("ERROR: Nios II " x " different for kernel and DTS\n") | ||
34 | |||
35 | static inline u32 fcpu(struct device_node *cpu, const char *n) | ||
36 | { | ||
37 | u32 val = 0; | ||
38 | |||
39 | of_property_read_u32(cpu, n, &val); | ||
40 | |||
41 | return val; | ||
42 | } | ||
43 | |||
44 | static inline u32 fcpu_has(struct device_node *cpu, const char *n) | ||
45 | { | ||
46 | return of_get_property(cpu, n, NULL) ? 1 : 0; | ||
47 | } | ||
48 | |||
49 | void __init setup_cpuinfo(void) | ||
50 | { | ||
51 | struct device_node *cpu; | ||
52 | const char *str; | ||
53 | int len; | ||
54 | |||
55 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
56 | if (!cpu) | ||
57 | panic("%s: No CPU found in devicetree!\n", __func__); | ||
58 | |||
59 | if (!fcpu_has(cpu, "altr,has-initda")) | ||
60 | panic("initda instruction is unimplemented. Please update your " | ||
61 | "hardware system to have more than 4-byte line data " | ||
62 | "cache\n"); | ||
63 | |||
64 | cpuinfo.cpu_clock_freq = fcpu(cpu, "clock-frequency"); | ||
65 | |||
66 | str = of_get_property(cpu, "altr,implementation", &len); | ||
67 | if (str) | ||
68 | strlcpy(cpuinfo.cpu_impl, str, sizeof(cpuinfo.cpu_impl)); | ||
69 | else | ||
70 | strcpy(cpuinfo.cpu_impl, "<unknown>"); | ||
71 | |||
72 | cpuinfo.has_div = fcpu_has(cpu, "altr,has-div"); | ||
73 | cpuinfo.has_mul = fcpu_has(cpu, "altr,has-mul"); | ||
74 | cpuinfo.has_mulx = fcpu_has(cpu, "altr,has-mulx"); | ||
75 | |||
76 | #ifdef CONFIG_NIOS2_HW_DIV_SUPPORT | ||
77 | if (!cpuinfo.has_div) | ||
78 | err_cpu("DIV"); | ||
79 | #endif | ||
80 | #ifdef CONFIG_NIOS2_HW_MUL_SUPPORT | ||
81 | if (!cpuinfo.has_mul) | ||
82 | err_cpu("MUL"); | ||
83 | #endif | ||
84 | #ifdef CONFIG_NIOS2_HW_MULX_SUPPORT | ||
85 | if (!cpuinfo.has_mulx) | ||
86 | err_cpu("MULX"); | ||
87 | #endif | ||
88 | |||
89 | cpuinfo.tlb_num_ways = fcpu(cpu, "altr,tlb-num-ways"); | ||
90 | if (!cpuinfo.tlb_num_ways) | ||
91 | panic("altr,tlb-num-ways can't be 0. Please check your hardware " | ||
92 | "system\n"); | ||
93 | cpuinfo.icache_line_size = fcpu(cpu, "icache-line-size"); | ||
94 | cpuinfo.icache_size = fcpu(cpu, "icache-size"); | ||
95 | if (CONFIG_NIOS2_ICACHE_SIZE != cpuinfo.icache_size) | ||
96 | pr_warn("Warning: icache size configuration mismatch " | ||
97 | "(0x%x vs 0x%x) of CONFIG_NIOS2_ICACHE_SIZE vs " | ||
98 | "device tree icache-size\n", | ||
99 | CONFIG_NIOS2_ICACHE_SIZE, cpuinfo.icache_size); | ||
100 | |||
101 | cpuinfo.dcache_line_size = fcpu(cpu, "dcache-line-size"); | ||
102 | if (CONFIG_NIOS2_DCACHE_LINE_SIZE != cpuinfo.dcache_line_size) | ||
103 | pr_warn("Warning: dcache line size configuration mismatch " | ||
104 | "(0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_LINE_SIZE vs " | ||
105 | "device tree dcache-line-size\n", | ||
106 | CONFIG_NIOS2_DCACHE_LINE_SIZE, cpuinfo.dcache_line_size); | ||
107 | cpuinfo.dcache_size = fcpu(cpu, "dcache-size"); | ||
108 | if (CONFIG_NIOS2_DCACHE_SIZE != cpuinfo.dcache_size) | ||
109 | pr_warn("Warning: dcache size configuration mismatch " | ||
110 | "(0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_SIZE vs " | ||
111 | "device tree dcache-size\n", | ||
112 | CONFIG_NIOS2_DCACHE_SIZE, cpuinfo.dcache_size); | ||
113 | |||
114 | cpuinfo.tlb_pid_num_bits = fcpu(cpu, "altr,pid-num-bits"); | ||
115 | cpuinfo.tlb_num_ways_log2 = ilog2(cpuinfo.tlb_num_ways); | ||
116 | cpuinfo.tlb_num_entries = fcpu(cpu, "altr,tlb-num-entries"); | ||
117 | cpuinfo.tlb_num_lines = cpuinfo.tlb_num_entries / cpuinfo.tlb_num_ways; | ||
118 | cpuinfo.tlb_ptr_sz = fcpu(cpu, "altr,tlb-ptr-sz"); | ||
119 | |||
120 | cpuinfo.reset_addr = fcpu(cpu, "altr,reset-addr"); | ||
121 | cpuinfo.exception_addr = fcpu(cpu, "altr,exception-addr"); | ||
122 | cpuinfo.fast_tlb_miss_exc_addr = fcpu(cpu, "altr,fast-tlb-miss-addr"); | ||
123 | } | ||
124 | |||
125 | #ifdef CONFIG_PROC_FS | ||
126 | |||
127 | /* | ||
128 | * Get CPU information for use by the procfs. | ||
129 | */ | ||
130 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
131 | { | ||
132 | int count = 0; | ||
133 | const u32 clockfreq = cpuinfo.cpu_clock_freq; | ||
134 | |||
135 | count = seq_printf(m, | ||
136 | "CPU:\t\tNios II/%s\n" | ||
137 | "MMU:\t\t%s\n" | ||
138 | "FPU:\t\tnone\n" | ||
139 | "Clocking:\t%u.%02u MHz\n" | ||
140 | "BogoMips:\t%lu.%02lu\n" | ||
141 | "Calibration:\t%lu loops\n", | ||
142 | cpuinfo.cpu_impl, | ||
143 | cpuinfo.mmu ? "present" : "none", | ||
144 | clockfreq / 1000000, (clockfreq / 100000) % 10, | ||
145 | (loops_per_jiffy * HZ) / 500000, | ||
146 | ((loops_per_jiffy * HZ) / 5000) % 100, | ||
147 | (loops_per_jiffy * HZ)); | ||
148 | |||
149 | count += seq_printf(m, | ||
150 | "HW:\n" | ||
151 | " MUL:\t\t%s\n" | ||
152 | " MULX:\t\t%s\n" | ||
153 | " DIV:\t\t%s\n", | ||
154 | cpuinfo.has_mul ? "yes" : "no", | ||
155 | cpuinfo.has_mulx ? "yes" : "no", | ||
156 | cpuinfo.has_div ? "yes" : "no"); | ||
157 | |||
158 | count += seq_printf(m, | ||
159 | "Icache:\t\t%ukB, line length: %u\n", | ||
160 | cpuinfo.icache_size >> 10, | ||
161 | cpuinfo.icache_line_size); | ||
162 | |||
163 | count += seq_printf(m, | ||
164 | "Dcache:\t\t%ukB, line length: %u\n", | ||
165 | cpuinfo.dcache_size >> 10, | ||
166 | cpuinfo.dcache_line_size); | ||
167 | |||
168 | count += seq_printf(m, | ||
169 | "TLB:\t\t%u ways, %u entries, %u PID bits\n", | ||
170 | cpuinfo.tlb_num_ways, | ||
171 | cpuinfo.tlb_num_entries, | ||
172 | cpuinfo.tlb_pid_num_bits); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static void *cpuinfo_start(struct seq_file *m, loff_t *pos) | ||
178 | { | ||
179 | unsigned long i = *pos; | ||
180 | |||
181 | return i < num_possible_cpus() ? (void *) (i + 1) : NULL; | ||
182 | } | ||
183 | |||
184 | static void *cpuinfo_next(struct seq_file *m, void *v, loff_t *pos) | ||
185 | { | ||
186 | ++*pos; | ||
187 | return cpuinfo_start(m, pos); | ||
188 | } | ||
189 | |||
190 | static void cpuinfo_stop(struct seq_file *m, void *v) | ||
191 | { | ||
192 | } | ||
193 | |||
194 | const struct seq_operations cpuinfo_op = { | ||
195 | .start = cpuinfo_start, | ||
196 | .next = cpuinfo_next, | ||
197 | .stop = cpuinfo_stop, | ||
198 | .show = show_cpuinfo | ||
199 | }; | ||
200 | |||
201 | #endif /* CONFIG_PROC_FS */ | ||