Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/m68k/kernel/setup.c | |
3 | * | |
4 | * Copyright (C) 1995 Hamish Macdonald | |
5 | */ | |
6 | ||
7 | /* | |
8 | * This file handles the architecture-dependent parts of system setup | |
9 | */ | |
10 | ||
1da177e4 LT |
11 | #include <linux/kernel.h> |
12 | #include <linux/mm.h> | |
13 | #include <linux/sched.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/fs.h> | |
17 | #include <linux/console.h> | |
18 | #include <linux/genhd.h> | |
19 | #include <linux/errno.h> | |
20 | #include <linux/string.h> | |
21 | #include <linux/init.h> | |
22 | #include <linux/bootmem.h> | |
23 | #include <linux/seq_file.h> | |
24 | #include <linux/module.h> | |
25 | #include <linux/initrd.h> | |
26 | ||
27 | #include <asm/bootinfo.h> | |
28 | #include <asm/setup.h> | |
29 | #include <asm/irq.h> | |
30 | #include <asm/io.h> | |
31 | #include <asm/machdep.h> | |
32 | #ifdef CONFIG_AMIGA | |
33 | #include <asm/amigahw.h> | |
34 | #endif | |
35 | #ifdef CONFIG_ATARI | |
36 | #include <asm/atarihw.h> | |
37 | #include <asm/atari_stram.h> | |
38 | #endif | |
39 | #ifdef CONFIG_SUN3X | |
40 | #include <asm/dvma.h> | |
41 | #endif | |
42 | ||
43 | unsigned long m68k_machtype; | |
44 | unsigned long m68k_cputype; | |
2e811488 AV |
45 | EXPORT_SYMBOL(m68k_machtype); |
46 | EXPORT_SYMBOL(m68k_cputype); | |
1da177e4 LT |
47 | unsigned long m68k_fputype; |
48 | unsigned long m68k_mmutype; | |
49 | #ifdef CONFIG_VME | |
50 | unsigned long vme_brdtype; | |
2e811488 | 51 | EXPORT_SYMBOL(vme_brdtype); |
1da177e4 LT |
52 | #endif |
53 | ||
54 | int m68k_is040or060; | |
2e811488 | 55 | EXPORT_SYMBOL(m68k_is040or060); |
1da177e4 LT |
56 | |
57 | extern int end; | |
58 | extern unsigned long availmem; | |
59 | ||
60 | int m68k_num_memory; | |
88f8bb78 | 61 | EXPORT_SYMBOL(m68k_num_memory); |
1da177e4 | 62 | int m68k_realnum_memory; |
2e811488 | 63 | EXPORT_SYMBOL(m68k_realnum_memory); |
1da177e4 | 64 | unsigned long m68k_memoffset; |
2e811488 | 65 | EXPORT_SYMBOL(m68k_memoffset); |
1da177e4 | 66 | struct mem_info m68k_memory[NUM_MEMINFO]; |
2e811488 | 67 | EXPORT_SYMBOL(m68k_memory); |
1da177e4 | 68 | |
12d810c1 | 69 | struct mem_info m68k_ramdisk; |
1da177e4 LT |
70 | |
71 | static char m68k_command_line[CL_SIZE]; | |
72 | ||
40220c1a | 73 | void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; |
1da177e4 LT |
74 | /* machine dependent irq functions */ |
75 | void (*mach_init_IRQ) (void) __initdata = NULL; | |
1da177e4 LT |
76 | void (*mach_get_model) (char *model); |
77 | int (*mach_get_hardware_list) (char *buffer); | |
1da177e4 LT |
78 | /* machine dependent timer functions */ |
79 | unsigned long (*mach_gettimeoffset) (void); | |
80 | int (*mach_hwclk) (int, struct rtc_time*); | |
2e811488 | 81 | EXPORT_SYMBOL(mach_hwclk); |
1da177e4 LT |
82 | int (*mach_set_clock_mmss) (unsigned long); |
83 | unsigned int (*mach_get_ss)(void); | |
84 | int (*mach_get_rtc_pll)(struct rtc_pll_info *); | |
85 | int (*mach_set_rtc_pll)(struct rtc_pll_info *); | |
2e811488 AV |
86 | EXPORT_SYMBOL(mach_get_ss); |
87 | EXPORT_SYMBOL(mach_get_rtc_pll); | |
88 | EXPORT_SYMBOL(mach_set_rtc_pll); | |
1da177e4 LT |
89 | void (*mach_reset)( void ); |
90 | void (*mach_halt)( void ); | |
91 | void (*mach_power_off)( void ); | |
92 | long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ | |
1da177e4 LT |
93 | #ifdef CONFIG_HEARTBEAT |
94 | void (*mach_heartbeat) (int); | |
95 | EXPORT_SYMBOL(mach_heartbeat); | |
96 | #endif | |
97 | #ifdef CONFIG_M68K_L2_CACHE | |
98 | void (*mach_l2_flush) (int); | |
99 | #endif | |
100 | #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) | |
101 | void (*mach_beep)(unsigned int, unsigned int); | |
2e811488 | 102 | EXPORT_SYMBOL(mach_beep); |
1da177e4 LT |
103 | #endif |
104 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | |
105 | int isa_type; | |
106 | int isa_sex; | |
aa7e02fe AV |
107 | EXPORT_SYMBOL(isa_type); |
108 | EXPORT_SYMBOL(isa_sex); | |
1da177e4 LT |
109 | #endif |
110 | ||
111 | extern int amiga_parse_bootinfo(const struct bi_record *); | |
112 | extern int atari_parse_bootinfo(const struct bi_record *); | |
113 | extern int mac_parse_bootinfo(const struct bi_record *); | |
114 | extern int q40_parse_bootinfo(const struct bi_record *); | |
115 | extern int bvme6000_parse_bootinfo(const struct bi_record *); | |
116 | extern int mvme16x_parse_bootinfo(const struct bi_record *); | |
117 | extern int mvme147_parse_bootinfo(const struct bi_record *); | |
118 | extern int hp300_parse_bootinfo(const struct bi_record *); | |
119 | ||
120 | extern void config_amiga(void); | |
121 | extern void config_atari(void); | |
122 | extern void config_mac(void); | |
123 | extern void config_sun3(void); | |
124 | extern void config_apollo(void); | |
125 | extern void config_mvme147(void); | |
126 | extern void config_mvme16x(void); | |
127 | extern void config_bvme6000(void); | |
128 | extern void config_hp300(void); | |
129 | extern void config_q40(void); | |
130 | extern void config_sun3x(void); | |
131 | ||
1da177e4 LT |
132 | #define MASK_256K 0xfffc0000 |
133 | ||
134 | extern void paging_init(void); | |
135 | ||
136 | static void __init m68k_parse_bootinfo(const struct bi_record *record) | |
137 | { | |
6ff5801a RZ |
138 | while (record->tag != BI_LAST) { |
139 | int unknown = 0; | |
140 | const unsigned long *data = record->data; | |
141 | ||
142 | switch (record->tag) { | |
143 | case BI_MACHTYPE: | |
144 | case BI_CPUTYPE: | |
145 | case BI_FPUTYPE: | |
146 | case BI_MMUTYPE: | |
147 | /* Already set up by head.S */ | |
148 | break; | |
149 | ||
150 | case BI_MEMCHUNK: | |
151 | if (m68k_num_memory < NUM_MEMINFO) { | |
152 | m68k_memory[m68k_num_memory].addr = data[0]; | |
153 | m68k_memory[m68k_num_memory].size = data[1]; | |
154 | m68k_num_memory++; | |
155 | } else | |
156 | printk("m68k_parse_bootinfo: too many memory chunks\n"); | |
157 | break; | |
158 | ||
159 | case BI_RAMDISK: | |
160 | m68k_ramdisk.addr = data[0]; | |
161 | m68k_ramdisk.size = data[1]; | |
162 | break; | |
163 | ||
164 | case BI_COMMAND_LINE: | |
165 | strlcpy(m68k_command_line, (const char *)data, | |
166 | sizeof(m68k_command_line)); | |
167 | break; | |
168 | ||
169 | default: | |
170 | if (MACH_IS_AMIGA) | |
171 | unknown = amiga_parse_bootinfo(record); | |
172 | else if (MACH_IS_ATARI) | |
173 | unknown = atari_parse_bootinfo(record); | |
174 | else if (MACH_IS_MAC) | |
175 | unknown = mac_parse_bootinfo(record); | |
176 | else if (MACH_IS_Q40) | |
177 | unknown = q40_parse_bootinfo(record); | |
178 | else if (MACH_IS_BVME6000) | |
179 | unknown = bvme6000_parse_bootinfo(record); | |
180 | else if (MACH_IS_MVME16x) | |
181 | unknown = mvme16x_parse_bootinfo(record); | |
182 | else if (MACH_IS_MVME147) | |
183 | unknown = mvme147_parse_bootinfo(record); | |
184 | else if (MACH_IS_HP300) | |
185 | unknown = hp300_parse_bootinfo(record); | |
186 | else | |
187 | unknown = 1; | |
188 | } | |
189 | if (unknown) | |
190 | printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", | |
191 | record->tag); | |
192 | record = (struct bi_record *)((unsigned long)record + | |
193 | record->size); | |
1da177e4 | 194 | } |
1da177e4 | 195 | |
6ff5801a | 196 | m68k_realnum_memory = m68k_num_memory; |
1da177e4 | 197 | #ifdef CONFIG_SINGLE_MEMORY_CHUNK |
6ff5801a RZ |
198 | if (m68k_num_memory > 1) { |
199 | printk("Ignoring last %i chunks of physical memory\n", | |
200 | (m68k_num_memory - 1)); | |
201 | m68k_num_memory = 1; | |
202 | } | |
203 | m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; | |
1da177e4 LT |
204 | #endif |
205 | } | |
206 | ||
207 | void __init setup_arch(char **cmdline_p) | |
208 | { | |
209 | extern int _etext, _edata, _end; | |
1da177e4 | 210 | int i; |
1da177e4 LT |
211 | |
212 | /* The bootinfo is located right after the kernel bss */ | |
213 | m68k_parse_bootinfo((const struct bi_record *)&_end); | |
214 | ||
215 | if (CPU_IS_040) | |
216 | m68k_is040or060 = 4; | |
217 | else if (CPU_IS_060) | |
218 | m68k_is040or060 = 6; | |
219 | ||
220 | /* FIXME: m68k_fputype is passed in by Penguin booter, which can | |
221 | * be confused by software FPU emulation. BEWARE. | |
222 | * We should really do our own FPU check at startup. | |
223 | * [what do we do with buggy 68LC040s? if we have problems | |
224 | * with them, we should add a test to check_bugs() below] */ | |
225 | #ifndef CONFIG_M68KFPU_EMU_ONLY | |
226 | /* clear the fpu if we have one */ | |
227 | if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { | |
228 | volatile int zero = 0; | |
6ff5801a | 229 | asm volatile ("frestore %0" : : "m" (zero)); |
1da177e4 LT |
230 | } |
231 | #endif | |
232 | ||
233 | if (CPU_IS_060) { | |
234 | u32 pcr; | |
235 | ||
236 | asm (".chip 68060; movec %%pcr,%0; .chip 68k" | |
237 | : "=d" (pcr)); | |
238 | if (((pcr >> 8) & 0xff) <= 5) { | |
239 | printk("Enabling workaround for errata I14\n"); | |
240 | asm (".chip 68060; movec %0,%%pcr; .chip 68k" | |
241 | : : "d" (pcr | 0x20)); | |
242 | } | |
243 | } | |
244 | ||
245 | init_mm.start_code = PAGE_OFFSET; | |
246 | init_mm.end_code = (unsigned long) &_etext; | |
247 | init_mm.end_data = (unsigned long) &_edata; | |
248 | init_mm.brk = (unsigned long) &_end; | |
249 | ||
250 | *cmdline_p = m68k_command_line; | |
187959f3 | 251 | memcpy(boot_command_line, *cmdline_p, CL_SIZE); |
1da177e4 | 252 | |
d6713b40 | 253 | parse_early_param(); |
1da177e4 | 254 | |
0c79358b AV |
255 | #ifdef CONFIG_DUMMY_CONSOLE |
256 | conswitchp = &dummy_con; | |
257 | #endif | |
258 | ||
1da177e4 LT |
259 | switch (m68k_machtype) { |
260 | #ifdef CONFIG_AMIGA | |
6ff5801a | 261 | case MACH_AMIGA: |
1da177e4 LT |
262 | config_amiga(); |
263 | break; | |
264 | #endif | |
265 | #ifdef CONFIG_ATARI | |
6ff5801a | 266 | case MACH_ATARI: |
1da177e4 LT |
267 | config_atari(); |
268 | break; | |
269 | #endif | |
270 | #ifdef CONFIG_MAC | |
6ff5801a | 271 | case MACH_MAC: |
1da177e4 LT |
272 | config_mac(); |
273 | break; | |
274 | #endif | |
275 | #ifdef CONFIG_SUN3 | |
6ff5801a | 276 | case MACH_SUN3: |
1da177e4 LT |
277 | config_sun3(); |
278 | break; | |
279 | #endif | |
280 | #ifdef CONFIG_APOLLO | |
6ff5801a | 281 | case MACH_APOLLO: |
1da177e4 LT |
282 | config_apollo(); |
283 | break; | |
284 | #endif | |
285 | #ifdef CONFIG_MVME147 | |
6ff5801a | 286 | case MACH_MVME147: |
1da177e4 LT |
287 | config_mvme147(); |
288 | break; | |
289 | #endif | |
290 | #ifdef CONFIG_MVME16x | |
6ff5801a | 291 | case MACH_MVME16x: |
1da177e4 LT |
292 | config_mvme16x(); |
293 | break; | |
294 | #endif | |
295 | #ifdef CONFIG_BVME6000 | |
6ff5801a | 296 | case MACH_BVME6000: |
1da177e4 LT |
297 | config_bvme6000(); |
298 | break; | |
299 | #endif | |
300 | #ifdef CONFIG_HP300 | |
6ff5801a | 301 | case MACH_HP300: |
1da177e4 LT |
302 | config_hp300(); |
303 | break; | |
304 | #endif | |
305 | #ifdef CONFIG_Q40 | |
6ff5801a RZ |
306 | case MACH_Q40: |
307 | config_q40(); | |
1da177e4 LT |
308 | break; |
309 | #endif | |
310 | #ifdef CONFIG_SUN3X | |
6ff5801a | 311 | case MACH_SUN3X: |
1da177e4 LT |
312 | config_sun3x(); |
313 | break; | |
314 | #endif | |
6ff5801a RZ |
315 | default: |
316 | panic("No configuration setup"); | |
1da177e4 LT |
317 | } |
318 | ||
12d810c1 | 319 | paging_init(); |
1da177e4 | 320 | |
12d810c1 RZ |
321 | #ifndef CONFIG_SUN3 |
322 | for (i = 1; i < m68k_num_memory; i++) | |
323 | free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, | |
324 | m68k_memory[i].size); | |
1da177e4 LT |
325 | #ifdef CONFIG_BLK_DEV_INITRD |
326 | if (m68k_ramdisk.size) { | |
12d810c1 RZ |
327 | reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)), |
328 | m68k_ramdisk.addr, m68k_ramdisk.size); | |
1da177e4 LT |
329 | initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); |
330 | initrd_end = initrd_start + m68k_ramdisk.size; | |
6ff5801a | 331 | printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); |
1da177e4 LT |
332 | } |
333 | #endif | |
334 | ||
335 | #ifdef CONFIG_ATARI | |
336 | if (MACH_IS_ATARI) | |
337 | atari_stram_reserve_pages((void *)availmem); | |
338 | #endif | |
339 | #ifdef CONFIG_SUN3X | |
340 | if (MACH_IS_SUN3X) { | |
341 | dvma_init(); | |
342 | } | |
343 | #endif | |
344 | ||
345 | #endif /* !CONFIG_SUN3 */ | |
346 | ||
1da177e4 LT |
347 | /* set ISA defs early as possible */ |
348 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | |
349 | #if defined(CONFIG_Q40) | |
350 | if (MACH_IS_Q40) { | |
6ff5801a RZ |
351 | isa_type = Q40_ISA; |
352 | isa_sex = 0; | |
1da177e4 LT |
353 | } |
354 | #elif defined(CONFIG_GG2) | |
6ff5801a RZ |
355 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) { |
356 | isa_type = GG2_ISA; | |
357 | isa_sex = 0; | |
1da177e4 LT |
358 | } |
359 | #elif defined(CONFIG_AMIGA_PCMCIA) | |
6ff5801a RZ |
360 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { |
361 | isa_type = AG_ISA; | |
362 | isa_sex = 1; | |
1da177e4 LT |
363 | } |
364 | #endif | |
365 | #endif | |
366 | } | |
367 | ||
368 | static int show_cpuinfo(struct seq_file *m, void *v) | |
369 | { | |
6ff5801a RZ |
370 | const char *cpu, *mmu, *fpu; |
371 | unsigned long clockfreq, clockfactor; | |
1da177e4 LT |
372 | |
373 | #define LOOP_CYCLES_68020 (8) | |
374 | #define LOOP_CYCLES_68030 (8) | |
375 | #define LOOP_CYCLES_68040 (3) | |
376 | #define LOOP_CYCLES_68060 (1) | |
377 | ||
6ff5801a RZ |
378 | if (CPU_IS_020) { |
379 | cpu = "68020"; | |
380 | clockfactor = LOOP_CYCLES_68020; | |
381 | } else if (CPU_IS_030) { | |
382 | cpu = "68030"; | |
383 | clockfactor = LOOP_CYCLES_68030; | |
384 | } else if (CPU_IS_040) { | |
385 | cpu = "68040"; | |
386 | clockfactor = LOOP_CYCLES_68040; | |
387 | } else if (CPU_IS_060) { | |
388 | cpu = "68060"; | |
389 | clockfactor = LOOP_CYCLES_68060; | |
390 | } else { | |
391 | cpu = "680x0"; | |
392 | clockfactor = 0; | |
393 | } | |
1da177e4 LT |
394 | |
395 | #ifdef CONFIG_M68KFPU_EMU_ONLY | |
6ff5801a | 396 | fpu = "none(soft float)"; |
1da177e4 | 397 | #else |
6ff5801a RZ |
398 | if (m68k_fputype & FPU_68881) |
399 | fpu = "68881"; | |
400 | else if (m68k_fputype & FPU_68882) | |
401 | fpu = "68882"; | |
402 | else if (m68k_fputype & FPU_68040) | |
403 | fpu = "68040"; | |
404 | else if (m68k_fputype & FPU_68060) | |
405 | fpu = "68060"; | |
406 | else if (m68k_fputype & FPU_SUNFPA) | |
407 | fpu = "Sun FPA"; | |
408 | else | |
409 | fpu = "none"; | |
1da177e4 LT |
410 | #endif |
411 | ||
6ff5801a RZ |
412 | if (m68k_mmutype & MMU_68851) |
413 | mmu = "68851"; | |
414 | else if (m68k_mmutype & MMU_68030) | |
415 | mmu = "68030"; | |
416 | else if (m68k_mmutype & MMU_68040) | |
417 | mmu = "68040"; | |
418 | else if (m68k_mmutype & MMU_68060) | |
419 | mmu = "68060"; | |
420 | else if (m68k_mmutype & MMU_SUN3) | |
421 | mmu = "Sun-3"; | |
422 | else if (m68k_mmutype & MMU_APOLLO) | |
423 | mmu = "Apollo"; | |
424 | else | |
425 | mmu = "unknown"; | |
426 | ||
427 | clockfreq = loops_per_jiffy * HZ * clockfactor; | |
428 | ||
429 | seq_printf(m, "CPU:\t\t%s\n" | |
1da177e4 LT |
430 | "MMU:\t\t%s\n" |
431 | "FPU:\t\t%s\n" | |
432 | "Clocking:\t%lu.%1luMHz\n" | |
433 | "BogoMips:\t%lu.%02lu\n" | |
434 | "Calibration:\t%lu loops\n", | |
435 | cpu, mmu, fpu, | |
436 | clockfreq/1000000,(clockfreq/100000)%10, | |
437 | loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, | |
438 | loops_per_jiffy); | |
6ff5801a | 439 | return 0; |
1da177e4 LT |
440 | } |
441 | ||
442 | static void *c_start(struct seq_file *m, loff_t *pos) | |
443 | { | |
444 | return *pos < 1 ? (void *)1 : NULL; | |
445 | } | |
446 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | |
447 | { | |
448 | ++*pos; | |
449 | return NULL; | |
450 | } | |
451 | static void c_stop(struct seq_file *m, void *v) | |
452 | { | |
453 | } | |
454 | struct seq_operations cpuinfo_op = { | |
6ff5801a RZ |
455 | .start = c_start, |
456 | .next = c_next, | |
457 | .stop = c_stop, | |
458 | .show = show_cpuinfo, | |
1da177e4 LT |
459 | }; |
460 | ||
461 | int get_hardware_list(char *buffer) | |
462 | { | |
6ff5801a RZ |
463 | int len = 0; |
464 | char model[80]; | |
465 | unsigned long mem; | |
466 | int i; | |
1da177e4 | 467 | |
6ff5801a RZ |
468 | if (mach_get_model) |
469 | mach_get_model(model); | |
470 | else | |
471 | strcpy(model, "Unknown m68k"); | |
1da177e4 | 472 | |
6ff5801a RZ |
473 | len += sprintf(buffer + len, "Model:\t\t%s\n", model); |
474 | for (mem = 0, i = 0; i < m68k_num_memory; i++) | |
475 | mem += m68k_memory[i].size; | |
476 | len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10); | |
1da177e4 | 477 | |
6ff5801a RZ |
478 | if (mach_get_hardware_list) |
479 | len += mach_get_hardware_list(buffer + len); | |
1da177e4 | 480 | |
6ff5801a | 481 | return len; |
1da177e4 LT |
482 | } |
483 | ||
1da177e4 LT |
484 | void check_bugs(void) |
485 | { | |
486 | #ifndef CONFIG_M68KFPU_EMU | |
487 | if (m68k_fputype == 0) { | |
6ff5801a RZ |
488 | printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " |
489 | "WHICH IS REQUIRED BY LINUX/M68K ***\n"); | |
490 | printk(KERN_EMERG "Upgrade your hardware or join the FPU " | |
491 | "emulation project\n"); | |
492 | panic("no FPU"); | |
1da177e4 LT |
493 | } |
494 | #endif /* !CONFIG_M68KFPU_EMU */ | |
495 | } | |
d95fd5fc FT |
496 | |
497 | #ifdef CONFIG_ADB | |
498 | static int __init adb_probe_sync_enable (char *str) { | |
499 | extern int __adb_probe_sync; | |
500 | __adb_probe_sync = 1; | |
501 | return 1; | |
502 | } | |
503 | ||
504 | __setup("adb_sync", adb_probe_sync_enable); | |
505 | #endif /* CONFIG_ADB */ |