Signed-off-by: Wolfgang Wegner <w.weg...@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.weg...@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-barda...@astro-kom.de>
+ * Wolfgang Wegner <w.weg...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to