CRIS: Merge machine dependent boot/compressed and boot/rescue
[linux-2.6.git] / arch / cris / boot / compressed / misc.c
1 /*
2  * misc.c
3  *
4  * This is a collection of several routines from gzip-1.0.3
5  * adapted for Linux.
6  *
7  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
8  * puts by Nick Holloway 1993, better puts by Martin Mares 1995
9  * adaptation for Linux/CRIS Axis Communications AB, 1999
10  *
11  */
12
13 /* where the piggybacked kernel image expects itself to live.
14  * it is the same address we use when we network load an uncompressed
15  * image into DRAM, and it is the address the kernel is linked to live
16  * at by vmlinux.lds.S
17  */
18
19 #define KERNEL_LOAD_ADR 0x40004000
20
21 #include <linux/types.h>
22
23 #ifdef CONFIG_ETRAX_ARCH_V32
24 #include <hwregs/reg_rdwr.h>
25 #include <hwregs/reg_map.h>
26 #include <hwregs/ser_defs.h>
27 #include <hwregs/pinmux_defs.h>
28 #ifdef CONFIG_CRIS_MACH_ARTPEC3
29 #include <hwregs/clkgen_defs.h>
30 #endif
31 #else
32 #include <arch/svinto.h>
33 #endif
34
35 /*
36  * gzip declarations
37  */
38
39 #define OF(args)  args
40 #define STATIC static
41
42 void *memset(void *s, int c, size_t n);
43 void *memcpy(void *__dest, __const void *__src, size_t __n);
44
45 #define memzero(s, n)     memset((s), 0, (n))
46
47 typedef unsigned char  uch;
48 typedef unsigned short ush;
49 typedef unsigned long  ulg;
50
51 #define WSIZE 0x8000            /* Window size must be at least 32k, */
52                                 /* and a power of two */
53
54 static uch *inbuf;           /* input buffer */
55 static uch window[WSIZE];    /* Sliding window buffer */
56
57 unsigned inptr = 0;     /* index of next byte to be processed in inbuf
58                          * After decompression it will contain the
59                          * compressed size, and head.S will read it.
60                          */
61
62 static unsigned outcnt = 0;  /* bytes in output buffer */
63
64 /* gzip flag byte */
65 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
66 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
67 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
68 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
69 #define COMMENT      0x10 /* bit 4 set: file comment present */
70 #define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
71 #define RESERVED     0xC0 /* bit 6,7:   reserved */
72
73 #define get_byte() (inbuf[inptr++])
74
75 /* Diagnostic functions */
76 #ifdef DEBUG
77 #  define Assert(cond, msg) do { \
78                 if (!(cond)) \
79                         error(msg); \
80         } while (0)
81 #  define Trace(x) fprintf x
82 #  define Tracev(x) do { \
83                 if (verbose) \
84                         fprintf x; \
85         } while (0)
86 #  define Tracevv(x) do { \
87                 if (verbose > 1) \
88                         fprintf x; \
89         } while (0)
90 #  define Tracec(c, x) do { \
91                 if (verbose && (c)) \
92                         fprintf x; \
93         } while (0)
94 #  define Tracecv(c, x) do { \
95                 if (verbose > 1 && (c)) \
96                         fprintf x; \
97         } while (0)
98 #else
99 #  define Assert(cond, msg)
100 #  define Trace(x)
101 #  define Tracev(x)
102 #  define Tracevv(x)
103 #  define Tracec(c, x)
104 #  define Tracecv(c, x)
105 #endif
106
107 static void flush_window(void);
108 static void error(char *m);
109 static void puts(const char *);
110
111 extern char *input_data;  /* lives in head.S */
112
113 static long bytes_out;
114 static uch *output_data;
115 static unsigned long output_ptr;
116
117 /* the "heap" is put directly after the BSS ends, at end */
118
119 extern int _end;
120 static long free_mem_ptr = (long)&_end;
121 static long free_mem_end_ptr;
122
123 #include "../../../../../lib/inflate.c"
124
125 /* decompressor info and error messages to serial console */
126
127 #ifdef CONFIG_ETRAX_ARCH_V32
128 static inline void serout(const char *s, reg_scope_instances regi_ser)
129 {
130         reg_ser_rs_stat_din rs;
131         reg_ser_rw_dout dout = {.data = *s};
132
133         do {
134                 rs = REG_RD(ser, regi_ser, rs_stat_din);
135         }
136         while (!rs.tr_rdy);/* Wait for transceiver. */
137
138         REG_WR(ser, regi_ser, rw_dout, dout);
139 }
140 #endif
141
142 static void puts(const char *s)
143 {
144 #ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
145         while (*s) {
146 #ifdef CONFIG_ETRAX_DEBUG_PORT0
147 #ifdef CONFIG_ETRAX_ARCH_V32
148                 serout(s, regi_ser0);
149 #else
150                 while (!(*R_SERIAL0_STATUS & (1 << 5)))
151                         ;
152                 *R_SERIAL0_TR_DATA = *s++;
153 #endif
154 #endif
155 #ifdef CONFIG_ETRAX_DEBUG_PORT1
156 #ifdef CONFIG_ETRAX_ARCH_V32
157                 serout(s, regi_ser1);
158 #else
159                 while (!(*R_SERIAL1_STATUS & (1 << 5)))
160                         ;
161                 *R_SERIAL1_TR_DATA = *s++;
162 #endif
163 #endif
164 #ifdef CONFIG_ETRAX_DEBUG_PORT2
165 #ifdef CONFIG_ETRAX_ARCH_V32
166                 serout(s, regi_ser2);
167 #else
168                 while (!(*R_SERIAL2_STATUS & (1 << 5)))
169                         ;
170                 *R_SERIAL2_TR_DATA = *s++;
171 #endif
172 #endif
173 #ifdef CONFIG_ETRAX_DEBUG_PORT3
174 #ifdef CONFIG_ETRAX_ARCH_V32
175                 serout(s, regi_ser3);
176 #else
177                 while (!(*R_SERIAL3_STATUS & (1 << 5)))
178                         ;
179                 *R_SERIAL3_TR_DATA = *s++;
180 #endif
181 #endif
182                 *s++;
183         }
184 /* CONFIG_ETRAX_DEBUG_PORT_NULL */
185 #endif
186 }
187
188 void *memset(void *s, int c, size_t n)
189 {
190         int i;
191         char *ss = (char*)s;
192
193         for (i=0;i<n;i++) ss[i] = c;
194
195         return s;
196 }
197
198 void *memcpy(void *__dest, __const void *__src, size_t __n)
199 {
200         int i;
201         char *d = (char *)__dest, *s = (char *)__src;
202
203         for (i = 0; i < __n; i++)
204                 d[i] = s[i];
205
206         return __dest;
207 }
208
209 /* ===========================================================================
210  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
211  * (Used for the decompressed data only.)
212  */
213
214 static void flush_window(void)
215 {
216         ulg c = crc;         /* temporary variable */
217         unsigned n;
218         uch *in, *out, ch;
219
220         in = window;
221         out = &output_data[output_ptr];
222         for (n = 0; n < outcnt; n++) {
223                 ch = *out = *in;
224                 out++;
225                 in++;
226                 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
227         }
228         crc = c;
229         bytes_out += (ulg)outcnt;
230         output_ptr += (ulg)outcnt;
231         outcnt = 0;
232 }
233
234 static void error(char *x)
235 {
236         puts("\n\n");
237         puts(x);
238         puts("\n\n -- System halted\n");
239
240         while(1);       /* Halt */
241 }
242
243 void setup_normal_output_buffer(void)
244 {
245         output_data = (char *)KERNEL_LOAD_ADR;
246 }
247
248 #ifdef CONFIG_ETRAX_ARCH_V32
249 static inline void serial_setup(reg_scope_instances regi_ser)
250 {
251         reg_ser_rw_xoff xoff;
252         reg_ser_rw_tr_ctrl tr_ctrl;
253         reg_ser_rw_rec_ctrl rec_ctrl;
254         reg_ser_rw_tr_baud_div tr_baud;
255         reg_ser_rw_rec_baud_div rec_baud;
256
257         /* Turn off XOFF. */
258         xoff = REG_RD(ser, regi_ser, rw_xoff);
259
260         xoff.chr = 0;
261         xoff.automatic = regk_ser_no;
262
263         REG_WR(ser, regi_ser, rw_xoff, xoff);
264
265         /* Set baudrate and stopbits. */
266         tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
267         rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
268         tr_baud = REG_RD(ser, regi_ser, rw_tr_baud_div);
269         rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div);
270
271         tr_ctrl.stop_bits = 1;  /* 2 stop bits. */
272         tr_ctrl.en = 1; /* enable transmitter */
273         rec_ctrl.en = 1; /* enabler receiver */
274
275         /*
276          * The baudrate setup used to be a bit fishy, but now transmitter and
277          * receiver are both set to the intended baud rate, 115200.
278          * The magic value is 29.493 MHz.
279          */
280         tr_ctrl.base_freq = regk_ser_f29_493;
281         rec_ctrl.base_freq = regk_ser_f29_493;
282         tr_baud.div = (29493000 / 8) / 115200;
283         rec_baud.div = (29493000 / 8) / 115200;
284
285         REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
286         REG_WR(ser, regi_ser, rw_tr_baud_div, tr_baud);
287         REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
288         REG_WR(ser, regi_ser, rw_rec_baud_div, rec_baud);
289 }
290 #endif
291
292 void decompress_kernel(void)
293 {
294         char revision;
295         char compile_rev;
296
297 #ifdef CONFIG_ETRAX_ARCH_V32
298         /* Need at least a CRISv32 to run. */
299         compile_rev = 32;
300 #if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
301     defined(CONFIG_ETRAX_DEBUG_PORT2) || \
302     defined(CONFIG_ETRAX_DEBUG_PORT3)
303         reg_pinmux_rw_hwprot hwprot;
304
305 #ifdef CONFIG_CRIS_MACH_ARTPEC3
306         reg_clkgen_rw_clk_ctrl clk_ctrl;
307
308         /* Enable corresponding clock region when serial 1..3 selected */
309
310         clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
311         clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
312         REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
313 #endif
314
315         /* pinmux setup for ports 1..3 */
316         hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
317 #endif
318
319
320 #ifdef CONFIG_ETRAX_DEBUG_PORT0
321         serial_setup(regi_ser0);
322 #endif
323 #ifdef CONFIG_ETRAX_DEBUG_PORT1
324         hwprot.ser1 = regk_pinmux_yes;
325         serial_setup(regi_ser1);
326 #endif
327 #ifdef CONFIG_ETRAX_DEBUG_PORT2
328         hwprot.ser2 = regk_pinmux_yes;
329         serial_setup(regi_ser2);
330 #endif
331 #ifdef CONFIG_ETRAX_DEBUG_PORT3
332         hwprot.ser3 = regk_pinmux_yes;
333         serial_setup(regi_ser3);
334 #endif
335 #if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
336     defined(CONFIG_ETRAX_DEBUG_PORT2) || \
337     defined(CONFIG_ETRAX_DEBUG_PORT3)
338         REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
339 #endif
340
341         /* input_data is set in head.S */
342         inbuf = input_data;
343 #else /* CRISv10 */
344         /* Need at least a crisv10 to run. */
345         compile_rev = 10;
346
347         /* input_data is set in head.S */
348         inbuf = input_data;
349
350 #ifdef CONFIG_ETRAX_DEBUG_PORT0
351         *R_SERIAL0_XOFF = 0;
352         *R_SERIAL0_BAUD = 0x99;
353         *R_SERIAL0_TR_CTRL = 0x40;
354 #endif
355 #ifdef CONFIG_ETRAX_DEBUG_PORT1
356         *R_SERIAL1_XOFF = 0;
357         *R_SERIAL1_BAUD = 0x99;
358         *R_SERIAL1_TR_CTRL = 0x40;
359 #endif
360 #ifdef CONFIG_ETRAX_DEBUG_PORT2
361         *R_GEN_CONFIG = 0x08;
362         *R_SERIAL2_XOFF = 0;
363         *R_SERIAL2_BAUD = 0x99;
364         *R_SERIAL2_TR_CTRL = 0x40;
365 #endif
366 #ifdef CONFIG_ETRAX_DEBUG_PORT3
367         *R_GEN_CONFIG = 0x100;
368         *R_SERIAL3_XOFF = 0;
369         *R_SERIAL3_BAUD = 0x99;
370         *R_SERIAL3_TR_CTRL = 0x40;
371 #endif
372 #endif
373
374         setup_normal_output_buffer();
375
376         makecrc();
377
378         __asm__ volatile ("move $vr,%0" : "=rm" (revision));
379         if (revision < compile_rev) {
380 #ifdef CONFIG_ETRAX_ARCH_V32
381                 puts("You need an ETRAX FS to run Linux 2.6/crisv32\n");
382 #else
383                 puts("You need an ETRAX 100LX to run linux 2.6\n");
384 #endif
385                 while(1);
386         }
387
388         puts("Uncompressing Linux...\n");
389         gunzip();
390         puts("Done. Now booting the kernel\n");
391 }