This patch adds firmware updater to ADI's ICE-100B USB JTAG cable.
Below is an example firmware updating session:


$ jtag -q
jtag> cable ICE-100B
ICE-100B firmware version is 1.0.6
Error: The firmware on the ICE-100B needs to be updated.  Please go to:
  http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b
to learn how to update the firmware.

jtag> cable ICE-100B help
Usage: cable ICE-100B [vid=VID] [pid=PID] [desc=DESC]
[interface=INTERFACE] [firmware=FILE]

VID        USB Device Vendor ID (hex, e.g. 0abc)
PID        USB Device Product ID (hex, e.g. 0abc)
DESC       Some string to match in description or serial no.
INTERFACE  Interface to use (0=first, 1=second, etc).
FILE       Upgrade the ICE firmware.  See this page:
           <https://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b>

Default:   vid=64b pid=225 driver=libusb

jtag> cable ICE-100B firmware=/home/jie/Desktop/update.hex
ICE-100B firmware version is 1.0.6
Error: The firmware on the ICE-100B needs to be updated.  Please go to:
  http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b
to learn how to update the firmware.
Updating to firmware /home/jie/Desktop/update.hex ............
The firmware has been updated successfully.
Please unplug the ICE-100B cable and reconnect it to finish the update process.

jtag>

Then unplug the cable and reconnect it.

jtag> cable ICE-100B
ICE-100B firmware version is 2.0.0
jtag>


Any comments are welcome. If no objects, I will commit it in the
beginning of the next week.


Jie
  * include/urjtag/cable.h (urj_cable_param_key_t): Add
    URJ_CABLE_PARAM_KEY_FIRMWARE.
  * src/tap/cable.c (cable_param[]): Add URJ_CABLE_PARAM_KEY_FIRMWARE.
  * src/tap/cable/ice100.c (params_t): Add firmware_filename.
    (HOST_PROGRAM_FLASH): Define.
    (struct flash_block): Define.
    (get_hex_digit): New.
    (get_hex_byte): New.
    (get_hex_half_word): New.
    (ice_read_hex_file): New.
    (ice_calculate_crc): New.
    (ice_send_flash_data): New.
    (ice_firmware_crc): New.
    (ice_update_firmware): New.
    (ice_connect): Handle firmware parameter.
    (kit_10_connect): Initialize firmware_filename to NULL.
    (kit_20_connect): Likewise.
    (ice_init): Add firmware updater.
    (ice_cable_free): Free firmware_filename.
    (ice_cable_help): New.
    (urj_tap_cable_ice100B_driver): Use ice_cable_help.
    Add Emacs file local variables.


Index: include/urjtag/cable.h
===================================================================
--- include/urjtag/cable.h.orig	2011-06-16 09:06:53.000000000 -0400
+++ include/urjtag/cable.h	2011-06-16 15:48:46.000000000 -0400
@@ -64,6 +64,7 @@
     URJ_CABLE_PARAM_KEY_TMS,            /* lu           gpio used as TMS */
     URJ_CABLE_PARAM_KEY_TCK,            /* lu           gpio used as TCK */
     URJ_CABLE_PARAM_KEY_INTERFACE,      /* lu           ftdi */
+    URJ_CABLE_PARAM_KEY_FIRMWARE,       /* string       ice100 */
 }
 urj_cable_param_key_t;
 
Index: src/tap/cable.c
===================================================================
--- src/tap/cable.c.orig	2011-06-16 09:06:53.000000000 -0400
+++ src/tap/cable.c	2011-06-16 15:48:46.000000000 -0400
@@ -673,6 +673,7 @@
     { URJ_CABLE_PARAM_KEY_TMS,          URJ_PARAM_TYPE_LU,      "tms", },
     { URJ_CABLE_PARAM_KEY_TCK,          URJ_PARAM_TYPE_LU,      "tck", },
     { URJ_CABLE_PARAM_KEY_INTERFACE,    URJ_PARAM_TYPE_LU,      "interface", },
+    { URJ_CABLE_PARAM_KEY_FIRMWARE,     URJ_PARAM_TYPE_STRING,  "firmware", },
 };
 
 const urj_param_list_t urj_cable_param_list =
