Merge commit 'v2.6.27-rc1' into for-linus
[linux-2.6] / arch / xtensa / kernel / setup.c
1 /*
2  * arch/xtensa/kernel/setup.c
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 1995  Linus Torvalds
9  * Copyright (C) 2001 - 2005  Tensilica Inc.
10  *
11  * Chris Zankel <chris@zankel.net>
12  * Joe Taylor   <joe@tensilica.com, joetylr@yahoo.com>
13  * Kevin Chea
14  * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
15  */
16
17 #include <linux/errno.h>
18 #include <linux/init.h>
19 #include <linux/mm.h>
20 #include <linux/proc_fs.h>
21 #include <linux/screen_info.h>
22 #include <linux/bootmem.h>
23 #include <linux/kernel.h>
24
25 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
26 # include <linux/console.h>
27 #endif
28
29 #ifdef CONFIG_RTC
30 # include <linux/timex.h>
31 #endif
32
33 #ifdef CONFIG_PROC_FS
34 # include <linux/seq_file.h>
35 #endif
36
37 #include <asm/system.h>
38 #include <asm/bootparam.h>
39 #include <asm/pgtable.h>
40 #include <asm/processor.h>
41 #include <asm/timex.h>
42 #include <asm/platform.h>
43 #include <asm/page.h>
44 #include <asm/setup.h>
45 #include <asm/param.h>
46
47 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
48 struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
49 #endif
50
51 #ifdef CONFIG_BLK_DEV_FD
52 extern struct fd_ops no_fd_ops;
53 struct fd_ops *fd_ops;
54 #endif
55
56 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
57 extern struct ide_ops no_ide_ops;
58 struct ide_ops *ide_ops;
59 #endif
60
61 extern struct rtc_ops no_rtc_ops;
62 struct rtc_ops *rtc_ops;
63
64 #ifdef CONFIG_BLK_DEV_INITRD
65 extern void *initrd_start;
66 extern void *initrd_end;
67 extern void *__initrd_start;
68 extern void *__initrd_end;
69 int initrd_is_mapped = 0;
70 extern int initrd_below_start_ok;
71 #endif
72
73 unsigned char aux_device_present;
74 extern unsigned long loops_per_jiffy;
75
76 /* Command line specified as configuration option. */
77
78 static char __initdata command_line[COMMAND_LINE_SIZE];
79
80 #ifdef CONFIG_CMDLINE_BOOL
81 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
82 #endif
83
84 sysmem_info_t __initdata sysmem;
85
86 #ifdef CONFIG_BLK_DEV_INITRD
87 int initrd_is_mapped;
88 #endif
89
90 extern void init_mmu(void);
91
92 /*
93  * Boot parameter parsing.
94  *
95  * The Xtensa port uses a list of variable-sized tags to pass data to
96  * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
97  * to be recognised. The list is terminated with a zero-sized
98  * BP_TAG_LAST tag.
99  */
100
101 typedef struct tagtable {
102         u32 tag;
103         int (*parse)(const bp_tag_t*);
104 } tagtable_t;
105
106 #define __tagtable(tag, fn) static tagtable_t __tagtable_##fn           \
107         __attribute__((unused, __section__(".taglist"))) = { tag, fn }
108
109 /* parse current tag */
110
111 static int __init parse_tag_mem(const bp_tag_t *tag)
112 {
113         meminfo_t *mi = (meminfo_t*)(tag->data);
114
115         if (mi->type != MEMORY_TYPE_CONVENTIONAL)
116                 return -1;
117
118         if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
119                 printk(KERN_WARNING
120                        "Ignoring memory bank 0x%08lx size %ldKB\n",
121                        (unsigned long)mi->start,
122                        (unsigned long)mi->end - (unsigned long)mi->start);
123                 return -EINVAL;
124         }
125         sysmem.bank[sysmem.nr_banks].type  = mi->type;
126         sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
127         sysmem.bank[sysmem.nr_banks].end   = mi->end & PAGE_SIZE;
128         sysmem.nr_banks++;
129
130         return 0;
131 }
132
133 __tagtable(BP_TAG_MEMORY, parse_tag_mem);
134
135 #ifdef CONFIG_BLK_DEV_INITRD
136
137 static int __init parse_tag_initrd(const bp_tag_t* tag)
138 {
139         meminfo_t* mi;
140         mi = (meminfo_t*)(tag->data);
141         initrd_start = (void*)(mi->start);
142         initrd_end = (void*)(mi->end);
143
144         return 0;
145 }
146
147 __tagtable(BP_TAG_INITRD, parse_tag_initrd);
148
149 #endif /* CONFIG_BLK_DEV_INITRD */
150
151 static int __init parse_tag_cmdline(const bp_tag_t* tag)
152 {
153         strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
154         command_line[COMMAND_LINE_SIZE - 1] = '\0';
155         return 0;
156 }
157
158 __tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
159
160 static int __init parse_bootparam(const bp_tag_t* tag)
161 {
162         extern tagtable_t __tagtable_begin, __tagtable_end;
163         tagtable_t *t;
164
165         /* Boot parameters must start with a BP_TAG_FIRST tag. */
166
167         if (tag->id != BP_TAG_FIRST) {
168                 printk(KERN_WARNING "Invalid boot parameters!\n");
169                 return 0;
170         }
171
172         tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
173
174         /* Parse all tags. */
175
176         while (tag != NULL && tag->id != BP_TAG_LAST) {
177                 for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
178                         if (tag->id == t->tag) {
179                                 t->parse(tag);
180                                 break;
181                         }
182                 }
183                 if (t == &__tagtable_end)
184                         printk(KERN_WARNING "Ignoring tag "
185                                "0x%08x\n", tag->id);
186                 tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
187         }
188
189         return 0;
190 }
191
192 /*
193  * Initialize architecture. (Early stage)
194  */
195
196 void __init init_arch(bp_tag_t *bp_start)
197 {
198
199 #ifdef CONFIG_BLK_DEV_INITRD
200         initrd_start = &__initrd_start;
201         initrd_end = &__initrd_end;
202 #endif
203
204         sysmem.nr_banks = 0;
205
206 #ifdef CONFIG_CMDLINE_BOOL
207         strcpy(command_line, default_command_line);
208 #endif
209
210         /* Parse boot parameters */
211
212         if (bp_start)
213           parse_bootparam(bp_start);
214
215         if (sysmem.nr_banks == 0) {
216                 sysmem.nr_banks = 1;
217                 sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
218                 sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
219                                      + PLATFORM_DEFAULT_MEM_SIZE;
220         }
221
222         /* Early hook for platforms */
223
224         platform_init(bp_start);
225
226         /* Initialize MMU. */
227
228         init_mmu();
229 }
230
231 /*
232  * Initialize system. Setup memory and reserve regions.
233  */
234
235 extern char _end;
236 extern char _stext;
237 extern char _WindowVectors_text_start;
238 extern char _WindowVectors_text_end;
239 extern char _DebugInterruptVector_literal_start;
240 extern char _DebugInterruptVector_text_end;
241 extern char _KernelExceptionVector_literal_start;
242 extern char _KernelExceptionVector_text_end;
243 extern char _UserExceptionVector_literal_start;
244 extern char _UserExceptionVector_text_end;
245 extern char _DoubleExceptionVector_literal_start;
246 extern char _DoubleExceptionVector_text_end;
247
248 void __init setup_arch(char **cmdline_p)
249 {
250         extern int mem_reserve(unsigned long, unsigned long, int);
251         extern void bootmem_init(void);
252
253         memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
254         boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
255         *cmdline_p = command_line;
256
257         /* Reserve some memory regions */
258
259 #ifdef CONFIG_BLK_DEV_INITRD
260         if (initrd_start < initrd_end) {
261                 initrd_is_mapped = mem_reserve(__pa(initrd_start),
262                                                __pa(initrd_end), 0);
263                 initrd_below_start_ok = 1;
264         } else {
265                 initrd_start = 0;
266         }
267 #endif
268
269         mem_reserve(__pa(&_stext),__pa(&_end), 1);
270
271         mem_reserve(__pa(&_WindowVectors_text_start),
272                     __pa(&_WindowVectors_text_end), 0);
273
274         mem_reserve(__pa(&_DebugInterruptVector_literal_start),
275                     __pa(&_DebugInterruptVector_text_end), 0);
276
277         mem_reserve(__pa(&_KernelExceptionVector_literal_start),
278                     __pa(&_KernelExceptionVector_text_end), 0);
279
280         mem_reserve(__pa(&_UserExceptionVector_literal_start),
281                     __pa(&_UserExceptionVector_text_end), 0);
282
283         mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
284                     __pa(&_DoubleExceptionVector_text_end), 0);
285
286         bootmem_init();
287
288         platform_setup(cmdline_p);
289
290
291         paging_init();
292
293 #ifdef CONFIG_VT
294 # if defined(CONFIG_VGA_CONSOLE)
295         conswitchp = &vga_con;
296 # elif defined(CONFIG_DUMMY_CONSOLE)
297         conswitchp = &dummy_con;
298 # endif
299 #endif
300
301 #ifdef CONFIG_PCI
302         platform_pcibios_init();
303 #endif
304 }
305
306 void machine_restart(char * cmd)
307 {
308         platform_restart();
309 }
310
311 void machine_halt(void)
312 {
313         platform_halt();
314         while (1);
315 }
316
317 void machine_power_off(void)
318 {
319         platform_power_off();
320         while (1);
321 }
322 #ifdef CONFIG_PROC_FS
323
324 /*
325  * Display some core information through /proc/cpuinfo.
326  */
327
328 static int
329 c_show(struct seq_file *f, void *slot)
330 {
331         /* high-level stuff */
332         seq_printf(f,"processor\t: 0\n"
333                      "vendor_id\t: Tensilica\n"
334                      "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
335                      "core ID\t\t: " XCHAL_CORE_ID "\n"
336                      "build ID\t: 0x%x\n"
337                      "byte order\t: %s\n"
338                      "cpu MHz\t\t: %lu.%02lu\n"
339                      "bogomips\t: %lu.%02lu\n",
340                      XCHAL_BUILD_UNIQUE_ID,
341                      XCHAL_HAVE_BE ?  "big" : "little",
342                      CCOUNT_PER_JIFFY/(1000000/HZ),
343                      (CCOUNT_PER_JIFFY/(10000/HZ)) % 100,
344                      loops_per_jiffy/(500000/HZ),
345                      (loops_per_jiffy/(5000/HZ)) % 100);
346
347         seq_printf(f,"flags\t\t: "
348 #if XCHAL_HAVE_NMI
349                      "nmi "
350 #endif
351 #if XCHAL_HAVE_DEBUG
352                      "debug "
353 # if XCHAL_HAVE_OCD
354                      "ocd "
355 # endif
356 #endif
357 #if XCHAL_HAVE_DENSITY
358                      "density "
359 #endif
360 #if XCHAL_HAVE_BOOLEANS
361                      "boolean "
362 #endif
363 #if XCHAL_HAVE_LOOPS
364                      "loop "
365 #endif
366 #if XCHAL_HAVE_NSA
367                      "nsa "
368 #endif
369 #if XCHAL_HAVE_MINMAX
370                      "minmax "
371 #endif
372 #if XCHAL_HAVE_SEXT
373                      "sext "
374 #endif
375 #if XCHAL_HAVE_CLAMPS
376                      "clamps "
377 #endif
378 #if XCHAL_HAVE_MAC16
379                      "mac16 "
380 #endif
381 #if XCHAL_HAVE_MUL16
382                      "mul16 "
383 #endif
384 #if XCHAL_HAVE_MUL32
385                      "mul32 "
386 #endif
387 #if XCHAL_HAVE_MUL32_HIGH
388                      "mul32h "
389 #endif
390 #if XCHAL_HAVE_FP
391                      "fpu "
392 #endif
393                      "\n");
394
395         /* Registers. */
396         seq_printf(f,"physical aregs\t: %d\n"
397                      "misc regs\t: %d\n"
398                      "ibreak\t\t: %d\n"
399                      "dbreak\t\t: %d\n",
400                      XCHAL_NUM_AREGS,
401                      XCHAL_NUM_MISC_REGS,
402                      XCHAL_NUM_IBREAK,
403                      XCHAL_NUM_DBREAK);
404
405
406         /* Interrupt. */
407         seq_printf(f,"num ints\t: %d\n"
408                      "ext ints\t: %d\n"
409                      "int levels\t: %d\n"
410                      "timers\t\t: %d\n"
411                      "debug level\t: %d\n",
412                      XCHAL_NUM_INTERRUPTS,
413                      XCHAL_NUM_EXTINTERRUPTS,
414                      XCHAL_NUM_INTLEVELS,
415                      XCHAL_NUM_TIMERS,
416                      XCHAL_DEBUGLEVEL);
417
418         /* Cache */
419         seq_printf(f,"icache line size: %d\n"
420                      "icache ways\t: %d\n"
421                      "icache size\t: %d\n"
422                      "icache flags\t: "
423 #if XCHAL_ICACHE_LINE_LOCKABLE
424                      "lock"
425 #endif
426                      "\n"
427                      "dcache line size: %d\n"
428                      "dcache ways\t: %d\n"
429                      "dcache size\t: %d\n"
430                      "dcache flags\t: "
431 #if XCHAL_DCACHE_IS_WRITEBACK
432                      "writeback"
433 #endif
434 #if XCHAL_DCACHE_LINE_LOCKABLE
435                      "lock"
436 #endif
437                      "\n",
438                      XCHAL_ICACHE_LINESIZE,
439                      XCHAL_ICACHE_WAYS,
440                      XCHAL_ICACHE_SIZE,
441                      XCHAL_DCACHE_LINESIZE,
442                      XCHAL_DCACHE_WAYS,
443                      XCHAL_DCACHE_SIZE);
444
445         return 0;
446 }
447
448 /*
449  * We show only CPU #0 info.
450  */
451 static void *
452 c_start(struct seq_file *f, loff_t *pos)
453 {
454         return (void *) ((*pos == 0) ? (void *)1 : NULL);
455 }
456
457 static void *
458 c_next(struct seq_file *f, void *v, loff_t *pos)
459 {
460         return NULL;
461 }
462
463 static void
464 c_stop(struct seq_file *f, void *v)
465 {
466 }
467
468 const struct seq_operations cpuinfo_op =
469 {
470         start:  c_start,
471         next:   c_next,
472         stop:   c_stop,
473         show:   c_show
474 };
475
476 #endif /* CONFIG_PROC_FS */
477