loader_prompt.c revision 163598
11573Srgrimes/******************************************************************************
21573Srgrimes *
31573Srgrimes * Filename: loader_prompt.c
41573Srgrimes *
51573Srgrimes * Instantiation of the interactive loader functions.
61573Srgrimes *
71573Srgrimes * Revision information:
81573Srgrimes *
91573Srgrimes * 20AUG2004	kb_admin	initial creation
101573Srgrimes * 12JAN2005	kb_admin	massive changes for tftp, strings, and more
111573Srgrimes * 05JUL2005	kb_admin	save tag address, and set registers on boot
121573Srgrimes *
131573Srgrimes * BEGIN_KBDD_BLOCK
141573Srgrimes * No warranty, expressed or implied, is included with this software.  It is
151573Srgrimes * provided "AS IS" and no warranty of any kind including statutory or aspects
161573Srgrimes * relating to merchantability or fitness for any purpose is provided.  All
171573Srgrimes * intellectual property rights of others is maintained with the respective
181573Srgrimes * owners.  This software is not copyrighted and is intended for reference
191573Srgrimes * only.
201573Srgrimes * END_BLOCK
211573Srgrimes *
221573Srgrimes * $FreeBSD: head/sys/boot/arm/at91/bootspi/loader_prompt.c 163598 2006-10-21 22:51:21Z imp $
231573Srgrimes *****************************************************************************/
241573Srgrimes
251573Srgrimes#include "at91rm9200_lowlevel.h"
261573Srgrimes#include "at91rm9200.h"
271573Srgrimes#include "emac.h"
281573Srgrimes#include "loader_prompt.h"
291573Srgrimes#include "env_vars.h"
301573Srgrimes#include "lib.h"
3123658Speter#include "spi_flash.h"
321573Srgrimes#include "ee.h"
3390039Sobrien
3490039Sobrien/******************************* GLOBALS *************************************/
351573Srgrimes
3671579Sdeischen
371573Srgrimes/*********************** PRIVATE FUNCTIONS/DATA ******************************/
381573Srgrimes
3953812Salfredstatic char	inputBuffer[MAX_INPUT_SIZE];
4061193Skrisstatic int	buffCount;
4153812Salfred
4271579Sdeischen// argv pointer are either NULL or point to locations in inputBuffer
431573Srgrimesstatic char	*argv[MAX_COMMAND_PARAMS];
4471579Sdeischen
45235647Sgleb#define FLASH_OFFSET (0 * FLASH_PAGE_SIZE)
46150065Sstefanf#define FPGA_OFFSET  (15 * FLASH_PAGE_SIZE)
4771579Sdeischen#define FPGA_LEN     (212608)
481573Srgrimes#define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE)
491573Srgrimes#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE)
501573Srgrimesstatic const char *backspaceString = "\010 \010";
511573Srgrimes
52178772Skibstatic const command_entry_t	CommandTable[] = {
5369656Sdeischen	{COMMAND_DUMP, "d"},
54178772Skib	{COMMAND_EXEC, "e"},
551573Srgrimes	{COMMAND_LOCAL_IP, "ip"},
5669656Sdeischen	{COMMAND_MAC, "m"},
57282979Sjulian	{COMMAND_SERVER_IP, "server_ip"},
58282979Sjulian	{COMMAND_TFTP, "tftp"},
591573Srgrimes	{COMMAND_XMODEM, "x"},
601573Srgrimes	{COMMAND_RESET, "R"},
6123658Speter	{COMMAND_LOAD_SPI_KERNEL, "k"},
6223658Speter	{COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"},
6323658Speter	{COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"},
64282979Sjulian	{COMMAND_REPLACE_FPGA_VIA_XMODEM, "F"},
65282979Sjulian	{COMMAND_REPLACE_ID_EEPROM, "E"},
6623658Speter	{COMMAND_FINAL_FLAG, 0}
6723658Speter};
68270002Sjhb
69270002Sjhb#ifdef TSC_FPGA
70282979Sjulian#include "fpga.h"
7171579Sdeischen
721573Srgrimesconst struct fpga main_fpga =
731573Srgrimes{
7423658Speter    AT91C_BASE_PIOB, AT91C_PIO_PB0,
75282979Sjulian    AT91C_BASE_PIOC, AT91C_PIO_PC11,
761573Srgrimes    AT91C_BASE_PIOB, AT91C_PIO_PB2,
77270002Sjhb    AT91C_BASE_PIOC, AT91C_PIO_PC12
781573Srgrimes};
7933665Sjb
8023658Spetervoid
811573Srgrimesfpga_load(void)
821573Srgrimes{
8323658Speter	int len, off, i, offset;
841573Srgrimes	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
85178772Skib
861573Srgrimes	len = FPGA_LEN;
8723658Speter	offset = FPGA_OFFSET;
8823658Speter	for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
891573Srgrimes		off = i + offset;
901573Srgrimes		SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
911573Srgrimes	}
9253812Salfred	fpga_init(&main_fpga);
9371579Sdeischen	fpga_clear(&main_fpga);
9471579Sdeischen	fpga_write_bytes(&main_fpga, addr, len);
9571579Sdeischen	fpga_done(&main_fpga);
9671579Sdeischen}
9771579Sdeischen#endif
9871579Sdeischen
9971579Sdeischen/*
100174221Sdes * .KB_C_FN_DEFINITION_START
101178772Skib * unsigned BuildIP(void)
102174221Sdes *  This private function packs the test IP info to an unsigned value.
10371579Sdeischen * .KB_C_FN_DEFINITION_END
10471579Sdeischen */
105178772Skibstatic unsigned
10671579SdeischenBuildIP(void)
10771579Sdeischen{
10871579Sdeischen	return ((p_ASCIIToDec(argv[1]) << 24) |
10953812Salfred	    (p_ASCIIToDec(argv[2]) << 16) |
11053812Salfred	    (p_ASCIIToDec(argv[3]) << 8) |
11153812Salfred	    p_ASCIIToDec(argv[4]));
11253812Salfred}
11353812Salfred
11453812Salfred
11553812Salfred/*
11669656Sdeischen * .KB_C_FN_DEFINITION_START
11753812Salfred * int StringToCommand(char *cPtr)
11853892Salfred *  This private function converts a command string to a command code.
11953812Salfred * .KB_C_FN_DEFINITION_END
12071579Sdeischen */
121174221Sdesstatic int
122178772SkibStringToCommand(char *cPtr)
12391330Salfred{
124174221Sdes	int	i;
12571579Sdeischen
126178772Skib	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
12791330Salfred		if (!strcmp(CommandTable[i].c_string, cPtr))
12871579Sdeischen			return (CommandTable[i].command);
12953892Salfred
13071579Sdeischen	return (COMMAND_INVALID);
13153892Salfred}
13253892Salfred
13353892Salfred
13453892Salfred/*
13553892Salfred * .KB_C_FN_DEFINITION_START
13653872Swes * int BreakCommand(char *)
13753892Salfred *  This private function splits the buffer into separate strings as pointed
13853812Salfred * by argv and returns the number of parameters (< 0 on failure).
13953892Salfred * .KB_C_FN_DEFINITION_END
14053892Salfred */
14153812Salfredstatic int
142BreakCommand(char *buffer)
143{
144	int	pCount, cCount, state;
145
146	state = pCount = 0;
147	p_memset((char*)argv, 0, sizeof(argv));
148
149	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
150
151		if (!state) {
152			/* look for next command */
153			if (!p_IsWhiteSpace(buffer[cCount])) {
154				argv[pCount++] = &buffer[cCount];
155				state = 1;
156			} else {
157				buffer[cCount] = 0;
158			}
159		} else {
160			/* in command, find next white space */
161			if (p_IsWhiteSpace(buffer[cCount])) {
162				buffer[cCount] = 0;
163				state = 0;
164			}
165		}
166
167		if (pCount >= MAX_COMMAND_PARAMS) {
168			return (-1);
169		}
170	}
171
172	return (pCount);
173}
174
175#if 0
176static void
177UpdateEEProm(int eeaddr)
178{
179	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
180	int len;
181
182	while ((len = xmodem_rx(addr)) == -1)
183		continue;
184	printf("\nDownloaded %u bytes.\n", len);
185	WriteEEPROM(eeaddr, 0, addr, len);
186}
187#endif
188
189static void
190UpdateFlash(int offset)
191{
192	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
193	int len, i, off;
194
195	while ((len = xmodem_rx(addr)) == -1)
196		continue;
197	printf("\nDownloaded %u bytes.\n", len);
198	for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
199		off = i + offset;
200		SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE);
201	}
202}
203
204static void
205LoadKernelFromSpi(char *addr)
206{
207	int i, off;
208
209	for (i = 0; i < KERNEL_LEN; i+= FLASH_PAGE_SIZE) {
210		off = i + KERNEL_OFFSET;
211		SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
212	}
213}
214
215/*
216 * .KB_C_FN_DEFINITION_START
217 * void ParseCommand(char *)
218 *  This private function executes matching functions.
219 * .KB_C_FN_DEFINITION_END
220 */
221static void
222ParseCommand(char *buffer)
223{
224	int		argc, i;
225
226	if ((argc = BreakCommand(buffer)) < 1)
227		return;
228
229	switch (StringToCommand(argv[0])) {
230	case COMMAND_DUMP:
231		// display boot commands
232		DumpBootCommands();
233		break;
234
235	case COMMAND_EXEC:
236	{
237		// "e <address>"
238		// execute at address
239		void (*execAddr)(unsigned, unsigned);
240
241		if (argc > 1) {
242			/* in future, include machtypes (MACH_KB9200 = 612) */
243			execAddr = (void (*)(unsigned, unsigned))
244			    p_ASCIIToHex(argv[1]);
245			(*execAddr)(0, 612);
246		}
247		break;
248	}
249
250	case COMMAND_TFTP:
251	{
252		// "tftp <local_dest_addr filename>"
253		//  tftp download
254		unsigned address = 0;
255
256		if (argc > 2)
257			address = p_ASCIIToHex(argv[1]);
258		TFTP_Download(address, argv[2]);
259		break;
260	}
261
262	case COMMAND_SERVER_IP:
263		// "server_ip <server IP 192 200 1 20>"
264		// set download server address
265		if (argc > 4)
266			SetServerIPAddress(BuildIP());
267		break;
268
269	case COMMAND_LOCAL_IP:
270		// "local_ip <local IP 192 200 1 21>
271		// set ip of this module
272		if (argc > 4)
273			SetLocalIPAddress(BuildIP());
274		break;
275
276	case COMMAND_MAC:
277	{
278		// "m <mac address 12 34 56 78 9a bc>
279		// set mac address using 6 byte values
280		unsigned char mac[6];
281
282		if (argc > 6) {
283			for (i = 0; i < 6; i++)
284				mac[i] = p_ASCIIToHex(argv[i + 1]);
285			EMAC_SetMACAddress(mac);
286		}
287		break;
288	}
289
290	case COMMAND_LOAD_SPI_KERNEL:
291		// "k <address>"
292		if (argc > 1)
293			LoadKernelFromSpi((char *)p_ASCIIToHex(argv[1]));
294		break;
295
296	case COMMAND_XMODEM:
297		// "x <address>"
298		// download X-modem record at address
299		if (argc > 1)
300			xmodem_rx((char *)p_ASCIIToHex(argv[1]));
301		break;
302
303	case COMMAND_RESET:
304		printf("Reset\n");
305		reset();
306		while (1) continue;
307		break;
308
309	case COMMAND_REPLACE_KERNEL_VIA_XMODEM:
310		printf("Updating KERNEL image\n");
311		UpdateFlash(KERNEL_OFFSET);
312		break;
313	case COMMAND_REPLACE_FPGA_VIA_XMODEM:
314		printf("Updating FPGA image\n");
315		UpdateFlash(FPGA_OFFSET);
316		break;
317	case COMMAND_REPLACE_FLASH_VIA_XMODEM:
318		printf("Updating FLASH image\n");
319		UpdateFlash(FLASH_OFFSET);
320		break;
321
322	case COMMAND_REPLACE_ID_EEPROM:
323	{
324	    char buf[25];
325		printf("Testing Config EEPROM\n");
326		EEWrite(0, "This is a test", 15);
327		EERead(0, buf, 15);
328		printf("Found '%s'\n", buf);
329		break;
330	}
331	default:
332		break;
333	}
334
335	printf("\n");
336}
337
338
339/*
340 * .KB_C_FN_DEFINITION_START
341 * void ServicePrompt(char)
342 *  This private function process each character checking for valid commands.
343 * This function is only executed if the character is considered valid.
344 * Each command is terminated with NULL (0) or ''.
345 * .KB_C_FN_DEFINITION_END
346 */
347static void
348ServicePrompt(char p_char)
349{
350	if (p_char == '\r')
351		p_char = 0;
352
353	if (p_char == '\010') {
354		if (buffCount) {
355			/* handle backspace BS */
356			inputBuffer[--buffCount] = 0;
357			printf(backspaceString);
358		}
359		return;
360	}
361	if (buffCount < MAX_INPUT_SIZE - 1) {
362		inputBuffer[buffCount++] = p_char;
363		putchar(p_char);
364	}
365	if (!p_char) {
366		printf("\n");
367		ParseCommand(inputBuffer);
368		p_memset(inputBuffer, 0, MAX_INPUT_SIZE);
369		buffCount = 0;
370		printf("\n>");
371	}
372}
373
374
375/* ************************** GLOBAL FUNCTIONS ********************************/
376
377
378/*
379 * .KB_C_FN_DEFINITION_START
380 * void Bootloader(void *inputFunction)
381 *  This global function is the entry point for the bootloader.  If the
382 * inputFunction pointer is NULL, the loader input will be serviced from
383 * the uart.  Otherwise, inputFunction is called to get characters which
384 * the loader will parse.
385 * .KB_C_FN_DEFINITION_END
386 */
387void
388Bootloader(int(*inputFunction)(int))
389{
390	int	ch = 0;
391
392	p_memset((void*)inputBuffer, 0, sizeof(inputBuffer));
393	buffCount = 0;
394
395	printf("\n>");
396
397	while (1)
398		if ((ch = ((*inputFunction)(0))) > 0)
399			ServicePrompt(ch);
400}
401