disable sstrip when using musl
[openwrt/openwrt.git] / target / linux / ubicom32 / files / arch / ubicom32 / kernel / processor.c
1 /*
2 * arch/ubicom32/kernel/processor.c
3 * Ubicom32 architecture processor info implementation.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 *
7 * This file is part of the Ubicom32 Linux Kernel Port.
8 *
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
22 *
23 * Ubicom32 implementation derived from (with many thanks):
24 * arch/m68knommu
25 * arch/blackfin
26 * arch/parisc
27 */
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/init.h>
31 #include <linux/sched.h>
32 #include <linux/interrupt.h>
33 #include <linux/irq.h>
34 #include <linux/profile.h>
35 #include <linux/clocksource.h>
36 #include <linux/types.h>
37 #include <linux/seq_file.h>
38 #include <linux/delay.h>
39 #include <linux/cpu.h>
40 #include <asm/devtree.h>
41 #include <asm/processor.h>
42 #include <asm/cpu.h>
43 #include <asm/ocm_size.h>
44
45 struct procnode {
46 struct devtree_node dn;
47 unsigned int threads;
48 unsigned int timers;
49 unsigned int frequency;
50 unsigned int ddr_frequency;
51 unsigned int interrupt0;
52 unsigned int interrupt1;
53 void *socm;
54 void *eocm;
55 void *sdram;
56 void *edram;
57 unsigned int arch_version;
58 void *os_syscall_begin;
59 void *os_syscall_end;
60 };
61
62 struct procnode *pn;
63
64 /*
65 * show_processorinfo()
66 * Print the actual processor information.
67 */
68 static void show_processorinfo(struct seq_file *m)
69 {
70 char *cpu, *mmu, *fpu;
71 unsigned int clockfreq;
72 unsigned int chipid;
73
74 cpu = CPU;
75 mmu = "none";
76 fpu = "none";
77
78 asm volatile (
79 "move.4 %0, CHIP_ID \n\t"
80 : "=r" (chipid)
81 );
82
83 /*
84 * General Processor Information.
85 */
86 seq_printf(m, "Vendor:\t\t%s\n", "Ubicom");
87 seq_printf(m, "CPU:\t\t%s\n", cpu);
88 seq_printf(m, "MMU:\t\t%s\n", mmu);
89 seq_printf(m, "FPU:\t\t%s\n", fpu);
90 seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16);
91 seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff));
92
93 /*
94 * Now compute the clock frequency in Mhz.
95 */
96 clockfreq = processor_frequency();
97 seq_printf(m, "Clock Freq:\t%u.0 MHz\n",
98 clockfreq / 1000000);
99 seq_printf(m, "DDR Freq:\t%u.0 MHz\n",
100 pn ? pn->ddr_frequency / 1000000 : 0);
101 seq_printf(m, "BogoMips:\t%lu.%02lu\n",
102 (loops_per_jiffy * HZ) / 500000,
103 ((loops_per_jiffy * HZ) / 5000) % 100);
104 seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ));
105 }
106
107 /*
108 * show_cpuinfo()
109 * Get CPU information for use by the procfs.
110 */
111 static int show_cpuinfo(struct seq_file *m, void *v)
112 {
113 unsigned long n = (unsigned long)v - 1;
114
115 #if defined(CONFIG_SMP)
116 struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n);
117 #endif
118
119 /*
120 * Print the general processor information on the first
121 * call.
122 */
123 if (n == 0) {
124 show_processorinfo(m);
125 }
126
127 #if defined(CONFIG_SMP)
128 /*
129 * For each hwthread, print if this hwthread is running Linux
130 * or is an I/O thread.
131 */
132 if (cpu_isset(n, cpu_online_map)) {
133 seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid);
134 } else {
135 seq_printf(m, "cpu[%02lu]:\toff-line\n", n);
136 }
137 #endif
138 return 0;
139
140 }
141
142 static void *c_start(struct seq_file *m, loff_t *pos)
143 {
144 unsigned long i = *pos;
145
146 return i < NR_CPUS ? (void *)(i + 1) : NULL;
147 }
148
149 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
150 {
151 ++*pos;
152 return c_start(m, pos);
153 }
154
155 static void c_stop(struct seq_file *m, void *v)
156 {
157 }
158
159 const struct seq_operations cpuinfo_op = {
160 .start = c_start,
161 .next = c_next,
162 .stop = c_stop,
163 .show = show_cpuinfo,
164 };
165
166 /*
167 * processor_timers()
168 * Returns the timers available to Linux.
169 */
170 unsigned int processor_timers(void)
171 {
172 if (!pn) {
173 return 0;
174 }
175 return pn->timers;
176 }
177
178 /*
179 * processor_threads()
180 * Returns the threads available to Linux.
181 */
182 unsigned int processor_threads(void)
183 {
184 if (!pn) {
185 return 0;
186 }
187 return pn->threads;
188 }
189
190 /*
191 * processor_frequency()
192 * Returns the frequency of the system clock.
193 */
194 unsigned int processor_frequency(void)
195 {
196 if (!pn) {
197 return 0;
198 }
199 return pn->frequency;
200 }
201 EXPORT_SYMBOL(processor_frequency);
202
203 /*
204 * processor_interrupts()
205 * Return the interrupts that are setup at boot time.
206 */
207 int processor_interrupts(unsigned int *int0, unsigned int *int1)
208 {
209 if (!pn) {
210 return -EFAULT;
211 }
212
213 if (int0) {
214 *int0 = pn->interrupt0;
215 }
216
217 if (int1) {
218 *int1 = pn->interrupt1;
219 }
220 return 0;
221 }
222
223 /*
224 * processor_ocm()
225 * Returns the start and end of OCM available to Linux.
226 */
227 void processor_ocm(unsigned long *socm, unsigned long *eocm)
228 {
229 *socm = (unsigned long)pn->socm;
230 *eocm = (unsigned long)pn->eocm;
231 }
232
233 /*
234 * processor_dram()
235 * Returns the start and end of dram available to Linux.
236 */
237 void processor_dram(unsigned long *sdram, unsigned long *edram)
238 {
239 *sdram = (unsigned long)pn->sdram;
240 *edram = (unsigned long)pn->edram;
241 }
242
243 /*
244 * processor_validate_failed()
245 * Returns the dram available to Linux.
246 */
247 static noinline void processor_validate_failed(void)
248 {
249 while (1)
250 THREAD_STALL;
251 }
252
253 /*
254 * processor_validate()
255 * Validates the procnode against limitations of this link/built.
256 */
257 static void processor_validate(void)
258 {
259 void *dram_start = (void *)(KERNELSTART);
260 void *dram_end = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE);
261 #if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
262 void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE);
263 void *ocm_data_end = (void *)(OCMEND - APP_OCM_DATA_SIZE);
264 #endif
265 extern void __os_syscall_begin;
266 extern void __os_syscall_end;
267 int proc_node_valid = 1;
268
269 if (!pn) {
270 printk(KERN_ERR "ERROR: processor node not found\n");
271 goto error;
272 }
273
274
275 if (dram_start < pn->sdram || dram_end > pn->edram) {
276 printk(KERN_ERR "ERROR: processor dram mismatch %p-%p "
277 "available but we are expecting %p-%p\n",
278 pn->sdram, pn->edram, dram_start, dram_end);
279 proc_node_valid = 0;
280 } else {
281 printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
282 pn->sdram, pn->edram, dram_start, dram_end);
283 }
284 if (&__os_syscall_begin < pn->os_syscall_begin ||
285 &__os_syscall_end > pn->os_syscall_end) {
286 printk(KERN_ERR "ERROR: processor syscall area mismatch "
287 "%p-%p available but we are expecting %p-%p\n",
288 pn->os_syscall_begin, pn->os_syscall_end,
289 &__os_syscall_begin, &__os_syscall_end);
290 proc_node_valid = 0;
291 } else {
292 printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
293 pn->sdram, pn->edram, dram_start, dram_end);
294 }
295 #if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
296 if (ocm_code_start < pn->socm || ocm_data_end > pn->eocm) {
297 printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p "
298 "available but we are expecting %p-%p\n",
299 pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
300 proc_node_valid = 0;
301 } else {
302 printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n",
303 pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
304
305 }
306 #endif
307
308 if (UBICOM32_ARCH_VERSION != pn->arch_version) {
309 printk(KERN_ERR "ERROR: processor arch mismatch, kernel"
310 "compiled for %d found %d\n",
311 UBICOM32_ARCH_VERSION, pn->arch_version);
312 proc_node_valid = 0;
313 }
314
315 if (proc_node_valid)
316 return;
317 error:
318 processor_validate_failed();
319 }
320
321 void __init processor_init(void)
322 {
323 /*
324 * If we do not have a trap node in the device tree, we leave the fault
325 * handling to the underlying hardware.
326 */
327 pn = (struct procnode *)devtree_find_node("processor");
328
329 processor_validate();
330
331 /*
332 * If necessary correct the initial range registers to cover the
333 * complete physical space
334 */
335 if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) {
336 printk(KERN_INFO "updating range registers for expanded dram\n");
337 asm volatile (
338 " move.4 D_RANGE1_HI, %0 \t\n"
339 " move.4 I_RANGE0_HI, %0 \t\n"
340 #ifdef CONFIG_PROTECT_KERNEL
341 " move.4 D_RANGE2_HI, %0 \t\n"
342 " move.4 I_RANGE2_HI, %0 \t\n"
343 #endif
344 : : "a"((unsigned long)pn->edram - 4)
345 );
346 }
347
348 }