105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Copyright © 2001 Stephen Williams (steve@icarus.com) 305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net) 405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net) 505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Copyright © 2012 Pete Batard (pete@akeo.ie) 6b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan * Copyright © 2013 Federico Manzan (f.manzan@gmail.com) 705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * This source code is free software; you can redistribute it 905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * and/or modify it in source code form under the terms of the GNU 1005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * General Public License as published by the Free Software 1105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Foundation; either version 2 of the License, or (at your option) 1205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * any later version. 1305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 1405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * This program is distributed in the hope that it will be useful, 1505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * but WITHOUT ANY WARRANTY; without even the implied warranty of 1605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * GNU General Public License for more details. 1805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 1905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * You should have received a copy of the GNU General Public License 2005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * along with this program; if not, write to the Free Software 2105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 2205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 2305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#include <stdio.h> 2405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#include <errno.h> 2505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#include <stdlib.h> 2605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#include <string.h> 2705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#include <stdint.h> 2805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 2938e6eb86b2ceb301d67fd4754c5a1493f7911eceLudovic Rousseau#include "libusb.h" 3005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#include "ezusb.h" 3105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 3205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardextern void logerror(const char *format, ...) 3305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard __attribute__ ((format(printf, 1, 2))); 3405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 3505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 3605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * This file contains functions for uploading firmware into Cypress 3705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * EZ-USB microcontrollers. These chips use control endpoint 0 and vendor 3805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * specific commands to support writing into the on-chip SRAM. They also 3905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * support writing into the CPUCS register, which is how we reset the 4005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * processor after loading firmware (including the reset vector). 4105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 4205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * These Cypress devices are 8-bit 8051 based microcontrollers with 4305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * special support for USB I/O. They come in several packages, and 4405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * some can be set up with external memory when device costs allow. 4505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Note that the design was originally by AnchorChips, so you may find 4605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * references to that vendor (which was later merged into Cypress). 4705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * The Cypress FX parts are largely compatible with the Anchorhip ones. 4805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 4905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 5077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batardint verbose = 1; 5105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 5205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 5305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * return true if [addr,addr+len] includes external RAM 5405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * for Anchorchips EZ-USB or Cypress EZ-USB FX 5505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 5605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardstatic bool fx_is_external(uint32_t addr, size_t len) 5705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 5805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* with 8KB RAM, 0x0000-0x1b3f can be written 5905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * we can't tell if it's a 4KB device here 6005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 6105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (addr <= 0x1b3f) 6205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return ((addr + len) > 0x1b40); 6305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 6405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* there may be more RAM; unclear if we can write it. 6505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * some bulk buffers may be unused, 0x1b3f-0x1f3f 6605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * firmware can set ISODISAB for 2KB at 0x2000-0x27ff 6705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 6805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return true; 6905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 7005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 7105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 7205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * return true if [addr,addr+len] includes external RAM 7305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * for Cypress EZ-USB FX2 7405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 7505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardstatic bool fx2_is_external(uint32_t addr, size_t len) 7605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 7705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* 1st 8KB for data/code, 0x0000-0x1fff */ 7805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (addr <= 0x1fff) 7905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return ((addr + len) > 0x2000); 8005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 8105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* and 512 for data, 0xe000-0xe1ff */ 8205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard else if (addr >= 0xe000 && addr <= 0xe1ff) 8305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return ((addr + len) > 0xe200); 8405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 8505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* otherwise, it's certainly external */ 8605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard else 8705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return true; 8805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 8905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 9005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 9105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * return true if [addr,addr+len] includes external RAM 9205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * for Cypress EZ-USB FX2LP 9305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 9405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardstatic bool fx2lp_is_external(uint32_t addr, size_t len) 9505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 9605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* 1st 16KB for data/code, 0x0000-0x3fff */ 9705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (addr <= 0x3fff) 9805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return ((addr + len) > 0x4000); 9905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 10005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* and 512 for data, 0xe000-0xe1ff */ 10105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard else if (addr >= 0xe000 && addr <= 0xe1ff) 10205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return ((addr + len) > 0xe200); 10305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 10405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* otherwise, it's certainly external */ 10505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard else 10605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return true; 10705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 10805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 10905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 11005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/*****************************************************************************/ 11105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 11205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 11305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * These are the requests (bRequest) that the bootstrap loader is expected 11405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * to recognize. The codes are reserved by Cypress, and these values match 11505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * what EZ-USB hardware, or "Vend_Ax" firmware (2nd stage loader) uses. 11605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Cypress' "a3load" is nice because it supports both FX and FX2, although 11705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * it doesn't have the EEPROM support (subset of "Vend_Ax"). 11805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 11905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#define RW_INTERNAL 0xA0 /* hardware implements this one */ 12005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#define RW_MEMORY 0xA3 12105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 12205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 12305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Issues the specified vendor-specific write request. 12405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 1259d50e95028c6cada096b821eb9872539efced402Ludovic Rousseaustatic int ezusb_write(libusb_device_handle *device, const char *label, 12605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len) 12705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 12805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int status; 12905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 13077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (verbose > 1) 13105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len); 13205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard status = libusb_control_transfer(device, 13305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 13405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard opcode, addr & 0xFFFF, addr >> 16, 13505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard (unsigned char*)data, (uint16_t)len, 1000); 1363661588fe6ccbb2ca7ad9bb51a8f64a2a0161c6cLudovic Rousseau if (status != (signed)len) { 13705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (status < 0) 13805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s: %s\n", label, libusb_error_name(status)); 13905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard else 14005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s ==> %d\n", label, status); 14105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 14205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return (status < 0) ? -EIO : 0; 14305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 14405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 14505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 146b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan * Issues the specified vendor-specific read request. 147b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan */ 148b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzanstatic int ezusb_read(libusb_device_handle *device, const char *label, 149b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len) 150b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan{ 151b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan int status; 152b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 15377a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (verbose > 1) 154b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len); 155b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan status = libusb_control_transfer(device, 156b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 157b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan opcode, addr & 0xFFFF, addr >> 16, 158b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan (unsigned char*)data, (uint16_t)len, 1000); 1593661588fe6ccbb2ca7ad9bb51a8f64a2a0161c6cLudovic Rousseau if (status != (signed)len) { 160b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan if (status < 0) 161b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan logerror("%s: %s\n", label, libusb_error_name(status)); 162b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan else 163b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan logerror("%s ==> %d\n", label, status); 164b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 165b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan return (status < 0) ? -EIO : 0; 166b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan} 167b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 168b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan/* 16905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Modifies the CPUCS register to stop or reset the CPU. 17005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Returns false on error. 17105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 17205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardstatic bool ezusb_cpucs(libusb_device_handle *device, uint32_t addr, bool doRun) 17305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 17405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int status; 17505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint8_t data = doRun ? 0x00 : 0x01; 17605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 17705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose) 17805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s\n", data ? "stop CPU" : "reset CPU"); 17905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard status = libusb_control_transfer(device, 18005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 18105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard RW_INTERNAL, addr & 0xFFFF, addr >> 16, 18205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard &data, 1, 1000); 18305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if ((status != 1) && 1841eff220474f63d7ea7f8f99bef2a3da9da5324ebhjelmn@cs.unm.edu /* We may get an I/O error from libusb as the device disappears */ 18505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ((!doRun) || (status != LIBUSB_ERROR_IO))) 18605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard { 1879d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau const char *mesg = "can't modify CPUCS"; 18805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (status < 0) 18905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s: %s\n", mesg, libusb_error_name(status)); 19005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard else 19105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s\n", mesg); 19205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return false; 19305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } else 19405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return true; 19505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 19605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 19777a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard/* 19877a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard * Send an FX3 jumpt to address command 19977a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard * Returns false on error. 20077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard */ 20177a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batardstatic bool ezusb_fx3_jump(libusb_device_handle *device, uint32_t addr) 20277a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard{ 20377a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard int status; 20477a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard 20577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (verbose) 20677a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("transfer execution to Program Entry at 0x%08x\n", addr); 20777a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard status = libusb_control_transfer(device, 20877a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 20977a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard RW_INTERNAL, addr & 0xFFFF, addr >> 16, 21077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard NULL, 0, 1000); 2111eff220474f63d7ea7f8f99bef2a3da9da5324ebhjelmn@cs.unm.edu /* We may get an I/O error from libusb as the device disappears */ 21277a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if ((status != 0) && (status != LIBUSB_ERROR_IO)) 21377a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard { 21477a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard const char *mesg = "failed to send jump command"; 21577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (status < 0) 21677a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("%s: %s\n", mesg, libusb_error_name(status)); 21777a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard else 21877a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("%s\n", mesg); 21977a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard return false; 22077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard } else 22177a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard return true; 22277a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard} 22377a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard 22405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/*****************************************************************************/ 22505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 22605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 22705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Parse an Intel HEX image file and invoke the poke() function on the 22805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * various segments to implement policies such as writing to RAM (with 22905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * a one or two stage loader setup, depending on the firmware) or to 23005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * EEPROM (two stages required). 23105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 23205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * image - the hex image file 23305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * context - for use by poke() 23405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * is_external - if non-null, used to check which segments go into 23505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * external memory (writable only by software loader) 23605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * poke - called with each memory segment; errors indicated 23705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * by returning negative values. 23805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 23905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Caller is responsible for halting CPU as needed, such as when 24005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * overwriting a second stage loader. 24105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 2429d50e95028c6cada096b821eb9872539efced402Ludovic Rousseaustatic int parse_ihex(FILE *image, void *context, 2439d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau bool (*is_external)(uint32_t addr, size_t len), 2449d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau int (*poke) (void *context, uint32_t addr, bool external, 2459d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau const unsigned char *data, size_t len)) 24605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 24705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard unsigned char data[1023]; 24805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint32_t data_addr = 0; 24905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard size_t data_len = 0; 25005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int rc; 25105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int first_line = 1; 25205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard bool external = false; 25305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 25405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Read the input file as an IHEX file, and report the memory segments 25505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * as we go. Each line holds a max of 16 bytes, but uploading is 25605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * faster (and EEPROM space smaller) if we merge those lines into larger 25705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * chunks. Most hex files keep memory segments together, which makes 25805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * such merging all but free. (But it may still be worth sorting the 25905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * hex files to make up for undesirable behavior from tools.) 26005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 26105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Note that EEPROM segments max out at 1023 bytes; the upload protocol 26205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * allows segments of up to 64 KBytes (more than a loader could handle). 26305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 26405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard for (;;) { 26505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard char buf[512], *cp; 26605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard char tmp, type; 26705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard size_t len; 26805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard unsigned idx, off; 26905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 27005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cp = fgets(buf, sizeof(buf), image); 27105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (cp == NULL) { 27205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("EOF without EOF record!\n"); 27305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 27405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 27505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 27605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */ 27705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (buf[0] == '#') 27805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard continue; 27905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 28005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (buf[0] != ':') { 28105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("not an ihex record: %s", buf); 28205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -2; 28305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 28405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 28505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* ignore any newline */ 28605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cp = strchr(buf, '\n'); 28705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (cp) 28805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard *cp = 0; 28905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 29005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose >= 3) 29105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("** LINE: %s\n", buf); 29205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 29305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Read the length field (up to 16 bytes) */ 29405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard tmp = buf[3]; 29505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard buf[3] = 0; 29605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard len = strtoul(buf+1, NULL, 16); 29705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard buf[3] = tmp; 29805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 29905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Read the target offset (address up to 64KB) */ 30005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard tmp = buf[7]; 30105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard buf[7] = 0; 302ad26880470dc957ee58dd8fa377184dad99e01faLudovic Rousseau off = (int)strtoul(buf+3, NULL, 16); 30305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard buf[7] = tmp; 30405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 30505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Initialize data_addr */ 30605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (first_line) { 30705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_addr = off; 30805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard first_line = 0; 30905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 31005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 31105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Read the record type */ 31205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard tmp = buf[9]; 31305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard buf[9] = 0; 31405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard type = (char)strtoul(buf+7, NULL, 16); 31505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard buf[9] = tmp; 31605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 31705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* If this is an EOF record, then make it so. */ 31805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (type == 1) { 31905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose >= 2) 32005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("EOF on hexfile\n"); 32105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 32205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 32305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 32405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (type != 0) { 32505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("unsupported record type: %u\n", type); 32605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -3; 32705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 32805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 32905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if ((len * 2) + 11 > strlen(buf)) { 33005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("record too short?\n"); 33105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -4; 33205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 33305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 33405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* FIXME check for _physically_ contiguous not just virtually 33505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * e.g. on FX2 0x1f00-0x2100 includes both on-chip and external 33605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * memory so it's not really contiguous */ 33705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 33805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* flush the saved data if it's not contiguous, 33905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * or when we've buffered as much as we can. 34005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 34105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (data_len != 0 34205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard && (off != (data_addr + data_len) 34305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* || !merge */ 34405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard || (data_len + len) > sizeof(data))) { 34505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (is_external) 34605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard external = is_external(data_addr, data_len); 34705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard rc = poke(context, data_addr, external, data, data_len); 34805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (rc < 0) 34905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 35005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_addr = off; 35105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_len = 0; 35205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 35305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 35405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* append to saved data, flush later */ 35505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) { 35605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard tmp = cp[2]; 35705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cp[2] = 0; 35805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data[data_len + idx] = (uint8_t)strtoul(cp, NULL, 16); 35905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cp[2] = tmp; 36005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 36105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_len += len; 36205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 36305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 36405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 36505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* flush any data remaining */ 36605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (data_len != 0) { 36705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (is_external) 36805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard external = is_external(data_addr, data_len); 36905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard rc = poke(context, data_addr, external, data, data_len); 37005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (rc < 0) 37105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 37205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 37305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return 0; 37405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 37505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 37605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 37705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Parse a binary image file and write it as is to the target. 37805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Applies to Cypress BIX images for RAM or Cypress IIC images 37905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * for EEPROM. 38005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 38105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * image - the BIX image file 38205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * context - for use by poke() 38305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * is_external - if non-null, used to check which segments go into 38405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * external memory (writable only by software loader) 38505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * poke - called with each memory segment; errors indicated 38605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * by returning negative values. 38705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 38805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Caller is responsible for halting CPU as needed, such as when 38905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * overwriting a second stage loader. 39005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 3919d50e95028c6cada096b821eb9872539efced402Ludovic Rousseaustatic int parse_bin(FILE *image, void *context, 3929d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau bool (*is_external)(uint32_t addr, size_t len), int (*poke)(void *context, 3939d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau uint32_t addr, bool external, const unsigned char *data, size_t len)) 39405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 39505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard unsigned char data[4096]; 39605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint32_t data_addr = 0; 39705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard size_t data_len = 0; 39805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int rc; 39905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard bool external = false; 40005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 40105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard for (;;) { 40205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_len = fread(data, 1, 4096, image); 40305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (data_len == 0) 40405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 40505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (is_external) 40605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard external = is_external(data_addr, data_len); 40705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard rc = poke(context, data_addr, external, data, data_len); 40805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (rc < 0) 40905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 41005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_addr += (uint32_t)data_len; 41105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 41205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return feof(image)?0:-1; 41305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 41405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 41505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 41605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Parse a Cypress IIC image file and invoke the poke() function on the 41705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * various segments for writing to RAM 41805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 41905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * image - the IIC image file 42005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * context - for use by poke() 42105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * is_external - if non-null, used to check which segments go into 42205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * external memory (writable only by software loader) 42305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * poke - called with each memory segment; errors indicated 42405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * by returning negative values. 42505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 42605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Caller is responsible for halting CPU as needed, such as when 42705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * overwriting a second stage loader. 42805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 4299d50e95028c6cada096b821eb9872539efced402Ludovic Rousseaustatic int parse_iic(FILE *image, void *context, 4309d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau bool (*is_external)(uint32_t addr, size_t len), 43105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) 43205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 43305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard unsigned char data[4096]; 43405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint32_t data_addr = 0; 43505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard size_t data_len = 0, read_len; 43605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint8_t block_header[4]; 43705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int rc; 43805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard bool external = false; 4393d84bba0a7ff2d9e28f5aac43775f9a267caa4e8Ludovic Rousseau long file_size, initial_pos; 4403d84bba0a7ff2d9e28f5aac43775f9a267caa4e8Ludovic Rousseau 4413d84bba0a7ff2d9e28f5aac43775f9a267caa4e8Ludovic Rousseau initial_pos = ftell(image); 4423d84bba0a7ff2d9e28f5aac43775f9a267caa4e8Ludovic Rousseau if (initial_pos < 0) 4433d84bba0a7ff2d9e28f5aac43775f9a267caa4e8Ludovic Rousseau return -1; 44405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 445bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard if (fseek(image, 0L, SEEK_END) != 0) 446bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard return -1; 44705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard file_size = ftell(image); 448bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard if (fseek(image, initial_pos, SEEK_SET) != 0) 449bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard return -1; 45005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard for (;;) { 45105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Ignore the trailing reset IIC data (5 bytes) */ 45205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (ftell(image) >= (file_size - 5)) 45305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 45405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (fread(&block_header, 1, sizeof(block_header), image) != 4) { 45505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("unable to read IIC block header\n"); 45605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 45705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 45805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_len = (block_header[0] << 8) + block_header[1]; 45905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard data_addr = (block_header[2] << 8) + block_header[3]; 46005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (data_len > sizeof(data)) { 46105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* If this is ever reported as an error, switch to using malloc/realloc */ 4621eff220474f63d7ea7f8f99bef2a3da9da5324ebhjelmn@cs.unm.edu logerror("IIC data block too small - please report this error to libusb.info\n"); 46305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 46405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 46505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard read_len = fread(data, 1, data_len, image); 46605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (read_len != data_len) { 46705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("read error\n"); 46805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 46905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 47005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (is_external) 47105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard external = is_external(data_addr, data_len); 47205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard rc = poke(context, data_addr, external, data, data_len); 47305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (rc < 0) 47405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -1; 47505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 47605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return 0; 47705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 47805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 47905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* the parse call will be selected according to the image type */ 480ce8da723b4e4c29268c0a15f010838f5a70c931aSean McBridestatic int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len), 481ce8da723b4e4c29268c0a15f010838f5a70c931aSean McBride int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) 482ce8da723b4e4c29268c0a15f010838f5a70c931aSean McBride = { parse_ihex, parse_iic, parse_bin }; 48305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 48405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/*****************************************************************************/ 48505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 48605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 48705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * For writing to RAM using a first (hardware) or second (software) 48805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * stage loader and 0xA0 or 0xA3 vendor requests 48905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 49005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardtypedef enum { 49105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard _undef = 0, 49205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard internal_only, /* hardware first-stage loader */ 49305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard skip_internal, /* first phase, second-stage loader */ 49405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard skip_external /* second phase, second-stage loader */ 49505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} ram_mode; 49605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 49705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardstruct ram_poke_context { 49805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard libusb_device_handle *device; 49905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ram_mode mode; 50005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard size_t total, count; 50105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard}; 50205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 50305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard#define RETRY_LIMIT 5 50405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 50505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardstatic int ram_poke(void *context, uint32_t addr, bool external, 50605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard const unsigned char *data, size_t len) 50705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 50805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard struct ram_poke_context *ctx = (struct ram_poke_context*)context; 50905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int rc; 51005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard unsigned retry = 0; 51105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 51205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard switch (ctx->mode) { 51305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard case internal_only: /* CPU should be stopped */ 51405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (external) { 51505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("can't write %u bytes external memory at 0x%08x\n", 51605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard (unsigned)len, addr); 51705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -EINVAL; 51805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 51905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 52005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard case skip_internal: /* CPU must be running */ 52105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (!external) { 52205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose >= 2) { 52305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("SKIP on-chip RAM, %u bytes at 0x%08x\n", 52405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard (unsigned)len, addr); 52505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 52605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return 0; 52705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 52805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 52905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard case skip_external: /* CPU should be stopped */ 53005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (external) { 53105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose >= 2) { 53205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("SKIP external RAM, %u bytes at 0x%08x\n", 53305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard (unsigned)len, addr); 53405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 53505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return 0; 53605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 53705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 5389d50e95028c6cada096b821eb9872539efced402Ludovic Rousseau case _undef: 53905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard default: 54005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("bug\n"); 54105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -EDOM; 54205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 54305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 54405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx->total += len; 54505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx->count++; 54605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 54705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* Retry this till we get a real error. Control messages are not 54805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * NAKed (just dropped) so time out means is a real problem. 54905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 55005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard while ((rc = ezusb_write(ctx->device, 55105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard external ? "write external" : "write on-chip", 55205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard external ? RW_MEMORY : RW_INTERNAL, 55305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard addr, data, len)) < 0 55405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard && retry < RETRY_LIMIT) { 55505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (rc != LIBUSB_ERROR_TIMEOUT) 55605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 55705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard retry += 1; 55805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 55905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return rc; 56005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 56105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 56205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard/* 56377a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard * Load a Cypress Image file into target RAM. 56477a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard * See http://www.cypress.com/?docID=41351 (AN76405 PDF) for more info. 565b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan */ 566e78d37b2acbd804841e8206216a9ffad2112ebb2Ludovic Rousseaustatic int fx3_load_ram(libusb_device_handle *device, const char *path) 567b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan{ 568d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan uint32_t dCheckSum, dExpectedCheckSum, dAddress, i, dLen, dLength; 569d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan uint32_t* dImageBuf; 57077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard unsigned char *bBuf, hBuf[4], blBuf[4], rBuf[4096]; 571b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan FILE *image; 5723c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau int ret = 0; 573b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 574b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan image = fopen(path, "rb"); 575b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan if (image == NULL) { 5768aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard logerror("unable to open '%s' for input\n", path); 577b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan return -2; 578b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } else if (verbose) 579b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan logerror("open firmware image %s for RAM upload\n", path); 580b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 5818aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard // Read header 5828aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard if (fread(hBuf, sizeof(char), sizeof(hBuf), image) != sizeof(hBuf)) { 5838aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard logerror("could not read image header"); 5843c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 5853c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 586d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan } 5878aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard 5888aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard // check "CY" signature byte and format 5898aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard if ((hBuf[0] != 'C') || (hBuf[1] != 'Y')) { 5908aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard logerror("image doesn't have a CYpress signature\n"); 5913c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 5923c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 5938aa50632adb1dff6eacf5a78b998b8def29b4c38Pete Batard } 59477a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard 59577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard // Check bImageType 59677a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard switch(hBuf[3]) { 59777a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard case 0xB0: 59877a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (verbose) 59977a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("normal FW binary %s image with checksum\n", (hBuf[2]&0x01)?"data":"executable"); 60077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard break; 60177a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard case 0xB1: 60277a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("security binary image is not currently supported\n"); 6033c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 6043c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 60577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard case 0xB2: 60677a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("VID:PID image is not currently supported\n"); 6073c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 6083c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 60977a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard default: 61077a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("invalid image type 0x%02X\n", hBuf[3]); 6113c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 6123c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 61377a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard } 61477a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard 61577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard // Read the bootloader version 61677a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (verbose) { 61777a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if ((ezusb_read(device, "read bootloader version", RW_INTERNAL, 0xFFFF0020, blBuf, 4) < 0)) { 61877a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("Could not read bootloader version\n"); 6193c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -8; 6203c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 62177a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard } 62277a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("FX3 bootloader version: 0x%02X%02X%02X%02X\n", blBuf[3], blBuf[2], blBuf[1], blBuf[0]); 623b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 624b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 625b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dCheckSum = 0; 62677a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (verbose) 62777a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard logerror("writing image...\n"); 628b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan while (1) { 629d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan if ((fread(&dLength, sizeof(uint32_t), 1, image) != 1) || // read dLength 630d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan (fread(&dAddress, sizeof(uint32_t), 1, image) != 1)) { // read dAddress 631d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan logerror("could not read image"); 6323c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 6333c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 634d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan } 635b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan if (dLength == 0) 636b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan break; // done 637b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 638bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard // coverity[tainted_data] 639bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard dImageBuf = (uint32_t*)calloc(dLength, sizeof(uint32_t)); 640d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan if (dImageBuf == NULL) { 641d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan logerror("could not allocate buffer for image chunk\n"); 6423c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -4; 6433c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 644d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan } 645d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan 646b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan // read sections 647d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan if (fread(dImageBuf, sizeof(uint32_t), dLength, image) != dLength) { 648d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan logerror("could not read image"); 649d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan free(dImageBuf); 6503c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -3; 6513c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 652d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan } 653b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan for (i = 0; i < dLength; i++) 654b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dCheckSum += dImageBuf[i]; 655b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dLength <<= 2; // convert to Byte length 656b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan bBuf = (unsigned char*) dImageBuf; 657b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 658b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan while (dLength > 0) { 659b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dLen = 4096; // 4K max 660b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan if (dLen > dLength) 661b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dLen = dLength; 662d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan if ((ezusb_write(device, "write firmware", RW_INTERNAL, dAddress, bBuf, dLen) < 0) || 663d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan (ezusb_read(device, "read firmware", RW_INTERNAL, dAddress, rBuf, dLen) < 0)) { 664d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan logerror("R/W error\n"); 665d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan free(dImageBuf); 6663c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -5; 6673c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 668d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan } 669b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan // Verify data: rBuf with bBuf 670b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan for (i = 0; i < dLen; i++) { 671b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan if (rBuf[i] != bBuf[i]) { 672d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan logerror("verify error"); 673d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan free(dImageBuf); 6743c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -6; 6753c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 676b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 677b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 678b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 679b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dLength -= dLen; 680b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan bBuf += dLen; 681b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan dAddress += dLen; 682b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 683d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan free(dImageBuf); 684b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 685b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 686b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan // read pre-computed checksum data 687d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan if ((fread(&dExpectedCheckSum, sizeof(uint32_t), 1, image) != 1) || 688d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan (dCheckSum != dExpectedCheckSum)) { 689d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan logerror("checksum error\n"); 6903c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -7; 6913c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau goto exit; 692b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan } 693b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 694b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan // transfer execution to Program Entry 69577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard if (!ezusb_fx3_jump(device, dAddress)) { 6963c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau ret = -6; 697d345a1ed6bbef289b27862c3d0eff58d5ab76674Federico Manzan } 698b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 6993c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseauexit: 7003c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau fclose(image); 7013c2e79cacfa286c7e990d97ac233b28db255a774Ludovic Rousseau return ret; 702b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan} 703b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 704b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan/* 7051eff220474f63d7ea7f8f99bef2a3da9da5324ebhjelmn@cs.unm.edu * Load a firmware file into target RAM. device is the open libusb 70605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * device, and the path is the name of the source file. Open the file, 70705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * parse the bytes, and write them in one or two phases. 70805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 70905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * If stage == 0, this uses the first stage loader, built into EZ-USB 71005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * hardware but limited to writing on-chip memory or CPUCS. Everything 71105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * is written during one stage, unless there's an error such as the image 71205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * holding data that needs to be written to external memory. 71305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * 71405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * Otherwise, things are written in two stages. First the external 71505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * memory is written, expecting a second stage loader to have already 71605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard * been loaded. Then file is re-parsed and on-chip memory is written. 71705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard */ 71805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batardint ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage) 71905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard{ 72005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard FILE *image; 72105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint32_t cpucs_addr; 72205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard bool (*is_external)(uint32_t off, size_t len); 72305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard struct ram_poke_context ctx; 72405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard int status; 72505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard uint8_t iic_header[8] = { 0 }; 72628d5514e61ca7f7459c200b187b8cc3ebeda9274Ludovic Rousseau int ret = 0; 72705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 728b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan if (fx_type == FX_TYPE_FX3) 729b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan return fx3_load_ram(device, path); 730b74b7f7390690f631274b46ef2bbe7984d825eecFederico Manzan 73105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard image = fopen(path, "rb"); 73205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (image == NULL) { 73305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("%s: unable to open for input.\n", path); 73405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard return -2; 73577a37cba5493de44f042095d69aaa200d9ff5fd5Pete Batard } else if (verbose > 1) 73605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("open firmware image %s for RAM upload\n", path); 73705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 73805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (img_type == IMG_TYPE_IIC) { 73905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header)) 74005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard || (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2)) 74105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard || ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2)) 74205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard || ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) { 74305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("IIC image does not contain executable code - cannot load to RAM.\n"); 744e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau ret = -1; 745e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau goto exit; 74605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 74705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 74805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 74905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */ 75005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard switch(fx_type) { 75105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard case FX_TYPE_FX2LP: 75205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cpucs_addr = 0xe600; 75305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard is_external = fx2lp_is_external; 75405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 75505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard case FX_TYPE_FX2: 75605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cpucs_addr = 0xe600; 75705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard is_external = fx2_is_external; 75805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 75905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard default: 76005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard cpucs_addr = 0x7f92; 76105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard is_external = fx_is_external; 76205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard break; 76305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 76405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 76505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* use only first stage loader? */ 76605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (stage == 0) { 76705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx.mode = internal_only; 76805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 76905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* if required, halt the CPU while we overwrite its code/data */ 77005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false)) 771e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau { 772e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau ret = -1; 773e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau goto exit; 774e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau } 77505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 77605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* 2nd stage, first part? loader was already uploaded */ 77705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } else { 77805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx.mode = skip_internal; 77905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 78005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* let CPU run; overwrite the 2nd stage loader later */ 78105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose) 78205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("2nd stage: write external memory\n"); 78305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 78405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 78505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* scan the image, first (maybe only) time */ 78605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx.device = device; 78705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx.total = ctx.count = 0; 78805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard status = parse[img_type](image, &ctx, is_external, ram_poke); 78905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (status < 0) { 79005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("unable to upload %s\n", path); 791e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau ret = status; 792e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau goto exit; 79305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 79405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 79505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* second part of 2nd stage: rescan */ 79605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard // TODO: what should we do for non HEX images there? 79705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (stage) { 79805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard ctx.mode = skip_external; 79905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 80005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* if needed, halt the CPU while we overwrite the 1st stage loader */ 80105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false)) 802e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau { 803e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau ret = -1; 804e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau goto exit; 805e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau } 80605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 80705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* at least write the interrupt vectors (at 0x0000) for reset! */ 80805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard rewind(image); 80905975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (verbose) 81005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("2nd stage: write on-chip memory\n"); 81105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard status = parse_ihex(image, &ctx, is_external, ram_poke); 81205975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (status < 0) { 81305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("unable to completely upload %s\n", path); 814e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau ret = status; 815e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau goto exit; 81605975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 81705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard } 81805975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 819bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard if (verbose && (ctx.count != 0)) { 82005975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard logerror("... WROTE: %d bytes, %d segments, avg %d\n", 821bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard (int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count)); 822bcc4e517d5ce41e541484ade9b2800ba06a9b903Pete Batard } 82305975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 82405975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard /* if required, reset the CPU so it runs what we just uploaded */ 82505975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true)) 826e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau ret = -1; 82705975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard 828e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseauexit: 829e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau fclose(image); 830e2babf7ec295bde9d0b04fe1c325131dc6aacf51Ludovic Rousseau return ret; 83105975333c53d58a98b1e91f1edd220d794c7dd46Pete Batard} 832