Linux-2.6.12-rc2
[linux-2.6/next.git] / arch / arm / kernel / setup.c
blobc2a7da3ac0f1fff7b310c8760984abfa70939299
1 /*
2 * linux/arch/arm/kernel/setup.c
4 * Copyright (C) 1995-2001 Russell King
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10 #include <linux/config.h>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/stddef.h>
14 #include <linux/ioport.h>
15 #include <linux/delay.h>
16 #include <linux/utsname.h>
17 #include <linux/initrd.h>
18 #include <linux/console.h>
19 #include <linux/bootmem.h>
20 #include <linux/seq_file.h>
21 #include <linux/tty.h>
22 #include <linux/init.h>
23 #include <linux/root_dev.h>
24 #include <linux/cpu.h>
25 #include <linux/interrupt.h>
27 #include <asm/cpu.h>
28 #include <asm/elf.h>
29 #include <asm/hardware.h>
30 #include <asm/io.h>
31 #include <asm/procinfo.h>
32 #include <asm/setup.h>
33 #include <asm/mach-types.h>
34 #include <asm/cacheflush.h>
35 #include <asm/tlbflush.h>
37 #include <asm/mach/arch.h>
38 #include <asm/mach/irq.h>
39 #include <asm/mach/time.h>
41 #ifndef MEM_SIZE
42 #define MEM_SIZE (16*1024*1024)
43 #endif
45 #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
46 char fpe_type[8];
48 static int __init fpe_setup(char *line)
50 memcpy(fpe_type, line, 8);
51 return 1;
54 __setup("fpe=", fpe_setup);
55 #endif
57 extern unsigned int mem_fclk_21285;
58 extern void paging_init(struct meminfo *, struct machine_desc *desc);
59 extern void convert_to_tag_list(struct tag *tags);
60 extern void squash_mem_tags(struct tag *tag);
61 extern void reboot_setup(char *str);
62 extern int root_mountflags;
63 extern void _stext, _text, _etext, __data_start, _edata, _end;
65 unsigned int processor_id;
66 unsigned int __machine_arch_type;
67 EXPORT_SYMBOL(__machine_arch_type);
69 unsigned int system_rev;
70 EXPORT_SYMBOL(system_rev);
72 unsigned int system_serial_low;
73 EXPORT_SYMBOL(system_serial_low);
75 unsigned int system_serial_high;
76 EXPORT_SYMBOL(system_serial_high);
78 unsigned int elf_hwcap;
79 EXPORT_SYMBOL(elf_hwcap);
82 #ifdef MULTI_CPU
83 struct processor processor;
84 #endif
85 #ifdef MULTI_TLB
86 struct cpu_tlb_fns cpu_tlb;
87 #endif
88 #ifdef MULTI_USER
89 struct cpu_user_fns cpu_user;
90 #endif
91 #ifdef MULTI_CACHE
92 struct cpu_cache_fns cpu_cache;
93 #endif
95 char elf_platform[ELF_PLATFORM_SIZE];
96 EXPORT_SYMBOL(elf_platform);
98 unsigned long phys_initrd_start __initdata = 0;
99 unsigned long phys_initrd_size __initdata = 0;
101 static struct meminfo meminfo __initdata = { 0, };
102 static const char *cpu_name;
103 static const char *machine_name;
104 static char command_line[COMMAND_LINE_SIZE];
106 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
107 static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
108 #define ENDIANNESS ((char)endian_test.l)
110 DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
113 * Standard memory resources
115 static struct resource mem_res[] = {
116 { "Video RAM", 0, 0, IORESOURCE_MEM },
117 { "Kernel text", 0, 0, IORESOURCE_MEM },
118 { "Kernel data", 0, 0, IORESOURCE_MEM }
121 #define video_ram mem_res[0]
122 #define kernel_code mem_res[1]
123 #define kernel_data mem_res[2]
125 static struct resource io_res[] = {
126 { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
127 { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
128 { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
131 #define lp0 io_res[0]
132 #define lp1 io_res[1]
133 #define lp2 io_res[2]
135 static const char *cache_types[16] = {
136 "write-through",
137 "write-back",
138 "write-back",
139 "undefined 3",
140 "undefined 4",
141 "undefined 5",
142 "write-back",
143 "write-back",
144 "undefined 8",
145 "undefined 9",
146 "undefined 10",
147 "undefined 11",
148 "undefined 12",
149 "undefined 13",
150 "write-back",
151 "undefined 15",
154 static const char *cache_clean[16] = {
155 "not required",
156 "read-block",
157 "cp15 c7 ops",
158 "undefined 3",
159 "undefined 4",
160 "undefined 5",
161 "cp15 c7 ops",
162 "cp15 c7 ops",
163 "undefined 8",
164 "undefined 9",
165 "undefined 10",
166 "undefined 11",
167 "undefined 12",
168 "undefined 13",
169 "cp15 c7 ops",
170 "undefined 15",
173 static const char *cache_lockdown[16] = {
174 "not supported",
175 "not supported",
176 "not supported",
177 "undefined 3",
178 "undefined 4",
179 "undefined 5",
180 "format A",
181 "format B",
182 "undefined 8",
183 "undefined 9",
184 "undefined 10",
185 "undefined 11",
186 "undefined 12",
187 "undefined 13",
188 "format C",
189 "undefined 15",
192 static const char *proc_arch[] = {
193 "undefined/unknown",
194 "3",
195 "4",
196 "4T",
197 "5",
198 "5T",
199 "5TE",
200 "5TEJ",
201 "6TEJ",
202 "?(10)",
203 "?(11)",
204 "?(12)",
205 "?(13)",
206 "?(14)",
207 "?(15)",
208 "?(16)",
209 "?(17)",
212 #define CACHE_TYPE(x) (((x) >> 25) & 15)
213 #define CACHE_S(x) ((x) & (1 << 24))
214 #define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
215 #define CACHE_ISIZE(x) ((x) & 4095)
217 #define CACHE_SIZE(y) (((y) >> 6) & 7)
218 #define CACHE_ASSOC(y) (((y) >> 3) & 7)
219 #define CACHE_M(y) ((y) & (1 << 2))
220 #define CACHE_LINE(y) ((y) & 3)
222 static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
224 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
226 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
227 cpu, prefix,
228 mult << (8 + CACHE_SIZE(cache)),
229 (mult << CACHE_ASSOC(cache)) >> 1,
230 8 << CACHE_LINE(cache),
231 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
232 CACHE_LINE(cache)));
235 static void __init dump_cpu_info(int cpu)
237 unsigned int info = read_cpuid(CPUID_CACHETYPE);
239 if (info != processor_id) {
240 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
241 cache_types[CACHE_TYPE(info)]);
242 if (CACHE_S(info)) {
243 dump_cache("I cache", cpu, CACHE_ISIZE(info));
244 dump_cache("D cache", cpu, CACHE_DSIZE(info));
245 } else {
246 dump_cache("cache", cpu, CACHE_ISIZE(info));
251 int cpu_architecture(void)
253 int cpu_arch;
255 if ((processor_id & 0x0000f000) == 0) {
256 cpu_arch = CPU_ARCH_UNKNOWN;
257 } else if ((processor_id & 0x0000f000) == 0x00007000) {
258 cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
259 } else {
260 cpu_arch = (processor_id >> 16) & 7;
261 if (cpu_arch)
262 cpu_arch += CPU_ARCH_ARMv3;
265 return cpu_arch;
269 * These functions re-use the assembly code in head.S, which
270 * already provide the required functionality.
272 extern struct proc_info_list *lookup_processor_type(void);
273 extern struct machine_desc *lookup_machine_type(unsigned int);
275 static void __init setup_processor(void)
277 struct proc_info_list *list;
280 * locate processor in the list of supported processor
281 * types. The linker builds this table for us from the
282 * entries in arch/arm/mm/proc-*.S
284 list = lookup_processor_type();
285 if (!list) {
286 printk("CPU configuration botched (ID %08x), unable "
287 "to continue.\n", processor_id);
288 while (1);
291 cpu_name = list->cpu_name;
293 #ifdef MULTI_CPU
294 processor = *list->proc;
295 #endif
296 #ifdef MULTI_TLB
297 cpu_tlb = *list->tlb;
298 #endif
299 #ifdef MULTI_USER
300 cpu_user = *list->user;
301 #endif
302 #ifdef MULTI_CACHE
303 cpu_cache = *list->cache;
304 #endif
306 printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
307 cpu_name, processor_id, (int)processor_id & 15,
308 proc_arch[cpu_architecture()]);
310 dump_cpu_info(smp_processor_id());
312 sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
313 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
314 elf_hwcap = list->elf_hwcap;
316 cpu_proc_init();
319 static struct machine_desc * __init setup_machine(unsigned int nr)
321 struct machine_desc *list;
324 * locate machine in the list of supported machines.
326 list = lookup_machine_type(nr);
327 if (!list) {
328 printk("Machine configuration botched (nr %d), unable "
329 "to continue.\n", nr);
330 while (1);
333 printk("Machine: %s\n", list->name);
335 return list;
338 static void __init early_initrd(char **p)
340 unsigned long start, size;
342 start = memparse(*p, p);
343 if (**p == ',') {
344 size = memparse((*p) + 1, p);
346 phys_initrd_start = start;
347 phys_initrd_size = size;
350 __early_param("initrd=", early_initrd);
353 * Pick out the memory size. We look for mem=size@start,
354 * where start and size are "size[KkMm]"
356 static void __init early_mem(char **p)
358 static int usermem __initdata = 0;
359 unsigned long size, start;
362 * If the user specifies memory size, we
363 * blow away any automatically generated
364 * size.
366 if (usermem == 0) {
367 usermem = 1;
368 meminfo.nr_banks = 0;
371 start = PHYS_OFFSET;
372 size = memparse(*p, p);
373 if (**p == '@')
374 start = memparse(*p + 1, p);
376 meminfo.bank[meminfo.nr_banks].start = start;
377 meminfo.bank[meminfo.nr_banks].size = size;
378 meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start);
379 meminfo.nr_banks += 1;
381 __early_param("mem=", early_mem);
384 * Initial parsing of the command line.
386 static void __init parse_cmdline(char **cmdline_p, char *from)
388 char c = ' ', *to = command_line;
389 int len = 0;
391 for (;;) {
392 if (c == ' ') {
393 extern struct early_params __early_begin, __early_end;
394 struct early_params *p;
396 for (p = &__early_begin; p < &__early_end; p++) {
397 int len = strlen(p->arg);
399 if (memcmp(from, p->arg, len) == 0) {
400 if (to != command_line)
401 to -= 1;
402 from += len;
403 p->fn(&from);
405 while (*from != ' ' && *from != '\0')
406 from++;
407 break;
411 c = *from++;
412 if (!c)
413 break;
414 if (COMMAND_LINE_SIZE <= ++len)
415 break;
416 *to++ = c;
418 *to = '\0';
419 *cmdline_p = command_line;
422 static void __init
423 setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
425 #ifdef CONFIG_BLK_DEV_RAM
426 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
428 rd_image_start = image_start;
429 rd_prompt = prompt;
430 rd_doload = doload;
432 if (rd_sz)
433 rd_size = rd_sz;
434 #endif
437 static void __init
438 request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
440 struct resource *res;
441 int i;
443 kernel_code.start = virt_to_phys(&_text);
444 kernel_code.end = virt_to_phys(&_etext - 1);
445 kernel_data.start = virt_to_phys(&__data_start);
446 kernel_data.end = virt_to_phys(&_end - 1);
448 for (i = 0; i < mi->nr_banks; i++) {
449 unsigned long virt_start, virt_end;
451 if (mi->bank[i].size == 0)
452 continue;
454 virt_start = __phys_to_virt(mi->bank[i].start);
455 virt_end = virt_start + mi->bank[i].size - 1;
457 res = alloc_bootmem_low(sizeof(*res));
458 res->name = "System RAM";
459 res->start = __virt_to_phys(virt_start);
460 res->end = __virt_to_phys(virt_end);
461 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
463 request_resource(&iomem_resource, res);
465 if (kernel_code.start >= res->start &&
466 kernel_code.end <= res->end)
467 request_resource(res, &kernel_code);
468 if (kernel_data.start >= res->start &&
469 kernel_data.end <= res->end)
470 request_resource(res, &kernel_data);
473 if (mdesc->video_start) {
474 video_ram.start = mdesc->video_start;
475 video_ram.end = mdesc->video_end;
476 request_resource(&iomem_resource, &video_ram);
480 * Some machines don't have the possibility of ever
481 * possessing lp0, lp1 or lp2
483 if (mdesc->reserve_lp0)
484 request_resource(&ioport_resource, &lp0);
485 if (mdesc->reserve_lp1)
486 request_resource(&ioport_resource, &lp1);
487 if (mdesc->reserve_lp2)
488 request_resource(&ioport_resource, &lp2);
492 * Tag parsing.
494 * This is the new way of passing data to the kernel at boot time. Rather
495 * than passing a fixed inflexible structure to the kernel, we pass a list
496 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
497 * tag for the list to be recognised (to distinguish the tagged list from
498 * a param_struct). The list is terminated with a zero-length tag (this tag
499 * is not parsed in any way).
501 static int __init parse_tag_core(const struct tag *tag)
503 if (tag->hdr.size > 2) {
504 if ((tag->u.core.flags & 1) == 0)
505 root_mountflags &= ~MS_RDONLY;
506 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
508 return 0;
511 __tagtable(ATAG_CORE, parse_tag_core);
513 static int __init parse_tag_mem32(const struct tag *tag)
515 if (meminfo.nr_banks >= NR_BANKS) {
516 printk(KERN_WARNING
517 "Ignoring memory bank 0x%08x size %dKB\n",
518 tag->u.mem.start, tag->u.mem.size / 1024);
519 return -EINVAL;
521 meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start;
522 meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size;
523 meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start);
524 meminfo.nr_banks += 1;
526 return 0;
529 __tagtable(ATAG_MEM, parse_tag_mem32);
531 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
532 struct screen_info screen_info = {
533 .orig_video_lines = 30,
534 .orig_video_cols = 80,
535 .orig_video_mode = 0,
536 .orig_video_ega_bx = 0,
537 .orig_video_isVGA = 1,
538 .orig_video_points = 8
541 static int __init parse_tag_videotext(const struct tag *tag)
543 screen_info.orig_x = tag->u.videotext.x;
544 screen_info.orig_y = tag->u.videotext.y;
545 screen_info.orig_video_page = tag->u.videotext.video_page;
546 screen_info.orig_video_mode = tag->u.videotext.video_mode;
547 screen_info.orig_video_cols = tag->u.videotext.video_cols;
548 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
549 screen_info.orig_video_lines = tag->u.videotext.video_lines;
550 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
551 screen_info.orig_video_points = tag->u.videotext.video_points;
552 return 0;
555 __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
556 #endif
558 static int __init parse_tag_ramdisk(const struct tag *tag)
560 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
561 (tag->u.ramdisk.flags & 2) == 0,
562 tag->u.ramdisk.start, tag->u.ramdisk.size);
563 return 0;
566 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
568 static int __init parse_tag_initrd(const struct tag *tag)
570 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
571 "please update your bootloader.\n");
572 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
573 phys_initrd_size = tag->u.initrd.size;
574 return 0;
577 __tagtable(ATAG_INITRD, parse_tag_initrd);
579 static int __init parse_tag_initrd2(const struct tag *tag)
581 phys_initrd_start = tag->u.initrd.start;
582 phys_initrd_size = tag->u.initrd.size;
583 return 0;
586 __tagtable(ATAG_INITRD2, parse_tag_initrd2);
588 static int __init parse_tag_serialnr(const struct tag *tag)
590 system_serial_low = tag->u.serialnr.low;
591 system_serial_high = tag->u.serialnr.high;
592 return 0;
595 __tagtable(ATAG_SERIAL, parse_tag_serialnr);
597 static int __init parse_tag_revision(const struct tag *tag)
599 system_rev = tag->u.revision.rev;
600 return 0;
603 __tagtable(ATAG_REVISION, parse_tag_revision);
605 static int __init parse_tag_cmdline(const struct tag *tag)
607 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
608 return 0;
611 __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
614 * Scan the tag table for this tag, and call its parse function.
615 * The tag table is built by the linker from all the __tagtable
616 * declarations.
618 static int __init parse_tag(const struct tag *tag)
620 extern struct tagtable __tagtable_begin, __tagtable_end;
621 struct tagtable *t;
623 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
624 if (tag->hdr.tag == t->tag) {
625 t->parse(tag);
626 break;
629 return t < &__tagtable_end;
633 * Parse all tags in the list, checking both the global and architecture
634 * specific tag tables.
636 static void __init parse_tags(const struct tag *t)
638 for (; t->hdr.size; t = tag_next(t))
639 if (!parse_tag(t))
640 printk(KERN_WARNING
641 "Ignoring unrecognised tag 0x%08x\n",
642 t->hdr.tag);
646 * This holds our defaults.
648 static struct init_tags {
649 struct tag_header hdr1;
650 struct tag_core core;
651 struct tag_header hdr2;
652 struct tag_mem32 mem;
653 struct tag_header hdr3;
654 } init_tags __initdata = {
655 { tag_size(tag_core), ATAG_CORE },
656 { 1, PAGE_SIZE, 0xff },
657 { tag_size(tag_mem32), ATAG_MEM },
658 { MEM_SIZE, PHYS_OFFSET },
659 { 0, ATAG_NONE }
662 static void (*init_machine)(void) __initdata;
664 static int __init customize_machine(void)
666 /* customizes platform devices, or adds new ones */
667 if (init_machine)
668 init_machine();
669 return 0;
671 arch_initcall(customize_machine);
673 void __init setup_arch(char **cmdline_p)
675 struct tag *tags = (struct tag *)&init_tags;
676 struct machine_desc *mdesc;
677 char *from = default_command_line;
679 setup_processor();
680 mdesc = setup_machine(machine_arch_type);
681 machine_name = mdesc->name;
683 if (mdesc->soft_reboot)
684 reboot_setup("s");
686 if (mdesc->param_offset)
687 tags = phys_to_virt(mdesc->param_offset);
690 * If we have the old style parameters, convert them to
691 * a tag list.
693 if (tags->hdr.tag != ATAG_CORE)
694 convert_to_tag_list(tags);
695 if (tags->hdr.tag != ATAG_CORE)
696 tags = (struct tag *)&init_tags;
698 if (mdesc->fixup)
699 mdesc->fixup(mdesc, tags, &from, &meminfo);
701 if (tags->hdr.tag == ATAG_CORE) {
702 if (meminfo.nr_banks != 0)
703 squash_mem_tags(tags);
704 parse_tags(tags);
707 init_mm.start_code = (unsigned long) &_text;
708 init_mm.end_code = (unsigned long) &_etext;
709 init_mm.end_data = (unsigned long) &_edata;
710 init_mm.brk = (unsigned long) &_end;
712 memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
713 saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
714 parse_cmdline(cmdline_p, from);
715 paging_init(&meminfo, mdesc);
716 request_standard_resources(&meminfo, mdesc);
719 * Set up various architecture-specific pointers
721 init_arch_irq = mdesc->init_irq;
722 system_timer = mdesc->timer;
723 init_machine = mdesc->init_machine;
725 #ifdef CONFIG_VT
726 #if defined(CONFIG_VGA_CONSOLE)
727 conswitchp = &vga_con;
728 #elif defined(CONFIG_DUMMY_CONSOLE)
729 conswitchp = &dummy_con;
730 #endif
731 #endif
735 static int __init topology_init(void)
737 int cpu;
739 for_each_cpu(cpu)
740 register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu, NULL);
742 return 0;
745 subsys_initcall(topology_init);
747 static const char *hwcap_str[] = {
748 "swp",
749 "half",
750 "thumb",
751 "26bit",
752 "fastmult",
753 "fpa",
754 "vfp",
755 "edsp",
756 "java",
757 NULL
760 static void
761 c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
763 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
765 seq_printf(m, "%s size\t\t: %d\n"
766 "%s assoc\t\t: %d\n"
767 "%s line length\t: %d\n"
768 "%s sets\t\t: %d\n",
769 type, mult << (8 + CACHE_SIZE(cache)),
770 type, (mult << CACHE_ASSOC(cache)) >> 1,
771 type, 8 << CACHE_LINE(cache),
772 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
773 CACHE_LINE(cache)));
776 static int c_show(struct seq_file *m, void *v)
778 int i;
780 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
781 cpu_name, (int)processor_id & 15, elf_platform);
783 #if defined(CONFIG_SMP)
784 for_each_online_cpu(i) {
785 seq_printf(m, "Processor\t: %d\n", i);
786 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
787 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
788 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
790 #else /* CONFIG_SMP */
791 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
792 loops_per_jiffy / (500000/HZ),
793 (loops_per_jiffy / (5000/HZ)) % 100);
794 #endif
796 /* dump out the processor features */
797 seq_puts(m, "Features\t: ");
799 for (i = 0; hwcap_str[i]; i++)
800 if (elf_hwcap & (1 << i))
801 seq_printf(m, "%s ", hwcap_str[i]);
803 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
804 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
806 if ((processor_id & 0x0000f000) == 0x00000000) {
807 /* pre-ARM7 */
808 seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
809 } else {
810 if ((processor_id & 0x0000f000) == 0x00007000) {
811 /* ARM7 */
812 seq_printf(m, "CPU variant\t: 0x%02x\n",
813 (processor_id >> 16) & 127);
814 } else {
815 /* post-ARM7 */
816 seq_printf(m, "CPU variant\t: 0x%x\n",
817 (processor_id >> 20) & 15);
819 seq_printf(m, "CPU part\t: 0x%03x\n",
820 (processor_id >> 4) & 0xfff);
822 seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
825 unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
826 if (cache_info != processor_id) {
827 seq_printf(m, "Cache type\t: %s\n"
828 "Cache clean\t: %s\n"
829 "Cache lockdown\t: %s\n"
830 "Cache format\t: %s\n",
831 cache_types[CACHE_TYPE(cache_info)],
832 cache_clean[CACHE_TYPE(cache_info)],
833 cache_lockdown[CACHE_TYPE(cache_info)],
834 CACHE_S(cache_info) ? "Harvard" : "Unified");
836 if (CACHE_S(cache_info)) {
837 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
838 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
839 } else {
840 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
845 seq_puts(m, "\n");
847 seq_printf(m, "Hardware\t: %s\n", machine_name);
848 seq_printf(m, "Revision\t: %04x\n", system_rev);
849 seq_printf(m, "Serial\t\t: %08x%08x\n",
850 system_serial_high, system_serial_low);
852 return 0;
855 static void *c_start(struct seq_file *m, loff_t *pos)
857 return *pos < 1 ? (void *)1 : NULL;
860 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
862 ++*pos;
863 return NULL;
866 static void c_stop(struct seq_file *m, void *v)
870 struct seq_operations cpuinfo_op = {
871 .start = c_start,
872 .next = c_next,
873 .stop = c_stop,
874 .show = c_show