File: /usr/src/linux/arch/ppc/boot/prep/misc.c

1     /*
2      * BK Id: SCCS/s.misc.c 1.18 07/30/01 17:19:40 trini
3      *
4      * arch/ppc/boot/prep/misc.c
5      *
6      * Adapted for PowerPC by Gary Thomas
7      *
8      * Rewritten by Cort Dougan (cort@cs.nmt.edu)
9      * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
10      */
11     
12     #include <linux/types.h>
13     #include <asm/residual.h>
14     #include <linux/config.h>
15     #include <linux/threads.h>
16     #include <linux/elf.h>
17     #include <linux/pci_ids.h>
18     #include <asm/page.h>
19     #include <asm/processor.h>
20     #include <asm/bootinfo.h>
21     #include <asm/mmu.h>
22     #include <asm/byteorder.h>
23     #include "nonstdio.h"
24     #include "zlib.h"
25     
26     /*
27      * Please send me load/board info and such data for hardware not
28      * listed here so I can keep track since things are getting tricky
29      * with the different load addrs with different firmware.  This will
30      * help to avoid breaking the load/boot process.
31      * -- Cort
32      */
33     char *avail_ram;
34     char *end_avail;
35     extern char _end[];
36     
37     #ifdef CONFIG_CMDLINE
38     #define CMDLINE CONFIG_CMDLINE
39     #else
40     #define CMDLINE "";
41     #endif
42     char cmd_preset[] = CMDLINE;
43     char cmd_buf[256];
44     char *cmd_line = cmd_buf;
45     
46     int keyb_present = 1;	/* keyboard controller is present by default */
47     RESIDUAL hold_resid_buf;
48     RESIDUAL *hold_residual = &hold_resid_buf;
49     unsigned long initrd_start = 0, initrd_end = 0;
50     char *zimage_start;
51     int zimage_size;
52     
53     #if defined(CONFIG_SERIAL_CONSOLE)
54     unsigned long com_port;
55     #endif /* CONFIG_SERIAL_CONSOLE */
56     #ifdef CONFIG_VGA_CONSOLE
57     char *vidmem = (char *)0xC00B8000;
58     int lines = 25, cols = 80;
59     int orig_x, orig_y = 24;
60     #endif /* CONFIG_VGA_CONSOLE */
61     
62     extern int CRT_tstc(void);
63     extern void of_init(void *handler);
64     extern int of_finddevice(const char *device_specifier, int *phandle);
65     extern int of_getprop(int phandle, const char *name, void *buf, int buflen, 
66     		int *size);
67     extern int vga_init(unsigned char *ISA_mem);
68     extern void gunzip(void *, int, unsigned char *, int *);
69     
70     extern void _put_HID0(unsigned int val);
71     extern void _put_MSR(unsigned int val);
72     extern unsigned int _get_HID0(void);
73     extern unsigned int _get_MSR(void);
74     extern unsigned long serial_init(int chan);
75     
76     void
77     writel(unsigned int val, unsigned int address)
78     {
79     	/* Ensure I/O operations complete */
80     	__asm__ volatile("eieio");
81     	*(unsigned int *)address = cpu_to_le32(val);
82     }
83     
84     unsigned int 
85     readl(unsigned int address)
86     {
87     	/* Ensure I/O operations complete */
88     	__asm__ volatile("eieio");
89     	return le32_to_cpu(*(unsigned int *)address);
90     }
91     
92     #define PCI_CFG_ADDR(dev,off)	((0x80<<24) | (dev<<8) | (off&0xfc)) 
93     #define PCI_CFG_DATA(off)	(0x80000cfc+(off&3))  
94     
95     static void
96     pci_read_config_32(unsigned char devfn,
97     		unsigned char offset,
98     		unsigned int *val)
99     {
100     	writel(PCI_CFG_ADDR(devfn,offset), 0x80000cf8);
101     	*val = readl(PCI_CFG_DATA(offset));
102     	return;
103     }
104     
105     #ifdef CONFIG_VGA_CONSOLE
106     void
107     scroll(void)
108     {
109     	int i;
110     
111     	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
112     	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
113     		vidmem[i] = ' ';
114     }
115     #endif /* CONFIG_VGA_CONSOLE */
116     
117     /*
118      * This routine is used to control the second processor on the 
119      * Motorola dual processor platforms.  
120      */
121     void
122     park_cpus(void)
123     {
124     	volatile void (*go)(RESIDUAL *, int, int, char *, int);
125     	unsigned int i;
126     	volatile unsigned long *smp_iar = &(hold_residual->VitalProductData.SmpIar);
127     
128     	/* Wait for indication to continue.  If the kernel
129     	   was not compiled with SMP support then the second 
130     	   processor will spin forever here makeing the kernel
131     	   multiprocessor safe. */
132     	while (*smp_iar == 0) {
133                     for (i=0; i < 512; i++);
134     	}
135     
136     	(unsigned long)go = hold_residual->VitalProductData.SmpIar;
137     	go(hold_residual, 0, 0, cmd_line, sizeof(cmd_preset));
138     }
139     
140     unsigned long
141     decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
142     		  RESIDUAL *residual, void *OFW_interface)
143     {
144     	int timer;
145     	extern unsigned long start;
146     	char *cp, ch;
147     	unsigned long TotalMemory;
148     	unsigned long orig_MSR;
149     	int dev_handle;
150     	int mem_info[2];
151     	int res, size;
152     	unsigned char board_type;
153     	unsigned char base_mod;
154     	int start_multi = 0;
155     	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
156     	
157     	/*
158     	 * IBM's have the MMU on, so we have to disable it or
159     	 * things get really unhappy in the kernel when
160     	 * trying to setup the BATs with the MMU on
161     	 * -- Cort
162     	 */
163     	flush_instruction_cache();
164     	_put_HID0(_get_HID0() & ~0x0000C000);
165     	_put_MSR((orig_MSR = _get_MSR()) & ~0x0030);
166     
167     #if defined(CONFIG_SERIAL_CONSOLE)
168     	com_port = serial_init(0);
169     #endif /* CONFIG_SERIAL_CONSOLE */
170     #if defined(CONFIG_VGA_CONSOLE)
171     	vga_init((unsigned char *)0xC0000000);
172     #endif /* CONFIG_VGA_CONSOLE */
173     
174     	if (residual)
175     	{
176     		/* Is this Motorola PPCBug? */
177     		if ((1 & residual->VitalProductData.FirmwareSupports) &&
178     		    (1 == residual->VitalProductData.FirmwareSupplier)) {
179     			board_type = inb(0x800) & 0xF0;
180     
181     			/*
182     			 * Reset the onboard 21x4x Ethernet
183     			 * Motorola Ethernet is at IDSEL 14 (devfn 0x70)
184     			 */
185     			pci_read_config_32(0x70, 0x00, &pci_viddid);
186     			pci_did = (pci_viddid & 0xffff0000) >> 16;
187     			/* Be sure we've really found a 21x4x chip */
188     			if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_DEC) &&
189     				((pci_did == PCI_DEVICE_ID_DEC_TULIP_FAST) ||
190     				(pci_did == PCI_DEVICE_ID_DEC_TULIP) ||
191     				(pci_did == PCI_DEVICE_ID_DEC_TULIP_PLUS) ||
192     				(pci_did == PCI_DEVICE_ID_DEC_21142)))
193     			{
194     				pci_read_config_32(0x70,
195     						0x10,
196     						&tulip_pci_base);
197     				/* Get the physical base address */
198     				tulip_base =
199     					(tulip_pci_base & ~0x03UL) + 0x80000000;
200     				/* Strobe the 21x4x reset bit in CSR0 */
201     				writel(0x1, tulip_base);
202     			}
203     
204     			/* If this is genesis 2 board then check for no
205     			 * keyboard controller and more than one processor.
206     			 */
207     			if (board_type == 0xe0) {	
208     				base_mod = inb(0x803);
209     				/* if a MVME2300/2400 or a Sitka then no keyboard */
210     				if((base_mod == 0xFA) || (base_mod == 0xF9) ||
211     				   (base_mod == 0xE1)) {
212     					keyb_present = 0;	/* no keyboard */
213     				}
214     			}
215     			/* If this is a multiprocessor system then
216     			 * park the other processor so that the
217     			 * kernel knows where to find them.
218     			 */
219     			if (residual->MaxNumCpus > 1) {
220     				start_multi = 1;
221     			}
222     		}
223     		memcpy(hold_residual,residual,sizeof(RESIDUAL));
224     	} else {
225     		/* Assume 32M in the absence of more info... */
226     		TotalMemory = 0x02000000;
227     		/*
228     		 * This is a 'best guess' check.  We want to make sure
229     		 * we don't try this on a PReP box without OF
230     		 *     -- Cort
231     		 */
232     		while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) )
233     		{
234     			/* The MMU needs to be on when we call OFW */
235     			_put_MSR(orig_MSR);
236     			of_init(OFW_interface);
237     
238     			/* get handle to memory description */
239     			res = of_finddevice("/memory@0", 
240     					    &dev_handle);
241     			// puthex(res);  puts("\n");
242     			if (res) break;
243     			
244     			/* get the info */
245     			// puts("get info = ");
246     			res = of_getprop(dev_handle, 
247     					 "reg", 
248     					 mem_info, 
249     					 sizeof(mem_info), 
250     					 &size);
251     			// puthex(res);  puts(", info = "); puthex(mem_info[0]);  
252     			// puts(" ");  puthex(mem_info[1]);   puts("\n");
253     			if (res) break;
254     			
255     			TotalMemory = mem_info[1];
256     			break;
257     		}
258     		hold_residual->TotalMemory = TotalMemory;
259     		residual = hold_residual;
260     		/* Turn MMU back off */
261     		_put_MSR(orig_MSR & ~0x0030);
262             }
263     
264     	if (start_multi) {
265     		hold_residual->VitalProductData.SmpIar = 0;
266     		hold_residual->Cpus[1].CpuState = CPU_GOOD_FW;
267     		residual->VitalProductData.SmpIar = (unsigned long)park_cpus;
268     		residual->Cpus[1].CpuState = CPU_GOOD;
269     		hold_residual->VitalProductData.Reserved5 = 0xdeadbeef;
270     	}
271     
272     	/* assume the chunk below 8M is free */
273     	end_avail = (char *)0x00800000;
274     
275     	/* tell the user where we were loaded at and where we
276     	 * were relocated to for debugging this process
277     	 */
278     	puts("loaded at:     "); puthex(load_addr);
279     	puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
280     	if ( (unsigned long)load_addr != (unsigned long)&start )
281     	{
282     		puts("relocated to:  "); puthex((unsigned long)&start);
283     		puts(" ");
284     		puthex((unsigned long)((unsigned long)&start + (4*num_words)));
285     		puts("\n");
286     	}
287     
288     	if ( residual )
289     	{
290     		puts("board data at: "); puthex((unsigned long)residual);
291     		puts(" ");
292     		puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL)));
293     		puts("\n");
294     		puts("relocated to:  ");
295     		puthex((unsigned long)hold_residual);
296     		puts(" ");
297     		puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL)));
298     		puts("\n");
299     	}
300     
301     	/* we have to subtract 0x10000 here to correct for objdump including the
302     	   size of the elf header which we strip -- Cort */
303     	zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
304     	zimage_size = ZIMAGE_SIZE;
305     
306     	if ( INITRD_OFFSET )
307     		initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
308     	else
309     		initrd_start = 0;
310     	initrd_end = INITRD_SIZE + initrd_start;
311     
312     	/*
313     	 * Find a place to stick the zimage and initrd and 
314     	 * relocate them if we have to. -- Cort
315     	 */
316     	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
317     	puts("zimage at:     "); puthex((unsigned long)zimage_start);
318     	puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
319     	if ( (unsigned long)zimage_start <= 0x00800000 )
320     	{
321     		memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
322     		zimage_start = (char *)avail_ram;
323     		puts("relocated to:  "); puthex((unsigned long)zimage_start);
324     		puts(" ");
325     		puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
326     		puts("\n");
327     
328     		/* relocate initrd */
329     		if ( initrd_start )
330     		{
331     			puts("initrd at:     "); puthex(initrd_start);
332     			puts(" "); puthex(initrd_end); puts("\n");
333     			avail_ram = (char *)PAGE_ALIGN(
334     				(unsigned long)zimage_size+(unsigned long)zimage_start);
335     			memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
336     			initrd_start = (unsigned long)avail_ram;
337     			initrd_end = initrd_start + INITRD_SIZE;
338     			puts("relocated to:  "); puthex(initrd_start);
339     			puts(" "); puthex(initrd_end); puts("\n");
340     		}
341     	} else if ( initrd_start ) {
342     		puts("initrd at:     "); puthex(initrd_start);
343     		puts(" "); puthex(initrd_end); puts("\n");
344     	}
345     
346     	avail_ram = (char *)0x00400000;
347     	end_avail = (char *)0x00800000;
348     	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
349     	puthex((unsigned long)end_avail); puts("\n");
350     
351     	if (keyb_present)
352     		CRT_tstc();  /* Forces keyboard to be initialized */
353     
354     	puts("\nLinux/PPC load: ");
355     	timer = 0;
356     	cp = cmd_line;
357     	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
358     	while ( *cp ) putc(*cp++);
359     	while (timer++ < 5*1000) {
360     		if (tstc()) {
361     			while ((ch = getc()) != '\n' && ch != '\r') {
362     				/* Test for backspace/delete */
363     				if (ch == '\b' || ch == '\177') {
364     					if (cp != cmd_line) {
365     						cp--;
366     						puts("\b \b");
367     					}
368     				/* Test for ^x/^u (and wipe the line) */
369     				} else if (ch == '\030' || ch == '\025') {
370     					while (cp != cmd_line) {
371     						cp--;
372     						puts("\b \b");
373     					}
374     				} else {
375     					*cp++ = ch;
376     					putc(ch);
377     				}
378     			}
379     			break;  /* Exit 'timer' loop */
380     		}
381     		udelay(1000);  /* 1 msec */
382     	}
383     	*cp = 0;
384     	puts("\n");
385     
386     	/* mappings on early boot can only handle 16M */
387     	if ( (int)(cmd_line[0]) > (16<<20))
388     		puts("cmd_line located > 16M\n");
389     	if ( (int)hold_residual > (16<<20))
390     		puts("hold_residual located > 16M\n");
391     	if ( initrd_start > (16<<20))
392     		puts("initrd_start located > 16M\n");
393     
394     	puts("Uncompressing Linux...");
395     	
396     	gunzip(0, 0x400000, zimage_start, &zimage_size);
397     	puts("done.\n");
398     	
399     	{
400     		struct bi_record *rec;
401     	    
402     		rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size)+(1<<20)-1,(1<<20));
403     	    
404     		rec->tag = BI_FIRST;
405     		rec->size = sizeof(struct bi_record);
406     		rec = (struct bi_record *)((unsigned long)rec + rec->size);
407     
408     		rec->tag = BI_BOOTLOADER_ID;
409     		memcpy( (void *)rec->data, "prepboot", 9);
410     		rec->size = sizeof(struct bi_record) + 8 + 1;
411     		rec = (struct bi_record *)((unsigned long)rec + rec->size);
412     	    
413     		rec->tag = BI_MACHTYPE;
414     		rec->data[0] = _MACH_prep;
415     		rec->data[1] = 0;
416     		rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
417     		rec = (struct bi_record *)((unsigned long)rec + rec->size);
418     	    
419     		rec->tag = BI_CMD_LINE;
420     		memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
421     		rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
422     		rec = (struct bi_record *)((ulong)rec + rec->size);
423     		
424     		rec->tag = BI_LAST;
425     		rec->size = sizeof(struct bi_record);
426     		rec = (struct bi_record *)((unsigned long)rec + rec->size);
427     	}
428     	puts("Now booting the kernel\n");
429     	return (unsigned long)hold_residual;
430     }
431     
432     /*
433      * PCI/ISA I/O support
434      */
435     unsigned long
436     local_to_PCI(unsigned long addr)
437     {
438     	return (addr | 0x80000000);
439     }
440