loader_prompt.c revision 163598
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 163598 2006-10-21 22:51:21Z 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 "ee.h"
33
34/******************************* GLOBALS *************************************/
35
36
37/*********************** PRIVATE FUNCTIONS/DATA ******************************/
38
39static char	inputBuffer[MAX_INPUT_SIZE];
40static int	buffCount;
41
42// argv pointer are either NULL or point to locations in inputBuffer
43static char	*argv[MAX_COMMAND_PARAMS];
44
45#define FLASH_OFFSET (0 * FLASH_PAGE_SIZE)
46#define FPGA_OFFSET  (15 * FLASH_PAGE_SIZE)
47#define FPGA_LEN     (212608)
48#define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE)
49#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE)
50static const char *backspaceString = "\010 \010";
51
52static const command_entry_t	CommandTable[] = {
53	{COMMAND_DUMP, "d"},
54	{COMMAND_EXEC, "e"},
55	{COMMAND_LOCAL_IP, "ip"},
56	{COMMAND_MAC, "m"},
57	{COMMAND_SERVER_IP, "server_ip"},
58	{COMMAND_TFTP, "tftp"},
59	{COMMAND_XMODEM, "x"},
60	{COMMAND_RESET, "R"},
61	{COMMAND_LOAD_SPI_KERNEL, "k"},
62	{COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"},
63	{COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"},
64	{COMMAND_REPLACE_FPGA_VIA_XMODEM, "F"},
65	{COMMAND_REPLACE_ID_EEPROM, "E"},
66	{COMMAND_FINAL_FLAG, 0}
67};
68
69#ifdef TSC_FPGA
70#include "fpga.h"
71
72const struct fpga main_fpga =
73{
74    AT91C_BASE_PIOB, AT91C_PIO_PB0,
75    AT91C_BASE_PIOC, AT91C_PIO_PC11,
76    AT91C_BASE_PIOB, AT91C_PIO_PB2,
77    AT91C_BASE_PIOC, AT91C_PIO_PC12
78};
79
80void
81fpga_load(void)
82{
83	int len, off, i, offset;
84	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
85
86	len = FPGA_LEN;
87	offset = FPGA_OFFSET;
88	for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
89		off = i + offset;
90		SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
91	}
92	fpga_init(&main_fpga);
93	fpga_clear(&main_fpga);
94	fpga_write_bytes(&main_fpga, addr, len);
95	fpga_done(&main_fpga);
96}
97#endif
98
99/*
100 * .KB_C_FN_DEFINITION_START
101 * unsigned BuildIP(void)
102 *  This private function packs the test IP info to an unsigned value.
103 * .KB_C_FN_DEFINITION_END
104 */
105static unsigned
106BuildIP(void)
107{
108	return ((p_ASCIIToDec(argv[1]) << 24) |
109	    (p_ASCIIToDec(argv[2]) << 16) |
110	    (p_ASCIIToDec(argv[3]) << 8) |
111	    p_ASCIIToDec(argv[4]));
112}
113
114
115/*
116 * .KB_C_FN_DEFINITION_START
117 * int StringToCommand(char *cPtr)
118 *  This private function converts a command string to a command code.
119 * .KB_C_FN_DEFINITION_END
120 */
121static int
122StringToCommand(char *cPtr)
123{
124	int	i;
125
126	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
127		if (!strcmp(CommandTable[i].c_string, cPtr))
128			return (CommandTable[i].command);
129
130	return (COMMAND_INVALID);
131}
132
133
134/*
135 * .KB_C_FN_DEFINITION_START
136 * int BreakCommand(char *)
137 *  This private function splits the buffer into separate strings as pointed
138 * by argv and returns the number of parameters (< 0 on failure).
139 * .KB_C_FN_DEFINITION_END
140 */
141static 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