[ubicom32]: move new files out from platform support patch
[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 }