Hi, Here is a patch, that provides support for the MSTAR ISP protocol.
Basically, among other chips, MSTAR manufactures SoCs that equip TV sets and computer screens, and it seems that all of their products use the same in-system programming protocol. Basically, they use the DDC channel of VGA or DVI connectors, which is actually an I2C bus, to encapsulate SPI frames (the flash chip is connected to the SoC through an SPI bus). I wrote this patch since the screen I bought had a software bug, and the manufacturer only released a new firmware binary, but no tool or instructions on flashing it. More details can be found here: http://boeglin.org/blog/index.php?entry=Flashing-a-BenQ-Z-series-for-free(dom) I only read code from Linux kernel archives published by Acer to figure out the protocol (for a touchscreen controller and a NFC chip, both by MSTAR, that shared the same ISP protocol), so I don't think there are any legal problems with it. Please let me know what you think about this patch, and whether you're interested in including it. Best regards, Alex -- Alexandre Boeglin email: alex (at) boeglin (dot) org jabber: alex (at) im (dot) boeglin (dot) org website: http://boeglin.org/
>From 5d7f9b766f59b4b567488fce21a70a6d967549c2 Mon Sep 17 00:00:00 2001 From: Alexandre Boeglin <[email protected]> Date: Tue, 29 Apr 2014 21:35:26 +0200 Subject: [PATCH] Add programmer for the MSTAR I2C ISP protocol --- Makefile | 13 ++++ flashrom.8.tmpl | 2 + flashrom.c | 12 +++ mstarddc_spi.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ programmer.h | 11 +++ 5 files changed, 275 insertions(+) create mode 100644 mstarddc_spi.c diff --git a/Makefile b/Makefile index 346d46a..d6e932e 100644 --- a/Makefile +++ b/Makefile @@ -280,6 +280,11 @@ UNSUPPORTED_FEATURES += CONFIG_LINUX_SPI=yes else override CONFIG_LINUX_SPI = no endif +ifeq ($(CONFIG_MSTARDDC_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_MSTARDDC_SPI=yes +else +override CONFIG_MSTARDDC_SPI = no +endif endif ############################################################################### @@ -390,6 +395,9 @@ CONFIG_FT2232_SPI ?= yes # Always enable Altera USB-Blaster dongles for now. CONFIG_USBBLASTER_SPI ?= yes +# Always enable MSTAR DDC for now. +CONFIG_MSTARDDC_SPI ?= yes + # Always enable dummy tracing for now. CONFIG_DUMMY ?= yes @@ -549,6 +557,11 @@ NEED_FTDI := yes PROGRAMMER_OBJS += usbblaster_spi.o endif +ifeq ($(CONFIG_MSTARDDC_SPI), yes) +FEATURE_CFLAGS += -D'CONFIG_MSTARDDC_SPI=1' +PROGRAMMER_OBJS += mstarddc_spi.o +endif + ifeq ($(NEED_FTDI), yes) FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'") diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 8d46ffe..fe0ac65 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -221,6 +221,8 @@ bitbanging adapter) .sp .BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)" .sp +.BR "* mstarddc_spi" " (for SPI flash ROMs accessible through DDC in MSTAR-equipped displays)" +.sp Some programmers have optional or mandatory parameters which are described in detail in the .B PROGRAMMER SPECIFIC INFO diff --git a/flashrom.c b/flashrom.c index 23728f6..ce0d760 100644 --- a/flashrom.c +++ b/flashrom.c @@ -321,6 +321,18 @@ const struct programmer_entry programmer_table[] = { }, #endif +#if CONFIG_MSTARDDC_SPI == 1 + { + .name = "mstarddc_spi", + .type = OTHER, + .devs.note = "Device files /dev/i2c-*\n", + .init = mstarddc_spi_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + {0}, /* This entry corresponds to PROGRAMMER_INVALID. */ }; diff --git a/mstarddc_spi.c b/mstarddc_spi.c new file mode 100644 index 0000000..34f58ad --- /dev/null +++ b/mstarddc_spi.c @@ -0,0 +1,237 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2014 Alexandre Boeglin <[email protected]> + * + * 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 + */ + +#if CONFIG_MSTARDDC_SPI == 1 + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <linux/i2c-dev.h> +#include <linux/i2c.h> +#include "flash.h" +#include "programmer.h" +#include "spi.h" + + +static const struct spi_programmer spi_programmer_mstarddc; + +static int mstarddc_fd; +static int mstarddc_addr; + +// MSTAR DDC Commands +#define MSTARDDC_SPI_WRITE 0x10 +#define MSTARDDC_SPI_READ 0x11 +#define MSTARDDC_SPI_END 0x12 +#define MSTARDDC_SPI_RESET 0x24 + +/* Returns 0 upon success, a negative number upon errors. */ +static int mstarddc_spi_shutdown(void *data) +{ + // Reset, disables ISP mode + uint8_t cmd = MSTARDDC_SPI_RESET; + if (write(mstarddc_fd, &cmd, 1) < 0) + { + int err = errno; + msg_perr("Error sending reset command: errno %d\n", err); + return -1; + } + + if (close(mstarddc_fd) < 0) + { + int err = errno; + msg_perr("Error closing device: errno %d\n", err); + return -1; + } + return 0; +} + +/* Returns 0 upon success, a negative number upon errors. */ +int mstarddc_spi_init(void) +{ + char *i2c_device; + char *i2c_address; + + // Get device, address from commandline + i2c_device = extract_programmer_param("dev"); + if (i2c_device && strlen(i2c_device)) + { + if ((i2c_address = strchr(i2c_device, ':'))) + { + *i2c_address = '\0'; + i2c_address++; + } + if (!i2c_address || !strlen(i2c_address)) + { + msg_perr("Error: no address specified.\n" + "Use flashrom -p mstarddc_spi:dev=/dev/device:address\n"); + return -1; + } + mstarddc_addr = strtol(i2c_address, NULL, 16); + } + else + { + msg_perr("Error: no device specified.\n" + "Use flashrom -p mstarddc_spi:dev=/dev/device:address\n"); + return -1; + } + msg_pinfo("Info: Will try to use device %s and address 0x%02x\n", i2c_device, mstarddc_addr); + + // Open device + if ((mstarddc_fd = open(i2c_device, O_RDWR)) < 0) + { + int err = errno; + switch (err) + { + case EACCES: + msg_perr("Error opening %s: Permission denied.\n" + "Please use sudo or run as root\n", i2c_device); + break; + case ENOENT: + msg_perr("Error opening %s: No such file.\n" + "Please check you specified the correct device\n", i2c_device); + break; + default: + msg_perr("Error opening %s: errno %d\n", i2c_device, err); + } + return -1; + } + + // Set slave address + if (ioctl(mstarddc_fd, I2C_SLAVE, mstarddc_addr) < 0) + { + int err = errno; + msg_perr("Error setting slave address 0x%02x: errno %d\n", mstarddc_addr, err); + return -1; + } + + // Enable ISP mode + uint8_t cmd[5] = {'M', 'S', 'T', 'A', 'R'}; + if (write(mstarddc_fd, cmd, 5) < 0) + { + int err = errno; + char end_cmd = MSTARDDC_SPI_END; + + // Assume device is already in ISP mode, try to send END command + if (write(mstarddc_fd, &end_cmd, 1) < 0) + { + msg_perr("Error enabling ISP mode: errno %d\n" + "Please check that device (%s) and address (0x%02x) are correct\n", + err, i2c_device, mstarddc_addr); + return -1; + } + } + + // Register shutdown function + register_shutdown(mstarddc_spi_shutdown, NULL); + + // Register programmer + register_spi_programmer(&spi_programmer_mstarddc); + return 0; +} + +/* Returns 0 upon success, a negative number upon errors. */ +static int mstarddc_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int ret = 0; + uint8_t *cmd; + static int count = 0; + + if (++count % 64 == 0) + // At 100kb/s, it's better to show the user something is still happening + msg_pinfo("."); + + if ((cmd = malloc((writecnt + 1) * sizeof(uint8_t))) < 0) + { + int err = errno; + msg_perr("Error allocating memory: errno %d\n", err); + ret = -1; + } + + if (!ret && writecnt) + { + cmd[0] = MSTARDDC_SPI_WRITE; + memcpy(cmd + 1, writearr, writecnt); + if (write(mstarddc_fd, cmd, writecnt + 1) < 0) + { + int err = errno; + msg_perr("Error sending write command: errno %d\n", err); + ret = -1; + } + } + + if (!ret && readcnt) + { + struct i2c_rdwr_ioctl_data i2c_data; + struct i2c_msg msg[2]; + + cmd[0] = MSTARDDC_SPI_READ; + i2c_data.nmsgs = 2; + i2c_data.msgs = msg; + i2c_data.msgs[0].addr = mstarddc_addr; + i2c_data.msgs[0].len = 1; + i2c_data.msgs[0].flags = 0; + i2c_data.msgs[0].buf = cmd; + i2c_data.msgs[1].addr = mstarddc_addr; + i2c_data.msgs[1].len = readcnt; + i2c_data.msgs[1].flags = I2C_M_RD; + i2c_data.msgs[1].buf = readarr; + + if (ioctl(mstarddc_fd, I2C_RDWR, &i2c_data) < 0) + { + int err = errno; + msg_perr("Error sending read command: errno %d\n", err); + ret = -1; + } + } + + if (!ret && (writecnt || readcnt)) + { + cmd[0] = MSTARDDC_SPI_END; + if (write(mstarddc_fd, cmd, 1) < 0) + { + int err = errno; + msg_perr("Error sending end command: errno %d\n", err); + ret = -1; + } + } + + return ret; +} + + +static const struct spi_programmer spi_programmer_mstarddc = { + .type = SPI_CONTROLLER_MSTARDDC, + .max_data_read = 256, + .max_data_write = 256, + .command = mstarddc_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, + .write_aai = default_spi_write_aai, +}; + +#endif diff --git a/programmer.h b/programmer.h index 4f4cc02..9aa2c8d 100644 --- a/programmer.h +++ b/programmer.h @@ -90,6 +90,9 @@ enum programmer { #if CONFIG_USBBLASTER_SPI == 1 PROGRAMMER_USBBLASTER_SPI, #endif +#if CONFIG_MSTARDDC_SPI == 1 + PROGRAMMER_MSTARDDC_SPI, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ }; @@ -446,6 +449,11 @@ int usbblaster_spi_init(void); extern const struct dev_entry devs_usbblasterspi[]; #endif +/* mstarddc_spi.c */ +#if CONFIG_MSTARDDC_SPI == 1 +int mstarddc_spi_init(void); +#endif + /* rayer_spi.c */ #if CONFIG_RAYER_SPI == 1 int rayer_spi_init(void); @@ -527,6 +535,9 @@ enum spi_controller { #if CONFIG_USBBLASTER_SPI == 1 SPI_CONTROLLER_USBBLASTER, #endif +#if CONFIG_MSTARDDC_SPI == 1 + SPI_CONTROLLER_MSTARDDC, +#endif }; #define MAX_DATA_UNSPECIFIED 0 -- 1.9.2
_______________________________________________ flashrom mailing list [email protected] http://www.flashrom.org/mailman/listinfo/flashrom
