[U-Boot] [PATCH - not for mainline] add update to ASTRO MCF5373L board

Wolfgang Wegner w.wegner at astro-kom.de
Mon Jan 25 11:28:24 CET 2010


Signed-off-by: Wolfgang Wegner <w.wegner at astro-kom.de>
---
This patch adds the external "update" command to ASTRO MCF5373L boards.
It needs this previous patch that is not included in mainline:
non-blocking flash write/erase/status check functions
(Message-Id 1260374411-11299-1-git-send-email-w.wegner at astro-kom.de)

 board/astro/mcf5373l/Makefile |    2 +-
 board/astro/mcf5373l/update.c |  615 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 616 insertions(+), 1 deletions(-)
 create mode 100644 board/astro/mcf5373l/update.c

diff --git a/board/astro/mcf5373l/Makefile b/board/astro/mcf5373l/Makefile
index c7a1d05..e0b1bc6 100644
--- a/board/astro/mcf5373l/Makefile
+++ b/board/astro/mcf5373l/Makefile
@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk
 
 LIB	= $(obj)lib$(BOARD).a
 
-COBJS	= $(BOARD).o fpga.o
+COBJS	= $(BOARD).o fpga.o update.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/board/astro/mcf5373l/update.c b/board/astro/mcf5373l/update.c
new file mode 100644
index 0000000..63170b3
--- /dev/null
+++ b/board/astro/mcf5373l/update.c
@@ -0,0 +1,615 @@
+/*
+ * (C) Copyright 2006-2009
+ * Adnan El-Bardawil <a.el-bardawil at astro-kom.de>
+ * Wolfgang Wegner <w.wegner at astro-kom.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/m5329.h>
+#include <asm/immap_5329.h>
+#include <asm/io.h>
+#include <flash.h>
+#include "astro.h"
+
+#include <asm/uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DEBUG_INFO		1
+#define DEBUG_ERROR		1
+
+/* dummy software version to signal card is in boot loader */
+#define SOFTWARE_VERSION	0x00
+#define SOFTWARE_SUBVERSION	' '
+
+typedef enum {
+	CMD_INIT = 0,
+	CMD_NEW,
+	CMD_TX,
+	CMD_RX,
+	CMD_RX_RDY,
+	CMD_RX_ERROR
+} cmd_stat_e;
+
+#define INT_CMD_IDLE		0
+#define INT_CMD_FLASH_MODE	1
+#define INT_CMD_WRITE_FLASH	2
+#define INT_CMD_RESTART		4
+
+#define FL_STAT_IDLE		0
+#define FL_STAT_ERASE		1
+#define FL_STAT_PROG		2
+#define FL_STAT_ERROR		4
+
+/*
+ * UART update subcommand codes
+ */
+
+#define	F_SAVE_PARAMETERS	 	0x00	/* save parameters on card */
+#define	F_READ_PARAMETERS	 	0x01	/* read parameters */
+#define	F_READ_CARDINFO 	 	0x10	/* read card information */
+#define	F_READ_ERROR_STATUS	 	0x11	/* read card error */
+#define	F_TRANSPARENT_DATA	 	0x20	/* length byte + data */
+
+#define SC_PREPARE_FOR_FLASH_DATA	0xc0
+#define SC_FLASH_DATA			0xc1
+#define SC_CLEAR_CRC			0xc2
+#define SC_CHECK_CRC			0xc3
+#define SC_RESTART			0xc4
+
+typedef struct {
+	unsigned char command;
+	unsigned char length;
+	unsigned char subcommand;
+} rcv_cmd_t;
+
+card_id_t card_information;
+
+struct {
+	parameters_t a;
+	parameters_t b;
+} parameters;
+
+typedef struct {
+	int cnt;
+	cmd_stat_e stat;
+} upd_command_t;
+
+typedef struct {
+	int cnt;
+	int length;
+	unsigned char *buffer;
+} comm_status_t;
+
+const unsigned long fl_base[3] = { 0x80000, 0x540000, 0x6c0000 };
+const char fl_type_str[3][6] = { "Kernel", "Xilinx", "Altera" };
+
+/* info for FLASH chips */
+extern flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
+
+unsigned long crc, crc_count;
+
+/* CRC divisor value */
+#define CRC_POLYNOM     0x800500
+
+void do_crc(unsigned char data)
+{
+	unsigned char count;
+
+	crc |= data;
+	for (count = 0; count < 8; count++) {
+		crc <<= 1;
+		if (crc & 0x1000000)
+			crc ^= CRC_POLYNOM;
+	}
+	crc_count++;
+}
+
+static unsigned char flash_buffer[0x10000];
+static unsigned long flash_data_length, flash_data_count;
+static unsigned long flash_prog_count, flash_sect_count;
+static unsigned char flash_data_type, crc_en;
+static int flash_prog_stat;
+static unsigned char uart_buffer[64];
+
+void fl_prog(int force_write)
+{
+	int s, i;
+	unsigned long fl_adr, fl_sector;
+
+	fl_adr = fl_base[flash_data_type] + flash_prog_count;
+	fl_sector = fl_adr >> 17;
+
+	switch (flash_prog_stat) {
+	case FL_STAT_IDLE:
+		if (((flash_prog_count & 0x1ffff) == 0) &&
+		    ((flash_prog_count >> 17) == flash_sect_count)) {
+			flash_protect(FLAG_PROTECT_CLEAR, fl_adr,
+					fl_adr + 0x1ffff, flash_info);
+			s = flash_erase_nb(flash_info, fl_sector);
+			flash_prog_stat = FL_STAT_ERASE;
+		} else if ((flash_data_count >= (flash_prog_count + 64))
+			   || (force_write
+			       && (flash_data_count > flash_prog_count))) {
+			s = write_buff_nb(flash_info,
+					flash_buffer +
+					(flash_prog_count & 0xffff),
+					fl_adr, 64);
+			flash_prog_stat = FL_STAT_PROG;
+		}
+		break;
+	case FL_STAT_ERASE:
+		s = flash_full_status_check_nb(flash_info, fl_sector,
+						0, "erase");
+		if (s != ERR_BUSY) {
+			if (s == ERR_OK) {
+				flash_sect_count++;
+				flash_prog_stat = FL_STAT_IDLE;
+			} else {
+				flash_prog_stat = FL_STAT_ERROR;
+			}
+		}
+		break;
+	case FL_STAT_PROG:
+		s = flash_full_status_check_nb(flash_info, fl_sector,
+						0, "write");
+		if (s == ERR_BUSY)
+			return;
+
+		if (s != ERR_OK) {
+			flash_prog_stat = FL_STAT_ERROR;
+			return;
+		}
+
+		flash_prog_stat = FL_STAT_IDLE;
+		for (i = 0; i < 64; i++) {
+			if (flash_buffer[(flash_prog_count + i) & 0xffff] !=
+					*((unsigned char *)fl_adr + i))
+				flash_prog_stat = FL_STAT_ERROR;
+		}
+		if ((flash_prog_count & 0xfff) == 0)
+			printf(".");
+		flash_prog_count += 64;
+		if (((flash_prog_count & 0x1ffff) == 0)
+		    || (force_write
+			&& (flash_data_count <= flash_prog_count))) {
+			flash_protect(FLAG_PROTECT_SET,
+					fl_adr & 0xfffe0000,
+					fl_adr | 0x1ffff,
+					flash_info);
+		}
+		break;
+	}
+}
+
+void handle_rx_char(unsigned char rx_data, upd_command_t *cmd,
+			int *rcv_cnt, rcv_cmd_t *rcv_cmd,
+			comm_status_t *rx_stat)
+{
+	uart_t *uart;
+
+	uart = (uart_t *)(MMAP_UART0);
+	if (readb(&uart->usr) & UART_USR_OE) {
+#if DEBUG_ERROR
+		printf("UART FIFO Overrun Error!\n");
+#endif
+		writeb(UART_UCR_RESET_ERROR, &uart->ucr);
+		cmd->stat = CMD_RX_ERROR;
+	}
+	if (cmd->stat == CMD_INIT) {
+		if (*rcv_cnt == 0) {
+			/* First received Byte is the Command */
+			rcv_cmd->command = rx_data;
+			/* non-Transparent Data: start Command Processing */
+			if (rcv_cmd->command != F_TRANSPARENT_DATA) {
+				cmd->stat = CMD_NEW;
+				cmd->cnt++;
+			} else {
+				(*rcv_cnt)++;
+			}
+		} else {
+			/* Length and Subcommand for Transparent Data */
+			if (*rcv_cnt == 1) {
+				rcv_cmd->length = rx_data;
+				(*rcv_cnt)++;
+			} else {
+				rcv_cmd->subcommand = rx_data;
+				cmd->stat = CMD_NEW;
+				cmd->cnt++;
+			}
+		}
+	} else if (cmd->stat == CMD_RX) {
+		/* Store received Data to Rx Buffer */
+		rx_stat->buffer[rx_stat->cnt] = rx_data;
+		if (crc_en)
+			do_crc(rx_data);
+		(rx_stat->cnt)++;
+		if (rx_stat->cnt == rx_stat->length)
+			cmd->stat = CMD_RX_RDY;
+	}
+}
+
+/*
+ * handle a transparent data command; these are used for software update
+ * return value is 1 if cmd_stat is set to CMD_INIT to let caller decide
+ * to reset the receive count, else 0.
+ */
+int handle_transparent_command(upd_command_t *cmd, rcv_cmd_t *rcv_cmd,
+				comm_status_t *rx_stat, comm_status_t *tx_stat,
+				unsigned char *int_command)
+{
+	int i;
+	unsigned char crc_status;
+
+	if (cmd->stat == CMD_NEW) {
+		rx_stat->cnt = 0;
+		rx_stat->length = rcv_cmd->length - 1;
+	}
+	switch (rcv_cmd->subcommand) {
+	case SC_PREPARE_FOR_FLASH_DATA:
+		if (cmd->stat == CMD_NEW) {
+			rx_stat->buffer = uart_buffer;
+			cmd->stat = CMD_RX;
+		} else if (cmd->stat == CMD_RX_RDY) {
+			for (i = 0; i < 4; i++)
+				flash_data_length = (flash_data_length << 8) +
+							uart_buffer[i + 1];
+			flash_data_type = uart_buffer[0];
+#if DEBUG_INFO
+			printf(" -- Flash Programming Initialized -- \n");
+			printf(" -- Receiving %lu Bytes of type ",
+				flash_data_length);
+			for (i = 0; i < 6; i++)
+				printf("%c", fl_type_str[flash_data_type][i]);
+			printf(" [0x%lx]\n", fl_base[flash_data_type]);
+#endif
+			uart_buffer[0] = rcv_cmd->command;
+			uart_buffer[1] = 1;
+			uart_buffer[2] = rcv_cmd->subcommand;
+			tx_stat->buffer = uart_buffer;
+			tx_stat->length = 3;
+			crc_count = 0;
+			crc = 0;
+			flash_data_count = 0;
+			flash_prog_count = 0;
+			flash_sect_count = 0;
+			flash_prog_stat = FL_STAT_IDLE;
+			crc_en = 0;
+			*int_command = INT_CMD_FLASH_MODE;
+			cmd->stat = CMD_TX;
+			return 1;
+		}
+		break;
+	case SC_FLASH_DATA:
+		if (cmd->stat == CMD_NEW) {
+			rx_stat->buffer = flash_buffer +
+						(flash_data_count & 0xffff);
+			rx_stat->cnt = 0;
+			cmd->stat = CMD_RX;
+			crc_en = 1;
+		} else if (cmd->stat == CMD_RX_RDY) {
+			crc_en = 0;
+			flash_data_count += rcv_cmd->length - 1;
+			cmd->stat = CMD_INIT;
+			return 1;
+		}
+		break;
+	case SC_CLEAR_CRC:
+		if (cmd->stat == CMD_NEW) {
+			uart_buffer[0] = rcv_cmd->command;
+			uart_buffer[1] = 1;
+			uart_buffer[2] = rcv_cmd->subcommand;
+			tx_stat->buffer = uart_buffer;
+			tx_stat->length = 3;
+			cmd->stat = CMD_TX;
+			crc_count = 0;
+			crc = 0;
+		}
+		break;
+	case SC_CHECK_CRC:
+		if (cmd->stat == CMD_NEW) {
+			rx_stat->buffer = uart_buffer;
+			cmd->stat = CMD_RX;
+		} else if (cmd->stat == CMD_RX_RDY) {
+			if ((flash_data_count <= flash_prog_count)
+			    || (flash_prog_stat == FL_STAT_ERROR)) {
+				crc_status = 0;
+				if (uart_buffer[0] != ((crc >> 16) & 0xff))
+					crc_status = 1;
+				if (uart_buffer[1] != ((crc >> 8)  & 0xff))
+					crc_status = 1;
+				if (flash_prog_stat == FL_STAT_ERROR)
+					crc_status |= 2;
+				uart_buffer[0] = rcv_cmd->command;
+				uart_buffer[1] = 4;
+				uart_buffer[2] = rcv_cmd->subcommand;
+				uart_buffer[3] = (crc >> 16);
+				uart_buffer[4] = (crc >> 8);
+				uart_buffer[5] = crc_status;
+#if DEBUG_INFO
+				printf(" CRC %u / %lu of %lu kB \n",
+					crc_status,
+					(flash_data_count >> 10),
+					(flash_data_length >> 10));
+#endif
+				tx_stat->buffer = uart_buffer;
+				tx_stat->length = 6;
+				cmd->stat = CMD_TX;
+				if (crc_status) {
+					flash_prog_count =
+					flash_data_count =
+					    (flash_data_count & 0xffff0000)
+					    - 0x10000;
+					flash_prog_stat = FL_STAT_IDLE;
+					*int_command = INT_CMD_FLASH_MODE;
+				}
+			}
+			if (flash_data_count & 0xffff)
+				*int_command |= INT_CMD_WRITE_FLASH;
+		}
+		break;
+	case SC_RESTART:
+		if (cmd->stat == CMD_NEW) {
+			uart_buffer[0] = rcv_cmd->command;
+			uart_buffer[1] = 1;
+			uart_buffer[2] = rcv_cmd->subcommand;
+			tx_stat->buffer = uart_buffer;
+			tx_stat->length = 3;
+			cmd->stat = CMD_TX;
+			crc_count = 0;
+			crc = 0;
+			/*
+			 * set restart command; sending the reply
+			 * is done before finishing the loop.
+			 */
+			*int_command = INT_CMD_RESTART;
+			return 1;
+		}
+		break;
+	default:
+		/*
+		 * for un-handled zero length transparent command,
+		 * we have to handle this condition first!
+		 */
+		if ((cmd->stat == CMD_RX_RDY)
+		    || (rx_stat->cnt == rx_stat->length))
+			cmd->stat = CMD_INIT;
+		else if (cmd->stat == CMD_NEW)
+			cmd->stat = CMD_RX;
+	}
+	return 0;
+}
+
+/*
+ * handle a general command (i.e. status and version information query)
+ * return value is always 0 except for transparent data where the
+ * return code is passed through to allow caller reset receive count.
+ */
+int handle_command(upd_command_t *cmd, rcv_cmd_t *rcv_cmd,
+			comm_status_t *rx_stat, comm_status_t *tx_stat,
+			unsigned char *int_command)
+{
+	int rv = 0;
+
+	switch (rcv_cmd->command) {
+	case F_READ_ERROR_STATUS:
+#if DEBUG_INFO
+		printf("read error status\n");
+#endif
+		uart_buffer[0] = 0;
+		uart_buffer[1] = 0;
+		uart_buffer[2] = 0;
+		uart_buffer[3] = 0;
+		tx_stat->buffer = uart_buffer;
+		tx_stat->length = 4;
+		cmd->stat = CMD_TX;
+		break;
+	case F_READ_PARAMETERS:
+		if (cmd->stat == CMD_NEW) {
+#if DEBUG_INFO
+			printf("read parameters\n");
+#endif
+			memcpy(uart_buffer, (unsigned char *)&parameters.a,
+				2 * sizeof(parameters_t));
+			cmd->stat = CMD_TX;
+			tx_stat->length = 2 * sizeof(parameters_t);
+		}
+		break;
+	case F_READ_CARDINFO:
+#if DEBUG_INFO
+		printf("read card info\n");
+#endif
+		card_information.software_version =
+					((*int_command) & INT_CMD_FLASH_MODE) ?
+					0xEE : SOFTWARE_VERSION;
+		tx_stat->buffer = (unsigned char *)&card_information;
+		tx_stat->length = 5;
+		cmd->stat = CMD_TX;
+		break;
+
+	case F_TRANSPARENT_DATA:
+		rv = handle_transparent_command(cmd, rcv_cmd, rx_stat,
+						tx_stat, int_command);
+		break;
+	}
+	return rv;
+}
+
+/* transmit data prepared in comm_status_t structure */
+void transmit_buffer(comm_status_t *tx_stat)
+{
+	int cnt;
+	for (cnt = 0; cnt < tx_stat->length; cnt++)
+		astro_put_char(tx_stat->buffer[cnt]);
+}
+
+int do_update(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unsigned char rx_data;
+	comm_status_t rx_stat, tx_stat;
+	upd_command_t cmd;
+	int rcv_cnt;
+	rcv_cmd_t rcv_cmd;
+	unsigned char int_command, tmp_char;
+	unsigned short tmp_short;
+
+	int select, old_select, got_char;
+	eport_t *eport = (eport_t *)MMAP_EPORT;
+	gpio_t *gpio = (gpio_t *)MMAP_GPIO;
+	uart_t *uart = (uart_t *)MMAP_UART0;
+	char *env_string;
+
+	cmd.cnt = 0;
+
+	/* we set some dummy parameters to make the protocol work */
+	card_information.card_type = ASTRO_ID;
+	env_string = getenv("loaderversion");
+	if (env_string != NULL) {
+		card_information.hardware_version =
+			(int)simple_strtol(env_string, NULL, 16);
+	} else {
+		card_information.hardware_version = 0x10;
+	}
+	card_information.software_version = SOFTWARE_VERSION;
+	card_information.software_subversion = SOFTWARE_SUBVERSION;
+	card_information.fpga_version_altera = 0x12;
+	card_information.fpga_version_xilinx = 0x13;
+
+	parameters.a.symbolrate = 0x5027;
+	parameters.a.viterbirate = 0x34;
+	parameters.a.satfreq = 0x6616;
+	parameters.a.card_error = 0;
+
+	parameters.b.symbolrate = 0x5027;
+	parameters.b.viterbirate = 0x34;
+	parameters.b.satfreq = 0x6616;
+	parameters.b.card_error = 0;
+
+	puts("Initializing serial port to ASTRO bus...\n");
+	/* init serial port */
+	rs_serial_init(0, 2400);
+	/* set UART pin for UART */
+	tmp_short = __raw_readw(&gpio->par_uart);
+	tmp_short |= 0x0003;
+	__raw_writew(tmp_short, &gpio->par_uart);
+	/* set select pin as GPIO */
+	tmp_short = __raw_readw(&gpio->par_irq);
+	tmp_short &= 0x0FF0;
+	__raw_writew(tmp_short, &gpio->par_irq);
+	/* set select pin as input */
+	tmp_char = readb(&eport->pdr);
+	tmp_char &= 0xBF;
+	writeb(tmp_char, &eport->pdr);
+	/*
+	 * set interrupt to both falling and rising edge
+	 * (no IRQ used, though)
+	 */
+	tmp_short = __raw_readw(&eport->par);
+	tmp_short |= 0x3000;
+	__raw_writew(tmp_short, &eport->par);
+
+	int_command = INT_CMD_IDLE;
+
+	rcv_cnt = 0;
+	cmd.stat = CMD_INIT;
+	old_select = 0; /* always start from "deselected" state */
+	rx_data = 0xFF;
+
+	while (int_command != INT_CMD_RESTART) {
+
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+		WATCHDOG_RESET();
+#endif
+
+		/* Flash program routine only called in flash mode */
+		if (int_command & INT_CMD_FLASH_MODE)
+			fl_prog(int_command & INT_CMD_WRITE_FLASH);
+
+		/*
+		 * UART Card Select Routine
+		 * Write ID on Card Select and switch baud rate
+		 */
+		select = ((readb(&eport->pdr) & 0x40) == 0x0);
+
+		if ((select) && (!old_select)) {
+			/* set low baud rate for ID only */
+			rs_serial_init(0, 2400);
+			astro_put_char(ASTRO_ID);
+
+			/* Wait for TX finished before switching baudrate */
+			while ((readb(&uart->usr) & UART_USR_TXEMP) == 0) {
+			}
+
+			/* set high baud rate */
+			rs_serial_init(0, 115200);
+			/* Reset the Receive Byte Counter */
+			rcv_cnt = 0;
+			cmd.stat = CMD_INIT;
+		} else if ((!select) && old_select && (cmd.stat != CMD_INIT)) {
+			cmd.stat = CMD_INIT;
+#if DEBUG_ERROR
+			printf("Command %u: 0x%02x (0x%02x) failed,"
+				" len %d, cnt %d\n",
+				cmd.cnt, rcv_cmd.command,
+				rcv_cmd.subcommand, rcv_cmd.length,
+				rx_stat.cnt);
+#endif
+		}
+
+		old_select = select;
+
+		got_char = astro_is_char();
+		if (got_char)
+			rx_data = astro_get_char();
+
+		if (select) {
+			/* UART RX Routine */
+			if (got_char)
+				handle_rx_char(rx_data, &cmd, &rcv_cnt,
+						&rcv_cmd, &rx_stat);
+
+			/* Command Control Routine */
+			if ((cmd.stat == CMD_NEW)
+			    || (cmd.stat == CMD_RX_RDY)) {
+				if (handle_command(&cmd, &rcv_cmd,
+							&rx_stat, &tx_stat,
+							&int_command))
+					rcv_cnt = 0;
+			}
+
+			/* UART TX Routine */
+			if (cmd.stat == CMD_TX) {
+				transmit_buffer(&tx_stat);
+				/* Reset the Receive Byte Counter */
+				rcv_cnt = 0;
+				cmd.stat = CMD_INIT;
+			}
+		}
+	}
+	/* restart is done outside, so we simply leave this function */
+	return 0;
+}
+
+U_BOOT_CMD(update, 1, 1, do_update,
+	    "automatic update via ASTRO bus",
+	    "\n    - start the update, waiting for transfer via bus");
-- 
1.5.6.5



More information about the U-Boot mailing list