[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 *)¶meters.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