diff --git a/README.md b/README.md index 6ccedd3..9997eb7 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,8 @@ That is, send the following packet: | 00 00 | +See ROM-BACKUP.txt for user-level instructions how to backup/restore +FlashROM of your device. Licensing --------- diff --git a/ROM-BACKUP.txt b/ROM-BACKUP.txt new file mode 100644 index 0000000..a6ab58b --- /dev/null +++ b/ROM-BACKUP.txt @@ -0,0 +1,41 @@ +Fernly doesn't require changing a firmware stored in FlashROM of +your device - it runs completely from RAM. You may still want +to backup the original firmware for various reasons. Following +gives a walkthru how to do this. + +1. Check out the latest flashrom HEAD: + +svn co http://code.coreboot.org/svn/flashrom/trunk flashrom + +Using latest HEAD is recommended, as it may have more chip definitions, +and there's less chance it won't recognize your FlashROM. + +2. Apply flashrom-fernvale.patch from fernly: + +patch -p0 + +Index: Makefile +=================================================================== +--- Makefile (revision 1897) ++++ Makefile (working copy) +@@ -272,6 +272,11 @@ + else + override CONFIG_BUSPIRATE_SPI = no + endif ++ifeq ($(CONFIG_FERNVALE_SPI), yes) ++UNSUPPORTED_FEATURES += CONFIG_FERNVALE_SPI=yes ++else ++override CONFIG_FERNVALE_SPI = no ++endif + ifeq ($(CONFIG_SERPROG), yes) + UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes + else +@@ -469,6 +474,9 @@ + # Always enable Bus Pirate SPI for now. + CONFIG_BUSPIRATE_SPI ?= yes + ++# Always enable Fernvale SPI, too ++CONFIG_FERNVALE_SPI ?= yes ++ + # Disable Dediprog SF100 until support is complete and tested. + CONFIG_DEDIPROG ?= no + +@@ -694,6 +702,12 @@ + NEED_SERIAL := yes + endif + ++ifeq ($(CONFIG_FERNVALE_SPI), yes) ++FEATURE_CFLAGS += -D'CONFIG_FERNVALE_SPI=1' ++PROGRAMMER_OBJS += fernvale_spi.o ++NEED_SERIAL := yes ++endif ++ + ifeq ($(CONFIG_DEDIPROG), yes) + FEATURE_CFLAGS += -D'CONFIG_DEDIPROG=1' + PROGRAMMER_OBJS += dediprog.o +Index: fernvale_spi.c +=================================================================== +--- fernvale_spi.c (revision 0) ++++ fernvale_spi.c (working copy) +@@ -0,0 +1,238 @@ ++/* ++ * This file is part of the flashrom project. ++ * ++ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger ++ * ++ * 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; version 2 of the License. ++ * ++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "flash.h" ++#include "programmer.h" ++#include "spi.h" ++ ++#define DEFAULT_DEV "/dev/fernvale" ++#define BAUDRATE B921600 ++ ++static struct { ++ int fd; ++} fernvale_data; ++ ++static int fernvale_spi_send_command(struct flashctx *flash, ++ unsigned int writecnt, unsigned int readcnt, ++ const unsigned char *writearr, ++ unsigned char *readarr); ++ ++static const struct spi_master spi_master_fernvale = { ++ .type = SPI_CONTROLLER_FERNVALE, ++ .max_data_read = 128, ++ .max_data_write = 128, ++ .command = fernvale_spi_send_command, ++ .multicommand = default_spi_send_multicommand, ++ .read = default_spi_read, ++ .write_256 = default_spi_write_256, ++ .write_aai = default_spi_write_aai, ++}; ++ ++static int fernvale_spi_shutdown(void *data) ++{ ++ const char cmd[] = { 0, 0 }; ++ ++ write(fernvale_data.fd, cmd, sizeof(cmd)); ++ ++ return 0; ++} ++ ++static int fernvale_spi_setserial(int serfd) ++{ ++ int ret; ++ struct termios t; ++ ++ ret = tcgetattr(serfd, &t); ++ if (-1 == ret) { ++ perror("Failed to get attributes"); ++ exit(1); ++ } ++ cfsetispeed(&t, BAUDRATE); ++ cfsetospeed(&t, BAUDRATE); ++ cfmakeraw(&t); ++ ret = tcsetattr(serfd, TCSANOW, &t); ++ if (-1 == ret) { ++ perror("Failed to set attributes"); ++ exit(1); ++ } ++ ++ return 0; ++} ++ ++int fernvale_spi_init(void) ++{ ++ struct spi_master mst = spi_master_fernvale; ++ char *dev; ++ ++ dev = extract_programmer_param("dev"); ++ if (dev && !strlen(dev)) { ++ free(dev); ++ dev = NULL; ++ } ++ if (!dev) ++ dev = DEFAULT_DEV; ++ ++ fernvale_data.fd = open(dev, O_RDWR); ++ if (fernvale_data.fd == -1) { ++ msg_perr("Unable to open serial device. " ++ "Use flashrom -p fernvale_spi:dev=/dev/ttyUSB0\n"); ++ return 1; ++ } ++ ++ fernvale_spi_setserial(fernvale_data.fd); ++ ++ const char cmd[] = "spi flashrom\n"; ++ char readback; ++ int ready_tries = 0; ++ write(fernvale_data.fd, cmd, strlen(cmd)); ++ ++ /* Look for "Ready" signal */ ++ do { ++ read(fernvale_data.fd, &readback, sizeof(readback)); ++ ready_tries++; ++ } while (readback != 0x05); ++ msg_gdbg("Found 'ready' signal after %d bytes\n", ready_tries); ++ ++ mst.data = &fernvale_data; ++ register_spi_master(&mst); ++ register_shutdown(fernvale_spi_shutdown, NULL); ++ ++ return 0; ++} ++ ++static int write_full(int fd, const void *bfr, int size) ++{ ++ int ret; ++ int left = size; ++ ++ while (left > 0) { ++ ret = write(fd, bfr, left); ++ if (ret == -1) { ++ if (errno == EAGAIN) ++ continue; ++ return ret; ++ } ++ ++ /* FD closed */ ++ if (!ret) ++ return -1; ++ ++ left -= ret; ++ bfr += ret; ++ } ++ return size; ++} ++ ++static int read_full(int fd, void *bfr, int size) ++{ ++ int ret; ++ int left = size; ++ ++ msg_gdbg(" Reading %d bytes:", size); ++ while (left > 0) { ++ ret = read(fd, bfr, 1); ++ if (ret == -1) { ++ if (errno == EAGAIN) ++ continue; ++ return ret; ++ } ++ msg_gdbg(" 0x%02x:", *((uint8_t *)bfr)); ++ ++ /* FD closed */ ++ if (!ret) ++ return -1; ++ ++ left -= ret; ++ bfr += ret; ++ } ++ return size; ++} ++ ++static int fernvale_spi_send_command(struct flashctx *flash, ++ unsigned int writecnt, unsigned int readcnt, ++ const unsigned char *writearr, ++ unsigned char *readarr) ++{ ++ uint8_t out_bytes = writecnt; ++ uint8_t in_bytes = readcnt; ++ int ret; ++ int fd = fernvale_data.fd; ++ int i; ++#if 1 ++ ret = write_full(fd, &out_bytes, sizeof(out_bytes)); ++ if (ret != sizeof(out_bytes)) ++ msg_perr("0: Wanted to write %d bytes, but got %d\n", ++ (int)sizeof(out_bytes), ret); ++ ++ ret = write_full(fd, &in_bytes, sizeof(in_bytes)); ++ if (ret != sizeof(in_bytes)) ++ msg_perr("1: Wanted to write %d bytes, but got %d\n", ++ (int)sizeof(in_bytes), ret); ++ ++ ret = write_full(fd, writearr, out_bytes); ++ if (ret != out_bytes) ++ msg_perr("0: Wanted to write %d bytes, but got %d\n", ++ out_bytes, ret); ++ ++ msg_gdbg(" Wrote %d bytes:", out_bytes); ++ for (i = 0; i < out_bytes; i++) ++ msg_gdbg(" %02x", writearr[i]); ++ msg_gdbg(" "); ++#else ++ uint8_t bfr[writecnt + 2]; ++ ++ bfr[0] = out_bytes; ++ bfr[1] = in_bytes; ++ memcpy(&bfr[2], writearr, out_bytes); ++ ++ ret = write_full(fd, bfr, sizeof(bfr)); ++ if (ret != sizeof(bfr)) ++ msg_perr("0: Wanted to write %d bytes, but got %d\n", ++ sizeof(bfr), ret); ++ ++ msg_gdbg(" Wrote %d bytes:", sizeof(bfr)); ++ for (i = 0; i < sizeof(bfr); i++) ++ msg_gdbg(" %02x", bfr[i]); ++ msg_gdbg(" "); ++#endif ++ ++ ret = read_full(fd, readarr, in_bytes); ++ if (ret != in_bytes) ++ msg_perr("3: Wanted to read %d bytes, but got %d\n", ++ in_bytes, ret); ++ ++ msg_gdbg(" Read %d bytes:", in_bytes); ++ for (i = 0; i < in_bytes; i++) ++ msg_gdbg(" %02x", readarr[i]); ++ msg_gdbg(" "); ++ ++ msg_gdbg("\n"); ++ ++ return 0; ++} +Index: flashrom.c +=================================================================== +--- flashrom.c (revision 1897) ++++ flashrom.c (working copy) +@@ -231,6 +231,19 @@ + }, + #endif + ++#if CONFIG_FERNVALE_SPI == 1 ++ { ++ .name = "fernvale_spi", ++ .type = OTHER, ++ /* FIXME */ ++ .devs.note = "Kosagi Fernvale\n", ++ .init = fernvale_spi_init, ++ .map_flash_region = fallback_map, ++ .unmap_flash_region = fallback_unmap, ++ .delay = internal_delay, ++ }, ++#endif ++ + #if CONFIG_DEDIPROG == 1 + { + .name = "dediprog", +Index: programmer.h +=================================================================== +--- programmer.h (revision 1897) ++++ programmer.h (working copy) +@@ -69,6 +69,9 @@ + #if CONFIG_BUSPIRATE_SPI == 1 + PROGRAMMER_BUSPIRATE_SPI, + #endif ++#if CONFIG_FERNVALE_SPI == 1 ++ PROGRAMMER_FERNVALE_SPI, ++#endif + #if CONFIG_DEDIPROG == 1 + PROGRAMMER_DEDIPROG, + #endif +@@ -506,6 +509,11 @@ + int buspirate_spi_init(void); + #endif + ++/* fernvale_spi.c */ ++#if CONFIG_FERNVALE_SPI == 1 ++int fernvale_spi_init(void); ++#endif ++ + /* linux_spi.c */ + #if CONFIG_LINUX_SPI == 1 + int linux_spi_init(void); +@@ -554,6 +562,9 @@ + #if CONFIG_BUSPIRATE_SPI == 1 + SPI_CONTROLLER_BUSPIRATE, + #endif ++#if CONFIG_FERNVALE_SPI == 1 ++ SPI_CONTROLLER_FERNVALE, ++#endif + #if CONFIG_DEDIPROG == 1 + SPI_CONTROLLER_DEDIPROG, + #endif