Basic SDRAM runtime lib, software working without SRAM
[mw/milkymist.git] / software / bios / boot.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <console.h>
20 #include <uart.h>
21 #include <system.h>
22 #include <board.h>
23 #include <cffat.h>
24 #include <crc.h>
25 #include <sfl.h>
26
27 #include <net/microudp.h>
28 #include <net/tftp.h>
29
30 #include <hw/hpdmc.h>
31
32 #include "boot.h"
33
34 extern const struct board_desc *brd_desc;
35
36 /*
37  * HACK: by defining this function as not inlinable, GCC will automatically
38  * put the values we want into the good registers because it has to respect
39  * the LM32 calling conventions.
40  */
41 static void __attribute__((noinline)) __attribute__((noreturn)) boot(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr)
42 {
43         asm volatile( /* Invalidate instruction cache */
44                 "wcsr ICC, r0\n"
45                 "nop\n"
46                 "nop\n"
47                 "nop\n"
48                 "nop\n"
49                 "call r4\n"
50         );
51 }
52
53 /* Note that we do not use the hw timer so that this function works
54  * even if the system controller does not.
55  */
56 static int check_ack()
57 {
58         int timeout;
59         int recognized;
60         static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
61         
62         timeout = 4500000;
63         recognized = 0;
64         while(timeout > 0) {
65                 if(readchar_nonblock()) {
66                         char c;
67                         c = readchar();
68                         if(c == str[recognized]) {
69                                 recognized++;
70                                 if(recognized == SFL_MAGIC_LEN)
71                                         return 1;
72                         } else {
73                                 if(c == str[0])
74                                         recognized = 1;
75                                 else
76                                         recognized = 0;
77                         }
78                 }
79                 timeout--;
80         }
81         return 0;
82 }
83
84 #define MAX_FAILED 5
85
86 void serialboot()
87 {
88         struct sfl_frame frame;
89         int failed;
90         unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
91         
92         printf("I: Attempting serial firmware loading\n");
93         putsnonl(SFL_MAGIC_REQ);
94         if(!check_ack()) {
95                 printf("E: Timeout\n");
96                 return;
97         }
98         
99         failed = 0;
100         cmdline_adr = initrdstart_adr = initrdend_adr = 0;
101         while(1) {
102                 int i;
103                 int actualcrc;
104                 int goodcrc;
105                 
106                 /* Grab one frame */
107                 frame.length = readchar();
108                 frame.crc[0] = readchar();
109                 frame.crc[1] = readchar();
110                 frame.cmd = readchar();
111                 for(i=0;i<frame.length;i++)
112                         frame.payload[i] = readchar();
113                 
114                 /* Check CRC */
115                 actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
116                 goodcrc = crc16(&frame.cmd, frame.length+1);
117                 if(actualcrc != goodcrc) {
118                         failed++;
119                         if(failed == MAX_FAILED) {
120                                 printf("E: Too many consecutive errors, aborting");
121                                 return;
122                         }
123                         writechar(SFL_ACK_CRCERROR);
124                         continue;
125                 }
126                 
127                 /* CRC OK */
128                 switch(frame.cmd) {
129                         case SFL_CMD_ABORT:
130                                 failed = 0;
131                                 writechar(SFL_ACK_SUCCESS);
132                                 return;
133                         case SFL_CMD_LOAD: {
134                                 char *writepointer;
135                                 
136                                 failed = 0;
137                                 writepointer = (char *)(
138                                          ((unsigned int)frame.payload[0] << 24)
139                                         |((unsigned int)frame.payload[1] << 16)
140                                         |((unsigned int)frame.payload[2] << 8)
141                                         |((unsigned int)frame.payload[3] << 0));
142                                 for(i=4;i<frame.length;i++)
143                                         *(writepointer++) = frame.payload[i];
144                                 writechar(SFL_ACK_SUCCESS);
145                                 break;
146                         }
147                         case SFL_CMD_JUMP: {
148                                 unsigned int addr;
149                                 
150                                 failed = 0;
151                                 addr =  ((unsigned int)frame.payload[0] << 24)
152                                         |((unsigned int)frame.payload[1] << 16)
153                                         |((unsigned int)frame.payload[2] << 8)
154                                         |((unsigned int)frame.payload[3] << 0);
155                                 writechar(SFL_ACK_SUCCESS);
156                                 boot(cmdline_adr, initrdstart_adr, initrdend_adr, addr);
157                                 break;
158                         }
159                         case SFL_CMD_CMDLINE:
160                                 failed = 0;
161                                 cmdline_adr =  ((unsigned int)frame.payload[0] << 24)
162                                               |((unsigned int)frame.payload[1] << 16)
163                                               |((unsigned int)frame.payload[2] << 8)
164                                               |((unsigned int)frame.payload[3] << 0);
165                                 writechar(SFL_ACK_SUCCESS);
166                                 break;
167                         case SFL_CMD_INITRDSTART:
168                                 failed = 0;
169                                 initrdstart_adr =  ((unsigned int)frame.payload[0] << 24)
170                                                   |((unsigned int)frame.payload[1] << 16)
171                                                   |((unsigned int)frame.payload[2] << 8)
172                                                   |((unsigned int)frame.payload[3] << 0);
173                                 writechar(SFL_ACK_SUCCESS);
174                                 break;
175                         case SFL_CMD_INITRDEND:
176                                 failed = 0;
177                                 initrdend_adr =  ((unsigned int)frame.payload[0] << 24)
178                                                 |((unsigned int)frame.payload[1] << 16)
179                                                 |((unsigned int)frame.payload[2] << 8)
180                                                 |((unsigned int)frame.payload[3] << 0);
181                                 writechar(SFL_ACK_SUCCESS);
182                                 break;
183                         default:
184                                 failed++;
185                                 if(failed == MAX_FAILED) {
186                                         printf("E: Too many consecutive errors, aborting");
187                                         return;
188                                 }
189                                 writechar(SFL_ACK_UNKNOWN);
190                                 break;
191                 }
192         }
193 }
194
195 static unsigned char macadr[] = {0xf8, 0x71, 0xfe, 0x01, 0x02, 0x03};
196
197 #define LOCALIP1 192
198 #define LOCALIP2 168
199 #define LOCALIP3 0
200 #define LOCALIP4 42
201 #define REMOTEIP1 192
202 #define REMOTEIP2 168
203 #define REMOTEIP3 0
204 #define REMOTEIP4 14
205
206 static int tftp_get_v(unsigned int ip, const char *filename, char *buffer)
207 {
208         int r;
209
210         r = tftp_get(ip, filename, buffer);
211         if(r > 0)
212                 printf("I: Successfully downloaded %d bytes from %s over TFTP\n", r, filename);
213         else
214                 printf("I: Unable to download %s over TFTP\n", filename);
215         return r;
216 }
217
218 static char microudp_buf[MICROUDP_BUFSIZE];
219
220 void netboot()
221 {
222         int size;
223         unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
224         unsigned int ip;
225
226         printf("I: Booting from network...\n");
227         printf("I: MAC      : %02x:%02x:%02x:%02x:%02x:%02x\n", macadr[0], macadr[1], macadr[2], macadr[3], macadr[4], macadr[5]);
228         printf("I: Local IP : %d.%d.%d.%d\n", LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4);
229         printf("I: Remote IP: %d.%d.%d.%d\n", REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
230
231         ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
232         
233         microudp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4), microudp_buf);
234         
235         if(tftp_get_v(ip, "boot.bin", (void *)SDRAM_BASE) <= 0) {
236                 printf("E: Network boot failed\n");
237                 return;
238         }
239         
240         cmdline_adr = SDRAM_BASE+0x1000000;
241         size = tftp_get_v(ip, "cmdline.txt", (void *)cmdline_adr);
242         if(size <= 0) {
243                 printf("I: No command line parameters found\n");
244                 cmdline_adr = 0;
245         } else
246                 *((char *)(cmdline_adr+size)) = 0x00;
247
248         initrdstart_adr = SDRAM_BASE+0x1002000;
249         size = tftp_get_v(ip, "initrd.bin", (void *)initrdstart_adr);
250         if(size <= 0) {
251                 printf("I: No initial ramdisk found\n");
252                 initrdstart_adr = 0;
253                 initrdend_adr = 0;
254         } else
255                 initrdend_adr = initrdstart_adr + size - 1;
256
257         microudp_shutdown();
258
259         printf("I: Booting...\n");
260         boot(cmdline_adr, initrdstart_adr, initrdend_adr, SDRAM_BASE);
261 }
262
263 static int tryload(char *filename, unsigned int address)
264 {
265         int devsize, realsize;
266         
267         devsize = cffat_load(filename, (char *)address, 16*1024*1024, &realsize);
268         if(devsize <= 0)
269                 return -1;
270         if(realsize > devsize) {
271                 printf("E: File size larger than the blocks read (corrupted FS or IO error ?)\n");
272                 cffat_done();
273                 return -1;
274         }
275         printf("I: Read a %d byte image from %s\n", realsize, filename);
276         
277         return realsize;
278 }
279
280
281 void cardboot(int alt)
282 {
283         int size;
284         unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
285
286         if(brd_desc->memory_card == MEMCARD_NONE) {
287                 printf("E: No memory card on this board\n");
288                 return;
289         }
290         
291         printf("I: Booting from CF card...\n");
292         if(!cffat_init()) {
293                 printf("E: Unable to initialize filesystem\n");
294                 return;
295         }
296
297         if(tryload(alt ? "ALTBOOT.BIN" : "BOOT.BIN", SDRAM_BASE) <= 0) {
298                 printf("E: Firmware image not found\n");
299                 return;
300         }
301
302         cmdline_adr = SDRAM_BASE+0x1000000;
303         size = tryload("CMDLINE.TXT", cmdline_adr);
304         if(size <= 0) {
305                 printf("I: No command line parameters found (CMDLINE.TXT)\n");
306                 cmdline_adr = 0;
307         } else
308                 *((char *)(cmdline_adr+size)) = 0x00;
309
310         initrdstart_adr = SDRAM_BASE+0x1002000;
311         size = tryload("INITRD.BIN", initrdstart_adr);
312         if(size <= 0) {
313                 printf("I: No initial ramdisk found (INITRD.BIN)\n");
314                 initrdstart_adr = 0;
315                 initrdend_adr = 0;
316         } else
317                 initrdend_adr = initrdstart_adr + size - 1;
318
319         cffat_done();
320         printf("I: Booting...\n");
321         boot(cmdline_adr, initrdstart_adr, initrdend_adr, SDRAM_BASE);
322 }