| /* MN10300 Arch-specific initialisation | |
| * | |
| * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| * Written by David Howells (dhowells@redhat.com) | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public Licence | |
| * as published by the Free Software Foundation; either version | |
| * 2 of the Licence, or (at your option) any later version. | |
| */ | |
| #include <linux/errno.h> | |
| #include <linux/sched.h> | |
| #include <linux/kernel.h> | |
| #include <linux/mm.h> | |
| #include <linux/stddef.h> | |
| #include <linux/unistd.h> | |
| #include <linux/ptrace.h> | |
| #include <linux/user.h> | |
| #include <linux/tty.h> | |
| #include <linux/ioport.h> | |
| #include <linux/delay.h> | |
| #include <linux/init.h> | |
| #include <linux/bootmem.h> | |
| #include <linux/seq_file.h> | |
| #include <linux/cpu.h> | |
| #include <asm/processor.h> | |
| #include <linux/console.h> | |
| #include <linux/uaccess.h> | |
| #include <asm/setup.h> | |
| #include <asm/io.h> | |
| #include <asm/smp.h> | |
| #include <proc/proc.h> | |
| #include <asm/fpu.h> | |
| #include <asm/sections.h> | |
| struct mn10300_cpuinfo boot_cpu_data; | |
| static char __initdata cmd_line[COMMAND_LINE_SIZE]; | |
| char redboot_command_line[COMMAND_LINE_SIZE] = | |
| "console=ttyS0,115200 root=/dev/mtdblock3 rw"; | |
| char __initdata redboot_platform_name[COMMAND_LINE_SIZE]; | |
| static struct resource code_resource = { | |
| .start = 0x100000, | |
| .end = 0, | |
| .name = "Kernel code", | |
| }; | |
| static struct resource data_resource = { | |
| .start = 0, | |
| .end = 0, | |
| .name = "Kernel data", | |
| }; | |
| static unsigned long __initdata phys_memory_base; | |
| static unsigned long __initdata phys_memory_end; | |
| static unsigned long __initdata memory_end; | |
| unsigned long memory_size; | |
| struct thread_info *__current_ti = &init_thread_union.thread_info; | |
| struct task_struct *__current = &init_task; | |
| #define mn10300_known_cpus 5 | |
| static const char *const mn10300_cputypes[] = { | |
| "am33-1", | |
| "am33-2", | |
| "am34-1", | |
| "am33-3", | |
| "am34-2", | |
| "unknown" | |
| }; | |
| /* | |
| * Pick out the memory size. We look for mem=size, | |
| * where size is "size[KkMm]" | |
| */ | |
| static int __init early_mem(char *p) | |
| { | |
| memory_size = memparse(p, &p); | |
| if (memory_size == 0) | |
| panic("Memory size not known\n"); | |
| return 0; | |
| } | |
| early_param("mem", early_mem); | |
| /* | |
| * architecture specific setup | |
| */ | |
| void __init setup_arch(char **cmdline_p) | |
| { | |
| unsigned long bootmap_size; | |
| unsigned long kstart_pfn, start_pfn, free_pfn, end_pfn; | |
| cpu_init(); | |
| unit_setup(); | |
| smp_init_cpus(); | |
| /* save unparsed command line copy for /proc/cmdline */ | |
| strlcpy(boot_command_line, redboot_command_line, COMMAND_LINE_SIZE); | |
| /* populate cmd_line too for later use, preserving boot_command_line */ | |
| strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); | |
| *cmdline_p = cmd_line; | |
| parse_early_param(); | |
| memory_end = (unsigned long) CONFIG_KERNEL_RAM_BASE_ADDRESS + | |
| memory_size; | |
| if (memory_end > phys_memory_end) | |
| memory_end = phys_memory_end; | |
| init_mm.start_code = (unsigned long)&_text; | |
| init_mm.end_code = (unsigned long) &_etext; | |
| init_mm.end_data = (unsigned long) &_edata; | |
| init_mm.brk = (unsigned long) &_end; | |
| code_resource.start = virt_to_bus(&_text); | |
| code_resource.end = virt_to_bus(&_etext)-1; | |
| data_resource.start = virt_to_bus(&_etext); | |
| data_resource.end = virt_to_bus(&_edata)-1; | |
| start_pfn = (CONFIG_KERNEL_RAM_BASE_ADDRESS >> PAGE_SHIFT); | |
| kstart_pfn = PFN_UP(__pa(&_text)); | |
| free_pfn = PFN_UP(__pa(&_end)); | |
| end_pfn = PFN_DOWN(__pa(memory_end)); | |
| bootmap_size = init_bootmem_node(&contig_page_data, | |
| free_pfn, | |
| start_pfn, | |
| end_pfn); | |
| if (kstart_pfn > start_pfn) | |
| free_bootmem(PFN_PHYS(start_pfn), | |
| PFN_PHYS(kstart_pfn - start_pfn)); | |
| free_bootmem(PFN_PHYS(free_pfn), | |
| PFN_PHYS(end_pfn - free_pfn)); | |
| /* If interrupt vector table is in main ram, then we need to | |
| reserve the page it is occupying. */ | |
| if (CONFIG_INTERRUPT_VECTOR_BASE >= CONFIG_KERNEL_RAM_BASE_ADDRESS && | |
| CONFIG_INTERRUPT_VECTOR_BASE < memory_end) | |
| reserve_bootmem(CONFIG_INTERRUPT_VECTOR_BASE, PAGE_SIZE, | |
| BOOTMEM_DEFAULT); | |
| reserve_bootmem(PAGE_ALIGN(PFN_PHYS(free_pfn)), bootmap_size, | |
| BOOTMEM_DEFAULT); | |
| #ifdef CONFIG_VT | |
| #if defined(CONFIG_VGA_CONSOLE) | |
| conswitchp = &vga_con; | |
| #elif defined(CONFIG_DUMMY_CONSOLE) | |
| conswitchp = &dummy_con; | |
| #endif | |
| #endif | |
| paging_init(); | |
| } | |
| /* | |
| * perform CPU initialisation | |
| */ | |
| void __init cpu_init(void) | |
| { | |
| unsigned long cpurev = CPUREV, type; | |
| type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S; | |
| if (type > mn10300_known_cpus) | |
| type = mn10300_known_cpus; | |
| printk(KERN_INFO "Panasonic %s, rev %ld\n", | |
| mn10300_cputypes[type], | |
| (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S); | |
| get_mem_info(&phys_memory_base, &memory_size); | |
| phys_memory_end = phys_memory_base + memory_size; | |
| fpu_init_state(); | |
| } | |
| static struct cpu cpu_devices[NR_CPUS]; | |
| static int __init topology_init(void) | |
| { | |
| int i; | |
| for_each_present_cpu(i) | |
| register_cpu(&cpu_devices[i], i); | |
| return 0; | |
| } | |
| subsys_initcall(topology_init); | |
| /* | |
| * Get CPU information for use by the procfs. | |
| */ | |
| static int show_cpuinfo(struct seq_file *m, void *v) | |
| { | |
| #ifdef CONFIG_SMP | |
| struct mn10300_cpuinfo *c = v; | |
| unsigned long cpu_id = c - cpu_data; | |
| unsigned long cpurev = c->type, type, icachesz, dcachesz; | |
| #else /* CONFIG_SMP */ | |
| unsigned long cpu_id = 0; | |
| unsigned long cpurev = CPUREV, type, icachesz, dcachesz; | |
| #endif /* CONFIG_SMP */ | |
| #ifdef CONFIG_SMP | |
| if (!cpu_online(cpu_id)) | |
| return 0; | |
| #endif | |
| type = (cpurev & CPUREV_TYPE) >> CPUREV_TYPE_S; | |
| if (type > mn10300_known_cpus) | |
| type = mn10300_known_cpus; | |
| icachesz = | |
| ((cpurev & CPUREV_ICWAY ) >> CPUREV_ICWAY_S) * | |
| ((cpurev & CPUREV_ICSIZE) >> CPUREV_ICSIZE_S) * | |
| 1024; | |
| dcachesz = | |
| ((cpurev & CPUREV_DCWAY ) >> CPUREV_DCWAY_S) * | |
| ((cpurev & CPUREV_DCSIZE) >> CPUREV_DCSIZE_S) * | |
| 1024; | |
| seq_printf(m, | |
| "processor : %ld\n" | |
| "vendor_id : " PROCESSOR_VENDOR_NAME "\n" | |
| "cpu core : %s\n" | |
| "cpu rev : %lu\n" | |
| "model name : " PROCESSOR_MODEL_NAME "\n" | |
| "icache size: %lu\n" | |
| "dcache size: %lu\n", | |
| cpu_id, | |
| mn10300_cputypes[type], | |
| (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S, | |
| icachesz, | |
| dcachesz | |
| ); | |
| seq_printf(m, | |
| "ioclk speed: %lu.%02luMHz\n" | |
| "bogomips : %lu.%02lu\n\n", | |
| MN10300_IOCLK / 1000000, | |
| (MN10300_IOCLK / 10000) % 100, | |
| #ifdef CONFIG_SMP | |
| c->loops_per_jiffy / (500000 / HZ), | |
| (c->loops_per_jiffy / (5000 / HZ)) % 100 | |
| #else /* CONFIG_SMP */ | |
| loops_per_jiffy / (500000 / HZ), | |
| (loops_per_jiffy / (5000 / HZ)) % 100 | |
| #endif /* CONFIG_SMP */ | |
| ); | |
| return 0; | |
| } | |
| static void *c_start(struct seq_file *m, loff_t *pos) | |
| { | |
| return *pos < NR_CPUS ? cpu_data + *pos : NULL; | |
| } | |
| static void *c_next(struct seq_file *m, void *v, loff_t *pos) | |
| { | |
| ++*pos; | |
| return c_start(m, pos); | |
| } | |
| static void c_stop(struct seq_file *m, void *v) | |
| { | |
| } | |
| const struct seq_operations cpuinfo_op = { | |
| .start = c_start, | |
| .next = c_next, | |
| .stop = c_stop, | |
| .show = show_cpuinfo, | |
| }; |