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