Index: src/tap/cable/ice100.c
===================================================================
--- src/tap/cable/ice100.c.orig	2011-06-16 11:04:21.000000000 -0400
+++ src/tap/cable/ice100.c	2011-06-16 15:53:23.000000000 -0400
@@ -93,6 +93,7 @@
     uint32_t wr_buf_addr;            /* USB: For Kits */
     uint32_t r_buf_addr;             /* USB: For Kits */
     num_tap_pairs tap_info;          /* For collecting and sending tap scans */
+    char *firmware_filename;         /* The update firmware file name */
 } params_t;
 
 /* Emulators's USB Data structure */
@@ -167,6 +168,7 @@
 #define HOST_GET_SINGLE_REG             0x08    /* set a JTAG register */
 #define HOST_SET_SINGLE_REG             0x09    /* set a JTAG register */
 #define HOST_DO_RAW_SCAN                0x0A    /* do a raw scan */
+#define HOST_PROGRAM_FLASH              0x0C    /* program flash */
 #define HOST_HARD_RESET_JTAG_CTRLR      0x0E    /* do a hard reset on JTAG controller */
 #define    HOST_FAST_MODE               0x10    /* Sets Kits in right mode */
 #define HOST_SC_AUTHENTICATE            0x17    /* Kit 20 */
@@ -395,13 +397,413 @@
     return URJ_STATUS_OK;
 }
 
