7b41b65860523237c17955939d8036595e6450cf
[mw/milkymist.git] / software / bios / boot.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009 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 #include <hw/hpdmc.h>
27
28 #include "boot.h"
29
30 extern const struct board_desc *brd_desc;
31
32 /*
33  * HACK: by defining this function as not inlinable, GCC will automatically
34  * put the values we want into the good registers because it has to respect
35  * the LM32 calling conventions.
36  */
37 static void __attribute__((noinline)) __attribute__((noreturn)) boot(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr)
38 {
39         asm volatile( /* Invalidate instruction cache */
40                 "wcsr ICC, r0\n"
41                 "nop\n"
42                 "nop\n"
43                 "nop\n"
44                 "nop\n"
45                 "call r4\n"
46         );
47 }
48
49 /* Note that we do not use the hw timer so that this function works
50  * even if the system controller has been disabled at synthesis.
51  */
52 static int check_ack()
53 {
54         int timeout;
55         int recognized;
56         static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
57         
58         timeout = 4500000;
59         recognized = 0;
60         while(timeout > 0) {
61                 if(readchar_nonblock()) {
62                         char c;
63                         c = readchar();
64                         if(c == str[recognized]) {
65                                 recognized++;
66                                 if(recognized == SFL_MAGIC_LEN)
67                                         return 1;
68                         } else {
69                                 if(c == str[0])
70                                         recognized = 1;
71                                 else
72                                         recognized = 0;
73                         }
74                 }
75                 timeout--;
76         }
77         return 0;
78 }
79
80 #define MAX_FAILED 5
81
82 void serialboot()
83 {
84         struct sfl_frame frame;
85         int failed;
86         unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
87         
88         printf("I: Attempting serial firmware loading\n");
89         putsnonl(SFL_MAGIC_REQ);
90         if(!check_ack()) {
91                 printf("E: Timeout\n");
92                 return;
93         }
94         
95         failed = 0;
96         cmdline_adr = initrdstart_adr = initrdend_adr = 0;
97         while(1) {
98                 int i;
99                 int actualcrc;
100                 int goodcrc;
101                 
102                 /* Grab one frame */
103                 frame.length = readchar();
104                 frame.crc[0] = readchar();
105                 frame.crc[1] = readchar();
106                 frame.cmd = readchar();
107                 for(i=0;i<frame.length;i++)
108                         frame.payload[i] = readchar();
109                 
110                 /* Check CRC */
111                 actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
112                 goodcrc = crc16(&frame.cmd, frame.length+1);
113                 if(actualcrc != goodcrc) {
114                         failed++;
115                         if(failed == MAX_FAILED) {
116                                 printf("E: Too many consecutive errors, aborting");
117                                 return;
118                         }
119                         writechar(SFL_ACK_CRCERROR);
120                         continue;
121                 }
122                 
123                 /* CRC OK */
124                 switch(frame.cmd) {
125                         case SFL_CMD_ABORT:
126                                 failed = 0;
127                                 writechar(SFL_ACK_SUCCESS);
128                                 return;
129                         case SFL_CMD_LOAD: {
130                                 char *writepointer;
131                                 
132                                 failed = 0;
133                                 writepointer = (char *)(
134                                          ((unsigned int)frame.payload[0] << 24)
135                                         |((unsigned int)frame.payload[1] << 16)
136                                         |((unsigned int)frame.payload[2] << 8)
137                                         |((unsigned int)frame.payload[3] << 0));
138                                 for(i=4;i<frame.length;i++)
139                                         *(writepointer++) = frame.payload[i];
140                                 writechar(SFL_ACK_SUCCESS);
141                                 break;
142                         }
143                         case SFL_CMD_JUMP: {
144                                 unsigned int addr;
145                                 
146                                 failed = 0;
147                                 addr =  ((unsigned int)frame.payload[0] << 24)
148                                         |((unsigned int)frame.payload[1] << 16)
149                                         |((unsigned int)frame.payload[2] << 8)
150                                         |((unsigned int)frame.payload[3] << 0);
151                                 writechar(SFL_ACK_SUCCESS);
152                                 boot(cmdline_adr, initrdstart_adr, initrdend_adr, addr);
153                                 break;
154                         }
155                         case SFL_CMD_CMDLINE:
156                                 failed = 0;
157                                 cmdline_adr =  ((unsigned int)frame.payload[0] << 24)
158                                               |((unsigned int)frame.payload[1] << 16)
159                                               |((unsigned int)frame.payload[2] << 8)
160                                               |((unsigned int)frame.payload[3] << 0);
161                                 writechar(SFL_ACK_SUCCESS);
162                                 break;
163                         case SFL_CMD_INITRDSTART:
164                                 failed = 0;
165                                 initrdstart_adr =  ((unsigned int)frame.payload[0] << 24)
166                                                   |((unsigned int)frame.payload[1] << 16)
167                                                   |((unsigned int)frame.payload[2] << 8)
168                                                   |((unsigned int)frame.payload[3] << 0);
169                                 writechar(SFL_ACK_SUCCESS);
170                                 break;
171                         case SFL_CMD_INITRDEND:
172                                 failed = 0;
173                                 initrdend_adr =  ((unsigned int)frame.payload[0] << 24)
174                                                 |((unsigned int)frame.payload[1] << 16)
175                                                 |((unsigned int)frame.payload[2] << 8)
176                                                 |((unsigned int)frame.payload[3] << 0);
177                                 writechar(SFL_ACK_SUCCESS);
178                                 break;
179                         default:
180                                 failed++;
181                                 if(failed == MAX_FAILED) {
182                                         printf("E: Too many consecutive errors, aborting");
183                                         return;
184                                 }
185                                 writechar(SFL_ACK_UNKNOWN);
186                                 break;
187                 }
188         }
189 }
190
191 static int tryload(char *filename, unsigned int address)
192 {
193         int devsize, realsize;
194         
195         devsize = cffat_load(filename, (char *)address, 16*1024*1024, &realsize);
196         if(devsize <= 0)
197                 return -1;
198         if(realsize > devsize) {
199                 printf("E: File size larger than the blocks read (corrupted FS or IO error ?)\n");
200                 cffat_done();
201                 return -1;
202         }
203         printf("I: Read a %d byte image from %s, CRC32 %08x\n", realsize, filename, crc32((unsigned char *)SDRAM_BASE, realsize));
204         
205         return realsize;
206 }
207
208 void cardboot(int alt)
209 {
210         int size;
211         unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
212
213         if(brd_desc->memory_card == MEMCARD_NONE) {
214                 printf("E: No memory card on this board\n");
215                 return;
216         }
217         
218         printf("I: Booting from CF card...\n");
219         if(!cffat_init()) {
220                 printf("E: Unable to initialize filesystem\n");
221                 return;
222         }
223
224         if(tryload(alt ? "ALTBOOT.BIN" : "BOOT.BIN", SDRAM_BASE) <= 0) {
225                 printf("E: Firmware image not found\n");
226                 return;
227         }
228
229         cmdline_adr = SDRAM_BASE+0x1000000;
230         if(tryload("CMDLINE.TXT", cmdline_adr) <= 0) {
231                 printf("I: No command line parameters found (CMDLINE.TXT)\n");
232                 cmdline_adr = 0;
233         }
234
235         initrdstart_adr = SDRAM_BASE+0x1002000;
236         size = tryload("INITRD.BIN", initrdstart_adr);
237         if(size <= 0) {
238                 printf("I: No initial ramdisk found (INITRD.BIN)\n");
239                 initrdstart_adr = 0;
240                 initrdend_adr = 0;
241         } else
242                 initrdend_adr = initrdstart_adr + size - 1;
243
244         cffat_done();
245         printf("I: Booting...\n");
246         boot(cmdline_adr, initrdstart_adr, initrdend_adr, SDRAM_BASE);
247 }