xref: /openbmc/linux/arch/sparc/kernel/setup_32.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   *  linux/arch/sparc/kernel/setup.c
4   *
5   *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
6   *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
7   */
8  
9  #include <linux/errno.h>
10  #include <linux/sched.h>
11  #include <linux/kernel.h>
12  #include <linux/mm.h>
13  #include <linux/stddef.h>
14  #include <linux/unistd.h>
15  #include <linux/ptrace.h>
16  #include <linux/slab.h>
17  #include <linux/initrd.h>
18  #include <asm/smp.h>
19  #include <linux/user.h>
20  #include <linux/screen_info.h>
21  #include <linux/delay.h>
22  #include <linux/fs.h>
23  #include <linux/seq_file.h>
24  #include <linux/syscalls.h>
25  #include <linux/kdev_t.h>
26  #include <linux/major.h>
27  #include <linux/string.h>
28  #include <linux/init.h>
29  #include <linux/interrupt.h>
30  #include <linux/console.h>
31  #include <linux/spinlock.h>
32  #include <linux/root_dev.h>
33  #include <linux/cpu.h>
34  #include <linux/kdebug.h>
35  #include <linux/export.h>
36  #include <linux/start_kernel.h>
37  #include <uapi/linux/mount.h>
38  
39  #include <asm/io.h>
40  #include <asm/processor.h>
41  #include <asm/oplib.h>
42  #include <asm/page.h>
43  #include <asm/traps.h>
44  #include <asm/vaddrs.h>
45  #include <asm/mbus.h>
46  #include <asm/idprom.h>
47  #include <asm/cpudata.h>
48  #include <asm/setup.h>
49  #include <asm/cacheflush.h>
50  #include <asm/sections.h>
51  
52  #include "kernel.h"
53  
54  struct screen_info screen_info = {
55  	0, 0,			/* orig-x, orig-y */
56  	0,			/* unused */
57  	0,			/* orig-video-page */
58  	0,			/* orig-video-mode */
59  	128,			/* orig-video-cols */
60  	0,0,0,			/* ega_ax, ega_bx, ega_cx */
61  	54,			/* orig-video-lines */
62  	0,                      /* orig-video-isVGA */
63  	16                      /* orig-video-points */
64  };
65  
66  /* Typing sync at the prom prompt calls the function pointed to by
67   * romvec->pv_synchook which I set to the following function.
68   * This should sync all filesystems and return, for now it just
69   * prints out pretty messages and returns.
70   */
71  
72  /* Pretty sick eh? */
prom_sync_me(void)73  static void prom_sync_me(void)
74  {
75  	unsigned long prom_tbr, flags;
76  
77  	/* XXX Badly broken. FIX! - Anton */
78  	local_irq_save(flags);
79  	__asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
80  	__asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
81  			     "nop\n\t"
82  			     "nop\n\t"
83  			     "nop\n\t" : : "r" (&trapbase));
84  
85  	prom_printf("PROM SYNC COMMAND...\n");
86  	show_mem();
87  	if (!is_idle_task(current)) {
88  		local_irq_enable();
89  		ksys_sync();
90  		local_irq_disable();
91  	}
92  	prom_printf("Returning to prom\n");
93  
94  	__asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
95  			     "nop\n\t"
96  			     "nop\n\t"
97  			     "nop\n\t" : : "r" (prom_tbr));
98  	local_irq_restore(flags);
99  }
100  
101  static unsigned int boot_flags __initdata = 0;
102  #define BOOTME_DEBUG  0x1
103  
104  /* Exported for mm/init.c:paging_init. */
105  unsigned long cmdline_memory_size __initdata = 0;
106  
107  /* which CPU booted us (0xff = not set) */
108  unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */
109  
110  static void
prom_console_write(struct console * con,const char * s,unsigned int n)111  prom_console_write(struct console *con, const char *s, unsigned int n)
112  {
113  	prom_write(s, n);
114  }
115  
116  static struct console prom_early_console = {
117  	.name =		"earlyprom",
118  	.write =	prom_console_write,
119  	.flags =	CON_PRINTBUFFER | CON_BOOT,
120  	.index =	-1,
121  };
122  
123  /*
124   * Process kernel command line switches that are specific to the
125   * SPARC or that require special low-level processing.
126   */
process_switch(char c)127  static void __init process_switch(char c)
128  {
129  	switch (c) {
130  	case 'd':
131  		boot_flags |= BOOTME_DEBUG;
132  		break;
133  	case 's':
134  		break;
135  	case 'h':
136  		prom_printf("boot_flags_init: Halt!\n");
137  		prom_halt();
138  		break;
139  	case 'p':
140  		prom_early_console.flags &= ~CON_BOOT;
141  		break;
142  	default:
143  		printk("Unknown boot switch (-%c)\n", c);
144  		break;
145  	}
146  }
147  
boot_flags_init(char * commands)148  static void __init boot_flags_init(char *commands)
149  {
150  	while (*commands) {
151  		/* Move to the start of the next "argument". */
152  		while (*commands == ' ')
153  			commands++;
154  
155  		/* Process any command switches, otherwise skip it. */
156  		if (*commands == '\0')
157  			break;
158  		if (*commands == '-') {
159  			commands++;
160  			while (*commands && *commands != ' ')
161  				process_switch(*commands++);
162  			continue;
163  		}
164  		if (!strncmp(commands, "mem=", 4)) {
165  			/*
166  			 * "mem=XXX[kKmM] overrides the PROM-reported
167  			 * memory size.
168  			 */
169  			cmdline_memory_size = simple_strtoul(commands + 4,
170  						     &commands, 0);
171  			if (*commands == 'K' || *commands == 'k') {
172  				cmdline_memory_size <<= 10;
173  				commands++;
174  			} else if (*commands=='M' || *commands=='m') {
175  				cmdline_memory_size <<= 20;
176  				commands++;
177  			}
178  		}
179  		while (*commands && *commands != ' ')
180  			commands++;
181  	}
182  }
183  
184  extern unsigned short root_flags;
185  extern unsigned short root_dev;
186  extern unsigned short ram_flags;
187  #define RAMDISK_IMAGE_START_MASK	0x07FF
188  #define RAMDISK_PROMPT_FLAG		0x8000
189  #define RAMDISK_LOAD_FLAG		0x4000
190  
191  extern int root_mountflags;
192  
193  char reboot_command[COMMAND_LINE_SIZE];
194  
195  struct cpuid_patch_entry {
196  	unsigned int	addr;
197  	unsigned int	sun4d[3];
198  	unsigned int	leon[3];
199  };
200  extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
201  
per_cpu_patch(void)202  static void __init per_cpu_patch(void)
203  {
204  	struct cpuid_patch_entry *p;
205  
206  	if (sparc_cpu_model == sun4m) {
207  		/* Nothing to do, this is what the unpatched code
208  		 * targets.
209  		 */
210  		return;
211  	}
212  
213  	p = &__cpuid_patch;
214  	while (p < &__cpuid_patch_end) {
215  		unsigned long addr = p->addr;
216  		unsigned int *insns;
217  
218  		switch (sparc_cpu_model) {
219  		case sun4d:
220  			insns = &p->sun4d[0];
221  			break;
222  
223  		case sparc_leon:
224  			insns = &p->leon[0];
225  			break;
226  		default:
227  			prom_printf("Unknown cpu type, halting.\n");
228  			prom_halt();
229  		}
230  		*(unsigned int *) (addr + 0) = insns[0];
231  		flushi(addr + 0);
232  		*(unsigned int *) (addr + 4) = insns[1];
233  		flushi(addr + 4);
234  		*(unsigned int *) (addr + 8) = insns[2];
235  		flushi(addr + 8);
236  
237  		p++;
238  	}
239  }
240  
241  struct leon_1insn_patch_entry {
242  	unsigned int addr;
243  	unsigned int insn;
244  };
245  
246  enum sparc_cpu sparc_cpu_model;
247  EXPORT_SYMBOL(sparc_cpu_model);
248  
leon_patch(void)249  static __init void leon_patch(void)
250  {
251  	struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch;
252  	struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end;
253  
254  	/* Default instruction is leon - no patching */
255  	if (sparc_cpu_model == sparc_leon)
256  		return;
257  
258  	while (start < end) {
259  		unsigned long addr = start->addr;
260  
261  		*(unsigned int *)(addr) = start->insn;
262  		flushi(addr);
263  
264  		start++;
265  	}
266  }
267  
268  struct tt_entry *sparc_ttable;
269  
270  /* Called from head_32.S - before we have setup anything
271   * in the kernel. Be very careful with what you do here.
272   */
sparc32_start_kernel(struct linux_romvec * rp)273  void __init sparc32_start_kernel(struct linux_romvec *rp)
274  {
275  	prom_init(rp);
276  
277  	/* Set sparc_cpu_model */
278  	sparc_cpu_model = sun_unknown;
279  	if (!strcmp(&cputypval[0], "sun4m"))
280  		sparc_cpu_model = sun4m;
281  	if (!strcmp(&cputypval[0], "sun4s"))
282  		sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
283  	if (!strcmp(&cputypval[0], "sun4d"))
284  		sparc_cpu_model = sun4d;
285  	if (!strcmp(&cputypval[0], "sun4e"))
286  		sparc_cpu_model = sun4e;
287  	if (!strcmp(&cputypval[0], "sun4u"))
288  		sparc_cpu_model = sun4u;
289  	if (!strncmp(&cputypval[0], "leon" , 4))
290  		sparc_cpu_model = sparc_leon;
291  
292  	leon_patch();
293  	start_kernel();
294  }
295  
setup_arch(char ** cmdline_p)296  void __init setup_arch(char **cmdline_p)
297  {
298  	int i;
299  	unsigned long highest_paddr;
300  
301  	sparc_ttable = &trapbase;
302  
303  	/* Initialize PROM console and command line. */
304  	*cmdline_p = prom_getbootargs();
305  	strscpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
306  	parse_early_param();
307  
308  	boot_flags_init(*cmdline_p);
309  
310  	register_console(&prom_early_console);
311  
312  	switch(sparc_cpu_model) {
313  	case sun4m:
314  		pr_info("ARCH: SUN4M\n");
315  		break;
316  	case sun4d:
317  		pr_info("ARCH: SUN4D\n");
318  		break;
319  	case sun4e:
320  		pr_info("ARCH: SUN4E\n");
321  		break;
322  	case sun4u:
323  		pr_info("ARCH: SUN4U\n");
324  		break;
325  	case sparc_leon:
326  		pr_info("ARCH: LEON\n");
327  		break;
328  	default:
329  		pr_info("ARCH: UNKNOWN!\n");
330  		break;
331  	}
332  
333  	idprom_init();
334  	load_mmu();
335  
336  	phys_base = 0xffffffffUL;
337  	highest_paddr = 0UL;
338  	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
339  		unsigned long top;
340  
341  		if (sp_banks[i].base_addr < phys_base)
342  			phys_base = sp_banks[i].base_addr;
343  		top = sp_banks[i].base_addr +
344  			sp_banks[i].num_bytes;
345  		if (highest_paddr < top)
346  			highest_paddr = top;
347  	}
348  	pfn_base = phys_base >> PAGE_SHIFT;
349  
350  	if (!root_flags)
351  		root_mountflags &= ~MS_RDONLY;
352  	ROOT_DEV = old_decode_dev(root_dev);
353  #ifdef CONFIG_BLK_DEV_RAM
354  	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
355  #endif
356  
357  	prom_setsync(prom_sync_me);
358  
359  	if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) &&
360  	   ((*(short *)linux_dbvec) != -1)) {
361  		printk("Booted under KADB. Syncing trap table.\n");
362  		(*(linux_dbvec->teach_debugger))();
363  	}
364  
365  	/* Run-time patch instructions to match the cpu model */
366  	per_cpu_patch();
367  
368  	paging_init();
369  
370  	smp_setup_cpu_possible_map();
371  }
372  
373  extern int stop_a_enabled;
374  
sun_do_break(void)375  void sun_do_break(void)
376  {
377  	if (!stop_a_enabled)
378  		return;
379  
380  	printk("\n");
381  	flush_user_windows();
382  
383  	prom_cmdline();
384  }
385  EXPORT_SYMBOL(sun_do_break);
386  
387  int stop_a_enabled = 1;
388  
topology_init(void)389  static int __init topology_init(void)
390  {
391  	int i, ncpus, err;
392  
393  	/* Count the number of physically present processors in
394  	 * the machine, even on uniprocessor, so that /proc/cpuinfo
395  	 * output is consistent with 2.4.x
396  	 */
397  	ncpus = 0;
398  	while (!cpu_find_by_instance(ncpus, NULL, NULL))
399  		ncpus++;
400  	ncpus_probed = ncpus;
401  
402  	err = 0;
403  	for_each_online_cpu(i) {
404  		struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
405  		if (!p)
406  			err = -ENOMEM;
407  		else
408  			register_cpu(p, i);
409  	}
410  
411  	return err;
412  }
413  
414  subsys_initcall(topology_init);
415  
416  #if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
arch_cpu_finalize_init(void)417  void __init arch_cpu_finalize_init(void)
418  {
419  	cpu_data(0).udelay_val = loops_per_jiffy;
420  }
421  #endif
422