+struct flash_block
+{
+    uint32_t addr;
+    int bytes;
+    uint8_t *data;
+    struct flash_block *next;
+};
+
+static int
+get_hex_digit (char *p)
+{
+    int digit;
+    switch (p[0])
+    {
+    case '0' ... '9':
+        digit = p[0] - '0';
+        break;
+    case 'a' ... 'f':
+        digit = p[0] - 'a' + 10;
+        break;
+    case 'A' ... 'F':
+        digit = p[0] - 'A' + 10;
+        break;
+    default:
+        return -1;
+    }
+    return digit;
+}
+
+static int
+get_hex_byte (char *p)
+{
+    int digit, byte;
+
+    digit = get_hex_digit (p);
+    if (digit == -1)
+        return -1;
+    byte = digit << 4;
+
+    digit = get_hex_digit (p + 1);
+    if (digit == -1)
+        return -1;
+    byte += digit;
+
+    return byte;
+}
+
+static int
+get_hex_half_word (char *p)
+{
+    int half_word, byte;
+
+    byte = get_hex_byte (p);
+    if (byte == -1)
+        return -1;
+    half_word = byte << 8;
+
+    byte = get_hex_byte (p + 2);
+    if (byte == -1)
+        return -1;
+    half_word += byte;
+
+    return half_word;
+}
+
+static int
+ice_read_hex_file (const char *filename, struct flash_block **flash_list)
+{
+    FILE *hex_file;
+    char *input_line, *p;
+    size_t len;
+    int lineno, i;
+    bool done = false;
+    struct flash_block *last_flash_block = NULL, *q;
+    int base_address = 0;
+
+    hex_file = fopen (filename, "r");
+    if (!hex_file)
+    {
+        urj_log (URJ_LOG_LEVEL_ERROR, _("Open file %s failed\n"), filename);
+        return URJ_STATUS_FAIL;
+    }
+
+    input_line = NULL;
+    len = 0;
+    lineno = 0;
+    while (getline (&input_line, &len, hex_file) != -1 && !done)
+    {
+        int byte_count, address, record_type, checksum;
+        int sum;
+
+        lineno++;
+        p = input_line;
+        /* A line should contain
+           1. start code : 1 character ':'
+           2. byte count : 2 hex digits
+           3. address    : 4 hex digits
+           4. record type: 2 hex digits
+           5. data       : 2n hex digits
+           6. checksum   : 2 hex digits */
+        if (len < 11)
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("Line %d is too short in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+
+        if (*p++ != ':')
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("Invalid start code on line %d in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+
+        byte_count = get_hex_byte (p);
+        if (byte_count == -1)
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("Bad byte count on line %d in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+        p += 2;
+        sum = byte_count;
+
+        address = get_hex_half_word (p);
+        if (address == -1)
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("Bad address on line %d in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+        p += 4;
+        sum += (address >> 8) + (address & 0xff);
+        sum &= 0xff;
+
+        /* record type */
+        record_type = get_hex_byte (p);
+        if (record_type == -1)
+            goto bad_record_type;
+        p += 2;
+        sum += record_type;
+        sum &= 0xff;
+
+        switch (record_type)
+        {
+        case 0:
+            q = last_flash_block;
+
+            if (!q
+                || q->addr + q->bytes != base_address + address)
+            {
+                q = (struct flash_block *) malloc (sizeof (struct flash_block));
+                if (!q)
+                {
+                    urj_log (URJ_LOG_LEVEL_ERROR, _("malloc failed.\n"));
+                    return URJ_STATUS_FAIL;
+                }
+                q->addr = base_address + address;
+                q->bytes = 0;
+                q->data = (uint8_t *) malloc (byte_count);
+                if (!q->data)
+                {
+                    urj_log (URJ_LOG_LEVEL_ERROR, _("malloc failed.\n"));
+                    return URJ_STATUS_FAIL;
+                }
+                q->next = NULL;
+
+                if (last_flash_block)
+                    last_flash_block->next = q;
+                else
+                    *flash_list = q;
+                last_flash_block = q;
+            }
+            else
+            {
+                q->data = (uint8_t *) realloc (q->data, q->bytes + byte_count);
+            }
+
+            for (i = 0; i < byte_count; i++)
+            {
+                int data;
+                data = get_hex_byte (p);
+                if (data == -1)
+                {
+                    urj_log (URJ_LOG_LEVEL_ERROR,
+                             _("Bad HEX data %c%c on line %d in file %s.\n"),
+                             p[0], p[1], lineno, filename);
+                    return URJ_STATUS_FAIL;
+                }
+                q->data[q->bytes] = data;
+                q->bytes++;
+                p += 2;
+                sum += data;
+            }
+            break;
+
+        case 1:
+            done = true;
+            break;
+
+        case 2:
+            /* fall through */
+        case 4:
+            base_address = get_hex_half_word (p);
+            if (base_address == -1)
+            {
+                urj_log (URJ_LOG_LEVEL_ERROR,
+                         _("Bad extended segment address on line %d in file %s.\n"),
+                         lineno, filename);
+                return URJ_STATUS_FAIL;
+            }
+            sum += (base_address >> 8) + (base_address & 0xff);
+            sum &= 0xff;
+            base_address <<= (record_type == 2 ? 4 : 16);
+            p += 4;
+            break;
+
+        default:
+        bad_record_type:
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("Bad HEX record type on line %d in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+
+        checksum = get_hex_byte (p);
+        if (checksum == -1)
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("Bad HEX checksum on line %d in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+        if (((sum + checksum) & 0xff) != 0)
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("The checksum is not correct on line %d in file %s.\n"),
+                     lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+    }
+    return URJ_STATUS_OK;
+}
+
+/* Calculate the CRC using forward CRC-16-CCITT algorithm.  */
+
+static uint16_t
+ice_calculate_crc (struct flash_block *p)
+{
+    uint16_t crc = 0xffff;
+
+    while (p)
+    {
+        int i;
+
+        for (i = 0; i < p->bytes; i++)
+        {
+            uint8_t byte = p->data[i];
+            int j;
+
+            for (j = 0; j < 8; j++)
+            {
+                bool add = ((crc >> 15) != (byte >> 7));
+                crc <<= 1;
+                byte <<= 1;
+                if (add)
+                    crc ^= 0x1021;
+            }
+        }
+        p = p->next;
+    }
+
+    return crc;
+}
+
+static int
+ice_send_flash_data (urj_cable_t *cable, struct flash_block *p, uint16_t crc)
+{
+    params_t *cable_params = cable->params;
+    /* ICE_100B_READ_BUFFER_SIZE / 4 (i.e. 0x2000) was chosen by experiments.
+       It might not be related to ICE_100B_READ_BUFFER_SIZE at all.  */
+    uint8_t buffer[ICE_100B_READ_BUFFER_SIZE / 4];
+    uint8_t first = 1, last = 0;
+
+    while (p)
+    {
+        int remaining = p->bytes;
+        uint32_t address = p->addr;
+
+        while (remaining)
+        {
+            usb_command_block usb_cmd_blk;
+            uint32_t count;
+
+            urj_log (URJ_LOG_LEVEL_NORMAL, ".");
+
+            if (remaining < ICE_100B_READ_BUFFER_SIZE / 4 - 16)
+                count = remaining;
+            else
+                count = ICE_100B_READ_BUFFER_SIZE / 4 - 16;
+            remaining -= count;
+            if (remaining == 0)
+                last = 1;
+
+            buffer[0] = first;
+            buffer[1] = last;
+            buffer[2] = HOST_PROGRAM_FLASH;
+            buffer[3] = 0;
+            memcpy (buffer + 4, (void *) &address, 4);
+            memcpy (buffer + 8, (void *) &count, 4);
+            memcpy (buffer + 12, (void *) &crc, 2);
+            memcpy (buffer + 16, p->data + p->bytes - remaining - count, count);
+
+            usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+            usb_cmd_blk.count = count + 16;
+            usb_cmd_blk.buffer = cable_params->wr_buf_addr;
+            adi_usb_write_or_ret (cable->link.usb->params, &usb_cmd_blk, sizeof (usb_cmd_blk));
+
+            adi_usb_write_or_ret (cable->link.usb->params, buffer, usb_cmd_blk.count);
+
+            first = 0;
+
+            address += count;
+        }
+
+        p = p->next;
+    }
+
+    return URJ_STATUS_OK;
+}
+
+/* The CRC is stored in the output buffer after programming the firmware
+   into the flash.  Read the buffer after programming get the CRC.  */
+
+static int
+ice_firmware_crc (urj_cable_t *cable, uint16_t *p)
+{
+    params_t *cable_params = cable->params;
+    usb_command_block usb_cmd_blk;
+
+    usb_cmd_blk.command = HOST_REQUEST_RX_DATA;
+    usb_cmd_blk.count = 2;
+    usb_cmd_blk.buffer = 0;
+
+    adi_usb_write_or_ret (cable->link.usb->params, &usb_cmd_blk, sizeof (usb_cmd_blk));
+
+    adi_usb_read_or_ret (cable->link.usb->params, p, sizeof (*p));
+
+    return URJ_STATUS_OK;
+}
+
+static int
+ice_update_firmware (urj_cable_t *cable, const char *filename)
+{
+    struct flash_block *flash_list = NULL, *p;
+    unsigned short crc1, crc2;
+    int ret;
+
+    urj_log (URJ_LOG_LEVEL_NORMAL, _("Updating to firmware %s "), filename);
+
+    if ((ret = ice_read_hex_file (filename, &flash_list)) != URJ_STATUS_OK)
+        return ret;
+
+    crc1 = ice_calculate_crc (flash_list);
+
+    ret = ice_send_flash_data (cable, flash_list, crc1);
+    urj_log (URJ_LOG_LEVEL_NORMAL, "\n");
+    if (ret != URJ_STATUS_OK)
+        return ret;
+
+    if ((ret = ice_firmware_crc (cable, &crc2)) != URJ_STATUS_OK)
+        return ret;
+
+    while (flash_list)
+    {
+        p = flash_list->next;
+        free (flash_list->data);
+        free (flash_list);
+        flash_list = p;
+    }
+
+    if (crc1 == crc2)
+    {
+        urj_log (URJ_LOG_LEVEL_NORMAL,
+                 _("The firmware has been updated successfully.\n"
+                   "Please unplug the ICE-100B cable and reconnect it to finish the update process.\n"));
+        return URJ_STATUS_OK;
+    }
+    else
+    {
+        urj_log (URJ_LOG_LEVEL_NORMAL,
+                 _("CRCs do NOT match.  The firmware failed to update.\n"));
+        return URJ_STATUS_FAIL;
+    }
+}
+
 /*
  * This function sets us up the cable and data
  */
 static int ice_connect (urj_cable_t *cable, const urj_param_t *params[])
 {
     params_t *cable_params;
-    int ret;
+    int ret, i;
 
     if ((ret = adi_connect (cable, params)) != URJ_STATUS_OK)
         return ret;
@@ -419,6 +821,26 @@
     cable_params->wr_buf_addr     = 0;
     cable_params->r_buf_addr      = 0;
     cable_params->bytewize_scan   = 1;
+    cable_params->firmware_filename = NULL;
+
+    if (params != NULL)
+        for (i = 0; params[i] != NULL; i++)
+        {
+            switch (params[i]->key)
+            {
+            case URJ_CABLE_PARAM_KEY_FIRMWARE:
+                cable_params->firmware_filename = strdup (params[i]->value.string);
+                if (!cable_params->firmware_filename)
+                {
+                    urj_log (URJ_LOG_LEVEL_ERROR,
+                             _("strdup (%s) fails\n"), params[i]->value.string);
+                    return URJ_STATUS_FAIL;
+                }
+                break;
+            default:
+                break;
+            }
+        }
 
     return URJ_STATUS_OK;
 }
@@ -447,6 +869,7 @@
     cable_params->wr_buf_addr     = BLACKFIN_OLD_DATA_BUFFER_OUT_ADDRESS;
     cable_params->r_buf_addr      = BLACKFIN_OLD_DATA_BUFFER_IN_ADDRESS;
     cable_params->bytewize_scan   = 0;
+    cable_params->firmware_filename = NULL;
 
     return URJ_STATUS_OK;
 }
@@ -475,6 +898,7 @@
     cable_params->wr_buf_addr     = BLACKFIN_DATA_BUFFER_OUT_ADDRESS;
     cable_params->r_buf_addr      = BLACKFIN_DATA_BUFFER_IN_ADDRESS;
     cable_params->bytewize_scan   = 0;
+    cable_params->firmware_filename = NULL;
 
     return URJ_STATUS_OK;
 }
@@ -492,7 +916,7 @@
 
     cable_params->version = do_host_cmd (cable, HOST_GET_FW_VERSION, 0, 1);
     do_host_cmd (cable, HOST_HARD_RESET_JTAG_CTRLR, 0, 0);
-    urj_log (URJ_LOG_LEVEL_NORMAL, "%s Firmware Version is %d.%d.%d\n",
+    urj_log (URJ_LOG_LEVEL_NORMAL, _("%s firmware version is %d.%d.%d\n"),
              cable->driver->name,
              ((cable_params->version >> 8) & 0xFF),
              ((cable_params->version >> 4) & 0x0F),
@@ -501,9 +925,16 @@
     if (cable_params->version < 0x0107)
     {
         urj_log (URJ_LOG_LEVEL_ERROR,
-                 _("The firmware on the ICE-100b needs to be upgraded. Please go to:\n"
-                   "%sto learn how to update the firmware.\n"),
-                   "http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b\n";);
+                 _("Error: The firmware on the ICE-100B needs to be updated.  Please go to:\n"
+                   "  %sto learn how to update the firmware.\n"),
+                 "http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b\n";);
+    }
+
+    if (cable_params->firmware_filename)
+        ice_update_firmware (cable, cable_params->firmware_filename);
+
+    if (cable_params->version < 0x0107 || cable_params->firmware_filename)
+    {
         return URJ_STATUS_FAIL;
     }
 
@@ -626,6 +1057,8 @@
         tap_info->cur_dat = -1;
         tap_info->rcv_dat = -1;
     }
+    if (cable_params->firmware_filename)
+        free (cable_params->firmware_filename);
     urj_tap_cable_generic_usbconn_free (cable);
 }
 
@@ -1849,6 +2282,15 @@
     return URJ_STATUS_OK;
 }
 
+static void
+ice_cable_help (urj_log_level_t ll, const char *cablename)
+{
+    const char *ex_short = "[firmware=FILE]";
+    const char *ex_desc = "FILE       Upgrade the ICE firmware.  See this page:\n"
+"           <https://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b>\n";
+    urj_tap_cable_generic_usbconn_help_ex (ll, cablename, ex_short, ex_desc);
+}
+
 /*
  * Cable Intefaces
  */
@@ -1870,7 +2312,7 @@
     ice_set_sig,
     ice_get_sig,
     adi_flush,
-    urj_tap_cable_generic_usbconn_help,
+    ice_cable_help,
     URJ_CABLE_QUIRK_ONESHOT
 };
 URJ_DECLARE_USBCONN_CABLE(0x064B, 0x0225, "libusb", "ICE-100B", ice100B)
@@ -1920,3 +2362,11 @@
 };
 URJ_DECLARE_USBCONN_CABLE(0x064B, 0x3217, "libusb", "EZ-KIT-2.0", ezkit_20_bf518)
 URJ_DECLARE_USBCONN_CABLE(0x064B, 0x3212, "libusb", "EZ-KIT-2.0", ezkit_20_bf526)
+
+/*
+ Local Variables:
+ mode:C
+ c-default-style:gnu
+ indent-tabs-mode:nil
+ End:
+*/
------------------------------------------------------------------------------
EditLive Enterprise is the world's most technically advanced content
authoring tool. Experience the power of Track Changes, Inline Image
Editing and ensure content is compliant with Accessibility Checking.
http://p.sf.net/sfu/ephox-dev2dev
_______________________________________________
UrJTAG-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/urjtag-development

Reply via email to