Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
[pandora-kernel.git] / arch / ppc / boot / simple / misc.c
1 /*
2  * Misc. bootloader code for many machines.  This assumes you have are using
3  * a 6xx/7xx/74xx CPU in your machine.  This assumes the chunk of memory
4  * below 8MB is free.  Finally, it assumes you have a NS16550-style uart for
5  * your serial console.  If a machine meets these requirements, it can quite
6  * likely use this code during boot.
7  *
8  * Author: Matt Porter <mporter@mvista.com>
9  * Derived from arch/ppc/boot/prep/misc.c
10  *
11  * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
12  * the terms of the GNU General Public License version 2.  This program
13  * is licensed "as is" without any warranty of any kind, whether express
14  * or implied.
15  */
16
17 #include <linux/types.h>
18 #include <linux/string.h>
19
20 #include <asm/page.h>
21 #include <asm/mmu.h>
22 #include <asm/bootinfo.h>
23 #ifdef CONFIG_4xx
24 #include <asm/ibm4xx.h>
25 #endif
26 #include <asm/reg.h>
27
28 #include "nonstdio.h"
29
30 /* Default cmdline */
31 #ifdef CONFIG_CMDLINE
32 #define CMDLINE CONFIG_CMDLINE
33 #else
34 #define CMDLINE ""
35 #endif
36
37 /* Keyboard (and VGA console)? */
38 #ifdef CONFIG_VGA_CONSOLE
39 #define HAS_KEYB 1
40 #else
41 #define HAS_KEYB 0
42 #endif
43
44 /* Will / Can the user give input?
45  * Val Henson has requested that Gemini doesn't wait for the
46  * user to edit the cmdline or not.
47  */
48 #if (defined(CONFIG_SERIAL_8250_CONSOLE) \
49         || defined(CONFIG_VGA_CONSOLE) \
50         || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
51         || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
52         && !defined(CONFIG_GEMINI)
53 #define INTERACTIVE_CONSOLE     1
54 #endif
55
56 char *avail_ram;
57 char *end_avail;
58 char *zimage_start;
59 char cmd_preset[] = CMDLINE;
60 char cmd_buf[256];
61 char *cmd_line = cmd_buf;
62 int keyb_present = HAS_KEYB;
63 int zimage_size;
64
65 unsigned long com_port;
66 unsigned long initrd_size = 0;
67
68 /* The linker tells us various locations in the image */
69 extern char __image_begin, __image_end;
70 extern char __ramdisk_begin, __ramdisk_end;
71 extern char _end[];
72 /* Original location */
73 extern unsigned long start;
74
75 extern int CRT_tstc(void);
76 extern unsigned long serial_init(int chan, void *ignored);
77 extern void serial_close(unsigned long com_port);
78 extern void gunzip(void *, int, unsigned char *, int *);
79 extern void serial_fixups(void);
80
81 /* Allow get_mem_size to be hooked into.  This is the default. */
82 unsigned long __attribute__ ((weak))
83 get_mem_size(void)
84 {
85         return 0;
86 }
87
88 #if defined(CONFIG_40x)
89 #define PPC4xx_EMAC0_MR0        EMAC0_BASE
90 #endif
91
92 #if defined(CONFIG_44x) && defined(PPC44x_EMAC0_MR0)
93 #define PPC4xx_EMAC0_MR0        PPC44x_EMAC0_MR0
94 #endif
95
96 struct bi_record *
97 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
98 {
99 #ifdef INTERACTIVE_CONSOLE
100         int timer = 0;
101         char ch;
102 #endif
103         char *cp;
104         struct bi_record *rec;
105         unsigned long initrd_loc = 0, TotalMemory = 0;
106
107 #if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPSC_CONSOLE)
108         com_port = serial_init(0, NULL);
109 #endif
110
111 #if defined(PPC4xx_EMAC0_MR0)
112         /* Reset MAL */
113         mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR);
114         /* Wait for reset */
115         while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {};
116         /* Reset EMAC */
117         *(volatile unsigned long *)PPC4xx_EMAC0_MR0 = 0x20000000;
118         __asm__ __volatile__("eieio");
119 #endif
120
121         /*
122          * Call get_mem_size(), which is memory controller dependent,
123          * and we must have the correct file linked in here.
124          */
125         TotalMemory = get_mem_size();
126
127         /* assume the chunk below 8M is free */
128         end_avail = (char *)0x00800000;
129
130         /*
131          * Reveal where we were loaded at and where we
132          * were relocated to.
133          */
134         puts("loaded at:     "); puthex(load_addr);
135         puts(" "); puthex((unsigned long)(load_addr + (4*num_words)));
136         puts("\n");
137         if ( (unsigned long)load_addr != (unsigned long)&start )
138         {
139                 puts("relocated to:  "); puthex((unsigned long)&start);
140                 puts(" ");
141                 puthex((unsigned long)((unsigned long)&start + (4*num_words)));
142                 puts("\n");
143         }
144
145         /*
146          * We link ourself to 0x00800000.  When we run, we relocate
147          * ourselves there.  So we just need __image_begin for the
148          * start. -- Tom
149          */
150         zimage_start = (char *)(unsigned long)(&__image_begin);
151         zimage_size = (unsigned long)(&__image_end) -
152                         (unsigned long)(&__image_begin);
153
154         initrd_size = (unsigned long)(&__ramdisk_end) -
155                 (unsigned long)(&__ramdisk_begin);
156
157         /*
158          * The zImage and initrd will be between start and _end, so they've
159          * already been moved once.  We're good to go now. -- Tom
160          */
161         avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
162         puts("zimage at:     "); puthex((unsigned long)zimage_start);
163         puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
164         puts("\n");
165
166         if ( initrd_size ) {
167                 puts("initrd at:     ");
168                 puthex((unsigned long)(&__ramdisk_begin));
169                 puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
170         }
171
172 #ifndef CONFIG_40x /* don't overwrite the 40x image located at 0x00400000! */
173         avail_ram = (char *)0x00400000;
174 #endif
175         end_avail = (char *)0x00800000;
176         puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
177         puthex((unsigned long)end_avail); puts("\n");
178
179         if (keyb_present)
180                 CRT_tstc();  /* Forces keyboard to be initialized */
181 #ifdef CONFIG_GEMINI
182         /*
183          * If cmd_line is empty and cmd_preset is not, copy cmd_preset
184          * to cmd_line.  This way we can override cmd_preset with the
185          * command line from Smon.
186          */
187
188         if ( (cmd_line[0] == '\0') && (cmd_preset[0] != '\0'))
189                 memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
190 #endif
191
192         /* Display standard Linux/PPC boot prompt for kernel args */
193         puts("\nLinux/PPC load: ");
194         cp = cmd_line;
195         memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
196         while ( *cp ) putc(*cp++);
197
198 #ifdef INTERACTIVE_CONSOLE
199         /*
200          * If they have a console, allow them to edit the command line.
201          * Otherwise, don't bother wasting the five seconds.
202          */
203         while (timer++ < 5*1000) {
204                 if (tstc()) {
205                         while ((ch = getc()) != '\n' && ch != '\r') {
206                                 /* Test for backspace/delete */
207                                 if (ch == '\b' || ch == '\177') {
208                                         if (cp != cmd_line) {
209                                                 cp--;
210                                                 puts("\b \b");
211                                         }
212                                 /* Test for ^x/^u (and wipe the line) */
213                                 } else if (ch == '\030' || ch == '\025') {
214                                         while (cp != cmd_line) {
215                                                 cp--;
216                                                 puts("\b \b");
217                                         }
218                                 } else {
219                                         *cp++ = ch;
220                                         putc(ch);
221                                 }
222                         }
223                         break;  /* Exit 'timer' loop */
224                 }
225                 udelay(1000);  /* 1 msec */
226         }
227         *cp = 0;
228 #endif
229         puts("\n");
230
231         puts("Uncompressing Linux...");
232         gunzip(NULL, 0x400000, zimage_start, &zimage_size);
233         puts("done.\n");
234
235         /* get the bi_rec address */
236         rec = bootinfo_addr(zimage_size);
237
238         /* We need to make sure that the initrd and bi_recs do not
239          * overlap. */
240         if ( initrd_size ) {
241                 unsigned long rec_loc = (unsigned long) rec;
242                 initrd_loc = (unsigned long)(&__ramdisk_begin);
243                 /* If the bi_recs are in the middle of the current
244                  * initrd, move the initrd to the next MB
245                  * boundary. */
246                 if ((rec_loc > initrd_loc) &&
247                                 ((initrd_loc + initrd_size) > rec_loc)) {
248                         initrd_loc = _ALIGN((unsigned long)(zimage_size)
249                                         + (2 << 20) - 1, (2 << 20));
250                         memmove((void *)initrd_loc, &__ramdisk_begin,
251                                  initrd_size);
252                         puts("initrd moved:  "); puthex(initrd_loc);
253                         puts(" "); puthex(initrd_loc + initrd_size);
254                         puts("\n");
255                 }
256         }
257
258         bootinfo_init(rec);
259         if ( TotalMemory )
260                 bootinfo_append(BI_MEMSIZE, sizeof(int), (void*)&TotalMemory);
261
262         bootinfo_append(BI_CMD_LINE, strlen(cmd_line)+1, (void*)cmd_line);
263
264         /* add a bi_rec for the initrd if it exists */
265         if (initrd_size) {
266                 unsigned long initrd[2];
267
268                 initrd[0] = initrd_loc;
269                 initrd[1] = initrd_size;
270
271                 bootinfo_append(BI_INITRD, sizeof(initrd), &initrd);
272         }
273         puts("Now booting the kernel\n");
274         serial_close(com_port);
275
276         return rec;
277 }
278
279 void __attribute__ ((weak))
280 board_isa_init(void)
281 {
282 }
283
284 /* Allow decompress_kernel to be hooked into.  This is the default. */
285 void * __attribute__ ((weak))
286 load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
287                 void *ign1, void *ign2)
288 {
289                 board_isa_init();
290                 return decompress_kernel(load_addr, num_words, cksum);
291 }