Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
[pandora-kernel.git] / arch / ppc / boot / common / misc-common.c
1 /*
2  * Misc. bootloader code (almost) all platforms can use
3  *
4  * Author: Johnnie Peters <jpeters@mvista.com>
5  * Editor: Tom Rini <trini@mvista.com>
6  *
7  * Derived from arch/ppc/boot/prep/misc.c
8  *
9  * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under
10  * the terms of the GNU General Public License version 2.  This program
11  * is licensed "as is" without any warranty of any kind, whether express
12  * or implied.
13  */
14
15 #include <stdarg.h>     /* for va_ bits */
16 #include <linux/string.h>
17 #include <linux/zlib.h>
18 #include "nonstdio.h"
19
20 /* If we're on a PReP, assume we have a keyboard controller
21  * Also note, if we're not PReP, we assume you are a serial
22  * console - Tom */
23 #if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE)
24 extern void cursor(int x, int y);
25 extern void scroll(void);
26 extern char *vidmem;
27 extern int lines, cols;
28 extern int orig_x, orig_y;
29 extern int keyb_present;
30 extern int CRT_tstc(void);
31 extern int CRT_getc(void);
32 #else
33 int cursor(int x, int y) {return 0;}
34 void scroll(void) {}
35 char vidmem[1];
36 #define lines 0
37 #define cols 0
38 int orig_x = 0;
39 int orig_y = 0;
40 #define keyb_present 0
41 int CRT_tstc(void) {return 0;}
42 int CRT_getc(void) {return 0;}
43 #endif
44
45 extern char *avail_ram;
46 extern char *end_avail;
47 extern char _end[];
48
49 void puts(const char *);
50 void putc(const char c);
51 void puthex(unsigned long val);
52 void gunzip(void *, int, unsigned char *, int *);
53 static int _cvt(unsigned long val, char *buf, long radix, char *digits);
54
55 void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap);
56 unsigned char *ISA_io = NULL;
57
58 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
59         || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
60         || defined(CONFIG_SERIAL_MPSC_CONSOLE)
61 extern unsigned long com_port;
62
63 extern int serial_tstc(unsigned long com_port);
64 extern unsigned char serial_getc(unsigned long com_port);
65 extern void serial_putc(unsigned long com_port, unsigned char c);
66 #endif
67
68 void pause(void)
69 {
70         puts("pause\n");
71 }
72
73 void exit(void)
74 {
75         puts("exit\n");
76         while(1);
77 }
78
79 int tstc(void)
80 {
81 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
82         || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
83         || defined(CONFIG_SERIAL_MPSC_CONSOLE)
84         if(keyb_present)
85                 return (CRT_tstc() || serial_tstc(com_port));
86         else
87                 return (serial_tstc(com_port));
88 #else
89         return CRT_tstc();
90 #endif
91 }
92
93 int getc(void)
94 {
95         while (1) {
96 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
97         || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
98         || defined(CONFIG_SERIAL_MPSC_CONSOLE)
99                 if (serial_tstc(com_port))
100                         return (serial_getc(com_port));
101 #endif /* serial console */
102                 if (keyb_present)
103                         if(CRT_tstc())
104                                 return (CRT_getc());
105         }
106 }
107
108 void
109 putc(const char c)
110 {
111         int x,y;
112
113 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
114         || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
115         || defined(CONFIG_SERIAL_MPSC_CONSOLE)
116         serial_putc(com_port, c);
117         if ( c == '\n' )
118                 serial_putc(com_port, '\r');
119 #endif /* serial console */
120
121         x = orig_x;
122         y = orig_y;
123
124         if ( c == '\n' ) {
125                 x = 0;
126                 if ( ++y >= lines ) {
127                         scroll();
128                         y--;
129                 }
130         } else if (c == '\r') {
131                 x = 0;
132         } else if (c == '\b') {
133                 if (x > 0) {
134                         x--;
135                 }
136         } else {
137                 vidmem [ ( x + cols * y ) * 2 ] = c;
138                 if ( ++x >= cols ) {
139                         x = 0;
140                         if ( ++y >= lines ) {
141                                 scroll();
142                                 y--;
143                         }
144                 }
145         }
146
147         cursor(x, y);
148
149         orig_x = x;
150         orig_y = y;
151 }
152
153 void puts(const char *s)
154 {
155         int x,y;
156         char c;
157
158         x = orig_x;
159         y = orig_y;
160
161         while ( ( c = *s++ ) != '\0' ) {
162 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
163         || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
164         || defined(CONFIG_SERIAL_MPSC_CONSOLE)
165                 serial_putc(com_port, c);
166                 if ( c == '\n' ) serial_putc(com_port, '\r');
167 #endif /* serial console */
168
169                 if ( c == '\n' ) {
170                         x = 0;
171                         if ( ++y >= lines ) {
172                                 scroll();
173                                 y--;
174                         }
175                 } else if (c == '\b') {
176                   if (x > 0) {
177                     x--;
178                   }
179                 } else {
180                         vidmem [ ( x + cols * y ) * 2 ] = c;
181                         if ( ++x >= cols ) {
182                                 x = 0;
183                                 if ( ++y >= lines ) {
184                                         scroll();
185                                         y--;
186                                 }
187                         }
188                 }
189         }
190
191         cursor(x, y);
192
193         orig_x = x;
194         orig_y = y;
195 }
196
197 void error(char *x)
198 {
199         puts("\n\n");
200         puts(x);
201         puts("\n\n -- System halted");
202
203         while(1);       /* Halt */
204 }
205
206 static void *zalloc(unsigned size)
207 {
208         void *p = avail_ram;
209
210         size = (size + 7) & -8;
211         avail_ram += size;
212         if (avail_ram > end_avail) {
213                 puts("oops... out of memory\n");
214                 pause();
215         }
216         return p;
217 }
218
219 #define HEAD_CRC        2
220 #define EXTRA_FIELD     4
221 #define ORIG_NAME       8
222 #define COMMENT         0x10
223 #define RESERVED        0xe0
224
225 void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
226 {
227         z_stream s;
228         int r, i, flags;
229
230         /* skip header */
231         i = 10;
232         flags = src[3];
233         if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
234                 puts("bad gzipped data\n");
235                 exit();
236         }
237         if ((flags & EXTRA_FIELD) != 0)
238                 i = 12 + src[10] + (src[11] << 8);
239         if ((flags & ORIG_NAME) != 0)
240                 while (src[i++] != 0)
241                         ;
242         if ((flags & COMMENT) != 0)
243                 while (src[i++] != 0)
244                         ;
245         if ((flags & HEAD_CRC) != 0)
246                 i += 2;
247         if (i >= *lenp) {
248                 puts("gunzip: ran out of data in header\n");
249                 exit();
250         }
251
252         /* Initialize ourself. */
253         s.workspace = zalloc(zlib_inflate_workspacesize());
254         r = zlib_inflateInit2(&s, -MAX_WBITS);
255         if (r != Z_OK) {
256                 puts("zlib_inflateInit2 returned "); puthex(r); puts("\n");
257                 exit();
258         }
259         s.next_in = src + i;
260         s.avail_in = *lenp - i;
261         s.next_out = dst;
262         s.avail_out = dstlen;
263         r = zlib_inflate(&s, Z_FINISH);
264         if (r != Z_OK && r != Z_STREAM_END) {
265                 puts("inflate returned "); puthex(r); puts("\n");
266                 exit();
267         }
268         *lenp = s.next_out - (unsigned char *) dst;
269         zlib_inflateEnd(&s);
270 }
271
272 void
273 puthex(unsigned long val)
274 {
275
276         unsigned char buf[10];
277         int i;
278         for (i = 7;  i >= 0;  i--)
279         {
280                 buf[i] = "0123456789ABCDEF"[val & 0x0F];
281                 val >>= 4;
282         }
283         buf[8] = '\0';
284         puts(buf);
285 }
286
287 #define FALSE 0
288 #define TRUE  1
289
290 void
291 _printk(char const *fmt, ...)
292 {
293         va_list ap;
294
295         va_start(ap, fmt);
296         _vprintk(putc, fmt, ap);
297         va_end(ap);
298         return;
299 }
300
301 #define is_digit(c) ((c >= '0') && (c <= '9'))
302
303 void
304 _vprintk(void(*putc)(const char), const char *fmt0, va_list ap)
305 {
306         char c, sign, *cp = 0;
307         int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right;
308         char buf[32];
309         long val;
310         while ((c = *fmt0++))
311         {
312                 if (c == '%')
313                 {
314                         c = *fmt0++;
315                         left_prec = right_prec = pad_on_right = 0;
316                         if (c == '-')
317                         {
318                                 c = *fmt0++;
319                                 pad_on_right++;
320                         }
321                         if (c == '0')
322                         {
323                                 zero_fill = TRUE;
324                                 c = *fmt0++;
325                         } else
326                         {
327                                 zero_fill = FALSE;
328                         }
329                         while (is_digit(c))
330                         {
331                                 left_prec = (left_prec * 10) + (c - '0');
332                                 c = *fmt0++;
333                         }
334                         if (c == '.')
335                         {
336                                 c = *fmt0++;
337                                 zero_fill++;
338                                 while (is_digit(c))
339                                 {
340                                         right_prec = (right_prec * 10) + (c - '0');
341                                         c = *fmt0++;
342                                 }
343                         } else
344                         {
345                                 right_prec = left_prec;
346                         }
347                         sign = '\0';
348                         switch (c)
349                         {
350                         case 'd':
351                         case 'x':
352                         case 'X':
353                                 val = va_arg(ap, long);
354                                 switch (c)
355                                 {
356                                 case 'd':
357                                         if (val < 0)
358                                         {
359                                                 sign = '-';
360                                                 val = -val;
361                                         }
362                                         length = _cvt(val, buf, 10, "0123456789");
363                                         break;
364                                 case 'x':
365                                         length = _cvt(val, buf, 16, "0123456789abcdef");
366                                         break;
367                                 case 'X':
368                                         length = _cvt(val, buf, 16, "0123456789ABCDEF");
369                                         break;
370                                 }
371                                 cp = buf;
372                                 break;
373                         case 's':
374                                 cp = va_arg(ap, char *);
375                                 length = strlen(cp);
376                                 break;
377                         case 'c':
378                                 c = va_arg(ap, long /*char*/);
379                                 (*putc)(c);
380                                 continue;
381                         default:
382                                 (*putc)('?');
383                         }
384                         pad = left_prec - length;
385                         if (sign != '\0')
386                         {
387                                 pad--;
388                         }
389                         if (zero_fill)
390                         {
391                                 c = '0';
392                                 if (sign != '\0')
393                                 {
394                                         (*putc)(sign);
395                                         sign = '\0';
396                                 }
397                         } else
398                         {
399                                 c = ' ';
400                         }
401                         if (!pad_on_right)
402                         {
403                                 while (pad-- > 0)
404                                 {
405                                         (*putc)(c);
406                                 }
407                         }
408                         if (sign != '\0')
409                         {
410                                 (*putc)(sign);
411                         }
412                         while (length-- > 0)
413                         {
414                                 (*putc)(c = *cp++);
415                                 if (c == '\n')
416                                 {
417                                         (*putc)('\r');
418                                 }
419                         }
420                         if (pad_on_right)
421                         {
422                                 while (pad-- > 0)
423                                 {
424                                         (*putc)(c);
425                                 }
426                         }
427                 } else
428                 {
429                         (*putc)(c);
430                         if (c == '\n')
431                         {
432                                 (*putc)('\r');
433                         }
434                 }
435         }
436 }
437
438 int
439 _cvt(unsigned long val, char *buf, long radix, char *digits)
440 {
441         char temp[80];
442         char *cp = temp;
443         int length = 0;
444         if (val == 0)
445         { /* Special case */
446                 *cp++ = '0';
447         } else
448                 while (val)
449                 {
450                         *cp++ = digits[val % radix];
451                         val /= radix;
452                 }
453         while (cp != temp)
454         {
455                 *buf++ = *--cp;
456                 length++;
457         }
458         *buf = '\0';
459         return (length);
460 }
461
462 void
463 _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
464 {
465         int i, c;
466         if ((unsigned int)s > (unsigned int)p)
467         {
468                 s = (unsigned int)s - (unsigned int)p;
469         }
470         while (s > 0)
471         {
472                 if (base)
473                 {
474                         _printk("%06X: ", (int)p - (int)base);
475                 } else
476                 {
477                         _printk("%06X: ", p);
478                 }
479                 for (i = 0;  i < 16;  i++)
480                 {
481                         if (i < s)
482                         {
483                                 _printk("%02X", p[i] & 0xFF);
484                         } else
485                         {
486                                 _printk("  ");
487                         }
488                         if ((i % 2) == 1) _printk(" ");
489                         if ((i % 8) == 7) _printk(" ");
490                 }
491                 _printk(" |");
492                 for (i = 0;  i < 16;  i++)
493                 {
494                         if (i < s)
495                         {
496                                 c = p[i] & 0xFF;
497                                 if ((c < 0x20) || (c >= 0x7F)) c = '.';
498                         } else
499                         {
500                                 c = ' ';
501                         }
502                         _printk("%c", c);
503                 }
504                 _printk("|\n");
505                 s -= 16;
506                 p += 16;
507         }
508 }
509
510 void
511 _dump_buf(unsigned char *p, int s)
512 {
513         _printk("\n");
514         _dump_buf_with_offset(p, s, 0);
515 }
516
517 /* Very simple inb/outb routines.  We declare ISA_io to be 0 above, and
518  * then modify it on platforms which need to.  We do it like this
519  * because on some platforms we give inb/outb an exact location, and
520  * on others it's an offset from a given location. -- Tom
521  */
522
523 void ISA_init(unsigned long base)
524 {
525         ISA_io = (unsigned char *)base;
526 }
527
528 void
529 outb(int port, unsigned char val)
530 {
531         /* Ensure I/O operations complete */
532         __asm__ volatile("eieio");
533         ISA_io[port] = val;
534 }
535
536 unsigned char
537 inb(int port)
538 {
539         /* Ensure I/O operations complete */
540         __asm__ volatile("eieio");
541         return (ISA_io[port]);
542 }
543
544 /*
545  * Local variables:
546  *  c-indent-level: 8
547  *  c-basic-offset: 8
548  *  tab-width: 8
549  * End:
550  */