1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/arch/m68k/kernel/setup.c |
4 | * |
5 | * Copyright (C) 1995 Hamish Macdonald |
6 | */ |
7 | |
8 | /* |
9 | * This file handles the architecture-dependent parts of system setup |
10 | */ |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/cpu.h> |
14 | #include <linux/mm.h> |
15 | #include <linux/sched.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/fs.h> |
19 | #include <linux/console.h> |
20 | #include <linux/errno.h> |
21 | #include <linux/string.h> |
22 | #include <linux/init.h> |
23 | #include <linux/memblock.h> |
24 | #include <linux/proc_fs.h> |
25 | #include <linux/seq_file.h> |
26 | #include <linux/module.h> |
27 | #include <linux/nvram.h> |
28 | #include <linux/initrd.h> |
29 | #include <linux/random.h> |
30 | |
31 | #include <asm/bootinfo.h> |
32 | #include <asm/byteorder.h> |
33 | #include <asm/sections.h> |
34 | #include <asm/setup.h> |
35 | #include <asm/fpu.h> |
36 | #include <asm/irq.h> |
37 | #include <asm/io.h> |
38 | #include <asm/machdep.h> |
39 | #ifdef CONFIG_AMIGA |
40 | #include <asm/amigahw.h> |
41 | #endif |
42 | #include <asm/atarihw.h> |
43 | #ifdef CONFIG_ATARI |
44 | #include <asm/atari_stram.h> |
45 | #endif |
46 | #ifdef CONFIG_SUN3X |
47 | #include <asm/dvma.h> |
48 | #endif |
49 | #include <asm/macintosh.h> |
50 | #include <asm/natfeat.h> |
51 | #include <asm/config.h> |
52 | |
53 | #if !FPSTATESIZE || !NR_IRQS |
54 | #warning No CPU/platform type selected, your kernel will not work! |
55 | #warning Are you building an allnoconfig kernel? |
56 | #endif |
57 | |
58 | unsigned long m68k_machtype; |
59 | EXPORT_SYMBOL(m68k_machtype); |
60 | unsigned long m68k_cputype; |
61 | EXPORT_SYMBOL(m68k_cputype); |
62 | unsigned long m68k_fputype; |
63 | unsigned long m68k_mmutype; |
64 | EXPORT_SYMBOL(m68k_mmutype); |
65 | #ifdef CONFIG_VME |
66 | unsigned long vme_brdtype; |
67 | EXPORT_SYMBOL(vme_brdtype); |
68 | #endif |
69 | |
70 | int m68k_is040or060; |
71 | EXPORT_SYMBOL(m68k_is040or060); |
72 | |
73 | extern unsigned long availmem; |
74 | |
75 | int m68k_num_memory; |
76 | EXPORT_SYMBOL(m68k_num_memory); |
77 | int m68k_realnum_memory; |
78 | EXPORT_SYMBOL(m68k_realnum_memory); |
79 | unsigned long m68k_memoffset; |
80 | struct m68k_mem_info m68k_memory[NUM_MEMINFO]; |
81 | EXPORT_SYMBOL(m68k_memory); |
82 | |
83 | static struct m68k_mem_info m68k_ramdisk __initdata; |
84 | |
85 | static char m68k_command_line[CL_SIZE] __initdata; |
86 | |
87 | void (*mach_sched_init) (void) __initdata = NULL; |
88 | /* machine dependent irq functions */ |
89 | void (*mach_init_IRQ) (void) __initdata = NULL; |
90 | void (*mach_get_model) (char *model); |
91 | void (*mach_get_hardware_list) (struct seq_file *m); |
92 | void (*mach_reset)( void ); |
93 | void (*mach_halt)( void ); |
94 | #ifdef CONFIG_HEARTBEAT |
95 | void (*mach_heartbeat) (int); |
96 | EXPORT_SYMBOL(mach_heartbeat); |
97 | #endif |
98 | #ifdef CONFIG_M68K_L2_CACHE |
99 | void (*mach_l2_flush) (int); |
100 | #endif |
101 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) |
102 | int isa_type; |
103 | int isa_sex; |
104 | EXPORT_SYMBOL(isa_type); |
105 | EXPORT_SYMBOL(isa_sex); |
106 | #endif |
107 | |
108 | #define MASK_256K 0xfffc0000 |
109 | |
110 | static void __init m68k_parse_bootinfo(const struct bi_record *record) |
111 | { |
112 | const struct bi_record *first_record = record; |
113 | uint16_t tag; |
114 | |
115 | while ((tag = be16_to_cpu(record->tag)) != BI_LAST) { |
116 | int unknown = 0; |
117 | const void *data = record->data; |
118 | uint16_t size = be16_to_cpu(record->size); |
119 | |
120 | switch (tag) { |
121 | case BI_MACHTYPE: |
122 | case BI_CPUTYPE: |
123 | case BI_FPUTYPE: |
124 | case BI_MMUTYPE: |
125 | /* Already set up by head.S */ |
126 | break; |
127 | |
128 | case BI_MEMCHUNK: |
129 | if (m68k_num_memory < NUM_MEMINFO) { |
130 | const struct mem_info *m = data; |
131 | m68k_memory[m68k_num_memory].addr = |
132 | be32_to_cpu(m->addr); |
133 | m68k_memory[m68k_num_memory].size = |
134 | be32_to_cpu(m->size); |
135 | m68k_num_memory++; |
136 | } else |
137 | pr_warn("%s: too many memory chunks\n" , |
138 | __func__); |
139 | break; |
140 | |
141 | case BI_RAMDISK: |
142 | { |
143 | const struct mem_info *m = data; |
144 | m68k_ramdisk.addr = be32_to_cpu(m->addr); |
145 | m68k_ramdisk.size = be32_to_cpu(m->size); |
146 | } |
147 | break; |
148 | |
149 | case BI_COMMAND_LINE: |
150 | strscpy(m68k_command_line, data, |
151 | sizeof(m68k_command_line)); |
152 | break; |
153 | |
154 | case BI_RNG_SEED: { |
155 | u16 len = be16_to_cpup(p: data); |
156 | add_bootloader_randomness(buf: data + 2, len); |
157 | /* |
158 | * Zero the data to preserve forward secrecy, and zero the |
159 | * length to prevent kexec from using it. |
160 | */ |
161 | memzero_explicit(s: (void *)data, count: len + 2); |
162 | break; |
163 | } |
164 | |
165 | default: |
166 | if (MACH_IS_AMIGA) |
167 | unknown = amiga_parse_bootinfo(record); |
168 | else if (MACH_IS_ATARI) |
169 | unknown = atari_parse_bootinfo(record); |
170 | else if (MACH_IS_MAC) |
171 | unknown = mac_parse_bootinfo(record); |
172 | else if (MACH_IS_Q40) |
173 | unknown = q40_parse_bootinfo(record); |
174 | else if (MACH_IS_BVME6000) |
175 | unknown = bvme6000_parse_bootinfo(record); |
176 | else if (MACH_IS_MVME16x) |
177 | unknown = mvme16x_parse_bootinfo(record); |
178 | else if (MACH_IS_MVME147) |
179 | unknown = mvme147_parse_bootinfo(record); |
180 | else if (MACH_IS_HP300) |
181 | unknown = hp300_parse_bootinfo(record); |
182 | else if (MACH_IS_APOLLO) |
183 | unknown = apollo_parse_bootinfo(record); |
184 | else if (MACH_IS_VIRT) |
185 | unknown = virt_parse_bootinfo(record); |
186 | else |
187 | unknown = 1; |
188 | } |
189 | if (unknown) |
190 | pr_warn("%s: unknown tag 0x%04x ignored\n" , __func__, |
191 | tag); |
192 | record = (struct bi_record *)((unsigned long)record + size); |
193 | } |
194 | |
195 | save_bootinfo(first_record); |
196 | |
197 | m68k_realnum_memory = m68k_num_memory; |
198 | #ifdef CONFIG_SINGLE_MEMORY_CHUNK |
199 | if (m68k_num_memory > 1) { |
200 | pr_warn("%s: ignoring last %i chunks of physical memory\n" , |
201 | __func__, (m68k_num_memory - 1)); |
202 | m68k_num_memory = 1; |
203 | } |
204 | #endif |
205 | } |
206 | |
207 | void __init setup_arch(char **cmdline_p) |
208 | { |
209 | /* The bootinfo is located right after the kernel */ |
210 | if (!CPU_IS_COLDFIRE) |
211 | m68k_parse_bootinfo(record: (const struct bi_record *)_end); |
212 | |
213 | if (CPU_IS_040) |
214 | m68k_is040or060 = 4; |
215 | else if (CPU_IS_060) |
216 | m68k_is040or060 = 6; |
217 | |
218 | /* FIXME: m68k_fputype is passed in by Penguin booter, which can |
219 | * be confused by software FPU emulation. BEWARE. |
220 | * We should really do our own FPU check at startup. |
221 | * [what do we do with buggy 68LC040s? if we have problems |
222 | * with them, we should add a test to check_bugs() below] */ |
223 | #if defined(CONFIG_FPU) && !defined(CONFIG_M68KFPU_EMU_ONLY) |
224 | /* clear the fpu if we have one */ |
225 | if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060|FPU_COLDFIRE)) { |
226 | volatile int zero = 0; |
227 | asm volatile ("frestore %0" : : "m" (zero)); |
228 | } |
229 | #endif |
230 | |
231 | if (CPU_IS_060) { |
232 | u32 pcr; |
233 | |
234 | asm (".chip 68060; movec %%pcr,%0; .chip 68k" |
235 | : "=d" (pcr)); |
236 | if (((pcr >> 8) & 0xff) <= 5) { |
237 | pr_warn("Enabling workaround for errata I14\n" ); |
238 | asm (".chip 68060; movec %0,%%pcr; .chip 68k" |
239 | : : "d" (pcr | 0x20)); |
240 | } |
241 | } |
242 | |
243 | setup_initial_init_mm(start_code: (void *)PAGE_OFFSET, end_code: _etext, end_data: _edata, brk: _end); |
244 | |
245 | #if defined(CONFIG_BOOTPARAM) |
246 | strncpy(m68k_command_line, CONFIG_BOOTPARAM_STRING, CL_SIZE); |
247 | m68k_command_line[CL_SIZE - 1] = 0; |
248 | #endif /* CONFIG_BOOTPARAM */ |
249 | process_uboot_commandline(&m68k_command_line[0], CL_SIZE); |
250 | *cmdline_p = m68k_command_line; |
251 | memcpy(boot_command_line, *cmdline_p, CL_SIZE); |
252 | |
253 | parse_early_param(); |
254 | |
255 | switch (m68k_machtype) { |
256 | #ifdef CONFIG_AMIGA |
257 | case MACH_AMIGA: |
258 | config_amiga(); |
259 | break; |
260 | #endif |
261 | #ifdef CONFIG_ATARI |
262 | case MACH_ATARI: |
263 | config_atari(); |
264 | break; |
265 | #endif |
266 | #ifdef CONFIG_MAC |
267 | case MACH_MAC: |
268 | config_mac(); |
269 | break; |
270 | #endif |
271 | #ifdef CONFIG_SUN3 |
272 | case MACH_SUN3: |
273 | config_sun3(); |
274 | break; |
275 | #endif |
276 | #ifdef CONFIG_APOLLO |
277 | case MACH_APOLLO: |
278 | config_apollo(); |
279 | break; |
280 | #endif |
281 | #ifdef CONFIG_MVME147 |
282 | case MACH_MVME147: |
283 | config_mvme147(); |
284 | break; |
285 | #endif |
286 | #ifdef CONFIG_MVME16x |
287 | case MACH_MVME16x: |
288 | config_mvme16x(); |
289 | break; |
290 | #endif |
291 | #ifdef CONFIG_BVME6000 |
292 | case MACH_BVME6000: |
293 | config_bvme6000(); |
294 | break; |
295 | #endif |
296 | #ifdef CONFIG_HP300 |
297 | case MACH_HP300: |
298 | config_hp300(); |
299 | break; |
300 | #endif |
301 | #ifdef CONFIG_Q40 |
302 | case MACH_Q40: |
303 | config_q40(); |
304 | break; |
305 | #endif |
306 | #ifdef CONFIG_SUN3X |
307 | case MACH_SUN3X: |
308 | config_sun3x(); |
309 | break; |
310 | #endif |
311 | #ifdef CONFIG_COLDFIRE |
312 | case MACH_M54XX: |
313 | case MACH_M5441X: |
314 | cf_bootmem_alloc(); |
315 | cf_mmu_context_init(); |
316 | config_BSP(NULL, 0); |
317 | break; |
318 | #endif |
319 | #ifdef CONFIG_VIRT |
320 | case MACH_VIRT: |
321 | config_virt(); |
322 | break; |
323 | #endif |
324 | default: |
325 | panic(fmt: "No configuration setup" ); |
326 | } |
327 | |
328 | if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && m68k_ramdisk.size) |
329 | memblock_reserve(base: m68k_ramdisk.addr, size: m68k_ramdisk.size); |
330 | |
331 | paging_init(); |
332 | |
333 | if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && m68k_ramdisk.size) { |
334 | initrd_start = (unsigned long)phys_to_virt(address: m68k_ramdisk.addr); |
335 | initrd_end = initrd_start + m68k_ramdisk.size; |
336 | pr_info("initrd: %08lx - %08lx\n" , initrd_start, initrd_end); |
337 | } |
338 | |
339 | #ifdef CONFIG_NATFEAT |
340 | nf_init(); |
341 | #endif |
342 | |
343 | #ifdef CONFIG_ATARI |
344 | if (MACH_IS_ATARI) |
345 | atari_stram_reserve_pages((void *)availmem); |
346 | #endif |
347 | #ifdef CONFIG_SUN3X |
348 | if (MACH_IS_SUN3X) { |
349 | dvma_init(); |
350 | } |
351 | #endif |
352 | |
353 | /* set ISA defs early as possible */ |
354 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) |
355 | if (MACH_IS_Q40) { |
356 | isa_type = ISA_TYPE_Q40; |
357 | isa_sex = 0; |
358 | } |
359 | #ifdef CONFIG_AMIGA_PCMCIA |
360 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { |
361 | isa_type = ISA_TYPE_AG; |
362 | isa_sex = 1; |
363 | } |
364 | #endif |
365 | #ifdef CONFIG_ATARI_ROM_ISA |
366 | if (MACH_IS_ATARI) { |
367 | isa_type = ISA_TYPE_ENEC; |
368 | isa_sex = 0; |
369 | } |
370 | #endif |
371 | #endif |
372 | } |
373 | |
374 | static int show_cpuinfo(struct seq_file *m, void *v) |
375 | { |
376 | const char *cpu, *mmu, *fpu; |
377 | unsigned long clockfreq, clockfactor; |
378 | |
379 | #define LOOP_CYCLES_68020 (8) |
380 | #define LOOP_CYCLES_68030 (8) |
381 | #define LOOP_CYCLES_68040 (3) |
382 | #define LOOP_CYCLES_68060 (1) |
383 | #define LOOP_CYCLES_COLDFIRE (2) |
384 | |
385 | if (CPU_IS_020) { |
386 | cpu = "68020" ; |
387 | clockfactor = LOOP_CYCLES_68020; |
388 | } else if (CPU_IS_030) { |
389 | cpu = "68030" ; |
390 | clockfactor = LOOP_CYCLES_68030; |
391 | } else if (CPU_IS_040) { |
392 | cpu = "68040" ; |
393 | clockfactor = LOOP_CYCLES_68040; |
394 | } else if (CPU_IS_060) { |
395 | cpu = "68060" ; |
396 | clockfactor = LOOP_CYCLES_68060; |
397 | } else if (CPU_IS_COLDFIRE) { |
398 | cpu = "ColdFire" ; |
399 | clockfactor = LOOP_CYCLES_COLDFIRE; |
400 | } else { |
401 | cpu = "680x0" ; |
402 | clockfactor = 0; |
403 | } |
404 | |
405 | #ifdef CONFIG_M68KFPU_EMU_ONLY |
406 | fpu = "none(soft float)" ; |
407 | #else |
408 | if (m68k_fputype & FPU_68881) |
409 | fpu = "68881" ; |
410 | else if (m68k_fputype & FPU_68882) |
411 | fpu = "68882" ; |
412 | else if (m68k_fputype & FPU_68040) |
413 | fpu = "68040" ; |
414 | else if (m68k_fputype & FPU_68060) |
415 | fpu = "68060" ; |
416 | else if (m68k_fputype & FPU_SUNFPA) |
417 | fpu = "Sun FPA" ; |
418 | else if (m68k_fputype & FPU_COLDFIRE) |
419 | fpu = "ColdFire" ; |
420 | else |
421 | fpu = "none" ; |
422 | #endif |
423 | |
424 | if (m68k_mmutype & MMU_68851) |
425 | mmu = "68851" ; |
426 | else if (m68k_mmutype & MMU_68030) |
427 | mmu = "68030" ; |
428 | else if (m68k_mmutype & MMU_68040) |
429 | mmu = "68040" ; |
430 | else if (m68k_mmutype & MMU_68060) |
431 | mmu = "68060" ; |
432 | else if (m68k_mmutype & MMU_SUN3) |
433 | mmu = "Sun-3" ; |
434 | else if (m68k_mmutype & MMU_APOLLO) |
435 | mmu = "Apollo" ; |
436 | else if (m68k_mmutype & MMU_COLDFIRE) |
437 | mmu = "ColdFire" ; |
438 | else |
439 | mmu = "unknown" ; |
440 | |
441 | clockfreq = loops_per_jiffy * HZ * clockfactor; |
442 | |
443 | seq_printf(m, fmt: "CPU:\t\t%s\n" |
444 | "MMU:\t\t%s\n" |
445 | "FPU:\t\t%s\n" |
446 | "Clocking:\t%lu.%1luMHz\n" |
447 | "BogoMips:\t%lu.%02lu\n" |
448 | "Calibration:\t%lu loops\n" , |
449 | cpu, mmu, fpu, |
450 | clockfreq/1000000,(clockfreq/100000)%10, |
451 | loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, |
452 | loops_per_jiffy); |
453 | return 0; |
454 | } |
455 | |
456 | static void *c_start(struct seq_file *m, loff_t *pos) |
457 | { |
458 | return *pos < 1 ? (void *)1 : NULL; |
459 | } |
460 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) |
461 | { |
462 | ++*pos; |
463 | return NULL; |
464 | } |
465 | static void c_stop(struct seq_file *m, void *v) |
466 | { |
467 | } |
468 | const struct seq_operations cpuinfo_op = { |
469 | .start = c_start, |
470 | .next = c_next, |
471 | .stop = c_stop, |
472 | .show = show_cpuinfo, |
473 | }; |
474 | |
475 | #ifdef CONFIG_PROC_HARDWARE |
476 | static int hardware_proc_show(struct seq_file *m, void *v) |
477 | { |
478 | char model[80]; |
479 | unsigned long mem; |
480 | int i; |
481 | |
482 | if (mach_get_model) |
483 | mach_get_model(model); |
484 | else |
485 | strcpy(model, "Unknown m68k" ); |
486 | |
487 | seq_printf(m, "Model:\t\t%s\n" , model); |
488 | for (mem = 0, i = 0; i < m68k_num_memory; i++) |
489 | mem += m68k_memory[i].size; |
490 | seq_printf(m, "System Memory:\t%ldK\n" , mem >> 10); |
491 | |
492 | if (mach_get_hardware_list) |
493 | mach_get_hardware_list(m); |
494 | |
495 | return 0; |
496 | } |
497 | |
498 | static int __init proc_hardware_init(void) |
499 | { |
500 | proc_create_single("hardware" , 0, NULL, hardware_proc_show); |
501 | return 0; |
502 | } |
503 | module_init(proc_hardware_init); |
504 | #endif |
505 | |
506 | void __init arch_cpu_finalize_init(void) |
507 | { |
508 | #if defined(CONFIG_FPU) && !defined(CONFIG_M68KFPU_EMU) |
509 | if (m68k_fputype == 0) { |
510 | pr_emerg("*** YOU DO NOT HAVE A FLOATING POINT UNIT, " |
511 | "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); |
512 | pr_emerg("Upgrade your hardware or join the FPU " |
513 | "emulation project\n" ); |
514 | panic("no FPU" ); |
515 | } |
516 | #endif /* !CONFIG_M68KFPU_EMU */ |
517 | } |
518 | |
519 | #ifdef CONFIG_ADB |
520 | static int __init adb_probe_sync_enable (char *str) { |
521 | extern int __adb_probe_sync; |
522 | __adb_probe_sync = 1; |
523 | return 1; |
524 | } |
525 | |
526 | __setup("adb_sync" , adb_probe_sync_enable); |
527 | #endif /* CONFIG_ADB */ |
528 | |
529 | #if IS_ENABLED(CONFIG_NVRAM) |
530 | #ifdef CONFIG_MAC |
531 | static unsigned char m68k_nvram_read_byte(int addr) |
532 | { |
533 | if (MACH_IS_MAC) |
534 | return mac_pram_read_byte(addr); |
535 | return 0xff; |
536 | } |
537 | |
538 | static void m68k_nvram_write_byte(unsigned char val, int addr) |
539 | { |
540 | if (MACH_IS_MAC) |
541 | mac_pram_write_byte(val, addr); |
542 | } |
543 | #endif /* CONFIG_MAC */ |
544 | |
545 | #ifdef CONFIG_ATARI |
546 | static ssize_t m68k_nvram_read(char *buf, size_t count, loff_t *ppos) |
547 | { |
548 | if (MACH_IS_ATARI) |
549 | return atari_nvram_read(buf, count, ppos); |
550 | else if (MACH_IS_MAC) |
551 | return nvram_read_bytes(buf, count, ppos); |
552 | return -EINVAL; |
553 | } |
554 | |
555 | static ssize_t m68k_nvram_write(char *buf, size_t count, loff_t *ppos) |
556 | { |
557 | if (MACH_IS_ATARI) |
558 | return atari_nvram_write(buf, count, ppos); |
559 | else if (MACH_IS_MAC) |
560 | return nvram_write_bytes(buf, count, ppos); |
561 | return -EINVAL; |
562 | } |
563 | |
564 | static long m68k_nvram_set_checksum(void) |
565 | { |
566 | if (MACH_IS_ATARI) |
567 | return atari_nvram_set_checksum(); |
568 | return -EINVAL; |
569 | } |
570 | |
571 | static long m68k_nvram_initialize(void) |
572 | { |
573 | if (MACH_IS_ATARI) |
574 | return atari_nvram_initialize(); |
575 | return -EINVAL; |
576 | } |
577 | #endif /* CONFIG_ATARI */ |
578 | |
579 | static ssize_t m68k_nvram_get_size(void) |
580 | { |
581 | if (MACH_IS_ATARI) |
582 | return atari_nvram_get_size(); |
583 | else if (MACH_IS_MAC) |
584 | return mac_pram_get_size(); |
585 | return -ENODEV; |
586 | } |
587 | |
588 | /* Atari device drivers call .read (to get checksum validation) whereas |
589 | * Mac and PowerMac device drivers just use .read_byte. |
590 | */ |
591 | const struct nvram_ops arch_nvram_ops = { |
592 | #ifdef CONFIG_MAC |
593 | .read_byte = m68k_nvram_read_byte, |
594 | .write_byte = m68k_nvram_write_byte, |
595 | #endif |
596 | #ifdef CONFIG_ATARI |
597 | .read = m68k_nvram_read, |
598 | .write = m68k_nvram_write, |
599 | .set_checksum = m68k_nvram_set_checksum, |
600 | .initialize = m68k_nvram_initialize, |
601 | #endif |
602 | .get_size = m68k_nvram_get_size, |
603 | }; |
604 | EXPORT_SYMBOL(arch_nvram_ops); |
605 | #endif /* CONFIG_NVRAM */ |
606 | |