loader_prompt.c revision 163597
1/****************************************************************************** 2 * 3 * Filename: loader_prompt.c 4 * 5 * Instantiation of the interactive loader functions. 6 * 7 * Revision information: 8 * 9 * 20AUG2004 kb_admin initial creation 10 * 12JAN2005 kb_admin massive changes for tftp, strings, and more 11 * 05JUL2005 kb_admin save tag address, and set registers on boot 12 * 13 * BEGIN_KBDD_BLOCK 14 * No warranty, expressed or implied, is included with this software. It is 15 * provided "AS IS" and no warranty of any kind including statutory or aspects 16 * relating to merchantability or fitness for any purpose is provided. All 17 * intellectual property rights of others is maintained with the respective 18 * owners. This software is not copyrighted and is intended for reference 19 * only. 20 * END_BLOCK 21 * 22 * $FreeBSD: head/sys/boot/arm/at91/bootspi/loader_prompt.c 163597 2006-10-21 22:44:26Z imp $ 23 *****************************************************************************/ 24 25#include "at91rm9200_lowlevel.h" 26#include "at91rm9200.h" 27#include "emac.h" 28#include "loader_prompt.h" 29#include "env_vars.h" 30#include "lib.h" 31#include "spi_flash.h" 32#include "fpga.h" 33#include "ee.h" 34 35/******************************* GLOBALS *************************************/ 36 37 38/*********************** PRIVATE FUNCTIONS/DATA ******************************/ 39 40static char inputBuffer[MAX_INPUT_SIZE]; 41static int buffCount; 42 43// argv pointer are either NULL or point to locations in inputBuffer 44static char *argv[MAX_COMMAND_PARAMS]; 45 46#define FLASH_OFFSET (0 * FLASH_PAGE_SIZE) 47#define FPGA_OFFSET (15 * FLASH_PAGE_SIZE) 48#define FPGA_LEN (212608) 49#define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE) 50#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE) 51static const char *backspaceString = "\010 \010"; 52 53static const command_entry_t CommandTable[] = { 54 {COMMAND_DUMP, "d"}, 55 {COMMAND_EXEC, "e"}, 56 {COMMAND_LOCAL_IP, "ip"}, 57 {COMMAND_MAC, "m"}, 58 {COMMAND_SERVER_IP, "server_ip"}, 59 {COMMAND_TFTP, "tftp"}, 60 {COMMAND_XMODEM, "x"}, 61 {COMMAND_RESET, "R"}, 62 {COMMAND_LOAD_SPI_KERNEL, "k"}, 63 {COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"}, 64 {COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"}, 65 {COMMAND_REPLACE_FPGA_VIA_XMODEM, "F"}, 66 {COMMAND_REPLACE_ID_EEPROM, "E"}, 67 {COMMAND_FINAL_FLAG, 0} 68}; 69 70#ifdef TSC_FPGA 71#include "fpga.h" 72 73const struct fpga main_fpga = 74{ 75 AT91C_BASE_PIOB, AT91C_PIO_PB0, 76 AT91C_BASE_PIOC, AT91C_PIO_PC11, 77 AT91C_BASE_PIOB, AT91C_PIO_PB2, 78 AT91C_BASE_PIOC, AT91C_PIO_PC12 79}; 80 81void 82fpga_load(void) 83{ 84 int len, off, i, offset; 85 char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */ 86 87 len = FPGA_LEN; 88 offset = FPGA_OFFSET; 89 for (i = 0; i < len; i+= FLASH_PAGE_SIZE) { 90 off = i + offset; 91 SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE); 92 } 93 fpga_init(&main_fpga); 94 fpga_clear(&main_fpga); 95 fpga_write_bytes(&main_fpga, addr, len); 96 fpga_done(&main_fpga); 97} 98#endif 99 100/* 101 * .KB_C_FN_DEFINITION_START 102 * unsigned BuildIP(void) 103 * This private function packs the test IP info to an unsigned value. 104 * .KB_C_FN_DEFINITION_END 105 */ 106static unsigned 107BuildIP(void) 108{ 109 return ((p_ASCIIToDec(argv[1]) << 24) | 110 (p_ASCIIToDec(argv[2]) << 16) | 111 (p_ASCIIToDec(argv[3]) << 8) | 112 p_ASCIIToDec(argv[4])); 113} 114 115 116/* 117 * .KB_C_FN_DEFINITION_START 118 * int StringToCommand(char *cPtr) 119 * This private function converts a command string to a command code. 120 * .KB_C_FN_DEFINITION_END 121 */ 122static int 123StringToCommand(char *cPtr) 124{ 125 int i; 126 127 for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i) 128 if (!strcmp(CommandTable[i].c_string, cPtr)) 129 return (CommandTable[i].command); 130 131 return (COMMAND_INVALID); 132} 133 134 135/* 136 * .KB_C_FN_DEFINITION_START 137 * int BreakCommand(char *) 138 * This private function splits the buffer into separate strings as pointed 139 * by argv and returns the number of parameters (< 0 on failure). 140 * .KB_C_FN_DEFINITION_END 141 */ 142static int 143BreakCommand(char *buffer) 144{ 145 int pCount, cCount, state; 146 147 state = pCount = 0; 148 p_memset((char*)argv, 0, sizeof(argv)); 149 150 for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) { 151 152 if (!state) { 153 /* look for next command */ 154 if (!p_IsWhiteSpace(buffer[cCount])) { 155 argv[pCount++] = &buffer[cCount]; 156 state = 1; 157 } else { 158 buffer[cCount] = 0; 159 } 160 } else { 161 /* in command, find next white space */ 162 if (p_IsWhiteSpace(buffer[cCount])) { 163 buffer[cCount] = 0; 164 state = 0; 165 } 166 } 167 168 if (pCount >= MAX_COMMAND_PARAMS) { 169 return (-1); 170 } 171 } 172 173 return (pCount); 174} 175 176#if 0 177static void 178UpdateEEProm(int eeaddr) 179{ 180 char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */ 181 int len; 182 183 while ((len = xmodem_rx(addr)) == -1) 184 continue; 185 printf("\nDownloaded %u bytes.\n", len); 186 WriteEEPROM(eeaddr, 0, addr, len); 187} 188#endif 189 190static void 191UpdateFlash(int offset) 192{ 193 char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */ 194 int len, i, off; 195 196 while ((len = xmodem_rx(addr)) == -1) 197 continue; 198 printf("\nDownloaded %u bytes.\n", len); 199 for (i = 0; i < len; i+= FLASH_PAGE_SIZE) { 200 off = i + offset; 201 SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE); 202 } 203} 204 205static void 206LoadKernelFromSpi(char *addr) 207{ 208 int i, off; 209 210 for (i = 0; i < KERNEL_LEN; i+= FLASH_PAGE_SIZE) { 211 off = i + KERNEL_OFFSET; 212 SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE); 213 } 214} 215 216/* 217 * .KB_C_FN_DEFINITION_START 218 * void ParseCommand(char *) 219 * This private function executes matching functions. 220 * .KB_C_FN_DEFINITION_END 221 */ 222static void 223ParseCommand(char *buffer) 224{ 225 int argc, i; 226 227 if ((argc = BreakCommand(buffer)) < 1) 228 return; 229 230 switch (StringToCommand(argv[0])) { 231 case COMMAND_DUMP: 232 // display boot commands 233 DumpBootCommands(); 234 break; 235 236 case COMMAND_EXEC: 237 { 238 // "e <address>" 239 // execute at address 240 void (*execAddr)(unsigned, unsigned); 241 242 if (argc > 1) { 243 /* in future, include machtypes (MACH_KB9200 = 612) */ 244 execAddr = (void (*)(unsigned, unsigned)) 245 p_ASCIIToHex(argv[1]); 246 (*execAddr)(0, 612); 247 } 248 break; 249 } 250 251 case COMMAND_TFTP: 252 { 253 // "tftp <local_dest_addr filename>" 254 // tftp download 255 unsigned address = 0; 256 257 if (argc > 2) 258 address = p_ASCIIToHex(argv[1]); 259 TFTP_Download(address, argv[2]); 260 break; 261 } 262 263 case COMMAND_SERVER_IP: 264 // "server_ip <server IP 192 200 1 20>" 265 // set download server address 266 if (argc > 4) 267 SetServerIPAddress(BuildIP()); 268 break; 269 270 case COMMAND_LOCAL_IP: 271 // "local_ip <local IP 192 200 1 21> 272 // set ip of this module 273 if (argc > 4) 274 SetLocalIPAddress(BuildIP()); 275 break; 276 277 case COMMAND_MAC: 278 { 279 // "m <mac address 12 34 56 78 9a bc> 280 // set mac address using 6 byte values 281 unsigned char mac[6]; 282 283 if (argc > 6) { 284 for (i = 0; i < 6; i++) 285 mac[i] = p_ASCIIToHex(argv[i + 1]); 286 EMAC_SetMACAddress(mac); 287 } 288 break; 289 } 290 291 case COMMAND_LOAD_SPI_KERNEL: 292 // "k <address>" 293 if (argc > 1) 294 LoadKernelFromSpi((char *)p_ASCIIToHex(argv[1])); 295 break; 296 297 case COMMAND_XMODEM: 298 // "x <address>" 299 // download X-modem record at address 300 if (argc > 1) 301 xmodem_rx((char *)p_ASCIIToHex(argv[1])); 302 break; 303 304 case COMMAND_RESET: 305 printf("Reset\n"); 306 reset(); 307 while (1) continue; 308 break; 309 310 case COMMAND_REPLACE_KERNEL_VIA_XMODEM: 311 printf("Updating KERNEL image\n"); 312 UpdateFlash(KERNEL_OFFSET); 313 break; 314 case COMMAND_REPLACE_FPGA_VIA_XMODEM: 315 printf("Updating FPGA image\n"); 316 UpdateFlash(FPGA_OFFSET); 317 break; 318 case COMMAND_REPLACE_FLASH_VIA_XMODEM: 319 printf("Updating FLASH image\n"); 320 UpdateFlash(FLASH_OFFSET); 321 break; 322 323 case COMMAND_REPLACE_ID_EEPROM: 324 { 325 char buf[25]; 326 printf("Testing Config EEPROM\n"); 327 EEWrite(0, "This is a test", 15); 328 EERead(0, buf, 15); 329 printf("Found '%s'\n", buf); 330 break; 331 } 332 default: 333 break; 334 } 335 336 printf("\n"); 337} 338 339 340/* 341 * .KB_C_FN_DEFINITION_START 342 * void ServicePrompt(char) 343 * This private function process each character checking for valid commands. 344 * This function is only executed if the character is considered valid. 345 * Each command is terminated with NULL (0) or ''. 346 * .KB_C_FN_DEFINITION_END 347 */ 348static void 349ServicePrompt(char p_char) 350{ 351 if (p_char == '\r') 352 p_char = 0; 353 354 if (p_char == '\010') { 355 if (buffCount) { 356 /* handle backspace BS */ 357 inputBuffer[--buffCount] = 0; 358 printf(backspaceString); 359 } 360 return; 361 } 362 if (buffCount < MAX_INPUT_SIZE - 1) { 363 inputBuffer[buffCount++] = p_char; 364 putchar(p_char); 365 } 366 if (!p_char) { 367 printf("\n"); 368 ParseCommand(inputBuffer); 369 p_memset(inputBuffer, 0, MAX_INPUT_SIZE); 370 buffCount = 0; 371 printf("\n>"); 372 } 373} 374 375 376/* ************************** GLOBAL FUNCTIONS ********************************/ 377 378 379/* 380 * .KB_C_FN_DEFINITION_START 381 * void Bootloader(void *inputFunction) 382 * This global function is the entry point for the bootloader. If the 383 * inputFunction pointer is NULL, the loader input will be serviced from 384 * the uart. Otherwise, inputFunction is called to get characters which 385 * the loader will parse. 386 * .KB_C_FN_DEFINITION_END 387 */ 388void 389Bootloader(int(*inputFunction)(int)) 390{ 391 int ch = 0; 392 393 p_memset((void*)inputBuffer, 0, sizeof(inputBuffer)); 394 buffCount = 0; 395 396 printf("\n>"); 397 398 while (1) 399 if ((ch = ((*inputFunction)(0))) > 0) 400 ServicePrompt(ch); 401} 402