401 lines
8.7 KiB
C
401 lines
8.7 KiB
C
/******************************************************************************
|
|
*
|
|
* Filename: loader_prompt.c
|
|
*
|
|
* Instantiation of the interactive loader functions.
|
|
*
|
|
* Revision information:
|
|
*
|
|
* 20AUG2004 kb_admin initial creation
|
|
* 12JAN2005 kb_admin massive changes for tftp, strings, and more
|
|
* 05JUL2005 kb_admin save tag address, and set registers on boot
|
|
*
|
|
* BEGIN_KBDD_BLOCK
|
|
* No warranty, expressed or implied, is included with this software. It is
|
|
* provided "AS IS" and no warranty of any kind including statutory or aspects
|
|
* relating to merchantability or fitness for any purpose is provided. All
|
|
* intellectual property rights of others is maintained with the respective
|
|
* owners. This software is not copyrighted and is intended for reference
|
|
* only.
|
|
* END_BLOCK
|
|
*
|
|
* $FreeBSD$
|
|
*****************************************************************************/
|
|
|
|
#include "at91rm9200_lowlevel.h"
|
|
#include "at91rm9200.h"
|
|
#include "emac.h"
|
|
#include "loader_prompt.h"
|
|
#include "env_vars.h"
|
|
#include "lib.h"
|
|
#include "spi_flash.h"
|
|
#include "ee.h"
|
|
|
|
/******************************* GLOBALS *************************************/
|
|
|
|
|
|
/*********************** PRIVATE FUNCTIONS/DATA ******************************/
|
|
|
|
static char inputBuffer[MAX_INPUT_SIZE];
|
|
static int buffCount;
|
|
|
|
// argv pointer are either NULL or point to locations in inputBuffer
|
|
static char *argv[MAX_COMMAND_PARAMS];
|
|
|
|
#define FLASH_OFFSET (0 * FLASH_PAGE_SIZE)
|
|
#define FPGA_OFFSET (15 * FLASH_PAGE_SIZE)
|
|
#define FPGA_LEN (212608)
|
|
#define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE)
|
|
#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE)
|
|
static const char *backspaceString = "\010 \010";
|
|
|
|
static const command_entry_t CommandTable[] = {
|
|
{COMMAND_DUMP, "d"},
|
|
{COMMAND_EXEC, "e"},
|
|
{COMMAND_LOCAL_IP, "ip"},
|
|
{COMMAND_MAC, "m"},
|
|
{COMMAND_SERVER_IP, "server_ip"},
|
|
{COMMAND_TFTP, "tftp"},
|
|
{COMMAND_XMODEM, "x"},
|
|
{COMMAND_RESET, "R"},
|
|
{COMMAND_LOAD_SPI_KERNEL, "k"},
|
|
{COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"},
|
|
{COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"},
|
|
{COMMAND_REPLACE_FPGA_VIA_XMODEM, "F"},
|
|
{COMMAND_REPLACE_ID_EEPROM, "E"},
|
|
{COMMAND_FINAL_FLAG, 0}
|
|
};
|
|
|
|
#ifdef TSC_FPGA
|
|
#include "fpga.h"
|
|
|
|
const struct fpga main_fpga =
|
|
{
|
|
AT91C_BASE_PIOB, AT91C_PIO_PB0,
|
|
AT91C_BASE_PIOC, AT91C_PIO_PC11,
|
|
AT91C_BASE_PIOB, AT91C_PIO_PB2,
|
|
AT91C_BASE_PIOC, AT91C_PIO_PC12
|
|
};
|
|
|
|
void
|
|
fpga_load(void)
|
|
{
|
|
int len, off, i, offset;
|
|
char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
|
|
|
|
len = FPGA_LEN;
|
|
offset = FPGA_OFFSET;
|
|
for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
|
|
off = i + offset;
|
|
SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
|
|
}
|
|
fpga_init(&main_fpga);
|
|
fpga_clear(&main_fpga);
|
|
fpga_write_bytes(&main_fpga, addr, len);
|
|
fpga_done(&main_fpga);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* .KB_C_FN_DEFINITION_START
|
|
* unsigned BuildIP(void)
|
|
* This private function packs the test IP info to an unsigned value.
|
|
* .KB_C_FN_DEFINITION_END
|
|
*/
|
|
static unsigned
|
|
BuildIP(void)
|
|
{
|
|
return ((p_ASCIIToDec(argv[1]) << 24) |
|
|
(p_ASCIIToDec(argv[2]) << 16) |
|
|
(p_ASCIIToDec(argv[3]) << 8) |
|
|
p_ASCIIToDec(argv[4]));
|
|
}
|
|
|
|
|
|
/*
|
|
* .KB_C_FN_DEFINITION_START
|
|
* int StringToCommand(char *cPtr)
|
|
* This private function converts a command string to a command code.
|
|
* .KB_C_FN_DEFINITION_END
|
|
*/
|
|
static int
|
|
StringToCommand(char *cPtr)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
|
|
if (!strcmp(CommandTable[i].c_string, cPtr))
|
|
return (CommandTable[i].command);
|
|
|
|
return (COMMAND_INVALID);
|
|
}
|
|
|
|
|
|
/*
|
|
* .KB_C_FN_DEFINITION_START
|
|
* int BreakCommand(char *)
|
|
* This private function splits the buffer into separate strings as pointed
|
|
* by argv and returns the number of parameters (< 0 on failure).
|
|
* .KB_C_FN_DEFINITION_END
|
|
*/
|
|
static int
|
|
BreakCommand(char *buffer)
|
|
{
|
|
int pCount, cCount, state;
|
|
|
|
state = pCount = 0;
|
|
p_memset((char*)argv, 0, sizeof(argv));
|
|
|
|
for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
|
|
|
|
if (!state) {
|
|
/* look for next command */
|
|
if (!p_IsWhiteSpace(buffer[cCount])) {
|
|
argv[pCount++] = &buffer[cCount];
|
|
state = 1;
|
|
} else {
|
|
buffer[cCount] = 0;
|
|
}
|
|
} else {
|
|
/* in command, find next white space */
|
|
if (p_IsWhiteSpace(buffer[cCount])) {
|
|
buffer[cCount] = 0;
|
|
state = 0;
|
|
}
|
|
}
|
|
|
|
if (pCount >= MAX_COMMAND_PARAMS) {
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
return (pCount);
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
UpdateEEProm(int eeaddr)
|
|
{
|
|
char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
|
|
int len;
|
|
|
|
while ((len = xmodem_rx(addr)) == -1)
|
|
continue;
|
|
printf("\nDownloaded %u bytes.\n", len);
|
|
WriteEEPROM(eeaddr, 0, addr, len);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
UpdateFlash(int offset)
|
|
{
|
|
char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
|
|
int len, i, off;
|
|
|
|
while ((len = xmodem_rx(addr)) == -1)
|
|
continue;
|
|
printf("\nDownloaded %u bytes.\n", len);
|
|
for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
|
|
off = i + offset;
|
|
SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
LoadKernelFromSpi(char *addr)
|
|
{
|
|
int i, off;
|
|
|
|
for (i = 0; i < KERNEL_LEN; i+= FLASH_PAGE_SIZE) {
|
|
off = i + KERNEL_OFFSET;
|
|
SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* .KB_C_FN_DEFINITION_START
|
|
* void ParseCommand(char *)
|
|
* This private function executes matching functions.
|
|
* .KB_C_FN_DEFINITION_END
|
|
*/
|
|
static void
|
|
ParseCommand(char *buffer)
|
|
{
|
|
int argc, i;
|
|
|
|
if ((argc = BreakCommand(buffer)) < 1)
|
|
return;
|
|
|
|
switch (StringToCommand(argv[0])) {
|
|
case COMMAND_DUMP:
|
|
// display boot commands
|
|
DumpBootCommands();
|
|
break;
|
|
|
|
case COMMAND_EXEC:
|
|
{
|
|
// "e <address>"
|
|
// execute at address
|
|
void (*execAddr)(unsigned, unsigned);
|
|
|
|
if (argc > 1) {
|
|
/* in future, include machtypes (MACH_KB9200 = 612) */
|
|
execAddr = (void (*)(unsigned, unsigned))
|
|
p_ASCIIToHex(argv[1]);
|
|
(*execAddr)(0, 612);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case COMMAND_TFTP:
|
|
{
|
|
// "tftp <local_dest_addr filename>"
|
|
// tftp download
|
|
unsigned address = 0;
|
|
|
|
if (argc > 2)
|
|
address = p_ASCIIToHex(argv[1]);
|
|
TFTP_Download(address, argv[2]);
|
|
break;
|
|
}
|
|
|
|
case COMMAND_SERVER_IP:
|
|
// "server_ip <server IP 192 200 1 20>"
|
|
// set download server address
|
|
if (argc > 4)
|
|
SetServerIPAddress(BuildIP());
|
|
break;
|
|
|
|
case COMMAND_LOCAL_IP:
|
|
// "local_ip <local IP 192 200 1 21>
|
|
// set ip of this module
|
|
if (argc > 4)
|
|
SetLocalIPAddress(BuildIP());
|
|
break;
|
|
|
|
case COMMAND_MAC:
|
|
{
|
|
// "m <mac address 12 34 56 78 9a bc>
|
|
// set mac address using 6 byte values
|
|
unsigned char mac[6];
|
|
|
|
if (argc > 6) {
|
|
for (i = 0; i < 6; i++)
|
|
mac[i] = p_ASCIIToHex(argv[i + 1]);
|
|
EMAC_SetMACAddress(mac);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case COMMAND_LOAD_SPI_KERNEL:
|
|
// "k <address>"
|
|
if (argc > 1)
|
|
LoadKernelFromSpi((char *)p_ASCIIToHex(argv[1]));
|
|
break;
|
|
|
|
case COMMAND_XMODEM:
|
|
// "x <address>"
|
|
// download X-modem record at address
|
|
if (argc > 1)
|
|
xmodem_rx((char *)p_ASCIIToHex(argv[1]));
|
|
break;
|
|
|
|
case COMMAND_RESET:
|
|
printf("Reset\n");
|
|
reset();
|
|
while (1) continue;
|
|
break;
|
|
|
|
case COMMAND_REPLACE_KERNEL_VIA_XMODEM:
|
|
printf("Updating KERNEL image\n");
|
|
UpdateFlash(KERNEL_OFFSET);
|
|
break;
|
|
case COMMAND_REPLACE_FPGA_VIA_XMODEM:
|
|
printf("Updating FPGA image\n");
|
|
UpdateFlash(FPGA_OFFSET);
|
|
break;
|
|
case COMMAND_REPLACE_FLASH_VIA_XMODEM:
|
|
printf("Updating FLASH image\n");
|
|
UpdateFlash(FLASH_OFFSET);
|
|
break;
|
|
|
|
case COMMAND_REPLACE_ID_EEPROM:
|
|
{
|
|
char buf[25];
|
|
printf("Testing Config EEPROM\n");
|
|
EEWrite(0, "This is a test", 15);
|
|
EERead(0, buf, 15);
|
|
printf("Found '%s'\n", buf);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/*
|
|
* .KB_C_FN_DEFINITION_START
|
|
* void ServicePrompt(char)
|
|
* This private function process each character checking for valid commands.
|
|
* This function is only executed if the character is considered valid.
|
|
* Each command is terminated with NULL (0) or ''.
|
|
* .KB_C_FN_DEFINITION_END
|
|
*/
|
|
static void
|
|
ServicePrompt(char p_char)
|
|
{
|
|
if (p_char == '\r')
|
|
p_char = 0;
|
|
|
|
if (p_char == '\010') {
|
|
if (buffCount) {
|
|
/* handle backspace BS */
|
|
inputBuffer[--buffCount] = 0;
|
|
printf(backspaceString);
|
|
}
|
|
return;
|
|
}
|
|
if (buffCount < MAX_INPUT_SIZE - 1) {
|
|
inputBuffer[buffCount++] = p_char;
|
|
putchar(p_char);
|
|
}
|
|
if (!p_char) {
|
|
printf("\n");
|
|
ParseCommand(inputBuffer);
|
|
p_memset(inputBuffer, 0, MAX_INPUT_SIZE);
|
|
buffCount = 0;
|
|
printf("\n>");
|
|
}
|
|
}
|
|
|
|
|
|
/* ************************** GLOBAL FUNCTIONS ********************************/
|
|
|
|
|
|
/*
|
|
* .KB_C_FN_DEFINITION_START
|
|
* void Bootloader(void *inputFunction)
|
|
* This global function is the entry point for the bootloader. If the
|
|
* inputFunction pointer is NULL, the loader input will be serviced from
|
|
* the uart. Otherwise, inputFunction is called to get characters which
|
|
* the loader will parse.
|
|
* .KB_C_FN_DEFINITION_END
|
|
*/
|
|
void
|
|
Bootloader(int(*inputFunction)(int))
|
|
{
|
|
int ch = 0;
|
|
|
|
p_memset((void*)inputBuffer, 0, sizeof(inputBuffer));
|
|
buffCount = 0;
|
|
|
|
printf("\n>");
|
|
|
|
while (1)
|
|
if ((ch = ((*inputFunction)(0))) > 0)
|
|
ServicePrompt(ch);
|
|
}
|