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