Removed ML401 support
[mw/milkymist.git] / software / bios / main.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 <string.h>
21 #include <uart.h>
22 #include <fatfs.h>
23 #include <crc.h>
24 #include <system.h>
25 #include <board.h>
26 #include <version.h>
27 #include <net/mdio.h>
28 #include <hw/vga.h>
29 #include <hw/fmlbrg.h>
30 #include <hw/sysctl.h>
31 #include <hw/capabilities.h>
32 #include <hw/gpio.h>
33 #include <hw/uart.h>
34 #include <hw/hpdmc.h>
35
36 #include "boot.h"
37 #include "splash.h"
38
39 const struct board_desc *brd_desc;
40
41 /* General address space functions */
42
43 #define NUMBER_OF_BYTES_ON_A_LINE 16
44 static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
45 {
46         char *data = (char *)ptr;
47         int line_bytes = 0, i = 0;
48
49         putsnonl("Memory dump:");
50         while(count > 0){
51                 line_bytes =
52                         (count > NUMBER_OF_BYTES_ON_A_LINE)?
53                                 NUMBER_OF_BYTES_ON_A_LINE : count;
54
55                 printf("\n0x%08x  ", addr);
56                 for(i=0;i<line_bytes;i++)
57                         printf("%02x ", *(unsigned char *)(data+i));
58         
59                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
60                         printf("   ");
61         
62                 printf(" ");
63
64                 for(i=0;i<line_bytes;i++) {
65                         if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
66                                 printf(".");
67                         else
68                                 printf("%c", *(data+i));
69                 }       
70
71                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
72                         printf(" ");
73
74                 data += (char)line_bytes;
75                 count -= line_bytes;
76                 addr += line_bytes;
77         }
78         printf("\n");
79 }
80
81
82 static void mr(char *startaddr, char *len)
83 {
84         char *c;
85         unsigned int *addr;
86         unsigned int length;
87
88         if(*startaddr == 0) {
89                 printf("mr <address> [length]\n");
90                 return;
91         }
92         addr = (unsigned *)strtoul(startaddr, &c, 0);
93         if(*c != 0) {
94                 printf("incorrect address\n");
95                 return;
96         }
97         if(*len == 0) {
98                 length = 1;
99         } else {
100                 length = strtoul(len, &c, 0);
101                 if(*c != 0) {
102                         printf("incorrect length\n");
103                         return;
104                 }
105         }
106
107         dump_bytes(addr, length, (unsigned)addr);
108 }
109
110 static void mw(char *addr, char *value, char *count)
111 {
112         char *c;
113         unsigned int *addr2;
114         unsigned int value2;
115         unsigned int count2;
116         unsigned int i;
117
118         if((*addr == 0) || (*value == 0)) {
119                 printf("mw <address> <value> [count]\n");
120                 return;
121         }
122         addr2 = (unsigned int *)strtoul(addr, &c, 0);
123         if(*c != 0) {
124                 printf("incorrect address\n");
125                 return;
126         }
127         value2 = strtoul(value, &c, 0);
128         if(*c != 0) {
129                 printf("incorrect value\n");
130                 return;
131         }
132         if(*count == 0) {
133                 count2 = 1;
134         } else {
135                 count2 = strtoul(count, &c, 0);
136                 if(*c != 0) {
137                         printf("incorrect count\n");
138                         return;
139                 }
140         }
141         for (i=0;i<count2;i++) *addr2++ = value2;
142 }
143
144 static void mc(char *dstaddr, char *srcaddr, char *count)
145 {
146         char *c;
147         unsigned int *dstaddr2;
148         unsigned int *srcaddr2;
149         unsigned int count2;
150         unsigned int i;
151
152         if((*dstaddr == 0) || (*srcaddr == 0)) {
153                 printf("mc <dst> <src> [count]\n");
154                 return;
155         }
156         dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0);
157         if(*c != 0) {
158                 printf("incorrect destination address\n");
159                 return;
160         }
161         srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0);
162         if(*c != 0) {
163                 printf("incorrect source address\n");
164                 return;
165         }
166         if(*count == 0) {
167                 count2 = 1;
168         } else {
169                 count2 = strtoul(count, &c, 0);
170                 if(*c != 0) {
171                         printf("incorrect count\n");
172                         return;
173                 }
174         }
175         for (i=0;i<count2;i++) *dstaddr2++ = *srcaddr2++;
176 }
177
178 static void crc(char *startaddr, char *len)
179 {
180         char *c;
181         char *addr;
182         unsigned int length;
183
184         if((*startaddr == 0)||(*len == 0)) {
185                 printf("crc <address> <length>\n");
186                 return;
187         }
188         addr = (char *)strtoul(startaddr, &c, 0);
189         if(*c != 0) {
190                 printf("incorrect address\n");
191                 return;
192         }
193         length = strtoul(len, &c, 0);
194         if(*c != 0) {
195                 printf("incorrect length\n");
196                 return;
197         }
198
199         printf("CRC32: %08x\n", crc32((unsigned char *)addr, length));
200 }
201
202 /* CF filesystem functions */
203
204 static int lscb(const char *filename, const char *longname, void *param)
205 {
206         printf("%12s [%s]\n", filename, longname);
207         return 1;
208 }
209
210 static void ls()
211 {
212         fatfs_init();
213         fatfs_list_files(lscb, NULL);
214         fatfs_done();
215 }
216
217 static void load(char *filename, char *addr)
218 {
219         char *c;
220         unsigned int *addr2;
221
222         if((*filename == 0) || (*addr == 0)) {
223                 printf("load <filename> <address>\n");
224                 return;
225         }
226         addr2 = (unsigned *)strtoul(addr, &c, 0);
227         if(*c != 0) {
228                 printf("incorrect address\n");
229                 return;
230         }
231         fatfs_init();
232         fatfs_load(filename, (char *)addr2, 16*1024*1024, NULL);
233         fatfs_done();
234 }
235
236 static void mdior(char *reg)
237 {
238         char *c;
239         int reg2;
240
241         if(*reg == 0) {
242                 printf("mdior <register>\n");
243                 return;
244         }
245         reg2 = strtoul(reg, &c, 0);
246         if(*c != 0) {
247                 printf("incorrect register\n");
248                 return;
249         }
250
251         printf("%04x\n", mdio_read(brd_desc->ethernet_phyadr, reg2));
252 }
253
254 static void mdiow(char *reg, char *value)
255 {
256         char *c;
257         int reg2;
258         int value2;
259
260         if((*reg == 0) || (*value == 0)) {
261                 printf("mdiow <register> <value>\n");
262                 return;
263         }
264         reg2 = strtoul(reg, &c, 0);
265         if(*c != 0) {
266                 printf("incorrect address\n");
267                 return;
268         }
269         value2 = strtoul(value, &c, 0);
270         if(*c != 0) {
271                 printf("incorrect value\n");
272                 return;
273         }
274
275         mdio_write(brd_desc->ethernet_phyadr, reg2, value2);
276 }
277
278 /* Init + command line */
279
280 static void help()
281 {
282         puts("This is the Milkymist BIOS debug shell.");
283         puts("It is used for system development and maintainance, and not");
284         puts("for regular operation.\n");
285         puts("Available commands:");
286         puts("flush      - flush FML bridge cache");
287         puts("mr         - read address space");
288         puts("mw         - write address space");
289         puts("mc         - copy address space");
290         puts("crc        - compute CRC32 of a part of the address space");
291         puts("ls         - list files on the memory card");
292         puts("load       - load a file from the memory card");
293         puts("serialboot - attempt SFL boot");
294         puts("netboot    - boot via TFTP");
295         puts("cardboot   - attempt booting from memory card");
296         puts("mdior      - read MDIO register");
297         puts("mdiow      - write MDIO register");
298         puts("reboot     - system reset");
299 }
300
301 static char *get_token(char **str)
302 {
303         char *c, *d;
304
305         c = (char *)strchr(*str, ' ');
306         if(c == NULL) {
307                 d = *str;
308                 *str = *str+strlen(*str);
309                 return d;
310         }
311         *c = 0;
312         d = *str;
313         *str = c+1;
314         return d;
315 }
316
317 static void do_command(char *c)
318 {
319         char *token;
320
321         token = get_token(&c);
322
323         if(strcmp(token, "flush") == 0) flush_bridge_cache();
324
325         else if(strcmp(token, "mr") == 0) mr(get_token(&c), get_token(&c));
326         else if(strcmp(token, "mw") == 0) mw(get_token(&c), get_token(&c), get_token(&c));
327         else if(strcmp(token, "mc") == 0) mc(get_token(&c), get_token(&c), get_token(&c));
328         else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c));
329         
330         else if(strcmp(token, "ls") == 0) ls();
331         else if(strcmp(token, "load") == 0) load(get_token(&c), get_token(&c));
332         
333         else if(strcmp(token, "serialboot") == 0) serialboot();
334         else if(strcmp(token, "netboot") == 0) netboot();
335         else if(strcmp(token, "cardboot") == 0) cardboot(0);
336
337         else if(strcmp(token, "mdior") == 0) mdior(get_token(&c));
338         else if(strcmp(token, "mdiow") == 0) mdiow(get_token(&c), get_token(&c));
339
340         else if(strcmp(token, "reboot") == 0) reboot();
341         
342         else if(strcmp(token, "help") == 0) help();
343         
344         else if(strcmp(token, "") != 0)
345                 printf("Command not found\n");
346 }
347
348 static int test_user_abort()
349 {
350         unsigned int i;
351         char c;
352         
353         puts("I: Press Q to abort boot");
354         for(i=0;i<4000000;i++) {
355                 if(readchar_nonblock()) {
356                         c = readchar();
357                         if(c == 'Q') {
358                                 puts("I: Aborted boot on user request");
359                                 return 0;
360                         }
361                 }
362         }
363         return 1;
364 }
365
366 extern unsigned int _edata;
367
368 static void crcbios()
369 {
370         unsigned int length;
371         unsigned int expected_crc;
372         unsigned int actual_crc;
373         
374         /*
375          * _edata is located right after the end of the flat
376          * binary image. The CRC tool writes the 32-bit CRC here.
377          * We also use the address of _edata to know the length
378          * of our code.
379          */
380         expected_crc = _edata;
381         length = (unsigned int)&_edata;
382         actual_crc = crc32((unsigned char *)0, length);
383         if(expected_crc == actual_crc)
384                 printf("I: BIOS CRC passed (%08x)\n", actual_crc);
385         else {
386                 printf("W: BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc);
387                 printf("W: The system will continue, but expect problems.\n");
388         }
389 }
390
391 static void display_board()
392 {
393         if(brd_desc == NULL) {
394                 printf("E: Running on unknown board (ID=0x%08x), startup aborted.\n", CSR_SYSTEM_ID);
395                 while(1);
396         }
397         printf("I: Running on %s\n", brd_desc->name);
398 }
399
400 #define display_capability(cap, val) if(val) printf("I: "cap": Yes\n"); else printf("I: "cap": No\n")
401
402 static void display_capabilities()
403 {
404         unsigned int cap;
405
406         cap = CSR_CAPABILITIES;
407         display_capability("Mem. card ", cap & CAP_MEMORYCARD);
408         display_capability("AC'97     ", cap & CAP_AC97);
409         display_capability("PFPU      ", cap & CAP_PFPU);
410         display_capability("TMU       ", cap & CAP_TMU);
411         display_capability("Ethernet  ", cap & CAP_ETHERNET);
412         display_capability("FML Meter ", cap & CAP_FMLMETER);
413 }
414
415 static const char banner[] =
416         "\nMILKYMIST(tm) v"VERSION" BIOS\thttp://www.milkymist.org\n"
417         "(c) Copyright 2007, 2008, 2009, 2010 Sebastien Bourdeauducq\n\n"
418         "This program is free software: you can redistribute it and/or modify\n"
419         "it under the terms of the GNU General Public License as published by\n"
420         "the Free Software Foundation, version 3 of the License.\n\n";
421
422 static void boot_sequence()
423 {
424         splash_display();
425         if(test_user_abort()) {
426                 serialboot(1);
427                 netboot();
428                 if(CSR_GPIO_IN & GPIO_BTN1)
429                         cardboot(1);
430                 else
431                         cardboot(0);
432                 printf("E: No boot medium found\n");
433         }
434 }
435
436 int main(int i, char **c)
437 {
438         char buffer[64];
439
440         brd_desc = get_board_desc();
441
442         /* Check for double baud rate */
443         if(brd_desc != NULL) {
444                 if(CSR_GPIO_IN & GPIO_BTN2)
445                         CSR_UART_DIVISOR = brd_desc->clk_frequency/230400/16;
446         }
447
448         /*┬áDisplay a banner as soon as possible to show that the system is alive */
449         putsnonl(banner);
450         
451         crcbios();
452         display_board();
453         display_capabilities();
454         
455         boot_sequence();
456
457         splash_showerr();
458         while(1) {
459                 putsnonl("\e[1mBIOS>\e[0m ");
460                 readstr(buffer, 64);
461                 do_command(buffer);
462         }
463         return 0;
464 }