Commit | Line | Data |
---|---|---|
141c943f G |
1 | /* |
2 | * linux/arch/unicore32/kernel/setup.c | |
3 | * | |
4 | * Code specific to PKUnity SoC and UniCore ISA | |
5 | * | |
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | #include <linux/module.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/stddef.h> | |
15 | #include <linux/ioport.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/utsname.h> | |
18 | #include <linux/initrd.h> | |
19 | #include <linux/console.h> | |
20 | #include <linux/bootmem.h> | |
21 | #include <linux/seq_file.h> | |
22 | #include <linux/screen_info.h> | |
23 | #include <linux/init.h> | |
24 | #include <linux/root_dev.h> | |
25 | #include <linux/cpu.h> | |
26 | #include <linux/interrupt.h> | |
27 | #include <linux/smp.h> | |
28 | #include <linux/fs.h> | |
29 | #include <linux/proc_fs.h> | |
30 | #include <linux/memblock.h> | |
31 | #include <linux/elf.h> | |
32 | #include <linux/io.h> | |
33 | ||
34 | #include <asm/cputype.h> | |
35 | #include <asm/sections.h> | |
36 | #include <asm/setup.h> | |
37 | #include <asm/cacheflush.h> | |
38 | #include <asm/tlbflush.h> | |
39 | #include <asm/traps.h> | |
1c16d242 | 40 | #include <asm/memblock.h> |
141c943f G |
41 | |
42 | #include "setup.h" | |
43 | ||
44 | #ifndef MEM_SIZE | |
45 | #define MEM_SIZE (16*1024*1024) | |
46 | #endif | |
47 | ||
48 | struct stack { | |
49 | u32 irq[3]; | |
50 | u32 abt[3]; | |
51 | u32 und[3]; | |
52 | } ____cacheline_aligned; | |
53 | ||
54 | static struct stack stacks[NR_CPUS]; | |
55 | ||
f80561e4 CG |
56 | #ifdef CONFIG_VGA_CONSOLE |
57 | struct screen_info screen_info; | |
58 | #endif | |
59 | ||
141c943f G |
60 | char elf_platform[ELF_PLATFORM_SIZE]; |
61 | EXPORT_SYMBOL(elf_platform); | |
62 | ||
63 | static char __initdata cmd_line[COMMAND_LINE_SIZE]; | |
64 | ||
65 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; | |
66 | ||
67 | /* | |
68 | * Standard memory resources | |
69 | */ | |
70 | static struct resource mem_res[] = { | |
141c943f | 71 | { |
8c939402 | 72 | .name = "Kernel code", |
141c943f G |
73 | .start = 0, |
74 | .end = 0, | |
35d98e93 | 75 | .flags = IORESOURCE_SYSTEM_RAM |
141c943f G |
76 | }, |
77 | { | |
78 | .name = "Kernel data", | |
79 | .start = 0, | |
80 | .end = 0, | |
35d98e93 | 81 | .flags = IORESOURCE_SYSTEM_RAM |
141c943f G |
82 | } |
83 | }; | |
84 | ||
6b794743 GX |
85 | #define kernel_code mem_res[0] |
86 | #define kernel_data mem_res[1] | |
141c943f G |
87 | |
88 | /* | |
89 | * These functions re-use the assembly code in head.S, which | |
90 | * already provide the required functionality. | |
91 | */ | |
92 | static void __init setup_processor(void) | |
93 | { | |
94 | printk(KERN_DEFAULT "CPU: UniCore-II [%08x] revision %d, cr=%08lx\n", | |
95 | uc32_cpuid, (int)(uc32_cpuid >> 16) & 15, cr_alignment); | |
96 | ||
97 | sprintf(init_utsname()->machine, "puv3"); | |
98 | sprintf(elf_platform, "ucv2"); | |
99 | } | |
100 | ||
101 | /* | |
102 | * cpu_init - initialise one CPU. | |
103 | * | |
104 | * cpu_init sets up the per-CPU stacks. | |
105 | */ | |
106 | void cpu_init(void) | |
107 | { | |
108 | unsigned int cpu = smp_processor_id(); | |
109 | struct stack *stk = &stacks[cpu]; | |
110 | ||
111 | /* | |
112 | * setup stacks for re-entrant exception handlers | |
113 | */ | |
114 | __asm__ ( | |
115 | "mov.a asr, %1\n\t" | |
116 | "add sp, %0, %2\n\t" | |
117 | "mov.a asr, %3\n\t" | |
118 | "add sp, %0, %4\n\t" | |
119 | "mov.a asr, %5\n\t" | |
120 | "add sp, %0, %6\n\t" | |
121 | "mov.a asr, %7" | |
122 | : | |
123 | : "r" (stk), | |
124 | "r" (PSR_R_BIT | PSR_I_BIT | INTR_MODE), | |
125 | "I" (offsetof(struct stack, irq[0])), | |
126 | "r" (PSR_R_BIT | PSR_I_BIT | ABRT_MODE), | |
127 | "I" (offsetof(struct stack, abt[0])), | |
128 | "r" (PSR_R_BIT | PSR_I_BIT | EXTN_MODE), | |
129 | "I" (offsetof(struct stack, und[0])), | |
130 | "r" (PSR_R_BIT | PSR_I_BIT | PRIV_MODE) | |
131 | : "r30", "cc"); | |
132 | } | |
133 | ||
134 | static int __init uc32_add_memory(unsigned long start, unsigned long size) | |
135 | { | |
136 | struct membank *bank = &meminfo.bank[meminfo.nr_banks]; | |
137 | ||
138 | if (meminfo.nr_banks >= NR_BANKS) { | |
139 | printk(KERN_CRIT "NR_BANKS too low, " | |
140 | "ignoring memory at %#lx\n", start); | |
141 | return -EINVAL; | |
142 | } | |
143 | ||
144 | /* | |
145 | * Ensure that start/size are aligned to a page boundary. | |
146 | * Size is appropriately rounded down, start is rounded up. | |
147 | */ | |
148 | size -= start & ~PAGE_MASK; | |
149 | ||
150 | bank->start = PAGE_ALIGN(start); | |
151 | bank->size = size & PAGE_MASK; | |
152 | ||
153 | /* | |
154 | * Check whether this memory region has non-zero size or | |
155 | * invalid node number. | |
156 | */ | |
157 | if (bank->size == 0) | |
158 | return -EINVAL; | |
159 | ||
160 | meminfo.nr_banks++; | |
161 | return 0; | |
162 | } | |
163 | ||
164 | /* | |
165 | * Pick out the memory size. We look for mem=size@start, | |
166 | * where start and size are "size[KkMm]" | |
167 | */ | |
168 | static int __init early_mem(char *p) | |
169 | { | |
170 | static int usermem __initdata = 1; | |
171 | unsigned long size, start; | |
172 | char *endp; | |
173 | ||
174 | /* | |
175 | * If the user specifies memory size, we | |
176 | * blow away any automatically generated | |
177 | * size. | |
178 | */ | |
179 | if (usermem) { | |
180 | usermem = 0; | |
181 | meminfo.nr_banks = 0; | |
182 | } | |
183 | ||
184 | start = PHYS_OFFSET; | |
185 | size = memparse(p, &endp); | |
186 | if (*endp == '@') | |
187 | start = memparse(endp + 1, NULL); | |
188 | ||
189 | uc32_add_memory(start, size); | |
190 | ||
191 | return 0; | |
192 | } | |
193 | early_param("mem", early_mem); | |
194 | ||
195 | static void __init | |
196 | request_standard_resources(struct meminfo *mi) | |
197 | { | |
198 | struct resource *res; | |
199 | int i; | |
200 | ||
201 | kernel_code.start = virt_to_phys(_stext); | |
202 | kernel_code.end = virt_to_phys(_etext - 1); | |
203 | kernel_data.start = virt_to_phys(_sdata); | |
204 | kernel_data.end = virt_to_phys(_end - 1); | |
205 | ||
206 | for (i = 0; i < mi->nr_banks; i++) { | |
207 | if (mi->bank[i].size == 0) | |
208 | continue; | |
209 | ||
210 | res = alloc_bootmem_low(sizeof(*res)); | |
211 | res->name = "System RAM"; | |
212 | res->start = mi->bank[i].start; | |
213 | res->end = mi->bank[i].start + mi->bank[i].size - 1; | |
35d98e93 | 214 | res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
141c943f G |
215 | |
216 | request_resource(&iomem_resource, res); | |
217 | ||
218 | if (kernel_code.start >= res->start && | |
219 | kernel_code.end <= res->end) | |
220 | request_resource(res, &kernel_code); | |
221 | if (kernel_data.start >= res->start && | |
222 | kernel_data.end <= res->end) | |
223 | request_resource(res, &kernel_data); | |
224 | } | |
141c943f G |
225 | } |
226 | ||
227 | static void (*init_machine)(void) __initdata; | |
228 | ||
229 | static int __init customize_machine(void) | |
230 | { | |
231 | /* customizes platform devices, or adds new ones */ | |
232 | if (init_machine) | |
233 | init_machine(); | |
234 | return 0; | |
235 | } | |
236 | arch_initcall(customize_machine); | |
237 | ||
238 | void __init setup_arch(char **cmdline_p) | |
239 | { | |
240 | char *from = default_command_line; | |
241 | ||
242 | setup_processor(); | |
243 | ||
244 | init_mm.start_code = (unsigned long) _stext; | |
245 | init_mm.end_code = (unsigned long) _etext; | |
246 | init_mm.end_data = (unsigned long) _edata; | |
247 | init_mm.brk = (unsigned long) _end; | |
248 | ||
249 | /* parse_early_param needs a boot_command_line */ | |
250 | strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); | |
251 | ||
252 | /* populate cmd_line too for later use, preserving boot_command_line */ | |
253 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); | |
254 | *cmdline_p = cmd_line; | |
255 | ||
256 | parse_early_param(); | |
257 | ||
258 | uc32_memblock_init(&meminfo); | |
259 | ||
260 | paging_init(); | |
261 | request_standard_resources(&meminfo); | |
262 | ||
263 | cpu_init(); | |
264 | ||
265 | /* | |
266 | * Set up various architecture-specific pointers | |
267 | */ | |
268 | init_machine = puv3_core_init; | |
269 | ||
270 | #ifdef CONFIG_VT | |
271 | #if defined(CONFIG_VGA_CONSOLE) | |
272 | conswitchp = &vga_con; | |
273 | #elif defined(CONFIG_DUMMY_CONSOLE) | |
274 | conswitchp = &dummy_con; | |
275 | #endif | |
276 | #endif | |
277 | early_trap_init(); | |
278 | } | |
279 | ||
280 | static struct cpu cpuinfo_unicore; | |
281 | ||
282 | static int __init topology_init(void) | |
283 | { | |
284 | int i; | |
285 | ||
286 | for_each_possible_cpu(i) | |
287 | register_cpu(&cpuinfo_unicore, i); | |
288 | ||
289 | return 0; | |
290 | } | |
291 | subsys_initcall(topology_init); | |
292 | ||
293 | #ifdef CONFIG_HAVE_PROC_CPU | |
294 | static int __init proc_cpu_init(void) | |
295 | { | |
296 | struct proc_dir_entry *res; | |
297 | ||
298 | res = proc_mkdir("cpu", NULL); | |
299 | if (!res) | |
300 | return -ENOMEM; | |
301 | return 0; | |
302 | } | |
303 | fs_initcall(proc_cpu_init); | |
304 | #endif | |
305 | ||
306 | static int c_show(struct seq_file *m, void *v) | |
307 | { | |
308 | seq_printf(m, "Processor\t: UniCore-II rev %d (%s)\n", | |
309 | (int)(uc32_cpuid >> 16) & 15, elf_platform); | |
310 | ||
311 | seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", | |
312 | loops_per_jiffy / (500000/HZ), | |
313 | (loops_per_jiffy / (5000/HZ)) % 100); | |
314 | ||
315 | /* dump out the processor features */ | |
316 | seq_puts(m, "Features\t: CMOV UC-F64"); | |
317 | ||
318 | seq_printf(m, "\nCPU implementer\t: 0x%02x\n", uc32_cpuid >> 24); | |
319 | seq_printf(m, "CPU architecture: 2\n"); | |
320 | seq_printf(m, "CPU revision\t: %d\n", (uc32_cpuid >> 16) & 15); | |
321 | ||
322 | seq_printf(m, "Cache type\t: write-back\n" | |
323 | "Cache clean\t: cp0 c5 ops\n" | |
324 | "Cache lockdown\t: not support\n" | |
325 | "Cache format\t: Harvard\n"); | |
326 | ||
327 | seq_puts(m, "\n"); | |
328 | ||
329 | seq_printf(m, "Hardware\t: PKUnity v3\n"); | |
330 | ||
331 | return 0; | |
332 | } | |
333 | ||
334 | static void *c_start(struct seq_file *m, loff_t *pos) | |
335 | { | |
336 | return *pos < 1 ? (void *)1 : NULL; | |
337 | } | |
338 | ||
339 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | |
340 | { | |
341 | ++*pos; | |
342 | return NULL; | |
343 | } | |
344 | ||
345 | static void c_stop(struct seq_file *m, void *v) | |
346 | { | |
347 | } | |
348 | ||
349 | const struct seq_operations cpuinfo_op = { | |
350 | .start = c_start, | |
351 | .next = c_next, | |
352 | .stop = c_stop, | |
353 | .show = c_show | |
354 | }; |