diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/boot/common |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/boot/common')
-rw-r--r-- | arch/ppc/boot/common/Makefile | 13 | ||||
-rw-r--r-- | arch/ppc/boot/common/bootinfo.c | 70 | ||||
-rw-r--r-- | arch/ppc/boot/common/crt0.S | 81 | ||||
-rw-r--r-- | arch/ppc/boot/common/misc-common.c | 553 | ||||
-rw-r--r-- | arch/ppc/boot/common/ns16550.c | 99 | ||||
-rw-r--r-- | arch/ppc/boot/common/serial_stub.c | 23 | ||||
-rw-r--r-- | arch/ppc/boot/common/string.S | 150 | ||||
-rw-r--r-- | arch/ppc/boot/common/util.S | 293 |
8 files changed, 1282 insertions, 0 deletions
diff --git a/arch/ppc/boot/common/Makefile b/arch/ppc/boot/common/Makefile new file mode 100644 index 000000000000..f88d647d5dd4 --- /dev/null +++ b/arch/ppc/boot/common/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # arch/ppc/boot/common/Makefile | ||
3 | # | ||
4 | # This file is subject to the terms and conditions of the GNU General Public | ||
5 | # License. See the file "COPYING" in the main directory of this archive | ||
6 | # for more details. | ||
7 | # | ||
8 | # Tom Rini January 2001 | ||
9 | # | ||
10 | |||
11 | lib-y := string.o util.o misc-common.o \ | ||
12 | serial_stub.o bootinfo.o | ||
13 | lib-$(CONFIG_SERIAL_8250_CONSOLE) += ns16550.o | ||
diff --git a/arch/ppc/boot/common/bootinfo.c b/arch/ppc/boot/common/bootinfo.c new file mode 100644 index 000000000000..9c6e528940e9 --- /dev/null +++ b/arch/ppc/boot/common/bootinfo.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * arch/ppc/common/bootinfo.c | ||
3 | * | ||
4 | * General bootinfo record utilities | ||
5 | * Author: Randy Vinson <rvinson@mvista.com> | ||
6 | * | ||
7 | * 2002 (c) MontaVista Software, Inc. This file is licensed under the terms | ||
8 | * of the GNU General Public License version 2. This program is licensed | ||
9 | * "as is" without any warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <asm/bootinfo.h> | ||
15 | |||
16 | #include "nonstdio.h" | ||
17 | |||
18 | static struct bi_record * birec = NULL; | ||
19 | |||
20 | static struct bi_record * | ||
21 | __bootinfo_build(struct bi_record *rec, unsigned long tag, unsigned long size, | ||
22 | void *data) | ||
23 | { | ||
24 | /* set the tag */ | ||
25 | rec->tag = tag; | ||
26 | |||
27 | /* if the caller has any data, copy it */ | ||
28 | if (size) | ||
29 | memcpy(rec->data, (char *)data, size); | ||
30 | |||
31 | /* set the record size */ | ||
32 | rec->size = sizeof(struct bi_record) + size; | ||
33 | |||
34 | /* advance to the next available space */ | ||
35 | rec = (struct bi_record *)((unsigned long)rec + rec->size); | ||
36 | |||
37 | return rec; | ||
38 | } | ||
39 | |||
40 | void | ||
41 | bootinfo_init(struct bi_record *rec) | ||
42 | { | ||
43 | |||
44 | /* save start of birec area */ | ||
45 | birec = rec; | ||
46 | |||
47 | /* create an empty list */ | ||
48 | rec = __bootinfo_build(rec, BI_FIRST, 0, NULL); | ||
49 | (void) __bootinfo_build(rec, BI_LAST, 0, NULL); | ||
50 | |||
51 | } | ||
52 | |||
53 | void | ||
54 | bootinfo_append(unsigned long tag, unsigned long size, void * data) | ||
55 | { | ||
56 | |||
57 | struct bi_record *rec = birec; | ||
58 | |||
59 | /* paranoia */ | ||
60 | if ((rec == NULL) || (rec->tag != BI_FIRST)) | ||
61 | return; | ||
62 | |||
63 | /* find the last entry in the list */ | ||
64 | while (rec->tag != BI_LAST) | ||
65 | rec = (struct bi_record *)((ulong)rec + rec->size); | ||
66 | |||
67 | /* overlay BI_LAST record with new one and tag on a new BI_LAST */ | ||
68 | rec = __bootinfo_build(rec, tag, size, data); | ||
69 | (void) __bootinfo_build(rec, BI_LAST, 0, NULL); | ||
70 | } | ||
diff --git a/arch/ppc/boot/common/crt0.S b/arch/ppc/boot/common/crt0.S new file mode 100644 index 000000000000..4d31b824bbd1 --- /dev/null +++ b/arch/ppc/boot/common/crt0.S | |||
@@ -0,0 +1,81 @@ | |||
1 | /* Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au> | ||
2 | * Initial Power Macintosh COFF version. | ||
3 | * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> | ||
4 | * Modifications for IBM PowerPC 400-class processor evaluation | ||
5 | * boards. | ||
6 | * | ||
7 | * Module name: crt0.S | ||
8 | * | ||
9 | * Description: | ||
10 | * Boot loader execution entry point. Clears out .bss section as per | ||
11 | * ANSI C requirements. Invalidates and flushes the caches over the | ||
12 | * range covered by the boot loader's .text section. Sets up a stack | ||
13 | * below the .text section entry point. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version | ||
18 | * 2 of the License, or (at your option) any later version. | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <asm/ppc_asm.h> | ||
23 | |||
24 | .text | ||
25 | |||
26 | .globl _start | ||
27 | _start: | ||
28 | #ifdef XCOFF | ||
29 | .long __start,0,0 | ||
30 | |||
31 | .globl __start | ||
32 | __start: | ||
33 | #endif | ||
34 | |||
35 | ## Flush and invalidate the caches for the range in memory covering | ||
36 | ## the .text section of the boot loader | ||
37 | |||
38 | lis r9,_start@h # r9 = &_start | ||
39 | lis r8,_etext@ha # | ||
40 | addi r8,r8,_etext@l # r8 = &_etext | ||
41 | 3: dcbf r0,r9 # Flush the data cache | ||
42 | icbi r0,r9 # Invalidate the instruction cache | ||
43 | addi r9,r9,0x10 # Increment by one cache line | ||
44 | cmplw cr0,r9,r8 # Are we at the end yet? | ||
45 | blt 3b # No, keep flushing and invalidating | ||
46 | sync # sync ; isync after flushing the icache | ||
47 | isync | ||
48 | |||
49 | ## Clear out the BSS as per ANSI C requirements | ||
50 | |||
51 | lis r7,_end@ha | ||
52 | addi r7,r7,_end@l # r7 = &_end | ||
53 | lis r8,__bss_start@ha # | ||
54 | addi r8,r8,__bss_start@l # r8 = &_bss_start | ||
55 | |||
56 | ## Determine how large an area, in number of words, to clear | ||
57 | |||
58 | subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 | ||
59 | addi r7,r7,3 # r7 += 3 | ||
60 | srwi. r7,r7,2 # r7 = size in words. | ||
61 | beq 2f # If the size is zero, do not bother | ||
62 | addi r8,r8,-4 # r8 -= 4 | ||
63 | mtctr r7 # SPRN_CTR = number of words to clear | ||
64 | li r0,0 # r0 = 0 | ||
65 | 1: stwu r0,4(r8) # Clear out a word | ||
66 | bdnz 1b # If we are not done yet, keep clearing | ||
67 | 2: | ||
68 | |||
69 | #ifdef CONFIG_40x | ||
70 | ## Set up the stack | ||
71 | |||
72 | lis r9,_start@h # r9 = &_start (text section entry) | ||
73 | ori r9,r9,_start@l | ||
74 | subi r1,r9,64 # Start the stack 64 bytes below _start | ||
75 | clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes. | ||
76 | li r0,0 | ||
77 | stwu r0,-16(r1) | ||
78 | mtlr r9 | ||
79 | #endif | ||
80 | |||
81 | b start # All done, start the real work. | ||
diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c new file mode 100644 index 000000000000..e79e6b3f276e --- /dev/null +++ b/arch/ppc/boot/common/misc-common.c | |||
@@ -0,0 +1,553 @@ | |||
1 | /* | ||
2 | * arch/ppc/boot/common/misc-common.c | ||
3 | * | ||
4 | * Misc. bootloader code (almost) all platforms can use | ||
5 | * | ||
6 | * Author: Johnnie Peters <jpeters@mvista.com> | ||
7 | * Editor: Tom Rini <trini@mvista.com> | ||
8 | * | ||
9 | * Derived from arch/ppc/boot/prep/misc.c | ||
10 | * | ||
11 | * 2000-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 <stdarg.h> /* for va_ bits */ | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/zlib.h> | ||
21 | #include "nonstdio.h" | ||
22 | |||
23 | /* If we're on a PReP, assume we have a keyboard controller | ||
24 | * Also note, if we're not PReP, we assume you are a serial | ||
25 | * console - Tom */ | ||
26 | #if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE) | ||
27 | extern void cursor(int x, int y); | ||
28 | extern void scroll(void); | ||
29 | extern char *vidmem; | ||
30 | extern int lines, cols; | ||
31 | extern int orig_x, orig_y; | ||
32 | extern int keyb_present; | ||
33 | extern int CRT_tstc(void); | ||
34 | extern int CRT_getc(void); | ||
35 | #else | ||
36 | int cursor(int x, int y) {return 0;} | ||
37 | void scroll(void) {} | ||
38 | char vidmem[1]; | ||
39 | #define lines 0 | ||
40 | #define cols 0 | ||
41 | int orig_x = 0; | ||
42 | int orig_y = 0; | ||
43 | #define keyb_present 0 | ||
44 | int CRT_tstc(void) {return 0;} | ||
45 | int CRT_getc(void) {return 0;} | ||
46 | #endif | ||
47 | |||
48 | extern char *avail_ram; | ||
49 | extern char *end_avail; | ||
50 | extern char _end[]; | ||
51 | |||
52 | void puts(const char *); | ||
53 | void putc(const char c); | ||
54 | void puthex(unsigned long val); | ||
55 | void gunzip(void *, int, unsigned char *, int *); | ||
56 | static int _cvt(unsigned long val, char *buf, long radix, char *digits); | ||
57 | |||
58 | void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap); | ||
59 | unsigned char *ISA_io = NULL; | ||
60 | |||
61 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
62 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
63 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
64 | extern unsigned long com_port; | ||
65 | |||
66 | extern int serial_tstc(unsigned long com_port); | ||
67 | extern unsigned char serial_getc(unsigned long com_port); | ||
68 | extern void serial_putc(unsigned long com_port, unsigned char c); | ||
69 | #endif | ||
70 | |||
71 | void pause(void) | ||
72 | { | ||
73 | puts("pause\n"); | ||
74 | } | ||
75 | |||
76 | void exit(void) | ||
77 | { | ||
78 | puts("exit\n"); | ||
79 | while(1); | ||
80 | } | ||
81 | |||
82 | int tstc(void) | ||
83 | { | ||
84 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
85 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
86 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
87 | if(keyb_present) | ||
88 | return (CRT_tstc() || serial_tstc(com_port)); | ||
89 | else | ||
90 | return (serial_tstc(com_port)); | ||
91 | #else | ||
92 | return CRT_tstc(); | ||
93 | #endif | ||
94 | } | ||
95 | |||
96 | int getc(void) | ||
97 | { | ||
98 | while (1) { | ||
99 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
100 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
101 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
102 | if (serial_tstc(com_port)) | ||
103 | return (serial_getc(com_port)); | ||
104 | #endif /* serial console */ | ||
105 | if (keyb_present) | ||
106 | if(CRT_tstc()) | ||
107 | return (CRT_getc()); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void | ||
112 | putc(const char c) | ||
113 | { | ||
114 | int x,y; | ||
115 | |||
116 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
117 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
118 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
119 | serial_putc(com_port, c); | ||
120 | if ( c == '\n' ) | ||
121 | serial_putc(com_port, '\r'); | ||
122 | #endif /* serial console */ | ||
123 | |||
124 | x = orig_x; | ||
125 | y = orig_y; | ||
126 | |||
127 | if ( c == '\n' ) { | ||
128 | x = 0; | ||
129 | if ( ++y >= lines ) { | ||
130 | scroll(); | ||
131 | y--; | ||
132 | } | ||
133 | } else if (c == '\r') { | ||
134 | x = 0; | ||
135 | } else if (c == '\b') { | ||
136 | if (x > 0) { | ||
137 | x--; | ||
138 | } | ||
139 | } else { | ||
140 | vidmem [ ( x + cols * y ) * 2 ] = c; | ||
141 | if ( ++x >= cols ) { | ||
142 | x = 0; | ||
143 | if ( ++y >= lines ) { | ||
144 | scroll(); | ||
145 | y--; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | cursor(x, y); | ||
151 | |||
152 | orig_x = x; | ||
153 | orig_y = y; | ||
154 | } | ||
155 | |||
156 | void puts(const char *s) | ||
157 | { | ||
158 | int x,y; | ||
159 | char c; | ||
160 | |||
161 | x = orig_x; | ||
162 | y = orig_y; | ||
163 | |||
164 | while ( ( c = *s++ ) != '\0' ) { | ||
165 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
166 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
167 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
168 | serial_putc(com_port, c); | ||
169 | if ( c == '\n' ) serial_putc(com_port, '\r'); | ||
170 | #endif /* serial console */ | ||
171 | |||
172 | if ( c == '\n' ) { | ||
173 | x = 0; | ||
174 | if ( ++y >= lines ) { | ||
175 | scroll(); | ||
176 | y--; | ||
177 | } | ||
178 | } else if (c == '\b') { | ||
179 | if (x > 0) { | ||
180 | x--; | ||
181 | } | ||
182 | } else { | ||
183 | vidmem [ ( x + cols * y ) * 2 ] = c; | ||
184 | if ( ++x >= cols ) { | ||
185 | x = 0; | ||
186 | if ( ++y >= lines ) { | ||
187 | scroll(); | ||
188 | y--; | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | |||
194 | cursor(x, y); | ||
195 | |||
196 | orig_x = x; | ||
197 | orig_y = y; | ||
198 | } | ||
199 | |||
200 | void error(char *x) | ||
201 | { | ||
202 | puts("\n\n"); | ||
203 | puts(x); | ||
204 | puts("\n\n -- System halted"); | ||
205 | |||
206 | while(1); /* Halt */ | ||
207 | } | ||
208 | |||
209 | static void *zalloc(unsigned size) | ||
210 | { | ||
211 | void *p = avail_ram; | ||
212 | |||
213 | size = (size + 7) & -8; | ||
214 | avail_ram += size; | ||
215 | if (avail_ram > end_avail) { | ||
216 | puts("oops... out of memory\n"); | ||
217 | pause(); | ||
218 | } | ||
219 | return p; | ||
220 | } | ||
221 | |||
222 | #define HEAD_CRC 2 | ||
223 | #define EXTRA_FIELD 4 | ||
224 | #define ORIG_NAME 8 | ||
225 | #define COMMENT 0x10 | ||
226 | #define RESERVED 0xe0 | ||
227 | |||
228 | void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) | ||
229 | { | ||
230 | z_stream s; | ||
231 | int r, i, flags; | ||
232 | |||
233 | /* skip header */ | ||
234 | i = 10; | ||
235 | flags = src[3]; | ||
236 | if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { | ||
237 | puts("bad gzipped data\n"); | ||
238 | exit(); | ||
239 | } | ||
240 | if ((flags & EXTRA_FIELD) != 0) | ||
241 | i = 12 + src[10] + (src[11] << 8); | ||
242 | if ((flags & ORIG_NAME) != 0) | ||
243 | while (src[i++] != 0) | ||
244 | ; | ||
245 | if ((flags & COMMENT) != 0) | ||
246 | while (src[i++] != 0) | ||
247 | ; | ||
248 | if ((flags & HEAD_CRC) != 0) | ||
249 | i += 2; | ||
250 | if (i >= *lenp) { | ||
251 | puts("gunzip: ran out of data in header\n"); | ||
252 | exit(); | ||
253 | } | ||
254 | |||
255 | /* Initialize ourself. */ | ||
256 | s.workspace = zalloc(zlib_inflate_workspacesize()); | ||
257 | r = zlib_inflateInit2(&s, -MAX_WBITS); | ||
258 | if (r != Z_OK) { | ||
259 | puts("zlib_inflateInit2 returned "); puthex(r); puts("\n"); | ||
260 | exit(); | ||
261 | } | ||
262 | s.next_in = src + i; | ||
263 | s.avail_in = *lenp - i; | ||
264 | s.next_out = dst; | ||
265 | s.avail_out = dstlen; | ||
266 | r = zlib_inflate(&s, Z_FINISH); | ||
267 | if (r != Z_OK && r != Z_STREAM_END) { | ||
268 | puts("inflate returned "); puthex(r); puts("\n"); | ||
269 | exit(); | ||
270 | } | ||
271 | *lenp = s.next_out - (unsigned char *) dst; | ||
272 | zlib_inflateEnd(&s); | ||
273 | } | ||
274 | |||
275 | void | ||
276 | puthex(unsigned long val) | ||
277 | { | ||
278 | |||
279 | unsigned char buf[10]; | ||
280 | int i; | ||
281 | for (i = 7; i >= 0; i--) | ||
282 | { | ||
283 | buf[i] = "0123456789ABCDEF"[val & 0x0F]; | ||
284 | val >>= 4; | ||
285 | } | ||
286 | buf[8] = '\0'; | ||
287 | puts(buf); | ||
288 | } | ||
289 | |||
290 | #define FALSE 0 | ||
291 | #define TRUE 1 | ||
292 | |||
293 | void | ||
294 | _printk(char const *fmt, ...) | ||
295 | { | ||
296 | va_list ap; | ||
297 | |||
298 | va_start(ap, fmt); | ||
299 | _vprintk(putc, fmt, ap); | ||
300 | va_end(ap); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | #define is_digit(c) ((c >= '0') && (c <= '9')) | ||
305 | |||
306 | void | ||
307 | _vprintk(void(*putc)(const char), const char *fmt0, va_list ap) | ||
308 | { | ||
309 | char c, sign, *cp = 0; | ||
310 | int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right; | ||
311 | char buf[32]; | ||
312 | long val; | ||
313 | while ((c = *fmt0++)) | ||
314 | { | ||
315 | if (c == '%') | ||
316 | { | ||
317 | c = *fmt0++; | ||
318 | left_prec = right_prec = pad_on_right = 0; | ||
319 | if (c == '-') | ||
320 | { | ||
321 | c = *fmt0++; | ||
322 | pad_on_right++; | ||
323 | } | ||
324 | if (c == '0') | ||
325 | { | ||
326 | zero_fill = TRUE; | ||
327 | c = *fmt0++; | ||
328 | } else | ||
329 | { | ||
330 | zero_fill = FALSE; | ||
331 | } | ||
332 | while (is_digit(c)) | ||
333 | { | ||
334 | left_prec = (left_prec * 10) + (c - '0'); | ||
335 | c = *fmt0++; | ||
336 | } | ||
337 | if (c == '.') | ||
338 | { | ||
339 | c = *fmt0++; | ||
340 | zero_fill++; | ||
341 | while (is_digit(c)) | ||
342 | { | ||
343 | right_prec = (right_prec * 10) + (c - '0'); | ||
344 | c = *fmt0++; | ||
345 | } | ||
346 | } else | ||
347 | { | ||
348 | right_prec = left_prec; | ||
349 | } | ||
350 | sign = '\0'; | ||
351 | switch (c) | ||
352 | { | ||
353 | case 'd': | ||
354 | case 'x': | ||
355 | case 'X': | ||
356 | val = va_arg(ap, long); | ||
357 | switch (c) | ||
358 | { | ||
359 | case 'd': | ||
360 | if (val < 0) | ||
361 | { | ||
362 | sign = '-'; | ||
363 | val = -val; | ||
364 | } | ||
365 | length = _cvt(val, buf, 10, "0123456789"); | ||
366 | break; | ||
367 | case 'x': | ||
368 | length = _cvt(val, buf, 16, "0123456789abcdef"); | ||
369 | break; | ||
370 | case 'X': | ||
371 | length = _cvt(val, buf, 16, "0123456789ABCDEF"); | ||
372 | break; | ||
373 | } | ||
374 | cp = buf; | ||
375 | break; | ||
376 | case 's': | ||
377 | cp = va_arg(ap, char *); | ||
378 | length = strlen(cp); | ||
379 | break; | ||
380 | case 'c': | ||
381 | c = va_arg(ap, long /*char*/); | ||
382 | (*putc)(c); | ||
383 | continue; | ||
384 | default: | ||
385 | (*putc)('?'); | ||
386 | } | ||
387 | pad = left_prec - length; | ||
388 | if (sign != '\0') | ||
389 | { | ||
390 | pad--; | ||
391 | } | ||
392 | if (zero_fill) | ||
393 | { | ||
394 | c = '0'; | ||
395 | if (sign != '\0') | ||
396 | { | ||
397 | (*putc)(sign); | ||
398 | sign = '\0'; | ||
399 | } | ||
400 | } else | ||
401 | { | ||
402 | c = ' '; | ||
403 | } | ||
404 | if (!pad_on_right) | ||
405 | { | ||
406 | while (pad-- > 0) | ||
407 | { | ||
408 | (*putc)(c); | ||
409 | } | ||
410 | } | ||
411 | if (sign != '\0') | ||
412 | { | ||
413 | (*putc)(sign); | ||
414 | } | ||
415 | while (length-- > 0) | ||
416 | { | ||
417 | (*putc)(c = *cp++); | ||
418 | if (c == '\n') | ||
419 | { | ||
420 | (*putc)('\r'); | ||
421 | } | ||
422 | } | ||
423 | if (pad_on_right) | ||
424 | { | ||
425 | while (pad-- > 0) | ||
426 | { | ||
427 | (*putc)(c); | ||
428 | } | ||
429 | } | ||
430 | } else | ||
431 | { | ||
432 | (*putc)(c); | ||
433 | if (c == '\n') | ||
434 | { | ||
435 | (*putc)('\r'); | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | int | ||
442 | _cvt(unsigned long val, char *buf, long radix, char *digits) | ||
443 | { | ||
444 | char temp[80]; | ||
445 | char *cp = temp; | ||
446 | int length = 0; | ||
447 | if (val == 0) | ||
448 | { /* Special case */ | ||
449 | *cp++ = '0'; | ||
450 | } else | ||
451 | while (val) | ||
452 | { | ||
453 | *cp++ = digits[val % radix]; | ||
454 | val /= radix; | ||
455 | } | ||
456 | while (cp != temp) | ||
457 | { | ||
458 | *buf++ = *--cp; | ||
459 | length++; | ||
460 | } | ||
461 | *buf = '\0'; | ||
462 | return (length); | ||
463 | } | ||
464 | |||
465 | void | ||
466 | _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) | ||
467 | { | ||
468 | int i, c; | ||
469 | if ((unsigned int)s > (unsigned int)p) | ||
470 | { | ||
471 | s = (unsigned int)s - (unsigned int)p; | ||
472 | } | ||
473 | while (s > 0) | ||
474 | { | ||
475 | if (base) | ||
476 | { | ||
477 | _printk("%06X: ", (int)p - (int)base); | ||
478 | } else | ||
479 | { | ||
480 | _printk("%06X: ", p); | ||
481 | } | ||
482 | for (i = 0; i < 16; i++) | ||
483 | { | ||
484 | if (i < s) | ||
485 | { | ||
486 | _printk("%02X", p[i] & 0xFF); | ||
487 | } else | ||
488 | { | ||
489 | _printk(" "); | ||
490 | } | ||
491 | if ((i % 2) == 1) _printk(" "); | ||
492 | if ((i % 8) == 7) _printk(" "); | ||
493 | } | ||
494 | _printk(" |"); | ||
495 | for (i = 0; i < 16; i++) | ||
496 | { | ||
497 | if (i < s) | ||
498 | { | ||
499 | c = p[i] & 0xFF; | ||
500 | if ((c < 0x20) || (c >= 0x7F)) c = '.'; | ||
501 | } else | ||
502 | { | ||
503 | c = ' '; | ||
504 | } | ||
505 | _printk("%c", c); | ||
506 | } | ||
507 | _printk("|\n"); | ||
508 | s -= 16; | ||
509 | p += 16; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | void | ||
514 | _dump_buf(unsigned char *p, int s) | ||
515 | { | ||
516 | _printk("\n"); | ||
517 | _dump_buf_with_offset(p, s, 0); | ||
518 | } | ||
519 | |||
520 | /* Very simple inb/outb routines. We declare ISA_io to be 0 above, and | ||
521 | * then modify it on platforms which need to. We do it like this | ||
522 | * because on some platforms we give inb/outb an exact location, and | ||
523 | * on others it's an offset from a given location. -- Tom | ||
524 | */ | ||
525 | |||
526 | void ISA_init(unsigned long base) | ||
527 | { | ||
528 | ISA_io = (unsigned char *)base; | ||
529 | } | ||
530 | |||
531 | void | ||
532 | outb(int port, unsigned char val) | ||
533 | { | ||
534 | /* Ensure I/O operations complete */ | ||
535 | __asm__ volatile("eieio"); | ||
536 | ISA_io[port] = val; | ||
537 | } | ||
538 | |||
539 | unsigned char | ||
540 | inb(int port) | ||
541 | { | ||
542 | /* Ensure I/O operations complete */ | ||
543 | __asm__ volatile("eieio"); | ||
544 | return (ISA_io[port]); | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Local variables: | ||
549 | * c-indent-level: 8 | ||
550 | * c-basic-offset: 8 | ||
551 | * tab-width: 8 | ||
552 | * End: | ||
553 | */ | ||
diff --git a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c new file mode 100644 index 000000000000..9017c547a6f6 --- /dev/null +++ b/arch/ppc/boot/common/ns16550.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * COM1 NS16550 support | ||
3 | */ | ||
4 | |||
5 | #include <linux/config.h> | ||
6 | #include <linux/types.h> | ||
7 | #include <linux/serial.h> | ||
8 | #include <linux/serial_reg.h> | ||
9 | #include <asm/serial.h> | ||
10 | |||
11 | #include "nonstdio.h" | ||
12 | #include "serial.h" | ||
13 | |||
14 | #define SERIAL_BAUD 9600 | ||
15 | |||
16 | extern unsigned long ISA_io; | ||
17 | |||
18 | static struct serial_state rs_table[RS_TABLE_SIZE] = { | ||
19 | SERIAL_PORT_DFNS /* Defined in <asm/serial.h> */ | ||
20 | }; | ||
21 | |||
22 | static int shift; | ||
23 | |||
24 | unsigned long serial_init(int chan, void *ignored) | ||
25 | { | ||
26 | unsigned long com_port; | ||
27 | unsigned char lcr, dlm; | ||
28 | |||
29 | /* We need to find out which type io we're expecting. If it's | ||
30 | * 'SERIAL_IO_PORT', we get an offset from the isa_io_base. | ||
31 | * If it's 'SERIAL_IO_MEM', we can the exact location. -- Tom */ | ||
32 | switch (rs_table[chan].io_type) { | ||
33 | case SERIAL_IO_PORT: | ||
34 | com_port = rs_table[chan].port; | ||
35 | break; | ||
36 | case SERIAL_IO_MEM: | ||
37 | com_port = (unsigned long)rs_table[chan].iomem_base; | ||
38 | break; | ||
39 | default: | ||
40 | /* We can't deal with it. */ | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | /* How far apart the registers are. */ | ||
45 | shift = rs_table[chan].iomem_reg_shift; | ||
46 | |||
47 | /* save the LCR */ | ||
48 | lcr = inb(com_port + (UART_LCR << shift)); | ||
49 | /* Access baud rate */ | ||
50 | outb(com_port + (UART_LCR << shift), 0x80); | ||
51 | dlm = inb(com_port + (UART_DLM << shift)); | ||
52 | /* | ||
53 | * Test if serial port is unconfigured. | ||
54 | * We assume that no-one uses less than 110 baud or | ||
55 | * less than 7 bits per character these days. | ||
56 | * -- paulus. | ||
57 | */ | ||
58 | |||
59 | if ((dlm <= 4) && (lcr & 2)) | ||
60 | /* port is configured, put the old LCR back */ | ||
61 | outb(com_port + (UART_LCR << shift), lcr); | ||
62 | else { | ||
63 | /* Input clock. */ | ||
64 | outb(com_port + (UART_DLL << shift), | ||
65 | (BASE_BAUD / SERIAL_BAUD) & 0xFF); | ||
66 | outb(com_port + (UART_DLM << shift), | ||
67 | (BASE_BAUD / SERIAL_BAUD) >> 8); | ||
68 | /* 8 data, 1 stop, no parity */ | ||
69 | outb(com_port + (UART_LCR << shift), 0x03); | ||
70 | /* RTS/DTR */ | ||
71 | outb(com_port + (UART_MCR << shift), 0x03); | ||
72 | } | ||
73 | /* Clear & enable FIFOs */ | ||
74 | outb(com_port + (UART_FCR << shift), 0x07); | ||
75 | |||
76 | return (com_port); | ||
77 | } | ||
78 | |||
79 | void | ||
80 | serial_putc(unsigned long com_port, unsigned char c) | ||
81 | { | ||
82 | while ((inb(com_port + (UART_LSR << shift)) & UART_LSR_THRE) == 0) | ||
83 | ; | ||
84 | outb(com_port, c); | ||
85 | } | ||
86 | |||
87 | unsigned char | ||
88 | serial_getc(unsigned long com_port) | ||
89 | { | ||
90 | while ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) == 0) | ||
91 | ; | ||
92 | return inb(com_port); | ||
93 | } | ||
94 | |||
95 | int | ||
96 | serial_tstc(unsigned long com_port) | ||
97 | { | ||
98 | return ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0); | ||
99 | } | ||
diff --git a/arch/ppc/boot/common/serial_stub.c b/arch/ppc/boot/common/serial_stub.c new file mode 100644 index 000000000000..03dfaa01fa63 --- /dev/null +++ b/arch/ppc/boot/common/serial_stub.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * arch/ppc/boot/common/serial_stub.c | ||
3 | * | ||
4 | * This is a few stub routines to make the boot code cleaner looking when | ||
5 | * there is no serial port support doesn't need to be closed, for example. | ||
6 | * | ||
7 | * Author: Tom Rini <trini@mvista.com> | ||
8 | * | ||
9 | * 2003 (c) MontaVista, Software, Inc. This file is licensed under the terms | ||
10 | * of the GNU General Public License version 2. This program is licensed "as | ||
11 | * is" without any warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | unsigned long __attribute__ ((weak)) | ||
15 | serial_init(int chan, void *ignored) | ||
16 | { | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | void __attribute__ ((weak)) | ||
21 | serial_close(unsigned long com_port) | ||
22 | { | ||
23 | } | ||
diff --git a/arch/ppc/boot/common/string.S b/arch/ppc/boot/common/string.S new file mode 100644 index 000000000000..8016e43c4771 --- /dev/null +++ b/arch/ppc/boot/common/string.S | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * String handling functions for PowerPC. | ||
3 | * | ||
4 | * Copyright (C) 1996 Paul Mackerras. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | #define r0 0 | ||
12 | #define r3 3 | ||
13 | #define r4 4 | ||
14 | #define r5 5 | ||
15 | #define r6 6 | ||
16 | #define r7 7 | ||
17 | #define r8 8 | ||
18 | |||
19 | .globl strlen | ||
20 | strlen: | ||
21 | addi r4,r3,-1 | ||
22 | 1: lbzu r0,1(r4) | ||
23 | cmpwi 0,r0,0 | ||
24 | bne 1b | ||
25 | subf r3,r3,r4 | ||
26 | blr | ||
27 | |||
28 | .globl memset | ||
29 | memset: | ||
30 | rlwimi r4,r4,8,16,23 | ||
31 | rlwimi r4,r4,16,0,15 | ||
32 | addi r6,r3,-4 | ||
33 | cmplwi 0,r5,4 | ||
34 | blt 7f | ||
35 | stwu r4,4(r6) | ||
36 | beqlr | ||
37 | andi. r0,r6,3 | ||
38 | add r5,r0,r5 | ||
39 | subf r6,r0,r6 | ||
40 | rlwinm r0,r5,32-2,2,31 | ||
41 | mtctr r0 | ||
42 | bdz 6f | ||
43 | 1: stwu r4,4(r6) | ||
44 | bdnz 1b | ||
45 | 6: andi. r5,r5,3 | ||
46 | 7: cmpwi 0,r5,0 | ||
47 | beqlr | ||
48 | mtctr r5 | ||
49 | addi r6,r6,3 | ||
50 | 8: stbu r4,1(r6) | ||
51 | bdnz 8b | ||
52 | blr | ||
53 | |||
54 | .globl memmove | ||
55 | memmove: | ||
56 | cmplw 0,r3,r4 | ||
57 | bgt backwards_memcpy | ||
58 | /* fall through */ | ||
59 | |||
60 | .globl memcpy | ||
61 | memcpy: | ||
62 | rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ | ||
63 | addi r6,r3,-4 | ||
64 | addi r4,r4,-4 | ||
65 | beq 2f /* if less than 8 bytes to do */ | ||
66 | andi. r0,r6,3 /* get dest word aligned */ | ||
67 | mtctr r7 | ||
68 | bne 5f | ||
69 | 1: lwz r7,4(r4) | ||
70 | lwzu r8,8(r4) | ||
71 | stw r7,4(r6) | ||
72 | stwu r8,8(r6) | ||
73 | bdnz 1b | ||
74 | andi. r5,r5,7 | ||
75 | 2: cmplwi 0,r5,4 | ||
76 | blt 3f | ||
77 | lwzu r0,4(r4) | ||
78 | addi r5,r5,-4 | ||
79 | stwu r0,4(r6) | ||
80 | 3: cmpwi 0,r5,0 | ||
81 | beqlr | ||
82 | mtctr r5 | ||
83 | addi r4,r4,3 | ||
84 | addi r6,r6,3 | ||
85 | 4: lbzu r0,1(r4) | ||
86 | stbu r0,1(r6) | ||
87 | bdnz 4b | ||
88 | blr | ||
89 | 5: subfic r0,r0,4 | ||
90 | mtctr r0 | ||
91 | 6: lbz r7,4(r4) | ||
92 | addi r4,r4,1 | ||
93 | stb r7,4(r6) | ||
94 | addi r6,r6,1 | ||
95 | bdnz 6b | ||
96 | subf r5,r0,r5 | ||
97 | rlwinm. r7,r5,32-3,3,31 | ||
98 | beq 2b | ||
99 | mtctr r7 | ||
100 | b 1b | ||
101 | |||
102 | .globl backwards_memcpy | ||
103 | backwards_memcpy: | ||
104 | rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ | ||
105 | add r6,r3,r5 | ||
106 | add r4,r4,r5 | ||
107 | beq 2f | ||
108 | andi. r0,r6,3 | ||
109 | mtctr r7 | ||
110 | bne 5f | ||
111 | 1: lwz r7,-4(r4) | ||
112 | lwzu r8,-8(r4) | ||
113 | stw r7,-4(r6) | ||
114 | stwu r8,-8(r6) | ||
115 | bdnz 1b | ||
116 | andi. r5,r5,7 | ||
117 | 2: cmplwi 0,r5,4 | ||
118 | blt 3f | ||
119 | lwzu r0,-4(r4) | ||
120 | subi r5,r5,4 | ||
121 | stwu r0,-4(r6) | ||
122 | 3: cmpwi 0,r5,0 | ||
123 | beqlr | ||
124 | mtctr r5 | ||
125 | 4: lbzu r0,-1(r4) | ||
126 | stbu r0,-1(r6) | ||
127 | bdnz 4b | ||
128 | blr | ||
129 | 5: mtctr r0 | ||
130 | 6: lbzu r7,-1(r4) | ||
131 | stbu r7,-1(r6) | ||
132 | bdnz 6b | ||
133 | subf r5,r0,r5 | ||
134 | rlwinm. r7,r5,32-3,3,31 | ||
135 | beq 2b | ||
136 | mtctr r7 | ||
137 | b 1b | ||
138 | |||
139 | .globl memcmp | ||
140 | memcmp: | ||
141 | cmpwi 0,r5,0 | ||
142 | blelr | ||
143 | mtctr r5 | ||
144 | addi r6,r3,-1 | ||
145 | addi r4,r4,-1 | ||
146 | 1: lbzu r3,1(r6) | ||
147 | lbzu r0,1(r4) | ||
148 | subf. r3,r0,r3 | ||
149 | bdnzt 2,1b | ||
150 | blr | ||
diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S new file mode 100644 index 000000000000..47e641455bc5 --- /dev/null +++ b/arch/ppc/boot/common/util.S | |||
@@ -0,0 +1,293 @@ | |||
1 | /* | ||
2 | * arch/ppc/boot/common/util.S | ||
3 | * | ||
4 | * Useful bootup functions, which are more easily done in asm than C. | ||
5 | * | ||
6 | * NOTE: Be very very careful about the registers you use here. | ||
7 | * We don't follow any ABI calling convention among the | ||
8 | * assembler functions that call each other, especially early | ||
9 | * in the initialization. Please preserve at least r3 and r4 | ||
10 | * for these early functions, as they often contain information | ||
11 | * passed from boot roms into the C decompress function. | ||
12 | * | ||
13 | * Author: Tom Rini | ||
14 | * trini@mvista.com | ||
15 | * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others). | ||
16 | * | ||
17 | * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
18 | * the terms of the GNU General Public License version 2. This program | ||
19 | * is licensed "as is" without any warranty of any kind, whether express | ||
20 | * or implied. | ||
21 | */ | ||
22 | |||
23 | #include <asm/processor.h> | ||
24 | #include <asm/cache.h> | ||
25 | #include <asm/ppc_asm.h> | ||
26 | |||
27 | |||
28 | .text | ||
29 | |||
30 | #ifdef CONFIG_6xx | ||
31 | .globl disable_6xx_mmu | ||
32 | disable_6xx_mmu: | ||
33 | /* Establish default MSR value, exception prefix 0xFFF. | ||
34 | * If necessary, this function must fix up the LR if we | ||
35 | * return to a different address space once the MMU is | ||
36 | * disabled. | ||
37 | */ | ||
38 | li r8,MSR_IP|MSR_FP | ||
39 | mtmsr r8 | ||
40 | isync | ||
41 | |||
42 | /* Test for a 601 */ | ||
43 | mfpvr r10 | ||
44 | srwi r10,r10,16 | ||
45 | cmpwi 0,r10,1 /* 601 ? */ | ||
46 | beq .clearbats_601 | ||
47 | |||
48 | /* Clear BATs */ | ||
49 | li r8,0 | ||
50 | mtspr SPRN_DBAT0U,r8 | ||
51 | mtspr SPRN_DBAT0L,r8 | ||
52 | mtspr SPRN_DBAT1U,r8 | ||
53 | mtspr SPRN_DBAT1L,r8 | ||
54 | mtspr SPRN_DBAT2U,r8 | ||
55 | mtspr SPRN_DBAT2L,r8 | ||
56 | mtspr SPRN_DBAT3U,r8 | ||
57 | mtspr SPRN_DBAT3L,r8 | ||
58 | .clearbats_601: | ||
59 | mtspr SPRN_IBAT0U,r8 | ||
60 | mtspr SPRN_IBAT0L,r8 | ||
61 | mtspr SPRN_IBAT1U,r8 | ||
62 | mtspr SPRN_IBAT1L,r8 | ||
63 | mtspr SPRN_IBAT2U,r8 | ||
64 | mtspr SPRN_IBAT2L,r8 | ||
65 | mtspr SPRN_IBAT3U,r8 | ||
66 | mtspr SPRN_IBAT3L,r8 | ||
67 | isync | ||
68 | sync | ||
69 | sync | ||
70 | |||
71 | /* Set segment registers */ | ||
72 | li r8,16 /* load up segment register values */ | ||
73 | mtctr r8 /* for context 0 */ | ||
74 | lis r8,0x2000 /* Ku = 1, VSID = 0 */ | ||
75 | li r10,0 | ||
76 | 3: mtsrin r8,r10 | ||
77 | addi r8,r8,0x111 /* increment VSID */ | ||
78 | addis r10,r10,0x1000 /* address of next segment */ | ||
79 | bdnz 3b | ||
80 | blr | ||
81 | |||
82 | .globl disable_6xx_l1cache | ||
83 | disable_6xx_l1cache: | ||
84 | /* Enable, invalidate and then disable the L1 icache/dcache. */ | ||
85 | li r8,0 | ||
86 | ori r8,r8,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI) | ||
87 | mfspr r11,SPRN_HID0 | ||
88 | or r11,r11,r8 | ||
89 | andc r10,r11,r8 | ||
90 | isync | ||
91 | mtspr SPRN_HID0,r8 | ||
92 | sync | ||
93 | isync | ||
94 | mtspr SPRN_HID0,r10 | ||
95 | sync | ||
96 | isync | ||
97 | blr | ||
98 | #endif | ||
99 | |||
100 | .globl _setup_L2CR | ||
101 | _setup_L2CR: | ||
102 | /* | ||
103 | * We should be skipping this section on CPUs where this results in an | ||
104 | * illegal instruction. If not, please send trini@kernel.crashing.org | ||
105 | * the PVR of your CPU. | ||
106 | */ | ||
107 | /* Invalidate/disable L2 cache */ | ||
108 | sync | ||
109 | isync | ||
110 | mfspr r8,SPRN_L2CR | ||
111 | rlwinm r8,r8,0,1,31 | ||
112 | oris r8,r8,L2CR_L2I@h | ||
113 | sync | ||
114 | isync | ||
115 | mtspr SPRN_L2CR,r8 | ||
116 | sync | ||
117 | isync | ||
118 | |||
119 | /* Wait for the invalidation to complete */ | ||
120 | mfspr r8,SPRN_PVR | ||
121 | srwi r8,r8,16 | ||
122 | cmplwi cr0,r8,0x8000 /* 7450 */ | ||
123 | cmplwi cr1,r8,0x8001 /* 7455 */ | ||
124 | cmplwi cr2,r8,0x8002 /* 7457 */ | ||
125 | cror 4*cr0+eq,4*cr0+eq,4*cr1+eq /* Now test if any are true. */ | ||
126 | cror 4*cr0+eq,4*cr0+eq,4*cr2+eq | ||
127 | bne 2f | ||
128 | |||
129 | 1: mfspr r8,SPRN_L2CR /* On 745x, poll L2I bit (bit 10) */ | ||
130 | rlwinm. r9,r8,0,10,10 | ||
131 | bne 1b | ||
132 | b 3f | ||
133 | |||
134 | 2: mfspr r8,SPRN_L2CR /* On 75x & 74[01]0, poll L2IP bit (bit 31) */ | ||
135 | rlwinm. r9,r8,0,31,31 | ||
136 | bne 2b | ||
137 | |||
138 | 3: rlwinm r8,r8,0,11,9 /* Turn off L2I bit */ | ||
139 | sync | ||
140 | isync | ||
141 | mtspr SPRN_L2CR,r8 | ||
142 | sync | ||
143 | isync | ||
144 | blr | ||
145 | |||
146 | .globl _setup_L3CR | ||
147 | _setup_L3CR: | ||
148 | /* Invalidate/disable L3 cache */ | ||
149 | sync | ||
150 | isync | ||
151 | mfspr r8,SPRN_L3CR | ||
152 | rlwinm r8,r8,0,1,31 | ||
153 | ori r8,r8,L3CR_L3I@l | ||
154 | sync | ||
155 | isync | ||
156 | mtspr SPRN_L3CR,r8 | ||
157 | sync | ||
158 | isync | ||
159 | |||
160 | /* Wait for the invalidation to complete */ | ||
161 | 1: mfspr r8,SPRN_L3CR | ||
162 | rlwinm. r9,r8,0,21,21 | ||
163 | bne 1b | ||
164 | |||
165 | rlwinm r8,r8,0,22,20 /* Turn off L3I bit */ | ||
166 | sync | ||
167 | isync | ||
168 | mtspr SPRN_L3CR,r8 | ||
169 | sync | ||
170 | isync | ||
171 | blr | ||
172 | |||
173 | |||
174 | /* udelay (on non-601 processors) needs to know the period of the | ||
175 | * timebase in nanoseconds. This used to be hardcoded to be 60ns | ||
176 | * (period of 66MHz/4). Now a variable is used that is initialized to | ||
177 | * 60 for backward compatibility, but it can be overridden as necessary | ||
178 | * with code something like this: | ||
179 | * extern unsigned long timebase_period_ns; | ||
180 | * timebase_period_ns = 1000000000 / bd->bi_tbfreq; | ||
181 | */ | ||
182 | .data | ||
183 | .globl timebase_period_ns | ||
184 | timebase_period_ns: | ||
185 | .long 60 | ||
186 | |||
187 | .text | ||
188 | /* | ||
189 | * Delay for a number of microseconds | ||
190 | */ | ||
191 | .globl udelay | ||
192 | udelay: | ||
193 | mfspr r4,SPRN_PVR | ||
194 | srwi r4,r4,16 | ||
195 | cmpwi 0,r4,1 /* 601 ? */ | ||
196 | bne .udelay_not_601 | ||
197 | 00: li r0,86 /* Instructions / microsecond? */ | ||
198 | mtctr r0 | ||
199 | 10: addi r0,r0,0 /* NOP */ | ||
200 | bdnz 10b | ||
201 | subic. r3,r3,1 | ||
202 | bne 00b | ||
203 | blr | ||
204 | |||
205 | .udelay_not_601: | ||
206 | mulli r4,r3,1000 /* nanoseconds */ | ||
207 | /* Change r4 to be the number of ticks using: | ||
208 | * (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns | ||
209 | * timebase_period_ns defaults to 60 (16.6MHz) */ | ||
210 | lis r5,timebase_period_ns@ha | ||
211 | lwz r5,timebase_period_ns@l(r5) | ||
212 | add r4,r4,r5 | ||
213 | addi r4,r4,-1 | ||
214 | divw r4,r4,r5 /* BUS ticks */ | ||
215 | 1: mftbu r5 | ||
216 | mftb r6 | ||
217 | mftbu r7 | ||
218 | cmpw 0,r5,r7 | ||
219 | bne 1b /* Get [synced] base time */ | ||
220 | addc r9,r6,r4 /* Compute end time */ | ||
221 | addze r8,r5 | ||
222 | 2: mftbu r5 | ||
223 | cmpw 0,r5,r8 | ||
224 | blt 2b | ||
225 | bgt 3f | ||
226 | mftb r6 | ||
227 | cmpw 0,r6,r9 | ||
228 | blt 2b | ||
229 | 3: blr | ||
230 | |||
231 | .section ".relocate_code","xa" | ||
232 | /* | ||
233 | * Flush and enable instruction cache | ||
234 | * First, flush the data cache in case it was enabled and may be | ||
235 | * holding instructions for copy back. | ||
236 | */ | ||
237 | _GLOBAL(flush_instruction_cache) | ||
238 | mflr r6 | ||
239 | bl flush_data_cache | ||
240 | |||
241 | #ifdef CONFIG_8xx | ||
242 | lis r3, IDC_INVALL@h | ||
243 | mtspr SPRN_IC_CST, r3 | ||
244 | lis r3, IDC_ENABLE@h | ||
245 | mtspr SPRN_IC_CST, r3 | ||
246 | lis r3, IDC_DISABLE@h | ||
247 | mtspr SPRN_DC_CST, r3 | ||
248 | #elif CONFIG_4xx | ||
249 | lis r3,start@h # r9 = &_start | ||
250 | lis r4,_etext@ha | ||
251 | addi r4,r4,_etext@l # r8 = &_etext | ||
252 | 1: dcbf r0,r3 # Flush the data cache | ||
253 | icbi r0,r3 # Invalidate the instruction cache | ||
254 | addi r3,r3,0x10 # Increment by one cache line | ||
255 | cmplwi cr0,r3,r4 # Are we at the end yet? | ||
256 | blt 1b # No, keep flushing and invalidating | ||
257 | #else | ||
258 | /* Enable, invalidate and then disable the L1 icache/dcache. */ | ||
259 | li r3,0 | ||
260 | ori r3,r3,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI) | ||
261 | mfspr r4,SPRN_HID0 | ||
262 | or r5,r4,r3 | ||
263 | isync | ||
264 | mtspr SPRN_HID0,r5 | ||
265 | sync | ||
266 | isync | ||
267 | ori r5,r4,HID0_ICE /* Enable cache */ | ||
268 | mtspr SPRN_HID0,r5 | ||
269 | sync | ||
270 | isync | ||
271 | #endif | ||
272 | mtlr r6 | ||
273 | blr | ||
274 | |||
275 | #define NUM_CACHE_LINES 128*8 | ||
276 | #define cache_flush_buffer 0x1000 | ||
277 | |||
278 | /* | ||
279 | * Flush data cache | ||
280 | * Do this by just reading lots of stuff into the cache. | ||
281 | */ | ||
282 | _GLOBAL(flush_data_cache) | ||
283 | lis r3,cache_flush_buffer@h | ||
284 | ori r3,r3,cache_flush_buffer@l | ||
285 | li r4,NUM_CACHE_LINES | ||
286 | mtctr r4 | ||
287 | 00: lwz r4,0(r3) | ||
288 | addi r3,r3,L1_CACHE_BYTES /* Next line, please */ | ||
289 | bdnz 00b | ||
290 | 10: blr | ||
291 | |||
292 | .previous | ||
293 | |||