diff --git a/82802ab.c b/82802ab.c deleted file mode 100644 index 58d3467..0000000 --- a/82802ab.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * Datasheet: - * - Name: Intel 82802AB/82802AC Firmware Hub (FWH) - * - URL: http://www.intel.com/design/chipsets/datashts/290658.htm - * - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf - * - Order number: 290658-004 - */ - -#include -#include -#include "flash.h" - -// I need that Berkeley bit-map printer -void print_82802ab_status(uint8_t status) -{ - printf_debug("%s", status & 0x80 ? "Ready:" : "Busy:"); - printf_debug("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); - printf_debug("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); - printf_debug("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); - printf_debug("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); - printf_debug("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); - printf_debug("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); -} - -int probe_82802ab(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - /* Reset to get a clean state */ - chip_writeb(0xFF, bios); - programmer_delay(10); - - /* Enter ID mode */ - chip_writeb(0x90, bios); - programmer_delay(10); - - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - - /* Leave ID mode */ - chip_writeb(0xFF, bios); - - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 != flash->manufacture_id || id2 != flash->model_id) - return 0; - - map_flash_registers(flash); - - return 1; -} - -uint8_t wait_82802ab(chipaddr bios) -{ - uint8_t status; - - chip_writeb(0x70, bios); - if ((chip_readb(bios) & 0x80) == 0) { // it's busy - while ((chip_readb(bios) & 0x80) == 0) ; - } - - status = chip_readb(bios); - - /* Reset to get a clean state */ - chip_writeb(0xFF, bios); - - return status; -} - -int erase_82802ab_block(struct flashchip *flash, int offset) -{ - chipaddr bios = flash->virtual_memory + offset; - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t status; - - // clear status register - chip_writeb(0x50, bios); - - // clear write protect - chip_writeb(0, wrprotect); - - // now start it - chip_writeb(0x20, bios); - chip_writeb(0xd0, bios); - programmer_delay(10); - - // now let's see what the register is - status = wait_82802ab(flash->virtual_memory); - print_82802ab_status(status); - - if (check_erased_range(flash, offset, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("DONE BLOCK 0x%x\n", offset); - - return 0; -} - -int erase_82802ab(struct flashchip *flash) -{ - int i; - unsigned int total_size = flash->total_size * 1024; - - printf("total_size is %d; flash->page_size is %d\n", - total_size, flash->page_size); - for (i = 0; i < total_size; i += flash->page_size) - if (erase_82802ab_block(flash, i)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("DONE ERASE\n"); - - return 0; -} - -void write_page_82802ab(chipaddr bios, uint8_t *src, - chipaddr dst, int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - /* transfer data from source to destination */ - chip_writeb(0x40, dst); - chip_writeb(*src++, dst++); - wait_82802ab(bios); - } -} - -int write_82802ab(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - uint8_t *tmpbuf = malloc(page_size); - - if (!tmpbuf) { - printf("Could not allocate memory!\n"); - exit(1); - } - printf("Programming page: \n"); - for (i = 0; i < total_size / page_size; i++) { - printf - ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - printf("%04d at address: 0x%08x", i, i * page_size); - - /* Auto Skip Blocks, which already contain the desired data - * Faster, because we only write, what has changed - * More secure, because blocks, which are excluded - * (with the exclude or layout feature) - * or not erased and rewritten; their data is retained also in - * sudden power off situations - */ - chip_readn(tmpbuf, bios + i * page_size, page_size); - if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) { - printf("SKIPPED\n"); - continue; - } - - /* erase block by block and write block by block; this is the most secure way */ - if (erase_82802ab_block(flash, i * page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_82802ab(bios, buf + i * page_size, - bios + i * page_size, page_size); - } - printf("\n"); - free(tmpbuf); - - return 0; -} diff --git a/Makefile b/Makefile index ae06d7c..aad8393 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ INSTALL = install DIFF = diff PREFIX ?= /usr/local MANDIR ?= $(PREFIX)/share/man -CFLAGS ?= -Os -Wall -Werror +CFLAGS ?= -Os -Wall -Werror -Ilibflashrom/ EXPORTDIR ?= . OS_ARCH = $(shell uname) @@ -43,13 +43,17 @@ endif LIBS += -lpci -OBJS = chipset_enable.o board_enable.o udelay.o jedec.o stm50flw0x0x.o \ - sst28sf040.o am29f040b.o mx29f002.o m29f400bt.o pm29f002.o \ - w49f002u.o 82802ab.o pm49fl00x.o sst49lf040.o en29f002a.o \ - sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ - flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ - ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \ - pcidev.o print.o +OBJS = libflashrom/chipset_enable.o libflashrom/board_enable.o \ + libflashrom/jedec.o libflashrom/stm50flw0x0x.o libflashrom/sst28sf040.o \ + libflashrom/am29f040b.o libflashrom/mx29f002.o libflashrom/m29f400bt.o \ + libflashrom/pm29f002.o libflashrom/w49f002u.o libflashrom/82802ab.o \ + libflashrom/pm49fl00x.o libflashrom/sst49lf040.o libflashrom/en29f002a.o \ + libflashrom/sst49lfxxxc.o libflashrom/sst_fwhub.o libflashrom/flashchips.o \ + libflashrom/w39v080fa.o libflashrom/sharplhf00l04.o libflashrom/w29ee011.o \ + libflashrom/spi.o libflashrom/it87spi.o libflashrom/ichspi.o \ + libflashrom/w39v040c.o libflashrom/sb600spi.o libflashrom/wbsio_spi.o \ + libflashrom/m29f002.o libflashrom/internal.o libflashrom/pcidev.o \ + cli/print.o cli/udelay.o cli/cbtable.o cli/physmap.o cli/flashrom.o cli/layout.o all: pciutils features dep $(PROGRAM) @@ -97,7 +101,7 @@ CONFIG_PRINT_WIKI ?= no ifeq ($(CONFIG_SERPROG), yes) FEATURE_CFLAGS += -D'SERPROG_SUPPORT=1' -OBJS += serprog.o +OBJS += libflashrom/serprog.o ifeq ($(OS_ARCH), SunOS) LIBS += -lsocket endif @@ -105,22 +109,22 @@ endif ifeq ($(CONFIG_BITBANG_SPI), yes) FEATURE_CFLAGS += -D'BITBANG_SPI_SUPPORT=1' -OBJS += bitbang_spi.o +OBJS += libflashrom/bitbang_spi.o endif ifeq ($(CONFIG_NIC3COM), yes) FEATURE_CFLAGS += -D'NIC3COM_SUPPORT=1' -OBJS += nic3com.o +OBJS += libflashrom/nic3com.o endif ifeq ($(CONFIG_GFXNVIDIA), yes) FEATURE_CFLAGS += -D'GFXNVIDIA_SUPPORT=1' -OBJS += gfxnvidia.o +OBJS += libflashrom/gfxnvidia.o endif ifeq ($(CONFIG_SATASII), yes) FEATURE_CFLAGS += -D'SATASII_SUPPORT=1' -OBJS += satasii.o +OBJS += libflashrom/satasii.o endif FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") @@ -128,36 +132,36 @@ ifeq ($(CONFIG_FT2232SPI), yes) # This is a totally ugly hack. FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'FT2232_SPI_SUPPORT=1'") FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -OBJS += ft2232_spi.o +OBJS += libflashrom/ft2232_spi.o endif ifeq ($(CONFIG_DUMMY), yes) FEATURE_CFLAGS += -D'DUMMY_SUPPORT=1' -OBJS += dummyflasher.o +OBJS += libflashrom/dummyflasher.o endif ifeq ($(CONFIG_DRKAISER), yes) FEATURE_CFLAGS += -D'DRKAISER_SUPPORT=1' -OBJS += drkaiser.o +OBJS += libflashrom/drkaiser.o endif ifeq ($(CONFIG_BUSPIRATESPI), yes) FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1' -OBJS += buspirate_spi.o +OBJS += libflashrom/buspirate_spi.o endif # Ugly, but there's no elif/elseif. ifeq ($(CONFIG_SERPROG), yes) -OBJS += serial.o +OBJS += libflashrom/serial.o else ifeq ($(CONFIG_BUSPIRATESPI), yes) -OBJS += serial.o +OBJS += libflashrom/serial.o endif endif ifeq ($(CONFIG_PRINT_WIKI), yes) FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1' -OBJS += print_wiki.o +OBJS += cli/print_wiki.o endif # We could use PULLED_IN_LIBS, but that would be ugly. @@ -175,13 +179,13 @@ TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root -- $(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) -o $@ -c $< clean: - rm -f $(PROGRAM) *.o + rm -f $(PROGRAM) libflashrom/*.o cli/*.o distclean: clean rm -f .dependencies .features .libdeps dep: - @$(CC) $(CPPFLAGS) $(SVNDEF) -MM *.c > .dependencies + @$(CC) $(CPPFLAGS) $(SVNDEF) -MM libflashrom/*.c cli/*.c > .dependencies strip: $(PROGRAM) $(STRIP) $(STRIP_ARGS) $(PROGRAM) diff --git a/am29f040b.c b/am29f040b.c deleted file mode 100644 index 46a5ef4..0000000 --- a/am29f040b.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -/* FIMXE: check that the 2 second delay is really needed. - Use erase_sector_jedec if not? */ -static int erase_sector_29f040b(struct flashchip *flash, unsigned long address) -{ - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x80, bios + 0x555); - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x30, bios + address); - - programmer_delay(2 * 1000 * 1000); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios + address); - - if (check_erased_range(flash, address, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -/* FIXME: use write_sector_jedec? */ -static int write_sector_29f040b(chipaddr bios, uint8_t *src, chipaddr dst, - unsigned int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - if ((i & 0xfff) == 0xfff) - printf("0x%08lx", dst - bios); - - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0xA0, bios + 0x555); - chip_writeb(*src++, dst++); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios); - - if ((i & 0xfff) == 0xfff) - printf("\b\b\b\b\b\b\b\b\b\b"); - } - - return 0; -} - -int probe_29f040b(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x90, bios + 0x555); - - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - - chip_writeb(0xF0, bios); - - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} - -/* FIXME: use erase_chip_jedec? */ -int erase_29f040b(struct flashchip *flash) -{ - int total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory; - - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x80, bios + 0x555); - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x10, bios + 0x555); - - programmer_delay(10); - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, total_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int write_29f040b(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - printf("Programming page "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming */ - if (erase_sector_29f040b(flash, i * page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ - printf("%04d at address: ", i); - write_sector_29f040b(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - return 0; -} diff --git a/bitbang_spi.c b/bitbang_spi.c deleted file mode 100644 index abf5530..0000000 --- a/bitbang_spi.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 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 "flash.h" -#include "spi.h" - -/* Length of half a clock period in usecs */ -int bitbang_spi_half_period = 0; - -enum bitbang_spi_master bitbang_spi_master = BITBANG_SPI_INVALID; - -const struct bitbang_spi_master_entry bitbang_spi_master_table[] = { - {}, /* This entry corresponds to BITBANG_SPI_INVALID. */ -}; - -const int bitbang_spi_master_count = ARRAY_SIZE(bitbang_spi_master_table); - -void bitbang_spi_set_cs(int val) -{ - bitbang_spi_master_table[bitbang_spi_master].set_cs(val); -} - -void bitbang_spi_set_sck(int val) -{ - bitbang_spi_master_table[bitbang_spi_master].set_sck(val); -} - -void bitbang_spi_set_mosi(int val) -{ - bitbang_spi_master_table[bitbang_spi_master].set_mosi(val); -} - -int bitbang_spi_get_miso(void) -{ - return bitbang_spi_master_table[bitbang_spi_master].get_miso(); -} - -int bitbang_spi_init(void) -{ - bitbang_spi_set_cs(1); - bitbang_spi_set_sck(0); - buses_supported = CHIP_BUSTYPE_SPI; - return 0; -} - -uint8_t bitbang_spi_readwrite_byte(uint8_t val) -{ - uint8_t ret = 0; - int i; - - for (i = 7; i >= 0; i--) { - bitbang_spi_set_mosi((val >> i) & 1); - programmer_delay(bitbang_spi_half_period); - bitbang_spi_set_sck(1); - ret <<= 1; - ret |= bitbang_spi_get_miso(); - programmer_delay(bitbang_spi_half_period); - bitbang_spi_set_sck(0); - } - return ret; -} - -int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - static unsigned char *bufout = NULL; - static unsigned char *bufin = NULL; - static int oldbufsize = 0; - int bufsize; - int i; - - /* Arbitrary size limitation here. We're only constrained by memory. */ - if (writecnt > 65536 || readcnt > 65536) - return SPI_INVALID_LENGTH; - - bufsize = max(writecnt + readcnt, 260); - /* Never shrink. realloc() calls are expensive. */ - if (bufsize > oldbufsize) { - bufout = realloc(bufout, bufsize); - if (!bufout) { - fprintf(stderr, "Out of memory!\n"); - if (bufin) - free(bufin); - exit(1); - } - bufin = realloc(bufout, bufsize); - if (!bufin) { - fprintf(stderr, "Out of memory!\n"); - if (bufout) - free(bufout); - exit(1); - } - oldbufsize = bufsize; - } - - memcpy(bufout, writearr, writecnt); - /* Shift out 0x00 while reading data. */ - memset(bufout + writecnt, 0x00, readcnt); - /* Make sure any non-read data is 0xff. */ - memset(bufin + writecnt, 0xff, readcnt); - - bitbang_spi_set_cs(0); - for (i = 0; i < readcnt + writecnt; i++) { - bufin[i] = bitbang_spi_readwrite_byte(bufout[i]); - } - programmer_delay(bitbang_spi_half_period); - bitbang_spi_set_cs(1); - programmer_delay(bitbang_spi_half_period); - memcpy(readarr, bufin + writecnt, readcnt); - - return 0; -} - -int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - /* Maximum read length is unlimited, use 64k bytes. */ - return spi_read_chunked(flash, buf, start, len, 64 * 1024); -} - -int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf) -{ - int total_size = 1024 * flash->total_size; - int i; - - printf_debug("total_size is %d\n", total_size); - for (i = 0; i < total_size; i += 256) { - int l, r; - if (i + 256 <= total_size) - l = 256; - else - l = total_size - i; - - if ((r = spi_nbyte_program(i, &buf[i], l))) { - fprintf(stderr, "%s: write fail %d\n", __func__, r); - return 1; - } - - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - /* loop */; - } - - return 0; -} diff --git a/board_enable.c b/board_enable.c deleted file mode 100644 index 769b402..0000000 --- a/board_enable.c +++ /dev/null @@ -1,1326 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2005-2007 coresystems GmbH - * Copyright (C) 2006 Uwe Hermann - * Copyright (C) 2007-2009 Luc Verhaegen - * Copyright (C) 2007 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 - */ - -/* - * Contains the board specific flash enables. - */ - -#include -#include -#include "flash.h" - -/* - * Helper functions for many Winbond Super I/Os of the W836xx range. - */ -/* Enter extended functions */ -void w836xx_ext_enter(uint16_t port) -{ - OUTB(0x87, port); - OUTB(0x87, port); -} - -/* Leave extended functions */ -void w836xx_ext_leave(uint16_t port) -{ - OUTB(0xAA, port); -} - -/* Generic Super I/O helper functions */ -uint8_t sio_read(uint16_t port, uint8_t reg) -{ - OUTB(reg, port); - return INB(port + 1); -} - -void sio_write(uint16_t port, uint8_t reg, uint8_t data) -{ - OUTB(reg, port); - OUTB(data, port + 1); -} - -void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask) -{ - uint8_t tmp; - - OUTB(reg, port); - tmp = INB(port + 1) & ~mask; - OUTB(tmp | (data & mask), port + 1); -} - -/** - * Winbond W83627HF: Raise GPIO24. - * - * Suited for: - * - Agami Aruma - * - IWILL DK8-HTX - */ -static int w83627hf_gpio24_raise(uint16_t port, const char *name) -{ - w836xx_ext_enter(port); - - /* Is this the W83627HF? */ - if (sio_read(port, 0x20) != 0x52) { /* Super I/O device ID reg. */ - fprintf(stderr, "\nERROR: %s: W83627HF: Wrong ID: 0x%02X.\n", - name, sio_read(port, 0x20)); - w836xx_ext_leave(port); - return -1; - } - - /* PIN89S: WDTO/GP24 multiplex -> GPIO24 */ - sio_mask(port, 0x2B, 0x10, 0x10); - - /* Select logical device 8: GPIO port 2 */ - sio_write(port, 0x07, 0x08); - - sio_mask(port, 0x30, 0x01, 0x01); /* Activate logical device. */ - sio_mask(port, 0xF0, 0x00, 0x10); /* GPIO24 -> output */ - sio_mask(port, 0xF2, 0x00, 0x10); /* Clear GPIO24 inversion */ - sio_mask(port, 0xF1, 0x10, 0x10); /* Raise GPIO24 */ - - w836xx_ext_leave(port); - - return 0; -} - -static int w83627hf_gpio24_raise_2e(const char *name) -{ - return w83627hf_gpio24_raise(0x2e, name); -} - -/** - * Winbond W83627THF: GPIO 4, bit 4 - * - * Suited for: - * - MSI K8T Neo2-F - * - MSI K8N-NEO3 - */ -static int w83627thf_gpio4_4_raise(uint16_t port, const char *name) -{ - w836xx_ext_enter(port); - - /* Is this the W83627THF? */ - if (sio_read(port, 0x20) != 0x82) { /* Super I/O device ID reg. */ - fprintf(stderr, "\nERROR: %s: W83627THF: Wrong ID: 0x%02X.\n", - name, sio_read(port, 0x20)); - w836xx_ext_leave(port); - return -1; - } - - /* PINxxxxS: GPIO4/bit 4 multiplex -> GPIOXXX */ - - sio_write(port, 0x07, 0x09); /* Select LDN 9: GPIO port 4 */ - sio_mask(port, 0x30, 0x02, 0x02); /* Activate logical device. */ - sio_mask(port, 0xF4, 0x00, 0x10); /* GPIO4 bit 4 -> output */ - sio_mask(port, 0xF6, 0x00, 0x10); /* Clear GPIO4 bit 4 inversion */ - sio_mask(port, 0xF5, 0x10, 0x10); /* Raise GPIO4 bit 4 */ - - w836xx_ext_leave(port); - - return 0; -} - -static int w83627thf_gpio4_4_raise_2e(const char *name) -{ - return w83627thf_gpio4_4_raise(0x2e, name); -} - -static int w83627thf_gpio4_4_raise_4e(const char *name) -{ - return w83627thf_gpio4_4_raise(0x4e, name); -} - -/** - * w83627: Enable MEMW# and set ROM size to max. - */ -static void w836xx_memw_enable(uint16_t port) -{ - w836xx_ext_enter(port); - if (!(sio_read(port, 0x24) & 0x02)) { /* Flash ROM enabled? */ - /* Enable MEMW# and set ROM size select to max. (4M). */ - sio_mask(port, 0x24, 0x28, 0x28); - } - w836xx_ext_leave(port); -} - -/** - * Common routine for several VT823x based boards. - */ -static void vt823x_set_all_writes_to_lpc(struct pci_dev *dev) -{ - uint8_t val; - - /* All memory cycles, not just ROM ones, go to LPC. */ - val = pci_read_byte(dev, 0x59); - val &= ~0x80; - pci_write_byte(dev, 0x59, val); -} - -/** - * VT823x: Set one of the GPIO pins. - */ -static void vt823x_gpio_set(struct pci_dev *dev, uint8_t gpio, int raise) -{ - uint16_t base; - uint8_t val, bit, offset; - - if ((gpio >= 12) && (gpio <= 15)) { - /* GPIO12-15 -> output */ - val = pci_read_byte(dev, 0xE4); - val |= 0x10; - pci_write_byte(dev, 0xE4, val); - } else if (gpio == 9) { - /* GPIO9 -> Output */ - val = pci_read_byte(dev, 0xE4); - val |= 0x20; - pci_write_byte(dev, 0xE4, val); - } else if (gpio == 5) { - val = pci_read_byte(dev, 0xE4); - val |= 0x01; - pci_write_byte(dev, 0xE4, val); - } else { - fprintf(stderr, "\nERROR: " - "VT823x GPIO%02d is not implemented.\n", gpio); - return; - } - - /* We need the I/O Base Address for this board's flash enable. */ - base = pci_read_word(dev, 0x88) & 0xff80; - - offset = 0x4C + gpio / 8; - bit = 0x01 << (gpio % 8); - - val = INB(base + offset); - if (raise) - val |= bit; - else - val &= ~bit; - OUTB(val, base + offset); -} - -/** - * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs. - * - * We don't need to do this when using coreboot, GPIO15 is never lowered there. - */ -static int board_via_epia_m(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n"); - return -1; - } - - /* GPIO15 is connected to write protect. */ - vt823x_gpio_set(dev, 15, 1); - - return 0; -} - -/** - * Suited for: - * - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235 - * - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237. - */ -static int board_asus_a7v8x_mx(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ - if (!dev) - dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); - return -1; - } - - vt823x_set_all_writes_to_lpc(dev); - w836xx_memw_enable(0x2E); - - return 0; -} - -/** - * Suited for VIAs EPIA SP and EPIA CN. - */ -static int board_via_epia_sp(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3227); /* VT8237R ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n"); - return -1; - } - - vt823x_set_all_writes_to_lpc(dev); - - return 0; -} - -/** - * Suited for VIAs EPIA N & NL. - */ -static int board_via_epia_n(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3227); /* VT8237R ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n"); - return -1; - } - - /* All memory cycles, not just ROM ones, go to LPC */ - vt823x_set_all_writes_to_lpc(dev); - - /* GPIO9 -> output */ - vt823x_gpio_set(dev, 9, 1); - - return 0; -} - -/** - * Suited for: - * - EPoX EP-8K5A2: VIA KT333 + VT8235. - * - Albatron PM266A Pro: VIA P4M266A + VT8235. - * - Shuttle AK31 (all versions): VIA KT266 + VT8233. - */ -static int w836xx_memw_enable_2e(const char *name) -{ - w836xx_memw_enable(0x2E); - - return 0; -} - -/** - * Suited for ASUS P5A. - * - * This is rather nasty code, but there's no way to do this cleanly. - * We're basically talking to some unknown device on SMBus, my guess - * is that it is the Winbond W83781D that lives near the DIP BIOS. - */ -static int board_asus_p5a(const char *name) -{ - uint8_t tmp; - int i; - -#define ASUSP5A_LOOP 5000 - - OUTB(0x00, 0xE807); - OUTB(0xEF, 0xE803); - - OUTB(0xFF, 0xE800); - - for (i = 0; i < ASUSP5A_LOOP; i++) { - OUTB(0xE1, 0xFF); - if (INB(0xE800) & 0x04) - break; - } - - if (i == ASUSP5A_LOOP) { - printf("%s: Unable to contact device.\n", name); - return -1; - } - - OUTB(0x20, 0xE801); - OUTB(0x20, 0xE1); - - OUTB(0xFF, 0xE802); - - for (i = 0; i < ASUSP5A_LOOP; i++) { - tmp = INB(0xE800); - if (tmp & 0x70) - break; - } - - if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) { - printf("%s: failed to read device.\n", name); - return -1; - } - - tmp = INB(0xE804); - tmp &= ~0x02; - - OUTB(0x00, 0xE807); - OUTB(0xEE, 0xE803); - - OUTB(tmp, 0xE804); - - OUTB(0xFF, 0xE800); - OUTB(0xE1, 0xFF); - - OUTB(0x20, 0xE801); - OUTB(0x20, 0xE1); - - OUTB(0xFF, 0xE802); - - for (i = 0; i < ASUSP5A_LOOP; i++) { - tmp = INB(0xE800); - if (tmp & 0x70) - break; - } - - if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) { - printf("%s: failed to write to device.\n", name); - return -1; - } - - return 0; -} - -/* - * Set GPIO lines in the Broadcom HT-1000 southbridge. - * - * It's not a Super I/O but it uses the same index/data port method. - */ -static int board_hp_dl145_g3_enable(const char *name) -{ - /* GPIO 0 reg from PM regs */ - /* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */ - sio_mask(0xcd6, 0x44, 0x24, 0x24); - - return 0; -} - -static int board_ibm_x3455(const char *name) -{ - /* raise gpio13 */ - sio_mask(0xcd6, 0x45, 0x20, 0x20); - - return 0; -} - -/** - * Suited for Shuttle FN25 (SN25P): AMD S939 + Nvidia CK804 (nForce4). - */ -static int board_shuttle_fn25(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x10DE, 0x0050); /* NVIDIA CK804 ISA Bridge. */ - if (!dev) { - fprintf(stderr, - "\nERROR: NVIDIA nForce4 ISA bridge not found.\n"); - return -1; - } - - /* one of those bits seems to be connected to TBL#, but -ENOINFO. */ - pci_write_byte(dev, 0x92, 0); - - return 0; -} - -/** - * Very similar to AMD 8111 IO Hub. - */ -static int nvidia_mcp_gpio_set(int gpio, int raise) -{ - struct pci_dev *dev; - uint16_t base; - uint8_t tmp; - - if ((gpio < 0) || (gpio > 31)) { - fprintf(stderr, "\nERROR: unsupported GPIO: %d.\n", gpio); - return -1; - } - - dev = pci_dev_find_vendorclass(0x10DE, 0x0C05); - switch (dev->device_id) { - case 0x0030: /* CK804 */ - case 0x0050: /* MCP04 */ - case 0x0060: /* MCP2 */ - break; - default: - fprintf(stderr, "\nERROR: no nVidia SMBus controller found.\n"); - return -1; - } - - base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */ - base += 0xC0; - - tmp = INB(base + gpio); - tmp &= ~0x0F; /* null lower nibble */ - tmp |= 0x04; /* gpio -> output. */ - if (raise) - tmp |= 0x01; - OUTB(tmp, base + gpio); - - return 0; -} - -/** - * Suited for ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04. - */ -static int nvidia_mcp_gpio10_raise(const char *name) -{ - return nvidia_mcp_gpio_set(0x10, 1); -} - -/** - * Suited for the Gigabyte GA-K8N-SLI: CK804 southbridge. - */ -static int nvidia_mcp_gpio21_raise(const char *name) -{ - return nvidia_mcp_gpio_set(0x21, 0x01); -} - -/** - * Suited for EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2. - */ -static int nvidia_mcp_gpio31_raise(const char *name) -{ - return nvidia_mcp_gpio_set(0x31, 0x01); -} - -/** - * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards. - */ -static int board_epox_ep_bx3(const char *name) -{ - uint8_t tmp; - - /* Raise GPIO22. */ - tmp = INB(0x4036); - OUTB(tmp, 0xEB); - - tmp |= 0x40; - - OUTB(tmp, 0x4036); - OUTB(tmp, 0xEB); - - return 0; -} - -/** - * Suited for Artec Group DBE61 and DBE62. - */ -static int board_artecgroup_dbe6x(const char *name) -{ -#define DBE6x_MSR_DIVIL_BALL_OPTS 0x51400015 -#define DBE6x_PRI_BOOT_LOC_SHIFT (2) -#define DBE6x_BOOT_OP_LATCHED_SHIFT (8) -#define DBE6x_SEC_BOOT_LOC_SHIFT (10) -#define DBE6x_PRI_BOOT_LOC (3 << DBE6x_PRI_BOOT_LOC_SHIFT) -#define DBE6x_BOOT_OP_LATCHED (3 << DBE6x_BOOT_OP_LATCHED_SHIFT) -#define DBE6x_SEC_BOOT_LOC (3 << DBE6x_SEC_BOOT_LOC_SHIFT) -#define DBE6x_BOOT_LOC_FLASH (2) -#define DBE6x_BOOT_LOC_FWHUB (3) - - msr_t msr; - unsigned long boot_loc; - - /* Geode only has a single core */ - if (setup_cpu_msr(0)) - return -1; - - msr = rdmsr(DBE6x_MSR_DIVIL_BALL_OPTS); - - if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) == - (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT)) - boot_loc = DBE6x_BOOT_LOC_FWHUB; - else - boot_loc = DBE6x_BOOT_LOC_FLASH; - - msr.lo &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC); - msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) | - (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT)); - - wrmsr(DBE6x_MSR_DIVIL_BALL_OPTS, msr); - - cleanup_cpu_msr(); - - return 0; -} - -/** - * Set a GPIO line on a given intel ICH LPC controller. - */ -static int intel_ich_gpio_set(int gpio, int raise) -{ - /* table mapping the different intel ICH LPC chipsets. */ - static struct { - uint16_t id; - uint8_t base_reg; - uint32_t bank0; - uint32_t bank1; - uint32_t bank2; - } intel_ich_gpio_table[] = { - {0x2410, 0x58, 0x0FE30000, 0, 0}, /* 82801AA (ICH) */ - {0x2420, 0x58, 0x0FE30000, 0, 0}, /* 82801AB (ICH0) */ - {0x2440, 0x58, 0x1BFF391B, 0, 0}, /* 82801BA (ICH2) */ - {0x244C, 0x58, 0x1A23399B, 0, 0}, /* 82801BAM (ICH2M) */ - {0x2450, 0x58, 0x1BFF0000, 0, 0}, /* 82801E (C-ICH) */ - {0x2480, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801CA (ICH3-S) */ - {0x248C, 0x58, 0x1A230000, 0x00000FFF, 0}, /* 82801CAM (ICH3-M) */ - {0x24C0, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801DB/DBL (ICH4/ICH4-L) */ - {0x24CC, 0x58, 0x1A030000, 0x00000FFF, 0}, /* 82801DBM (ICH4-M) */ - {0x24D0, 0x58, 0x1BFF0000, 0x00030305, 0}, /* 82801EB/ER (ICH5/ICH5R) */ - {0x2640, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FB/FR (ICH6/ICH6R) */ - {0x2641, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FBM (ICH6M) */ - {0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GB/GR (ICH7 Family) */ - {0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GBM (ICH7-M) */ - {0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GHM (ICH7-M DH) */ - {0x2810, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HB/HR (ICH8/R) */ - {0x2811, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HBM (ICH8M-E) */ - {0x2812, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HH (ICH8DH) */ - {0x2814, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HO (ICH8DO) */ - {0x2815, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HEM (ICH8M) */ - {0x2912, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IH (ICH9DH) */ - {0x2914, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IO (ICH9DO) */ - {0x2916, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IR (ICH9R) */ - {0x2917, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IEM (ICH9M-E) */ - {0x2918, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IB (ICH9) */ - {0x2919, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IBM (ICH9M) */ - {0x3A14, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JDO (ICH10DO) */ - {0x3A16, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIR (ICH10R) */ - {0x3A18, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIB (ICH10) */ - {0x3A1A, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JD (ICH10D) */ - {0, 0, 0, 0, 0} /* end marker */ - }; - - struct pci_dev *dev; - uint16_t base; - uint32_t tmp; - int i, allowed; - - /* First, look for a known LPC bridge */ - for (dev = pacc->devices; dev; dev = dev->next) - if ((dev->vendor_id == 0x8086) && - (dev->device_class == 0x0601)) { /* ISA Bridge */ - /* Is this device in our list? */ - for (i = 0; intel_ich_gpio_table[i].id; i++) - if (dev->device_id == intel_ich_gpio_table[i].id) - break; - - if (intel_ich_gpio_table[i].id) - break; - } - - if (!dev) { - fprintf(stderr, "\nERROR: No Known Intel LPC Bridge found.\n"); - return -1; - } - - /* According to the datasheets, all intel ICHs have the gpio bar 5:1 - strapped to zero. From some mobile ich9 version on, this becomes - 6:1. The mask below catches all. */ - base = pci_read_word(dev, intel_ich_gpio_table[i].base_reg) & 0xFFC0; - - /* check whether the line is allowed */ - if (gpio < 32) - allowed = (intel_ich_gpio_table[i].bank0 >> gpio) & 0x01; - else if (gpio < 64) - allowed = (intel_ich_gpio_table[i].bank1 >> (gpio - 32)) & 0x01; - else - allowed = (intel_ich_gpio_table[i].bank2 >> (gpio - 64)) & 0x01; - - if (!allowed) { - fprintf(stderr, "\nERROR: This Intel LPC Bridge does not allow" - " setting GPIO%02d\n", gpio); - return -1; - } - - printf("\nIntel ICH LPC Bridge: %sing GPIO%02d.\n", - raise ? "Rais" : "Dropp", gpio); - - if (gpio < 32) { - /* Set line to GPIO */ - tmp = INL(base); - /* ICH/ICH0 multiplexes 27/28 on the line set. */ - if ((gpio == 28) && - ((dev->device_id == 0x2410) || (dev->device_id == 0x2420))) - tmp |= 1 << 27; - else - tmp |= 1 << gpio; - OUTL(tmp, base); - - /* As soon as we are talking to ICH8 and above, this register - decides whether we can set the gpio or not. */ - if (dev->device_id > 0x2800) { - tmp = INL(base); - if (!(tmp & (1 << gpio))) { - fprintf(stderr, "\nERROR: This Intel LPC Bridge" - " does not allow setting GPIO%02d\n", - gpio); - return -1; - } - } - - /* Set GPIO to OUTPUT */ - tmp = INL(base + 0x04); - tmp &= ~(1 << gpio); - OUTL(tmp, base + 0x04); - - /* Raise GPIO line */ - tmp = INL(base + 0x0C); - if (raise) - tmp |= 1 << gpio; - else - tmp &= ~(1 << gpio); - OUTL(tmp, base + 0x0C); - } else if (gpio < 64) { - gpio -= 32; - - /* Set line to GPIO */ - tmp = INL(base + 0x30); - tmp |= 1 << gpio; - OUTL(tmp, base + 0x30); - - /* As soon as we are talking to ICH8 and above, this register - decides whether we can set the gpio or not. */ - if (dev->device_id > 0x2800) { - tmp = INL(base + 30); - if (!(tmp & (1 << gpio))) { - fprintf(stderr, "\nERROR: This Intel LPC Bridge" - " does not allow setting GPIO%02d\n", - gpio + 32); - return -1; - } - } - - /* Set GPIO to OUTPUT */ - tmp = INL(base + 0x34); - tmp &= ~(1 << gpio); - OUTL(tmp, base + 0x34); - - /* Raise GPIO line */ - tmp = INL(base + 0x38); - if (raise) - tmp |= 1 << gpio; - else - tmp &= ~(1 << gpio); - OUTL(tmp, base + 0x38); - } else { - gpio -= 64; - - /* Set line to GPIO */ - tmp = INL(base + 0x40); - tmp |= 1 << gpio; - OUTL(tmp, base + 0x40); - - tmp = INL(base + 40); - if (!(tmp & (1 << gpio))) { - fprintf(stderr, "\nERROR: This Intel LPC Bridge does " - "not allow setting GPIO%02d\n", gpio + 64); - return -1; - } - - /* Set GPIO to OUTPUT */ - tmp = INL(base + 0x44); - tmp &= ~(1 << gpio); - OUTL(tmp, base + 0x44); - - /* Raise GPIO line */ - tmp = INL(base + 0x48); - if (raise) - tmp |= 1 << gpio; - else - tmp &= ~(1 << gpio); - OUTL(tmp, base + 0x48); - } - - return 0; -} - -/** - * Suited for Abit IP35: Intel P35 + ICH9R. - */ -static int intel_ich_gpio16_raise(const char *name) -{ - return intel_ich_gpio_set(16, 1); -} - -/** - * Suited for MSI MS-7046: LGA775 + 915P + ICH6. - */ -static int intel_ich_gpio19_raise(const char *name) -{ - return intel_ich_gpio_set(19, 1); -} - -/** - * Suited for: - * - Asus P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2. - * - Asus P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R. - */ -static int intel_ich_gpio21_raise(const char *name) -{ - return intel_ich_gpio_set(21, 1); -} - -/** - * Suited for ASUS P4B266: socket478 + intel 845D + ICH2. - */ -static int intel_ich_gpio22_raise(const char *name) -{ - return intel_ich_gpio_set(22, 1); -} - -/** - * Suited for: - * - Dell Poweredge 1850: Intel PPGA604 + E7520 + ICH5R. - * - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R. - */ -static int intel_ich_gpio23_raise(const char *name) -{ - return intel_ich_gpio_set(23, 1); -} - -/** - * Suited for Acorp 6A815EPD: socket 370 + intel 815 + ICH2. - */ -static int board_acorp_6a815epd(const char *name) -{ - int ret; - - /* Lower Blocks Lock -- pin 7 of PLCC32 */ - ret = intel_ich_gpio_set(22, 1); - if (!ret) /* Top Block Lock -- pin 8 of PLCC32 */ - ret = intel_ich_gpio_set(23, 1); - - return ret; -} - -/** - * Suited for Kontron 986LCD-M: socket478 + 915GM + ICH7R. - */ -static int board_kontron_986lcd_m(const char *name) -{ - int ret; - - ret = intel_ich_gpio_set(34, 1); /* #TBL */ - if (!ret) - ret = intel_ich_gpio_set(35, 1); /* #WP */ - - return ret; -} - -/** - * Suited for: - * - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF - * - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705 - * - * SIS950 superio probably requires the same flash write enable. - */ -static int it8705_rom_write_enable(const char *name) -{ - /* enter IT87xx conf mode */ - enter_conf_mode_ite(0x2e); - - /* select right flash chip */ - sio_mask(0x2e, 0x22, 0x80, 0x80); - - /* bit 3: flash chip write enable - * bit 7: map flash chip at 1MB-128K (why though? ignoring this.) - */ - sio_mask(0x2e, 0x24, 0x04, 0x04); - - /* exit IT87xx conf mode */ - exit_conf_mode_ite(0x2e); - - return 0; -} - -/** - * Suited for AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F. - */ -static int board_aopen_vkm400(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT8237 ISA bridge not found.\n"); - return -1; - } - - vt823x_set_all_writes_to_lpc(dev); - - return it8705_rom_write_enable(name); -} - -/** - * Winbond W83697HF Super I/O + VIA VT8235 southbridge - * - * Suited for: - * - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235 - * - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235 - */ -static int board_msi_kt4v(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); - return -1; - } - - vt823x_set_all_writes_to_lpc(dev); - - vt823x_gpio_set(dev, 12, 1); - w836xx_memw_enable(0x2E); - - return 0; -} - -/** - * Suited for Soyo SY-7VCA: Pro133A + VT82C686. - */ -static int board_soyo_sy_7vca(const char *name) -{ - struct pci_dev *dev; - uint32_t base; - uint8_t tmp; - - /* VT82C686 Power management */ - dev = pci_dev_find(0x1106, 0x3057); - if (!dev) { - fprintf(stderr, "\nERROR: VT82C686 PM device not found.\n"); - return -1; - } - - /* GPO0 output from PM IO base + 0x4C */ - tmp = pci_read_byte(dev, 0x54); - tmp &= ~0x03; - pci_write_byte(dev, 0x54, tmp); - - /* PM IO base */ - base = pci_read_long(dev, 0x48) & 0x0000FF00; - - /* Drop GPO0 */ - tmp = INB(base + 0x4C); - tmp &= ~0x01; - OUTB(tmp, base + 0x4C); - - return 0; -} - -static int it8705f_write_enable(uint8_t port, const char *name) -{ - enter_conf_mode_ite(port); - sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */ - exit_conf_mode_ite(port); - - return 0; -} - -/** - * Suited for: - * - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F - * - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F - */ -static int it8705f_write_enable_2e(const char *name) -{ - return it8705f_write_enable(0x2e, name); -} - -/** - * Find the runtime registers of an SMSC Super I/O, after verifying its - * chip ID. - * - * Returns the base port of the runtime register block, or 0 on error. - */ -static uint16_t smsc_find_runtime(uint16_t sio_port, uint16_t chip_id, - uint8_t logical_device) -{ - uint16_t rt_port = 0; - - /* Verify the chip ID. */ - OUTB(0x55, sio_port); /* Enable configuration. */ - if (sio_read(sio_port, 0x20) != chip_id) { - fprintf(stderr, "\nERROR: SMSC Super I/O not found.\n"); - goto out; - } - - /* If the runtime block is active, get its address. */ - sio_write(sio_port, 0x07, logical_device); - if (sio_read(sio_port, 0x30) & 1) { - rt_port = (sio_read(sio_port, 0x60) << 8) - | sio_read(sio_port, 0x61); - } - - if (rt_port == 0) { - fprintf(stderr, "\nERROR: " - "Super I/O runtime interface not available.\n"); - } -out: - OUTB(0xaa, sio_port); /* Disable configuration. */ - return rt_port; -} - -/** - * Disable write protection on the Mitac 6513WU. WP# on the FWH is - * connected to GP30 on the Super I/O, and TBL# is always high. - */ -static int board_mitac_6513wu(const char *name) -{ - struct pci_dev *dev; - uint16_t rt_port; - uint8_t val; - - dev = pci_dev_find(0x8086, 0x2410); /* Intel 82801AA ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: Intel 82801AA ISA bridge not found.\n"); - return -1; - } - - rt_port = smsc_find_runtime(0x4e, 0x54 /* LPC47U33x */, 0xa); - if (rt_port == 0) - return -1; - - /* Configure the GPIO pin. */ - val = INB(rt_port + 0x33); /* GP30 config */ - val &= ~0x87; /* Output, non-inverted, GPIO, push/pull */ - OUTB(val, rt_port + 0x33); - - /* Disable write protection. */ - val = INB(rt_port + 0x4d); /* GP3 values */ - val |= 0x01; /* Set GP30 high. */ - OUTB(val, rt_port + 0x4d); - - return 0; -} - -/** - * Suited for Asus A7V8X: VIA KT400 + VT8235 + IT8703F-A - */ -static int board_asus_a7v8x(const char *name) -{ - uint16_t id, base; - uint8_t tmp; - - /* find the IT8703F */ - w836xx_ext_enter(0x2E); - id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21); - w836xx_ext_leave(0x2E); - - if (id != 0x8701) { - fprintf(stderr, "\nERROR: IT8703F SuperIO not found.\n"); - return -1; - } - - /* Get the GP567 IO base */ - w836xx_ext_enter(0x2E); - sio_write(0x2E, 0x07, 0x0C); - base = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61); - w836xx_ext_leave(0x2E); - - if (!base) { - fprintf(stderr, "\nERROR: Failed to read IT8703F SuperIO GPIO" - " Base.\n"); - return -1; - } - - /* Raise GP51. */ - tmp = INB(base); - tmp |= 0x02; - OUTB(tmp, base); - - return 0; -} - -/* - * General routine for raising/dropping GPIO lines on the ITE IT8712F. - * There is only some limited checking on the port numbers. - */ -static int -it8712f_gpio_set(unsigned int line, int raise) -{ - unsigned int port; - uint16_t id, base; - uint8_t tmp; - - port = line / 10; - port--; - line %= 10; - - /* Check line */ - if ((port > 4) || /* also catches unsigned -1 */ - ((port < 4) && (line > 7)) || ((port == 4) && (line > 5))) { - fprintf(stderr, - "\nERROR: Unsupported IT8712F GPIO Line %02d.\n", line); - return -1; - } - - /* find the IT8712F */ - enter_conf_mode_ite(0x2E); - id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21); - exit_conf_mode_ite(0x2E); - - if (id != 0x8712) { - fprintf(stderr, "\nERROR: IT8712F SuperIO not found.\n"); - return -1; - } - - /* Get the GPIO base */ - enter_conf_mode_ite(0x2E); - sio_write(0x2E, 0x07, 0x07); - base = (sio_read(0x2E, 0x62) << 8) | sio_read(0x2E, 0x63); - exit_conf_mode_ite(0x2E); - - if (!base) { - fprintf(stderr, "\nERROR: Failed to read IT8712F SuperIO GPIO" - " Base.\n"); - return -1; - } - - /* set GPIO. */ - tmp = INB(base + port); - if (raise) - tmp |= 1 << line; - else - tmp &= ~(1 << line); - OUTB(tmp, base + port); - - return 0; -} - -/** - * Suited for Asus A7V600-X: VIA KT600 + VT8237 + IT8712F - */ -static int board_asus_a7v600x(const char *name) -{ - return it8712f_gpio_set(32, 1); -} - -/** - * Suited for Asus M2V-MX: VIA K8M890 + VT8237A + IT8716F - */ -static int board_asus_m2v_mx(const char *name) -{ - struct pci_dev *dev; - - dev = pci_dev_find(0x1106, 0x3337); /* VT8237A ISA bridge */ - if (!dev) { - fprintf(stderr, "\nERROR: VT8237A ISA bridge not found.\n"); - return -1; - } - - /* GPO5 is connected to WP# and TBL#. */ - vt823x_gpio_set(dev, 5, 1); - - return 0; -} - - -/** - * Below is the list of boards which need a special "board enable" code in - * flashrom before their ROM chip can be accessed/written to. - * - * NOTE: Please add boards that _don't_ need such enables or don't work yet - * to the respective tables in print.c. Thanks! - * - * We use 2 sets of IDs here, you're free to choose which is which. This - * is to provide a very high degree of certainty when matching a board on - * the basis of subsystem/card IDs. As not every vendor handles - * subsystem/card IDs in a sane manner. - * - * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs - * NULLed if they don't identify the board fully. But please take care to - * provide an as complete set of pci ids as possible; autodetection is the - * preferred behaviour and we would like to make sure that matches are unique. - * - * The coreboot ids are used two fold. When running with a coreboot firmware, - * the ids uniquely matches the coreboot board identification string. When a - * legacy bios is installed and when autodetection is not possible, these ids - * can be used to identify the board through the -m command line argument. - * - * When a board is identified through its coreboot ids (in both cases), the - * main pci ids are still required to match, as a safeguard. - */ - -/* Please keep this list alphabetically ordered by vendor/board name. */ -struct board_pciid_enable board_pciid_enables[] = { - /* first pci-id set [4], second pci-id set [4], coreboot id [2], vendor name board name flash enable */ - {0x8086, 0x2926, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, "Abit", "IP35", intel_ich_gpio16_raise}, - {0x105a, 0x0d30, 0x105a, 0x4d33, 0x8086, 0x1130, 0x8086, 0, NULL, NULL, "Acorp", "6A815EPD", board_acorp_6a815epd}, - {0x8086, 0x24D4, 0x1849, 0x24D0, 0x8086, 0x24D5, 0x1849, 0x9739, NULL, NULL, "ASRock", "P4i65GV", intel_ich_gpio23_raise}, - {0x1022, 0x746B, 0, 0, 0, 0, 0, 0, "AGAMI", "ARUMA", "agami", "Aruma", w83627hf_gpio24_raise_2e}, - {0x1106, 0x3177, 0x17F2, 0x3177, 0x1106, 0x3148, 0x17F2, 0x3148, NULL, NULL, "Albatron", "PM266A", w836xx_memw_enable_2e}, - {0x1106, 0x3205, 0x1106, 0x3205, 0x10EC, 0x8139, 0xA0A0, 0x0477, NULL, NULL, "AOpen", "vKM400Am-S", board_aopen_vkm400}, - {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, "artecgroup", "dbe61", "Artec Group", "DBE61", board_artecgroup_dbe6x}, - {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, "artecgroup", "dbe62", "Artec Group", "DBE62", board_artecgroup_dbe6x}, - {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, "ASUS", "A7V600-X", board_asus_a7v600x}, - {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, "ASUS", "A7V8X", board_asus_a7v8x}, - {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, "ASUS", "A7V8X-MX SE", board_asus_a7v8x_mx}, - {0x1106, 0x1336, 0x1043, 0x80ed, 0x1106, 0x3288, 0x1043, 0x8249, NULL, NULL, "ASUS", "M2V-MX", board_asus_m2v_mx}, - {0x8086, 0x1a30, 0x1043, 0x8070, 0x8086, 0x244b, 0x1043, 0x8028, NULL, NULL, "ASUS", "P4B266", intel_ich_gpio22_raise}, - {0x8086, 0x1A30, 0x1043, 0x8025, 0x8086, 0x244B, 0x104D, 0x80F0, NULL, NULL, "ASUS", "P4B266-LM", intel_ich_gpio21_raise}, - {0x8086, 0x2570, 0x1043, 0x80F2, 0x105A, 0x3373, 0x1043, 0x80F5, NULL, NULL, "ASUS", "P4P800-E Deluxe", intel_ich_gpio21_raise}, - {0x10B9, 0x1541, 0, 0, 0x10B9, 0x1533, 0, 0, "asus", "p5a", "ASUS", "P5A", board_asus_p5a}, - {0x10DE, 0x0030, 0x1043, 0x818a, 0x8086, 0x100E, 0x1043, 0x80EE, NULL, NULL, "ASUS", "P5ND2-SLI Deluxe", nvidia_mcp_gpio10_raise}, - {0x1106, 0x3149, 0x1565, 0x3206, 0x1106, 0x3344, 0x1565, 0x1202, NULL, NULL, "Biostar", "P4M80-M4", it8705_rom_write_enable}, - {0x8086, 0x3590, 0x1028, 0x016c, 0x1000, 0x0030, 0x1028, 0x016c, NULL, NULL, "Dell", "PowerEdge 1850", intel_ich_gpio23_raise}, - {0x1106, 0x3038, 0x1019, 0x0996, 0x1106, 0x3177, 0x1019, 0x0996, NULL, NULL, "Elitegroup", "K7VTA3", it8705f_write_enable_2e}, - {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3059, 0x1695, 0x3005, NULL, NULL, "EPoX", "EP-8K5A2", w836xx_memw_enable_2e}, - {0x10EC, 0x8139, 0x1695, 0x9001, 0x11C1, 0x5811, 0x1695, 0x9015, NULL, NULL, "EPoX", "EP-8RDA3+", nvidia_mcp_gpio31_raise}, - {0x8086, 0x7110, 0, 0, 0x8086, 0x7190, 0, 0, "epox", "ep-bx3", "EPoX", "EP-BX3", board_epox_ep_bx3}, - {0x1039, 0x0761, 0, 0, 0x10EC, 0x8168, 0, 0, "gigabyte", "2761gxdk", "GIGABYTE", "GA-2761GXDK", it87xx_probe_spi_flash}, - {0x1106, 0x3227, 0x1458, 0x5001, 0x10ec, 0x8139, 0x1458, 0xe000, NULL, NULL, "GIGABYTE", "GA-7VT600", it8705_rom_write_enable}, - {0x10DE, 0x0050, 0x1458, 0x0C11, 0x10DE, 0x005e, 0x1458, 0x5000, NULL, NULL, "GIGABYTE", "GA-K8N-SLI", nvidia_mcp_gpio21_raise}, - {0x10DE, 0x0360, 0x1458, 0x0C11, 0x10DE, 0x0369, 0x1458, 0x5001, "gigabyte", "m57sli", "GIGABYTE", "GA-M57SLI-S4", it87xx_probe_spi_flash}, - {0x10de, 0x03e0, 0, 0, 0x10DE, 0x03D0, 0, 0, NULL, NULL, "GIGABYTE", "GA-M61P-S3", it87xx_probe_spi_flash}, - {0x1002, 0x4398, 0x1458, 0x5004, 0x1002, 0x4391, 0x1458, 0xb000, NULL, NULL, "GIGABYTE", "GA-MA78G-DS3H", it87xx_probe_spi_flash}, - {0x1002, 0x4398, 0x1458, 0x5004, 0x1002, 0x4391, 0x1458, 0xb002, NULL, NULL, "GIGABYTE", "GA-MA78GM-S2H", it87xx_probe_spi_flash}, - {0x1002, 0x438d, 0x1458, 0x5001, 0x1002, 0x5956, 0x1002, 0x5956, NULL, NULL, "GIGABYTE", "GA-MA790FX-DQ6", it87xx_probe_spi_flash}, - {0x1166, 0x0223, 0x103c, 0x320d, 0x102b, 0x0522, 0x103c, 0x31fa, "hp", "dl145_g3", "HP", "DL145 G3", board_hp_dl145_g3_enable}, - {0x1166, 0x0205, 0x1014, 0x0347, 0x1002, 0x515E, 0x1014, 0x0325, NULL, NULL, "IBM", "x3455", board_ibm_x3455}, - {0x1039, 0x5513, 0x8086, 0xd61f, 0x1039, 0x6330, 0x8086, 0xd61f, NULL, NULL, "Intel", "D201GLY", wbsio_check_for_spi}, - {0x1022, 0x7468, 0, 0, 0, 0, 0, 0, "iwill", "dk8_htx", "IWILL", "DK8-HTX", w83627hf_gpio24_raise_2e}, - {0x8086, 0x27A0, 0, 0, 0x8086, 0x27b8, 0, 0, "kontron", "986lcd-m", "Kontron", "986LCD-M", board_kontron_986lcd_m}, - {0x8086, 0x2411, 0x8086, 0x2411, 0x8086, 0x7125, 0x0e11, 0xb165, NULL, NULL, "Mitac", "6513WU", board_mitac_6513wu}, - {0x13f6, 0x0111, 0x1462, 0x5900, 0x1106, 0x3177, 0x1106, 0, NULL, NULL, "MSI", "MS-6590 (KT4 Ultra)",board_msi_kt4v}, - {0x1106, 0x3149, 0x1462, 0x7094, 0x10ec, 0x8167, 0x1462, 0x094c, NULL, NULL, "MSI", "MS-6702E (K8T Neo2-F)",w83627thf_gpio4_4_raise_2e}, - {0x1106, 0x0571, 0x1462, 0x7120, 0x1106, 0x3065, 0x1462, 0x7120, NULL, NULL, "MSI", "MS-6712 (KT4V)", board_msi_kt4v}, - {0x8086, 0x2658, 0x1462, 0x7046, 0x1106, 0x3044, 0x1462, 0x046d, NULL, NULL, "MSI", "MS-7046", intel_ich_gpio19_raise}, - {0x10DE, 0x005E, 0x1462, 0x7135, 0x10DE, 0x0050, 0x1462, 0x7135, "msi", "k8n-neo3", "MSI", "MS-7135 (K8N Neo3)", w83627thf_gpio4_4_raise_4e}, - {0x1106, 0x3099, 0, 0, 0x1106, 0x3074, 0, 0, "shuttle", "ak31", "Shuttle", "AK31", w836xx_memw_enable_2e}, - {0x1106, 0x3104, 0x1297, 0xa238, 0x1106, 0x3059, 0x1297, 0xc063, NULL, NULL, "Shuttle", "AK38N", it8705f_write_enable_2e}, - {0x10DE, 0x0050, 0x1297, 0x5036, 0x1412, 0x1724, 0x1297, 0x5036, NULL, NULL, "Shuttle", "FN25", board_shuttle_fn25}, - {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x3058, 0x15DD, 0x7609, NULL, NULL, "Soyo", "SY-7VCA", board_soyo_sy_7vca}, - {0x8086, 0x1076, 0x8086, 0x1176, 0x1106, 0x3059, 0x10f1, 0x2498, NULL, NULL, "Tyan", "S2498 (Tomcat K7M)", board_asus_a7v8x_mx}, - {0x1106, 0x0314, 0x1106, 0xaa08, 0x1106, 0x3227, 0x1106, 0xAA08, NULL, NULL, "VIA", "EPIA-CN", board_via_epia_sp}, - {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, "VIA", "EPIA M/MII/...", board_via_epia_m}, - {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, NULL, NULL, "VIA", "EPIA-N/NL", board_via_epia_n}, - {0x1106, 0x3227, 0x1106, 0xAA01, 0x1106, 0x0259, 0x1106, 0xAA01, NULL, NULL, "VIA", "EPIA SP", board_via_epia_sp}, - {0x1106, 0x5337, 0x1458, 0xb003, 0x1106, 0x287e, 0x1106, 0x337e, NULL, NULL, "VIA", "PC3500G", it87xx_probe_spi_flash}, - - { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}, /* end marker */ -}; - -/** - * Match boards on coreboot table gathered vendor and part name. - * Require main PCI IDs to match too as extra safety. - */ -static struct board_pciid_enable *board_match_coreboot_name(const char *vendor, - const char *part) -{ - struct board_pciid_enable *board = board_pciid_enables; - struct board_pciid_enable *partmatch = NULL; - - for (; board->vendor_name; board++) { - if (vendor && (!board->lb_vendor - || strcasecmp(board->lb_vendor, vendor))) - continue; - - if (!board->lb_part || strcasecmp(board->lb_part, part)) - continue; - - if (!pci_dev_find(board->first_vendor, board->first_device)) - continue; - - if (board->second_vendor && - !pci_dev_find(board->second_vendor, board->second_device)) - continue; - - if (vendor) - return board; - - if (partmatch) { - /* a second entry has a matching part name */ - printf("AMBIGUOUS BOARD NAME: %s\n", part); - printf("At least vendors '%s' and '%s' match.\n", - partmatch->lb_vendor, board->lb_vendor); - printf("Please use the full -m vendor:part syntax.\n"); - return NULL; - } - partmatch = board; - } - - if (partmatch) - return partmatch; - - if (!partvendor_from_cbtable) { - /* Only warn if the mainboard type was not gathered from the - * coreboot table. If it was, the coreboot implementor is - * expected to fix flashrom, too. - */ - printf("\nUnknown vendor:board from -m option: %s:%s\n\n", - vendor, part); - } - return NULL; -} - -/** - * Match boards on PCI IDs and subsystem IDs. - * Second set of IDs can be main only or missing completely. - */ -static struct board_pciid_enable *board_match_pci_card_ids(void) -{ - struct board_pciid_enable *board = board_pciid_enables; - - for (; board->vendor_name; board++) { - if (!board->first_card_vendor || !board->first_card_device) - continue; - - if (!pci_card_find(board->first_vendor, board->first_device, - board->first_card_vendor, - board->first_card_device)) - continue; - - if (board->second_vendor) { - if (board->second_card_vendor) { - if (!pci_card_find(board->second_vendor, - board->second_device, - board->second_card_vendor, - board->second_card_device)) - continue; - } else { - if (!pci_dev_find(board->second_vendor, - board->second_device)) - continue; - } - } - - return board; - } - - return NULL; -} - -int board_flash_enable(const char *vendor, const char *part) -{ - struct board_pciid_enable *board = NULL; - int ret = 0; - - if (part) - board = board_match_coreboot_name(vendor, part); - - if (!board) - board = board_match_pci_card_ids(); - - if (board) { - printf("Disabling flash write protection for board \"%s %s\"... ", - board->vendor_name, board->board_name); - - ret = board->enable(board->vendor_name); - if (ret) - printf("FAILED!\n"); - else - printf("OK.\n"); - } - - return ret; -} diff --git a/buspirate_spi.c b/buspirate_spi.c deleted file mode 100644 index a1c8265..0000000 --- a/buspirate_spi.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 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 "flash.h" -#include "spi.h" - -/* Change this to #define if you want to test without a serial implementation */ -#undef FAKE_COMMUNICATION - -#ifndef FAKE_COMMUNICATION -int buspirate_serialport_setup(char *dev) -{ - /* 115200bps, 8 databits, no parity, 1 stopbit */ - sp_fd = sp_openserport(dev, 115200); - return 0; -} - -int buspirate_serialport_shutdown(void) -{ - close(sp_fd); - return 0; -} - -int serialport_write(unsigned char *buf, unsigned int writecnt) -{ - int tmp = 0; - - while (tmp != writecnt) { - tmp = write(sp_fd, buf + tmp, writecnt - tmp); - if (tmp == -1) - return 1; - if (!tmp) - printf_debug("Empty write\n"); - } - - return 0; -} - -int serialport_read(unsigned char *buf, unsigned int readcnt) -{ - int tmp = 0; - - while (tmp != readcnt) { - tmp = read(sp_fd, buf + tmp, readcnt - tmp); - if (tmp == -1) - return 1; - if (!tmp) - printf_debug("Empty read\n"); - } - - return 0; -} - -int buspirate_discard_read(void) -{ - int flags; - - printf_debug("%s\n", __func__); - flags = fcntl(sp_fd, F_GETFL); - flags |= O_NONBLOCK; - fcntl(sp_fd, F_SETFL, flags); - sp_flush_incoming(); - flags &= ~O_NONBLOCK; - fcntl(sp_fd, F_SETFL, flags); - - return 0; -} -#else -#define buspirate_serialport_setup(...) 0 -#define buspirate_serialport_shutdown(...) 0 -#define serialport_write(...) 0 -#define serialport_read(...) 0 -#define buspirate_discard_read(...) 0 -#endif - -int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt) -{ - int i, ret = 0; - - printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt); - if (!writecnt && !readcnt) { - fprintf(stderr, "Zero length command!\n"); - return 1; - } - printf_debug("Sending"); - for (i = 0; i < writecnt; i++) - printf_debug(" 0x%02x", buf[i]); -#ifdef FAKE_COMMUNICATION - /* Placate the caller for now. */ - if (readcnt) { - buf[0] = 0x01; - memset(buf + 1, 0xff, readcnt - 1); - } - ret = 0; -#else - if (writecnt) - ret = serialport_write(buf, writecnt); - if (ret) - return ret; - if (readcnt) - ret = serialport_read(buf, readcnt); - if (ret) - return ret; -#endif - printf_debug(", receiving"); - for (i = 0; i < readcnt; i++) - printf_debug(" 0x%02x", buf[i]); - printf_debug("\n"); - return 0; -} - -static const struct buspirate_spispeeds spispeeds[] = { - {"30k", 0x0}, - {"125k", 0x1}, - {"250k", 0x2}, - {"1M", 0x3}, - {"2M", 0x4}, - {"2.6M", 0x5}, - {"4M", 0x6}, - {"8M", 0x7}, - {NULL, 0x0} -}; - -int buspirate_spi_init(void) -{ - unsigned char buf[512]; - int ret = 0; - int i; - char *dev = NULL; - char *speed = NULL; - int spispeed = 0x7; - - if (programmer_param && !strlen(programmer_param)) { - free(programmer_param); - programmer_param = NULL; - } - if (programmer_param) { - dev = extract_param(&programmer_param, "dev=", ",:"); - speed = extract_param(&programmer_param, "spispeed=", ",:"); - if (strlen(programmer_param)) - fprintf(stderr, "Unhandled programmer parameters: %s\n", - programmer_param); - free(programmer_param); - programmer_param = NULL; - } - if (!dev) { - fprintf(stderr, "No serial device given. Use flashrom -p " - "buspiratespi:dev=/dev/ttyUSB0\n"); - return 1; - } - if (speed) { - for (i = 0; spispeeds[i].name; i++) - if (!strncasecmp(spispeeds[i].name, speed, - strlen(spispeeds[i].name))) { - spispeed = spispeeds[i].speed; - break; - } - if (!spispeeds[i].name) - fprintf(stderr, "Invalid SPI speed, using default.\n"); - } - /* This works because speeds numbering starts at 0 and is contiguous. */ - printf_debug("SPI speed is %sHz\n", spispeeds[spispeed].name); - - ret = buspirate_serialport_setup(dev); - if (ret) - return ret; - - /* This is the brute force version, but it should work. */ - for (i = 0; i < 19; i++) { - /* Enter raw bitbang mode */ - buf[0] = 0x00; - /* Send the command, don't read the response. */ - ret = buspirate_sendrecv(buf, 1, 0); - if (ret) - return ret; - /* Read any response and discard it. */ - ret = buspirate_discard_read(); - if (ret) - return ret; - } - /* Enter raw bitbang mode */ - buf[0] = 0x00; - ret = buspirate_sendrecv(buf, 1, 5); - if (ret) - return ret; - if (memcmp(buf, "BBIO", 4)) { - fprintf(stderr, "Entering raw bitbang mode failed!\n"); - return 1; - } - printf_debug("Raw bitbang mode version %c\n", buf[4]); - if (buf[4] != '1') { - fprintf(stderr, "Can't handle raw bitbang mode version %c!\n", - buf[4]); - return 1; - } - /* Enter raw SPI mode */ - buf[0] = 0x01; - ret = buspirate_sendrecv(buf, 1, 4); - if (memcmp(buf, "SPI", 3)) { - fprintf(stderr, "Entering raw SPI mode failed!\n"); - return 1; - } - printf_debug("Raw SPI mode version %c\n", buf[3]); - if (buf[3] != '1') { - fprintf(stderr, "Can't handle raw SPI mode version %c!\n", - buf[3]); - return 1; - } - - /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */ - buf[0] = 0x40 | 0xb; - ret = buspirate_sendrecv(buf, 1, 1); - if (ret) - return 1; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while setting power/CS/AUX!\n"); - return 1; - } - - /* Set SPI speed */ - buf[0] = 0x60 | spispeed; - ret = buspirate_sendrecv(buf, 1, 1); - if (ret) - return 1; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while setting SPI speed!\n"); - return 1; - } - - /* Set SPI config: output type, idle, clock edge, sample */ - buf[0] = 0x80 | 0xa; - ret = buspirate_sendrecv(buf, 1, 1); - if (ret) - return 1; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while setting SPI config!\n"); - return 1; - } - - /* De-assert CS# */ - buf[0] = 0x03; - ret = buspirate_sendrecv(buf, 1, 1); - if (ret) - return 1; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while raising CS#!\n"); - return 1; - } - - buses_supported = CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_BUSPIRATE; - - return 0; -} - -int buspirate_spi_shutdown(void) -{ - unsigned char buf[5]; - int ret = 0; - - /* Exit raw SPI mode (enter raw bitbang mode) */ - buf[0] = 0x00; - ret = buspirate_sendrecv(buf, 1, 5); - if (ret) - return ret; - if (memcmp(buf, "BBIO", 4)) { - fprintf(stderr, "Entering raw bitbang mode failed!\n"); - return 1; - } - printf_debug("Raw bitbang mode version %c\n", buf[4]); - if (buf[4] != '1') { - fprintf(stderr, "Can't handle raw bitbang mode version %c!\n", - buf[4]); - return 1; - } - /* Reset Bus Pirate (return to user terminal) */ - buf[0] = 0x0f; - ret = buspirate_sendrecv(buf, 1, 0); - if (ret) - return ret; - - /* Shut down serial port communication */ - ret = buspirate_serialport_shutdown(); - if (ret) - return ret; - printf_debug("Bus Pirate shutdown completed.\n"); - - return 0; -} - -int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - static unsigned char *buf = NULL; - int i = 0, ret = 0; - - if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16) - return SPI_INVALID_LENGTH; - - /* +2 is pretty arbitrary. */ - buf = realloc(buf, writecnt + readcnt + 2); - if (!buf) { - fprintf(stderr, "Out of memory!\n"); - exit(1); // -1 - } - - /* Assert CS# */ - buf[i++] = 0x02; - ret = buspirate_sendrecv(buf, 1, 1); - if (ret) - return SPI_GENERIC_ERROR; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while lowering CS#!\n"); - return SPI_GENERIC_ERROR; - } - - i = 0; - buf[i++] = 0x10 | (writecnt + readcnt - 1); - memcpy(buf + i, writearr, writecnt); - i += writecnt; - memset(buf + i, 0, readcnt); - ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt); - if (ret) - return SPI_GENERIC_ERROR; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while reading/writing SPI!\n"); - return SPI_GENERIC_ERROR; - } - memcpy(readarr, buf + i, readcnt); - - i = 0; - /* De-assert CS# */ - buf[i++] = 0x03; - ret = buspirate_sendrecv(buf, 1, 1); - if (ret) - return SPI_GENERIC_ERROR; - if (buf[0] != 0x01) { - fprintf(stderr, "Protocol error while raising CS#!\n"); - return SPI_GENERIC_ERROR; - } - - return ret; -} - -int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - return spi_read_chunked(flash, buf, start, len, 12); -} - -/* We could do 12-byte writes, but for now we use the generic 1-byte code. */ diff --git a/cbtable.c b/cbtable.c deleted file mode 100644 index 9d7e758..0000000 --- a/cbtable.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2002 Steven James - * Copyright (C) 2002 Linux Networx - * (Written by Eric Biederman for Linux Networx) - * Copyright (C) 2006-2009 coresystems GmbH - * (Written by Stefan Reinauer for coresystems GmbH) - * - * 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 "flash.h" -#include "coreboot_tables.h" - -char *lb_part = NULL, *lb_vendor = NULL; -int partvendor_from_cbtable = 0; - -static unsigned long compute_checksum(void *addr, unsigned long length) -{ - uint8_t *ptr; - volatile union { - uint8_t byte[2]; - uint16_t word; - } value; - unsigned long sum; - unsigned long i; - - /* In the most straight forward way possible, - * compute an ip style checksum. - */ - sum = 0; - ptr = addr; - for (i = 0; i < length; i++) { - unsigned long value; - value = ptr[i]; - if (i & 1) { - value <<= 8; - } - /* Add the new value */ - sum += value; - /* Wrap around the carry */ - if (sum > 0xFFFF) { - sum = (sum + (sum >> 16)) & 0xFFFF; - } - } - value.byte[0] = sum & 0xff; - value.byte[1] = (sum >> 8) & 0xff; - - return (~value.word) & 0xFFFF; -} - -#define for_each_lbrec(head, rec) \ - for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \ - (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \ - (rec->size >= 1) && \ - ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \ - rec = (struct lb_record *)(((char *)rec) + rec->size)) - -static int count_lb_records(struct lb_header *head) -{ - struct lb_record *rec; - int count; - - count = 0; - for_each_lbrec(head, rec) { - count++; - } - - return count; -} - -static struct lb_header *find_lb_table(void *base, unsigned long start, - unsigned long end) -{ - unsigned long addr; - - /* For now be stupid.... */ - for (addr = start; addr < end; addr += 16) { - struct lb_header *head = - (struct lb_header *)(((char *)base) + addr); - struct lb_record *recs = - (struct lb_record *)(((char *)base) + addr + sizeof(*head)); - if (memcmp(head->signature, "LBIO", 4) != 0) - continue; - printf_debug("Found candidate at: %08lx-%08lx\n", - addr, addr + head->table_bytes); - if (head->header_bytes != sizeof(*head)) { - fprintf(stderr, "Header bytes of %d are incorrect.\n", - head->header_bytes); - continue; - } - if (count_lb_records(head) != head->table_entries) { - fprintf(stderr, "Bad record count: %d.\n", - head->table_entries); - continue; - } - if (compute_checksum((uint8_t *) head, sizeof(*head)) != 0) { - fprintf(stderr, "Bad header checksum.\n"); - continue; - } - if (compute_checksum(recs, head->table_bytes) - != head->table_checksum) { - fprintf(stderr, "Bad table checksum: %04x.\n", - head->table_checksum); - continue; - } - printf_debug("Found coreboot table at 0x%08lx.\n", addr); - return head; - - }; - - return 0; -} - -static void find_mainboard(struct lb_record *ptr, unsigned long addr) -{ - struct lb_mainboard *rec; - int max_size; - char vendor[256], part[256]; - - rec = (struct lb_mainboard *)ptr; - max_size = rec->size - sizeof(*rec); - printf("Vendor ID: %.*s, part ID: %.*s\n", - max_size - rec->vendor_idx, - rec->strings + rec->vendor_idx, - max_size - rec->part_number_idx, - rec->strings + rec->part_number_idx); - snprintf(vendor, 255, "%.*s", max_size - rec->vendor_idx, - rec->strings + rec->vendor_idx); - snprintf(part, 255, "%.*s", max_size - rec->part_number_idx, - rec->strings + rec->part_number_idx); - - if (lb_part) { - printf("Overwritten by command line, vendor ID: %s, part ID: %s.\n", lb_vendor, lb_part); - } else { - partvendor_from_cbtable = 1; - lb_part = strdup(part); - lb_vendor = strdup(vendor); - } -} - -static struct lb_record *next_record(struct lb_record *rec) -{ - return (struct lb_record *)(((char *)rec) + rec->size); -} - -static void search_lb_records(struct lb_record *rec, struct lb_record *last, - unsigned long addr) -{ - struct lb_record *next; - int count; - count = 0; - - for (next = next_record(rec); (rec < last) && (next <= last); - rec = next, addr += rec->size) { - next = next_record(rec); - count++; - if (rec->tag == LB_TAG_MAINBOARD) { - find_mainboard(rec, addr); - break; - } - } -} - -#define BYTES_TO_MAP (1024*1024) -int coreboot_init(void) -{ - uint8_t *table_area; - unsigned long addr, start; - struct lb_header *lb_table; - struct lb_record *rec, *last; - -#ifdef __DARWIN__ - /* This is a hack. DirectIO fails to map physical address 0x00000000. - * Why? - */ - start = 0x400; -#else - start = 0x0; -#endif - table_area = physmap("low megabyte", start, BYTES_TO_MAP); - - lb_table = find_lb_table(table_area, 0x00000, 0x1000); - if (!lb_table) - lb_table = find_lb_table(table_area, 0xf0000, BYTES_TO_MAP); - if (lb_table) { - struct lb_forward *forward = (struct lb_forward *) - (((char *)lb_table) + lb_table->header_bytes); - if (forward->tag == LB_TAG_FORWARD) { - start = forward->forward; - start &= ~(getpagesize() - 1); - physunmap(table_area, BYTES_TO_MAP); - table_area = physmap("high tables", start, BYTES_TO_MAP); - lb_table = find_lb_table(table_area, 0x00000, 0x1000); - } - } - - if (!lb_table) { - printf("No coreboot table found.\n"); - return -1; - } - - addr = ((char *)lb_table) - ((char *)table_area) + start; - fprintf(stdout, "coreboot table found at 0x%lx.\n", - (unsigned long)lb_table - (unsigned long)table_area + start); - rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes); - last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes); - printf_debug("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n", - lb_table->header_bytes, lb_table->header_checksum, - lb_table->table_bytes, lb_table->table_checksum, - lb_table->table_entries); - search_lb_records(rec, last, addr + lb_table->header_bytes); - - return 0; -} diff --git a/chipset_enable.c b/chipset_enable.c deleted file mode 100644 index 3bdd7d0..0000000 --- a/chipset_enable.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2005-2009 coresystems GmbH - * Copyright (C) 2006 Uwe Hermann - * - * 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 - */ - -/* - * Contains the chipset specific flash enables. - */ - -#define _LARGEFILE64_SOURCE - -#include -#include -#include -#include -#include -#include "flash.h" - -unsigned long flashbase = 0; - -/** - * flashrom defaults to Parallel/LPC/FWH flash devices. If a known host - * controller is found, the init routine sets the buses_supported bitfield to - * contain the supported buses for that controller. - */ - -enum chipbustype buses_supported = CHIP_BUSTYPE_NONSPI; - -/** - * Programmers supporting multiple buses can have differing size limits on - * each bus. Store the limits for each bus in a common struct. - */ -struct decode_sizes max_rom_decode = { - .parallel = 0xffffffff, - .lpc = 0xffffffff, - .fwh = 0xffffffff, - .spi = 0xffffffff -}; - -extern int ichspi_lock; - -static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name) -{ - uint8_t tmp; - - /* - * ROM Write enable, 0xFFFC0000-0xFFFDFFFF and - * 0xFFFE0000-0xFFFFFFFF ROM select enable. - */ - tmp = pci_read_byte(dev, 0x47); - tmp |= 0x46; - pci_write_byte(dev, 0x47, tmp); - - return 0; -} - -static int enable_flash_sis85c496(struct pci_dev *dev, const char *name) -{ - uint8_t tmp; - - tmp = pci_read_byte(dev, 0xd0); - tmp |= 0xf8; - pci_write_byte(dev, 0xd0, tmp); - - return 0; -} - -static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name) -{ - uint8_t new, newer; - - /* Extended BIOS enable = 1, Lower BIOS Enable = 1 */ - /* This is 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */ - new = pci_read_byte(dev, 0x40); - new &= (~0x04); /* No idea why we clear bit 2. */ - new |= 0xb; /* 0x3 for some chipsets, bit 7 seems to be don't care. */ - pci_write_byte(dev, 0x40, new); - newer = pci_read_byte(dev, 0x40); - if (newer != new) { - printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name); - printf_debug("Stuck at 0x%x\n", newer); - return -1; - } - return 0; -} - -static struct pci_dev *find_southbridge(uint16_t vendor, const char *name) -{ - struct pci_dev *sbdev; - - sbdev = pci_dev_find_vendorclass(vendor, 0x0601); - if (!sbdev) - sbdev = pci_dev_find_vendorclass(vendor, 0x0680); - if (!sbdev) - sbdev = pci_dev_find_vendorclass(vendor, 0x0000); - if (!sbdev) - fprintf(stderr, "No southbridge found for %s!\n", name); - if (sbdev) - printf_debug("Found southbridge %04x:%04x at %02x:%02x:%01x\n", - sbdev->vendor_id, sbdev->device_id, - sbdev->bus, sbdev->dev, sbdev->func); - return sbdev; -} - -static int enable_flash_sis501(struct pci_dev *dev, const char *name) -{ - uint8_t tmp; - int ret = 0; - struct pci_dev *sbdev; - - sbdev = find_southbridge(dev->vendor_id, name); - if (!sbdev) - return -1; - - ret = enable_flash_sis_mapping(sbdev, name); - - tmp = sio_read(0x22, 0x80); - tmp &= (~0x20); - tmp |= 0x4; - sio_write(0x22, 0x80, tmp); - - tmp = sio_read(0x22, 0x70); - tmp &= (~0x20); - tmp |= 0x4; - sio_write(0x22, 0x70, tmp); - - return ret; -} - -static int enable_flash_sis5511(struct pci_dev *dev, const char *name) -{ - uint8_t tmp; - int ret = 0; - struct pci_dev *sbdev; - - sbdev = find_southbridge(dev->vendor_id, name); - if (!sbdev) - return -1; - - ret = enable_flash_sis_mapping(sbdev, name); - - tmp = sio_read(0x22, 0x50); - tmp &= (~0x20); - tmp |= 0x4; - sio_write(0x22, 0x50, tmp); - - return ret; -} - -static int enable_flash_sis5596(struct pci_dev *dev, const char *name) -{ - int ret; - - ret = enable_flash_sis5511(dev, name); - - /* FIXME: Needs same superio handling as enable_flash_sis630 */ - return ret; -} - -static int enable_flash_sis530(struct pci_dev *dev, const char *name) -{ - uint8_t new, newer; - int ret = 0; - struct pci_dev *sbdev; - - sbdev = find_southbridge(dev->vendor_id, name); - if (!sbdev) - return -1; - - ret = enable_flash_sis_mapping(sbdev, name); - - new = pci_read_byte(sbdev, 0x45); - new &= (~0x20); - new |= 0x4; - pci_write_byte(sbdev, 0x45, new); - newer = pci_read_byte(dev, 0x45); - if (newer != new) { - printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); - printf_debug("Stuck at 0x%x\n", newer); - ret = -1; - } - - return ret; -} - -static int enable_flash_sis540(struct pci_dev *dev, const char *name) -{ - uint8_t new, newer; - int ret = 0; - struct pci_dev *sbdev; - - sbdev = find_southbridge(dev->vendor_id, name); - if (!sbdev) - return -1; - - ret = enable_flash_sis_mapping(sbdev, name); - - new = pci_read_byte(sbdev, 0x45); - new &= (~0x80); - new |= 0x40; - pci_write_byte(sbdev, 0x45, new); - newer = pci_read_byte(dev, 0x45); - if (newer != new) { - printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); - printf_debug("Stuck at 0x%x\n", newer); - ret = -1; - } - - return ret; -} - -/* Datasheet: - * - Name: 82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4) - * - URL: http://www.intel.com/design/intarch/datashts/290562.htm - * - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf - * - Order Number: 290562-001 - */ -static int enable_flash_piix4(struct pci_dev *dev, const char *name) -{ - uint16_t old, new; - uint16_t xbcs = 0x4e; /* X-Bus Chip Select register. */ - - buses_supported = CHIP_BUSTYPE_PARALLEL; - - old = pci_read_word(dev, xbcs); - - /* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to - * FFF00000-FFF7FFFF are forwarded to ISA). - * Note: This bit is reserved on PIIX/PIIX3/MPIIX. - * Set bit 7: Extended BIOS Enable (PCI master accesses to - * FFF80000-FFFDFFFF are forwarded to ISA). - * Set bit 6: Lower BIOS Enable (PCI master, or ISA master accesses to - * the lower 64-Kbyte BIOS block (E0000-EFFFF) at the top - * of 1 Mbyte, or the aliases at the top of 4 Gbyte - * (FFFE0000-FFFEFFFF) result in the generation of BIOSCS#. - * Note: Accesses to FFFF0000-FFFFFFFF are always forwarded to ISA. - * Set bit 2: BIOSCS# Write Enable (1=enable, 0=disable). - */ - if (dev->device_id == 0x122e || dev->device_id == 0x7000 - || dev->device_id == 0x1234) - new = old | 0x00c4; /* PIIX/PIIX3/MPIIX: Bit 9 is reserved. */ - else - new = old | 0x02c4; - - if (new == old) - return 0; - - pci_write_word(dev, xbcs, new); - - if (pci_read_word(dev, xbcs) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", xbcs, new, name); - return -1; - } - - return 0; -} - -/* - * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet" - * http://download.intel.com/design/chipsets/datashts/30701303.pdf - */ -static int enable_flash_ich(struct pci_dev *dev, const char *name, - int bios_cntl) -{ - uint8_t old, new; - - /* - * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, but - * just treating it as 8 bit wide seems to work fine in practice. - */ - old = pci_read_byte(dev, bios_cntl); - - printf_debug("\nBIOS Lock Enable: %sabled, ", - (old & (1 << 1)) ? "en" : "dis"); - printf_debug("BIOS Write Enable: %sabled, ", - (old & (1 << 0)) ? "en" : "dis"); - printf_debug("BIOS_CNTL is 0x%x\n", old); - - new = old | 1; - - if (new == old) - return 0; - - pci_write_byte(dev, bios_cntl, new); - - if (pci_read_byte(dev, bios_cntl) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", bios_cntl, new, name); - return -1; - } - - return 0; -} - -static int enable_flash_ich_4e(struct pci_dev *dev, const char *name) -{ - /* - * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and - * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and - * FB_DEC_EN2. - */ - return enable_flash_ich(dev, name, 0x4e); -} - -static int enable_flash_ich_dc(struct pci_dev *dev, const char *name) -{ - uint32_t fwh_conf; - int i; - char *idsel = NULL; - - /* Ignore all legacy ranges below 1 MB. */ - /* FWH_SEL1 */ - fwh_conf = pci_read_long(dev, 0xd0); - for (i = 7; i >= 0; i--) - printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x", - (0x1ff8 + i) * 0x80000, - (0x1ff0 + i) * 0x80000, - (fwh_conf >> (i * 4)) & 0xf); - /* FWH_SEL2 */ - fwh_conf = pci_read_word(dev, 0xd4); - for (i = 3; i >= 0; i--) - printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x", - (0xff4 + i) * 0x100000, - (0xff0 + i) * 0x100000, - (fwh_conf >> (i * 4)) & 0xf); - /* FWH_DEC_EN1 */ - fwh_conf = pci_read_word(dev, 0xd8); - for (i = 7; i >= 0; i--) - printf_debug("\n0x%08x/0x%08x FWH decode %sabled", - (0x1ff8 + i) * 0x80000, - (0x1ff0 + i) * 0x80000, - (fwh_conf >> (i + 0x8)) & 0x1 ? "en" : "dis"); - for (i = 3; i >= 0; i--) - printf_debug("\n0x%08x/0x%08x FWH decode %sabled", - (0xff4 + i) * 0x100000, - (0xff0 + i) * 0x100000, - (fwh_conf >> i) & 0x1 ? "en" : "dis"); - - if (programmer_param) - idsel = strstr(programmer_param, "fwh_idsel="); - - if (idsel) { - idsel += strlen("fwh_idsel="); - fwh_conf = (uint32_t)strtoul(idsel, NULL, 0); - - /* FIXME: Need to undo this on shutdown. */ - printf("\nSetting IDSEL=0x%x for top 16 MB", fwh_conf); - pci_write_long(dev, 0xd0, fwh_conf); - pci_write_word(dev, 0xd4, fwh_conf); - } - - return enable_flash_ich(dev, name, 0xdc); -} - -#define ICH_STRAP_RSVD 0x00 -#define ICH_STRAP_SPI 0x01 -#define ICH_STRAP_PCI 0x02 -#define ICH_STRAP_LPC 0x03 - -static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name) -{ - uint32_t mmio_base; - - mmio_base = (pci_read_long(dev, 0xbc)) << 8; - printf_debug("MMIO base at = 0x%x\n", mmio_base); - spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70); - - printf_debug("0x6c: 0x%04x (CLOCK/DEBUG)\n", - mmio_readw(spibar + 0x6c)); - - /* Not sure if it speaks all these bus protocols. */ - buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_VIA; - ich_init_opcodes(); - - return 0; -} - -static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, - int ich_generation) -{ - int ret, i; - uint8_t old, new, bbs, buc; - uint16_t spibar_offset, tmp2; - uint32_t tmp, gcs; - void *rcrb; - //TODO: These names are incorrect for EP80579. For that, the solution would look like the commented line - //static const char *straps_names[] = {"SPI", "reserved", "reserved", "LPC" }; - static const char *straps_names[] = { "reserved", "SPI", "PCI", "LPC" }; - - /* Enable Flash Writes */ - ret = enable_flash_ich_dc(dev, name); - - /* Get physical address of Root Complex Register Block */ - tmp = pci_read_long(dev, 0xf0) & 0xffffc000; - printf_debug("\nRoot Complex Register Block address = 0x%x\n", tmp); - - /* Map RCBA to virtual memory */ - rcrb = physmap("ICH RCRB", tmp, 0x4000); - - gcs = mmio_readl(rcrb + 0x3410); - printf_debug("GCS = 0x%x: ", gcs); - printf_debug("BIOS Interface Lock-Down: %sabled, ", - (gcs & 0x1) ? "en" : "dis"); - bbs = (gcs >> 10) & 0x3; - printf_debug("BOOT BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]); - - buc = mmio_readb(rcrb + 0x3414); - printf_debug("Top Swap : %s\n", - (buc & 1) ? "enabled (A16 inverted)" : "not enabled"); - - /* It seems the ICH7 does not support SPI and LPC chips at the same - * time. At least not with our current code. So we prevent searching - * on ICH7 when the southbridge is strapped to LPC - */ - - if (ich_generation == 7 && bbs == ICH_STRAP_LPC) { - /* Not sure if it speaks LPC as well. */ - buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH; - /* No further SPI initialization required */ - return ret; - } - - switch (ich_generation) { - case 7: - buses_supported = CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_ICH7; - spibar_offset = 0x3020; - break; - case 8: - /* Not sure if it speaks LPC as well. */ - buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_ICH9; - spibar_offset = 0x3020; - break; - case 9: - case 10: - default: /* Future version might behave the same */ - /* Not sure if it speaks LPC as well. */ - buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_ICH9; - spibar_offset = 0x3800; - break; - } - - /* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */ - printf_debug("SPIBAR = 0x%x + 0x%04x\n", tmp, spibar_offset); - - /* Assign Virtual Address */ - spibar = rcrb + spibar_offset; - - switch (spi_controller) { - case SPI_CONTROLLER_ICH7: - printf_debug("0x00: 0x%04x (SPIS)\n", - mmio_readw(spibar + 0)); - printf_debug("0x02: 0x%04x (SPIC)\n", - mmio_readw(spibar + 2)); - printf_debug("0x04: 0x%08x (SPIA)\n", - mmio_readl(spibar + 4)); - for (i = 0; i < 8; i++) { - int offs; - offs = 8 + (i * 8); - printf_debug("0x%02x: 0x%08x (SPID%d)\n", offs, - mmio_readl(spibar + offs), i); - printf_debug("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4, - mmio_readl(spibar + offs + 4), i); - } - printf_debug("0x50: 0x%08x (BBAR)\n", - mmio_readl(spibar + 0x50)); - printf_debug("0x54: 0x%04x (PREOP)\n", - mmio_readw(spibar + 0x54)); - printf_debug("0x56: 0x%04x (OPTYPE)\n", - mmio_readw(spibar + 0x56)); - printf_debug("0x58: 0x%08x (OPMENU)\n", - mmio_readl(spibar + 0x58)); - printf_debug("0x5c: 0x%08x (OPMENU+4)\n", - mmio_readl(spibar + 0x5c)); - for (i = 0; i < 4; i++) { - int offs; - offs = 0x60 + (i * 4); - printf_debug("0x%02x: 0x%08x (PBR%d)\n", offs, - mmio_readl(spibar + offs), i); - } - printf_debug("\n"); - if (mmio_readw(spibar) & (1 << 15)) { - printf("WARNING: SPI Configuration Lockdown activated.\n"); - ichspi_lock = 1; - } - ich_init_opcodes(); - break; - case SPI_CONTROLLER_ICH9: - tmp2 = mmio_readw(spibar + 4); - printf_debug("0x04: 0x%04x (HSFS)\n", tmp2); - printf_debug("FLOCKDN %i, ", (tmp2 >> 15 & 1)); - printf_debug("FDV %i, ", (tmp2 >> 14) & 1); - printf_debug("FDOPSS %i, ", (tmp2 >> 13) & 1); - printf_debug("SCIP %i, ", (tmp2 >> 5) & 1); - printf_debug("BERASE %i, ", (tmp2 >> 3) & 3); - printf_debug("AEL %i, ", (tmp2 >> 2) & 1); - printf_debug("FCERR %i, ", (tmp2 >> 1) & 1); - printf_debug("FDONE %i\n", (tmp2 >> 0) & 1); - - tmp = mmio_readl(spibar + 0x50); - printf_debug("0x50: 0x%08x (FRAP)\n", tmp); - printf_debug("BMWAG %i, ", (tmp >> 24) & 0xff); - printf_debug("BMRAG %i, ", (tmp >> 16) & 0xff); - printf_debug("BRWA %i, ", (tmp >> 8) & 0xff); - printf_debug("BRRA %i\n", (tmp >> 0) & 0xff); - - printf_debug("0x54: 0x%08x (FREG0)\n", - mmio_readl(spibar + 0x54)); - printf_debug("0x58: 0x%08x (FREG1)\n", - mmio_readl(spibar + 0x58)); - printf_debug("0x5C: 0x%08x (FREG2)\n", - mmio_readl(spibar + 0x5C)); - printf_debug("0x60: 0x%08x (FREG3)\n", - mmio_readl(spibar + 0x60)); - printf_debug("0x64: 0x%08x (FREG4)\n", - mmio_readl(spibar + 0x64)); - printf_debug("0x74: 0x%08x (PR0)\n", - mmio_readl(spibar + 0x74)); - printf_debug("0x78: 0x%08x (PR1)\n", - mmio_readl(spibar + 0x78)); - printf_debug("0x7C: 0x%08x (PR2)\n", - mmio_readl(spibar + 0x7C)); - printf_debug("0x80: 0x%08x (PR3)\n", - mmio_readl(spibar + 0x80)); - printf_debug("0x84: 0x%08x (PR4)\n", - mmio_readl(spibar + 0x84)); - printf_debug("0x90: 0x%08x (SSFS, SSFC)\n", - mmio_readl(spibar + 0x90)); - printf_debug("0x94: 0x%04x (PREOP)\n", - mmio_readw(spibar + 0x94)); - printf_debug("0x96: 0x%04x (OPTYPE)\n", - mmio_readw(spibar + 0x96)); - printf_debug("0x98: 0x%08x (OPMENU)\n", - mmio_readl(spibar + 0x98)); - printf_debug("0x9C: 0x%08x (OPMENU+4)\n", - mmio_readl(spibar + 0x9C)); - printf_debug("0xA0: 0x%08x (BBAR)\n", - mmio_readl(spibar + 0xA0)); - printf_debug("0xB0: 0x%08x (FDOC)\n", - mmio_readl(spibar + 0xB0)); - if (tmp2 & (1 << 15)) { - printf("WARNING: SPI Configuration Lockdown activated.\n"); - ichspi_lock = 1; - } - ich_init_opcodes(); - break; - default: - /* Nothing */ - break; - } - - old = pci_read_byte(dev, 0xdc); - printf_debug("SPI Read Configuration: "); - new = (old >> 2) & 0x3; - switch (new) { - case 0: - case 1: - case 2: - printf_debug("prefetching %sabled, caching %sabled, ", - (new & 0x2) ? "en" : "dis", - (new & 0x1) ? "dis" : "en"); - break; - default: - printf_debug("invalid prefetching/caching settings, "); - break; - } - - return ret; -} - -static int enable_flash_ich7(struct pci_dev *dev, const char *name) -{ - return enable_flash_ich_dc_spi(dev, name, 7); -} - -static int enable_flash_ich8(struct pci_dev *dev, const char *name) -{ - return enable_flash_ich_dc_spi(dev, name, 8); -} - -static int enable_flash_ich9(struct pci_dev *dev, const char *name) -{ - return enable_flash_ich_dc_spi(dev, name, 9); -} - -static int enable_flash_ich10(struct pci_dev *dev, const char *name) -{ - return enable_flash_ich_dc_spi(dev, name, 10); -} - -static int enable_flash_vt823x(struct pci_dev *dev, const char *name) -{ - uint8_t val; - - /* enable ROM decode range (1MB) FFC00000 - FFFFFFFF */ - pci_write_byte(dev, 0x41, 0x7f); - - /* ROM write enable */ - val = pci_read_byte(dev, 0x40); - val |= 0x10; - pci_write_byte(dev, 0x40, val); - - if (pci_read_byte(dev, 0x40) != val) { - printf("\nWARNING: Failed to enable flash write on \"%s\"\n", - name); - return -1; - } - - return 0; -} - -static int enable_flash_cs5530(struct pci_dev *dev, const char *name) -{ - uint8_t reg8; - -#define DECODE_CONTROL_REG2 0x5b /* F0 index 0x5b */ -#define ROM_AT_LOGIC_CONTROL_REG 0x52 /* F0 index 0x52 */ - -#define LOWER_ROM_ADDRESS_RANGE (1 << 0) -#define ROM_WRITE_ENABLE (1 << 1) -#define UPPER_ROM_ADDRESS_RANGE (1 << 2) -#define BIOS_ROM_POSITIVE_DECODE (1 << 5) - - /* Decode 0x000E0000-0x000FFFFF (128 KB), not just 64 KB, and - * decode 0xFF000000-0xFFFFFFFF (16 MB), not just 256 KB. - * Make the configured ROM areas writable. - */ - reg8 = pci_read_byte(dev, ROM_AT_LOGIC_CONTROL_REG); - reg8 |= LOWER_ROM_ADDRESS_RANGE; - reg8 |= UPPER_ROM_ADDRESS_RANGE; - reg8 |= ROM_WRITE_ENABLE; - pci_write_byte(dev, ROM_AT_LOGIC_CONTROL_REG, reg8); - - /* Set positive decode on ROM. */ - reg8 = pci_read_byte(dev, DECODE_CONTROL_REG2); - reg8 |= BIOS_ROM_POSITIVE_DECODE; - pci_write_byte(dev, DECODE_CONTROL_REG2, reg8); - - return 0; -} - -/** - * Geode systems write protect the BIOS via RCONFs (cache settings similar - * to MTRRs). To unlock, change MSR 0x1808 top byte to 0x22. - * - * Geode systems also write protect the NOR flash chip itself via MSR_NORF_CTL. - * To enable write to NOR Boot flash for the benefit of systems that have such - * a setup, raise MSR 0x51400018 WE_CS3 (write enable Boot Flash Chip Select). - */ -static int enable_flash_cs5536(struct pci_dev *dev, const char *name) -{ -#define MSR_RCONF_DEFAULT 0x1808 -#define MSR_NORF_CTL 0x51400018 - - msr_t msr; - - /* Geode only has a single core */ - if (setup_cpu_msr(0)) - return -1; - - msr = rdmsr(MSR_RCONF_DEFAULT); - if ((msr.hi >> 24) != 0x22) { - msr.hi &= 0xfbffffff; - wrmsr(MSR_RCONF_DEFAULT, msr); - } - - msr = rdmsr(MSR_NORF_CTL); - /* Raise WE_CS3 bit. */ - msr.lo |= 0x08; - wrmsr(MSR_NORF_CTL, msr); - - cleanup_cpu_msr(); - -#undef MSR_RCONF_DEFAULT -#undef MSR_NORF_CTL - return 0; -} - -static int enable_flash_sc1100(struct pci_dev *dev, const char *name) -{ - uint8_t new; - - pci_write_byte(dev, 0x52, 0xee); - - new = pci_read_byte(dev, 0x52); - - if (new != 0xee) { - printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x52, new, name); - return -1; - } - - return 0; -} - -/* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */ -static int enable_flash_amd8111(struct pci_dev *dev, const char *name) -{ - uint8_t old, new; - - /* Enable decoding at 0xffb00000 to 0xffffffff. */ - old = pci_read_byte(dev, 0x43); - new = old | 0xC0; - if (new != old) { - pci_write_byte(dev, 0x43, new); - if (pci_read_byte(dev, 0x43) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x43, new, name); - } - } - - /* Enable 'ROM write' bit. */ - old = pci_read_byte(dev, 0x40); - new = old | 0x01; - if (new == old) - return 0; - pci_write_byte(dev, 0x40, new); - - if (pci_read_byte(dev, 0x40) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name); - return -1; - } - - return 0; -} - -static int enable_flash_sb600(struct pci_dev *dev, const char *name) -{ - uint32_t tmp, prot; - uint8_t reg; - struct pci_dev *smbus_dev; - int has_spi = 1; - - /* Clear ROM protect 0-3. */ - for (reg = 0x50; reg < 0x60; reg += 4) { - prot = pci_read_long(dev, reg); - /* No protection flags for this region?*/ - if ((prot & 0x3) == 0) - continue; - printf_debug("SB600 %s%sprotected from %u to %u\n", - (prot & 0x1) ? "write " : "", - (prot & 0x2) ? "read " : "", - (prot & 0xfffffc00), - (prot & 0xfffffc00) + ((prot & 0x3ff) << 8)); - prot &= 0xfffffffc; - pci_write_byte(dev, reg, prot); - prot = pci_read_long(dev, reg); - if (prot & 0x3) - printf("SB600 %s%sunprotect failed from %u to %u\n", - (prot & 0x1) ? "write " : "", - (prot & 0x2) ? "read " : "", - (prot & 0xfffffc00), - (prot & 0xfffffc00) + ((prot & 0x3ff) << 8)); - } - - /* Read SPI_BaseAddr */ - tmp = pci_read_long(dev, 0xa0); - tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */ - printf_debug("SPI base address is at 0x%x\n", tmp); - - /* If the BAR has address 0, it is unlikely SPI is used. */ - if (!tmp) - has_spi = 0; - - if (has_spi) { - /* Physical memory has to be mapped at page (4k) boundaries. */ - sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000, - 0x1000); - /* The low bits of the SPI base address are used as offset into - * the mapped page. - */ - sb600_spibar += tmp & 0xfff; - - tmp = pci_read_long(dev, 0xa0); - printf_debug("AltSpiCSEnable=%i, SpiRomEnable=%i, " - "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1, - (tmp & 0x4) >> 2); - tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2; - printf_debug("PrefetchEnSPIFromIMC=%i, ", tmp); - - tmp = pci_read_byte(dev, 0xbb); - printf_debug("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n", - tmp & 0x1, (tmp & 0x20) >> 5); - tmp = mmio_readl(sb600_spibar); - printf_debug("SpiArbEnable=%i, SpiAccessMacRomEn=%i, " - "SpiHostAccessRomEn=%i, ArbWaitCount=%i, " - "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n", - (tmp >> 19) & 0x1, (tmp >> 22) & 0x1, - (tmp >> 23) & 0x1, (tmp >> 24) & 0x7, - (tmp >> 27) & 0x1, (tmp >> 28) & 0x1); - } - - /* Look for the SMBus device. */ - smbus_dev = pci_dev_find(0x1002, 0x4385); - - if (has_spi && !smbus_dev) { - fprintf(stderr, "ERROR: SMBus device not found. Not enabling SPI.\n"); - has_spi = 0; - } - if (has_spi) { - /* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */ - /* GPIO11/SPI_DO and GPIO12/SPI_DI status */ - reg = pci_read_byte(smbus_dev, 0xAB); - reg &= 0xC0; - printf_debug("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO"); - printf_debug("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI"); - if (reg != 0x00) - has_spi = 0; - /* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */ - reg = pci_read_byte(smbus_dev, 0x83); - reg &= 0xC0; - printf_debug("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD"); - printf_debug("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS"); - /* SPI_HOLD is not used on all boards, filter it out. */ - if ((reg & 0x80) != 0x00) - has_spi = 0; - /* GPIO47/SPI_CLK status */ - reg = pci_read_byte(smbus_dev, 0xA7); - reg &= 0x40; - printf_debug("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK"); - if (reg != 0x00) - has_spi = 0; - } - - buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH; - if (has_spi) { - buses_supported |= CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_SB600; - } - - /* Read ROM strap override register. */ - OUTB(0x8f, 0xcd6); - reg = INB(0xcd7); - reg &= 0x0e; - printf_debug("ROM strap override is %sactive", (reg & 0x02) ? "" : "not "); - if (reg & 0x02) { - switch ((reg & 0x0c) >> 2) { - case 0x00: - printf_debug(": LPC"); - break; - case 0x01: - printf_debug(": PCI"); - break; - case 0x02: - printf_debug(": FWH"); - break; - case 0x03: - printf_debug(": SPI"); - break; - } - } - printf_debug("\n"); - - /* Force enable SPI ROM in SB600 PM register. - * If we enable SPI ROM here, we have to disable it after we leave. - * But how can we know which ROM we are going to handle? So we have - * to trade off. We only access LPC ROM if we boot via LPC ROM. And - * only SPI ROM if we boot via SPI ROM. If you want to access SPI on - * boards with LPC straps, you have to use the code below. - */ - /* - OUTB(0x8f, 0xcd6); - OUTB(0x0e, 0xcd7); - */ - - return 0; -} - -static int enable_flash_nvidia_nforce2(struct pci_dev *dev, const char *name) -{ - uint8_t tmp; - - pci_write_byte(dev, 0x92, 0); - - tmp = pci_read_byte(dev, 0x6d); - tmp |= 0x01; - pci_write_byte(dev, 0x6d, tmp); - - return 0; -} - -static int enable_flash_ck804(struct pci_dev *dev, const char *name) -{ - uint8_t old, new; - - old = pci_read_byte(dev, 0x88); - new = old | 0xc0; - if (new != old) { - pci_write_byte(dev, 0x88, new); - if (pci_read_byte(dev, 0x88) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x88, new, name); - } - } - - old = pci_read_byte(dev, 0x6d); - new = old | 0x01; - if (new == old) - return 0; - pci_write_byte(dev, 0x6d, new); - - if (pci_read_byte(dev, 0x6d) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name); - return -1; - } - - return 0; -} - -/* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */ -static int enable_flash_sb400(struct pci_dev *dev, const char *name) -{ - uint8_t tmp; - struct pci_dev *smbusdev; - - /* Look for the SMBus device. */ - smbusdev = pci_dev_find(0x1002, 0x4372); - - if (!smbusdev) { - fprintf(stderr, "ERROR: SMBus device not found. Aborting.\n"); - exit(1); - } - - /* Enable some SMBus stuff. */ - tmp = pci_read_byte(smbusdev, 0x79); - tmp |= 0x01; - pci_write_byte(smbusdev, 0x79, tmp); - - /* Change southbridge. */ - tmp = pci_read_byte(dev, 0x48); - tmp |= 0x21; - pci_write_byte(dev, 0x48, tmp); - - /* Now become a bit silly. */ - tmp = INB(0xc6f); - OUTB(tmp, 0xeb); - OUTB(tmp, 0xeb); - tmp |= 0x40; - OUTB(tmp, 0xc6f); - OUTB(tmp, 0xeb); - OUTB(tmp, 0xeb); - - return 0; -} - -static int enable_flash_mcp55(struct pci_dev *dev, const char *name) -{ - uint8_t old, new, byte; - uint16_t word; - - /* Set the 0-16 MB enable bits. */ - byte = pci_read_byte(dev, 0x88); - byte |= 0xff; /* 256K */ - pci_write_byte(dev, 0x88, byte); - byte = pci_read_byte(dev, 0x8c); - byte |= 0xff; /* 1M */ - pci_write_byte(dev, 0x8c, byte); - word = pci_read_word(dev, 0x90); - word |= 0x7fff; /* 16M */ - pci_write_word(dev, 0x90, word); - - old = pci_read_byte(dev, 0x6d); - new = old | 0x01; - if (new == old) - return 0; - pci_write_byte(dev, 0x6d, new); - - if (pci_read_byte(dev, 0x6d) != new) { - printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name); - return -1; - } - - return 0; -} - -static int enable_flash_ht1000(struct pci_dev *dev, const char *name) -{ - uint8_t byte; - - /* Set the 4MB enable bit. */ - byte = pci_read_byte(dev, 0x41); - byte |= 0x0e; - pci_write_byte(dev, 0x41, byte); - - byte = pci_read_byte(dev, 0x43); - byte |= (1 << 4); - pci_write_byte(dev, 0x43, byte); - - return 0; -} - -/** - * Usually on the x86 architectures (and on other PC-like platforms like some - * Alphas or Itanium) the system flash is mapped right below 4G. On the AMD - * Elan SC520 only a small piece of the system flash is mapped there, but the - * complete flash is mapped somewhere below 1G. The position can be determined - * by the BOOTCS PAR register. - */ -static int get_flashbase_sc520(struct pci_dev *dev, const char *name) -{ - int i, bootcs_found = 0; - uint32_t parx = 0; - void *mmcr; - - /* 1. Map MMCR */ - mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize()); - - /* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for - * BOOTCS region (PARx[31:29] = 100b)e - */ - for (i = 0x88; i <= 0xc4; i += 4) { - parx = mmio_readl(mmcr + i); - if ((parx >> 29) == 4) { - bootcs_found = 1; - break; /* BOOTCS found */ - } - } - - /* 3. PARx[25] = 1b --> flashbase[29:16] = PARx[13:0] - * PARx[25] = 0b --> flashbase[29:12] = PARx[17:0] - */ - if (bootcs_found) { - if (parx & (1 << 25)) { - parx &= (1 << 14) - 1; /* Mask [13:0] */ - flashbase = parx << 16; - } else { - parx &= (1 << 18) - 1; /* Mask [17:0] */ - flashbase = parx << 12; - } - } else { - printf("AMD Elan SC520 detected, but no BOOTCS. Assuming flash at 4G\n"); - } - - /* 4. Clean up */ - physunmap(mmcr, getpagesize()); - return 0; -} - -/* Please keep this list alphabetically sorted by vendor/device. */ -const struct penable chipset_enables[] = { - {0x10B9, 0x1533, OK, "ALi", "M1533", enable_flash_ali_m1533}, - {0x1022, 0x7440, OK, "AMD", "AMD-768", enable_flash_amd8111}, - {0x1022, 0x7468, OK, "AMD", "AMD8111", enable_flash_amd8111}, - {0x1078, 0x0100, OK, "AMD", "CS5530(A)", enable_flash_cs5530}, - {0x1022, 0x2080, OK, "AMD", "CS5536", enable_flash_cs5536}, - {0x1022, 0x2090, OK, "AMD", "CS5536", enable_flash_cs5536}, - {0x1022, 0x3000, OK, "AMD", "Elan SC520", get_flashbase_sc520}, - {0x1002, 0x438D, OK, "AMD", "SB600", enable_flash_sb600}, - {0x1002, 0x439d, OK, "AMD", "SB700/SB710/SB750", enable_flash_sb600}, - {0x100b, 0x0510, NT, "AMD", "SC1100", enable_flash_sc1100}, - {0x1002, 0x4377, OK, "ATI", "SB400", enable_flash_sb400}, - {0x1166, 0x0205, OK, "Broadcom", "HT-1000", enable_flash_ht1000}, - {0x8086, 0x3b00, NT, "Intel", "3400 Desktop", enable_flash_ich10}, - {0x8086, 0x3b01, NT, "Intel", "3400 Mobile", enable_flash_ich10}, - {0x8086, 0x3b0d, NT, "Intel", "3400 Mobile SFF", enable_flash_ich10}, - {0x8086, 0x7198, OK, "Intel", "440MX", enable_flash_piix4}, - {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich_4e}, - {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc}, - {0x8086, 0x5031, OK, "Intel", "EP80579", enable_flash_ich7}, - {0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich_4e}, - {0x8086, 0x3a18, OK, "Intel", "ICH10", enable_flash_ich10}, - {0x8086, 0x3a1a, OK, "Intel", "ICH10D", enable_flash_ich10}, - {0x8086, 0x3a14, OK, "Intel", "ICH10DO", enable_flash_ich10}, - {0x8086, 0x3a16, OK, "Intel", "ICH10R", enable_flash_ich10}, - {0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich_4e}, - {0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich_4e}, - {0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich_4e}, - {0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich_4e}, - {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich_4e}, - {0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich_4e}, - {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich_4e}, - {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich_dc}, - {0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich_dc}, - {0x8086, 0x27b0, OK, "Intel", "ICH7DH", enable_flash_ich7}, - {0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R", enable_flash_ich7}, - {0x8086, 0x27b9, OK, "Intel", "ICH7M", enable_flash_ich7}, - {0x8086, 0x27bd, OK, "Intel", "ICH7MDH", enable_flash_ich7}, - {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich_4e}, - {0x8086, 0x2812, OK, "Intel", "ICH8DH", enable_flash_ich8}, - {0x8086, 0x2814, OK, "Intel", "ICH8DO", enable_flash_ich8}, - {0x8086, 0x2810, OK, "Intel", "ICH8/ICH8R", enable_flash_ich8}, - {0x8086, 0x2815, OK, "Intel", "ICH8M", enable_flash_ich8}, - {0x8086, 0x2811, OK, "Intel", "ICH8M-E", enable_flash_ich8}, - {0x8086, 0x2918, OK, "Intel", "ICH9", enable_flash_ich9}, - {0x8086, 0x2912, OK, "Intel", "ICH9DH", enable_flash_ich9}, - {0x8086, 0x2914, OK, "Intel", "ICH9DO", enable_flash_ich9}, - {0x8086, 0x2919, OK, "Intel", "ICH9M", enable_flash_ich9}, - {0x8086, 0x2917, OK, "Intel", "ICH9M-E", enable_flash_ich9}, - {0x8086, 0x2916, OK, "Intel", "ICH9R", enable_flash_ich9}, - {0x8086, 0x2910, OK, "Intel", "ICH9 Engineering Sample", enable_flash_ich9}, - {0x8086, 0x1234, NT, "Intel", "MPIIX", enable_flash_piix4}, - {0x8086, 0x7000, OK, "Intel", "PIIX3", enable_flash_piix4}, - {0x8086, 0x7110, OK, "Intel", "PIIX4/4E/4M", enable_flash_piix4}, - {0x8086, 0x122e, OK, "Intel", "PIIX", enable_flash_piix4}, - {0x10de, 0x0030, OK, "NVIDIA", "nForce4/MCP4", enable_flash_nvidia_nforce2}, - {0x10de, 0x0050, OK, "NVIDIA", "CK804", enable_flash_ck804}, /* LPC */ - {0x10de, 0x0051, OK, "NVIDIA", "CK804", enable_flash_ck804}, /* Pro */ - {0x10de, 0x0060, OK, "NVIDIA", "NForce2", enable_flash_nvidia_nforce2}, - /* Slave, should not be here, to fix known bug for A01. */ - {0x10de, 0x00d3, OK, "NVIDIA", "CK804", enable_flash_ck804}, - {0x10de, 0x0260, NT, "NVIDIA", "MCP51", enable_flash_ck804}, - {0x10de, 0x0261, NT, "NVIDIA", "MCP51", enable_flash_ck804}, - {0x10de, 0x0262, NT, "NVIDIA", "MCP51", enable_flash_ck804}, - {0x10de, 0x0263, NT, "NVIDIA", "MCP51", enable_flash_ck804}, - {0x10de, 0x0360, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* M57SLI*/ - {0x10de, 0x0361, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0362, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0363, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0364, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0365, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0366, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0367, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* Pro */ - {0x10de, 0x0548, OK, "NVIDIA", "MCP67", enable_flash_mcp55}, - {0x1039, 0x0496, NT, "SiS", "85C496+497", enable_flash_sis85c496}, - {0x1039, 0x0406, NT, "SiS", "501/5101/5501", enable_flash_sis501}, - {0x1039, 0x5511, NT, "SiS", "5511", enable_flash_sis5511}, - {0x1039, 0x5596, NT, "SiS", "5596", enable_flash_sis5596}, - {0x1039, 0x5571, NT, "SiS", "5571", enable_flash_sis530}, - {0x1039, 0x5591, NT, "SiS", "5591/5592", enable_flash_sis530}, - {0x1039, 0x5597, NT, "SiS", "5597/5598/5581/5120", enable_flash_sis530}, - {0x1039, 0x0530, NT, "SiS", "530", enable_flash_sis530}, - {0x1039, 0x5600, NT, "SiS", "600", enable_flash_sis530}, - {0x1039, 0x0620, NT, "SiS", "620", enable_flash_sis530}, - {0x1039, 0x0540, NT, "SiS", "540", enable_flash_sis540}, - {0x1039, 0x0630, NT, "SiS", "630", enable_flash_sis540}, - {0x1039, 0x0635, NT, "SiS", "635", enable_flash_sis540}, - {0x1039, 0x0640, NT, "SiS", "640", enable_flash_sis540}, - {0x1039, 0x0645, NT, "SiS", "645", enable_flash_sis540}, - {0x1039, 0x0646, NT, "SiS", "645DX", enable_flash_sis540}, - {0x1039, 0x0648, NT, "SiS", "648", enable_flash_sis540}, - {0x1039, 0x0650, NT, "SiS", "650", enable_flash_sis540}, - {0x1039, 0x0651, NT, "SiS", "651", enable_flash_sis540}, - {0x1039, 0x0655, NT, "SiS", "655", enable_flash_sis540}, - {0x1039, 0x0730, NT, "SiS", "730", enable_flash_sis540}, - {0x1039, 0x0733, NT, "SiS", "733", enable_flash_sis540}, - {0x1039, 0x0735, OK, "SiS", "735", enable_flash_sis540}, - {0x1039, 0x0740, NT, "SiS", "740", enable_flash_sis540}, - {0x1039, 0x0745, NT, "SiS", "745", enable_flash_sis540}, - {0x1039, 0x0746, NT, "SiS", "746", enable_flash_sis540}, - {0x1039, 0x0748, NT, "SiS", "748", enable_flash_sis540}, - {0x1039, 0x0755, NT, "SiS", "755", enable_flash_sis540}, - {0x1106, 0x8324, OK, "VIA", "CX700", enable_flash_vt823x}, - {0x1106, 0x8231, NT, "VIA", "VT8231", enable_flash_vt823x}, - {0x1106, 0x3074, NT, "VIA", "VT8233", enable_flash_vt823x}, - {0x1106, 0x3177, OK, "VIA", "VT8235", enable_flash_vt823x}, - {0x1106, 0x3227, OK, "VIA", "VT8237", enable_flash_vt823x}, - {0x1106, 0x3337, OK, "VIA", "VT8237A", enable_flash_vt823x}, - {0x1106, 0x3372, OK, "VIA", "VT8237S", enable_flash_vt8237s_spi}, - {0x1106, 0x8353, OK, "VIA", "VX800", enable_flash_vt8237s_spi}, - {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_amd8111}, - {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_amd8111}, - {0x1106, 0x0686, NT, "VIA", "VT82C686A/B", enable_flash_amd8111}, - - {}, -}; - -int chipset_flash_enable(void) -{ - struct pci_dev *dev = 0; - int ret = -2; /* Nothing! */ - int i; - - /* Now let's try to find the chipset we have... */ - for (i = 0; chipset_enables[i].vendor_name != NULL; i++) { - dev = pci_dev_find(chipset_enables[i].vendor_id, - chipset_enables[i].device_id); - if (dev) - break; - } - - if (dev) { - printf("Found chipset \"%s %s\", enabling flash write... ", - chipset_enables[i].vendor_name, - chipset_enables[i].device_name); - - ret = chipset_enables[i].doit(dev, - chipset_enables[i].device_name); - if (ret) - printf("FAILED!\n"); - else - printf("OK.\n"); - } - printf("This chipset supports the following protocols: %s.\n", - flashbuses_to_text(buses_supported)); - - return ret; -} diff --git a/cli/cbtable.c b/cli/cbtable.c new file mode 100644 index 0000000..7bd4718 --- /dev/null +++ b/cli/cbtable.c @@ -0,0 +1,230 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2002 Steven James + * Copyright (C) 2002 Linux Networx + * (Written by Eric Biederman for Linux Networx) + * Copyright (C) 2006-2009 coresystems GmbH + * (Written by Stefan Reinauer for coresystems GmbH) + * + * 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 "../libflashrom/flash.h" +#include "coreboot_tables.h" + +char *lb_part = NULL, *lb_vendor = NULL; +int partvendor_from_cbtable = 0; + +static unsigned long compute_checksum(void *addr, unsigned long length) +{ + uint8_t *ptr; + volatile union { + uint8_t byte[2]; + uint16_t word; + } value; + unsigned long sum; + unsigned long i; + + /* In the most straight forward way possible, + * compute an ip style checksum. + */ + sum = 0; + ptr = addr; + for (i = 0; i < length; i++) { + unsigned long value; + value = ptr[i]; + if (i & 1) { + value <<= 8; + } + /* Add the new value */ + sum += value; + /* Wrap around the carry */ + if (sum > 0xFFFF) { + sum = (sum + (sum >> 16)) & 0xFFFF; + } + } + value.byte[0] = sum & 0xff; + value.byte[1] = (sum >> 8) & 0xff; + + return (~value.word) & 0xFFFF; +} + +#define for_each_lbrec(head, rec) \ + for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \ + (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \ + (rec->size >= 1) && \ + ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \ + rec = (struct lb_record *)(((char *)rec) + rec->size)) + +static int count_lb_records(struct lb_header *head) +{ + struct lb_record *rec; + int count; + + count = 0; + for_each_lbrec(head, rec) { + count++; + } + + return count; +} + +static struct lb_header *find_lb_table(void *base, unsigned long start, + unsigned long end) +{ + unsigned long addr; + + /* For now be stupid.... */ + for (addr = start; addr < end; addr += 16) { + struct lb_header *head = + (struct lb_header *)(((char *)base) + addr); + struct lb_record *recs = + (struct lb_record *)(((char *)base) + addr + sizeof(*head)); + if (memcmp(head->signature, "LBIO", 4) != 0) + continue; + printf_debug("Found candidate at: %08lx-%08lx\n", + addr, addr + head->table_bytes); + if (head->header_bytes != sizeof(*head)) { + fprintf(stderr, "Header bytes of %d are incorrect.\n", + head->header_bytes); + continue; + } + if (count_lb_records(head) != head->table_entries) { + fprintf(stderr, "Bad record count: %d.\n", + head->table_entries); + continue; + } + if (compute_checksum((uint8_t *) head, sizeof(*head)) != 0) { + fprintf(stderr, "Bad header checksum.\n"); + continue; + } + if (compute_checksum(recs, head->table_bytes) + != head->table_checksum) { + fprintf(stderr, "Bad table checksum: %04x.\n", + head->table_checksum); + continue; + } + printf_debug("Found coreboot table at 0x%08lx.\n", addr); + return head; + + }; + + return 0; +} + +static void find_mainboard(struct lb_record *ptr, unsigned long addr) +{ + struct lb_mainboard *rec; + int max_size; + char vendor[256], part[256]; + + rec = (struct lb_mainboard *)ptr; + max_size = rec->size - sizeof(*rec); + printf("Vendor ID: %.*s, part ID: %.*s\n", + max_size - rec->vendor_idx, + rec->strings + rec->vendor_idx, + max_size - rec->part_number_idx, + rec->strings + rec->part_number_idx); + snprintf(vendor, 255, "%.*s", max_size - rec->vendor_idx, + rec->strings + rec->vendor_idx); + snprintf(part, 255, "%.*s", max_size - rec->part_number_idx, + rec->strings + rec->part_number_idx); + + if (lb_part) { + printf("Overwritten by command line, vendor ID: %s, part ID: %s.\n", lb_vendor, lb_part); + } else { + partvendor_from_cbtable = 1; + lb_part = strdup(part); + lb_vendor = strdup(vendor); + } +} + +static struct lb_record *next_record(struct lb_record *rec) +{ + return (struct lb_record *)(((char *)rec) + rec->size); +} + +static void search_lb_records(struct lb_record *rec, struct lb_record *last, + unsigned long addr) +{ + struct lb_record *next; + int count; + count = 0; + + for (next = next_record(rec); (rec < last) && (next <= last); + rec = next, addr += rec->size) { + next = next_record(rec); + count++; + if (rec->tag == LB_TAG_MAINBOARD) { + find_mainboard(rec, addr); + break; + } + } +} + +#define BYTES_TO_MAP (1024*1024) +int coreboot_init(void) +{ + uint8_t *table_area; + unsigned long addr, start; + struct lb_header *lb_table; + struct lb_record *rec, *last; + +#ifdef __DARWIN__ + /* This is a hack. DirectIO fails to map physical address 0x00000000. + * Why? + */ + start = 0x400; +#else + start = 0x0; +#endif + table_area = physmap("low megabyte", start, BYTES_TO_MAP); + + lb_table = find_lb_table(table_area, 0x00000, 0x1000); + if (!lb_table) + lb_table = find_lb_table(table_area, 0xf0000, BYTES_TO_MAP); + if (lb_table) { + struct lb_forward *forward = (struct lb_forward *) + (((char *)lb_table) + lb_table->header_bytes); + if (forward->tag == LB_TAG_FORWARD) { + start = forward->forward; + start &= ~(getpagesize() - 1); + physunmap(table_area, BYTES_TO_MAP); + table_area = physmap("high tables", start, BYTES_TO_MAP); + lb_table = find_lb_table(table_area, 0x00000, 0x1000); + } + } + + if (!lb_table) { + printf("No coreboot table found.\n"); + return -1; + } + + addr = ((char *)lb_table) - ((char *)table_area) + start; + fprintf(stdout, "coreboot table found at 0x%lx.\n", + (unsigned long)lb_table - (unsigned long)table_area + start); + rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes); + last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes); + printf_debug("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n", + lb_table->header_bytes, lb_table->header_checksum, + lb_table->table_bytes, lb_table->table_checksum, + lb_table->table_entries); + search_lb_records(rec, last, addr + lb_table->header_bytes); + + return 0; +} diff --git a/cli/coreboot_tables.h b/cli/coreboot_tables.h new file mode 100644 index 0000000..6944559 --- /dev/null +++ b/cli/coreboot_tables.h @@ -0,0 +1,150 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2002 Linux Networx + * (Written by Eric Biederman for Linux Networx) + * Copyright (C) 2005-2007 coresystems GmbH + * + * 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 + */ + +#ifndef COREBOOT_TABLES_H +#define COREBOOT_TABLES_H + +#include + +/* The coreboot table information is for conveying information + * from the firmware to the loaded OS image. Primarily this + * is expected to be information that cannot be discovered by + * other means, such as quering the hardware directly. + * + * All of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. For table that + * can reasonably be used on multiple architectures the data + * size should be fixed. This should ease the transition between + * 32 bit and 64 bit architectures etc. + * + * The completeness test for the information in this table is: + * - Can all of the hardware be detected? + * - Are the per motherboard constants available? + * - Is there enough to allow a kernel to run that was written before + * a particular motherboard is constructed? (Assuming the kernel + * has drivers for all of the hardware but it does not have + * assumptions on how the hardware is connected together). + * + * With this test it should be straight forward to determine if a + * table entry is required or not. This should remove much of the + * long term compatibility burden as table entries which are + * irrelevant or have been replaced by better alternatives may be + * dropped. Of course it is polite and expidite to include extra + * table entries and be backwards compatible, but it is not required. + */ + +/* Since coreboot is usually compiled 32bit, gcc will align 64bit + * types to 32bit boundaries. If the coreboot table is dumped on a + * 64bit system, a uint64_t would be aligned to 64bit boundaries, + * breaking the table format. + * + * lb_uint64 will keep 64bit coreboot table values aligned to 32bit + * to ensure compatibility. They can be accessed with the two functions + * below: unpack_lb64() and pack_lb64() + * + * See also: util/lbtdump/lbtdump.c + */ + +struct lb_uint64 { + uint32_t lo; + uint32_t hi; +}; + +struct lb_header { + uint8_t signature[4]; /* LBIO */ + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct lb_record { + uint32_t tag; /* tag ID */ + uint32_t size; /* size of record (in bytes) */ +}; + +#define LB_TAG_UNUSED 0x0000 + +#define LB_TAG_MEMORY 0x0001 + +struct lb_memory_range { + struct lb_uint64 start; + struct lb_uint64 size; + uint32_t type; +#define LB_MEM_RAM 1 /* Memory anyone can use */ +#define LB_MEM_RESERVED 2 /* Don't use this memory region */ +#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */ +}; + +struct lb_memory { + uint32_t tag; + uint32_t size; + struct lb_memory_range map[0]; +}; + +#define LB_TAG_HWRPB 0x0002 +struct lb_hwrpb { + uint32_t tag; + uint32_t size; + uint64_t hwrpb; +}; + +#define LB_TAG_MAINBOARD 0x0003 +struct lb_mainboard { + uint32_t tag; + uint32_t size; + uint8_t vendor_idx; + uint8_t part_number_idx; + uint8_t strings[0]; +}; + +#define LB_TAG_VERSION 0x0004 +#define LB_TAG_EXTRA_VERSION 0x0005 +#define LB_TAG_BUILD 0x0006 +#define LB_TAG_COMPILE_TIME 0x0007 +#define LB_TAG_COMPILE_BY 0x0008 +#define LB_TAG_COMPILE_HOST 0x0009 +#define LB_TAG_COMPILE_DOMAIN 0x000a +#define LB_TAG_COMPILER 0x000b +#define LB_TAG_LINKER 0x000c +#define LB_TAG_ASSEMBLER 0x000d +struct lb_string { + uint32_t tag; + uint32_t size; + uint8_t string[0]; +}; + +#define LB_TAG_FORWARD 0x0011 +struct lb_forward { + uint32_t tag; + uint32_t size; + uint64_t forward; +}; + +#endif /* COREBOOT_TABLES_H */ diff --git a/cli/flashrom.8 b/cli/flashrom.8 new file mode 100644 index 0000000..011840c --- /dev/null +++ b/cli/flashrom.8 @@ -0,0 +1,302 @@ +.TH FLASHROM 8 "May 21, 2009" +.SH NAME +flashrom \- detect, read, write, verify and erase flash chips +.SH SYNOPSIS +.B flashrom \fR[\fB\-VfLzhRn\fR] [\fB\-E\fR|\fB\-r\fR file|\fB\-w\fR file|\fB\-v\fR file] [\fB\-c\fR chipname] + [\fB\-m\fR [vendor:]part] [\fB\-l\fR file] [\fB\-i\fR image] [\fB\-p\fR programmer] +.SH DESCRIPTION +.B flashrom +is a utility for detecting, reading, writing, verifying and erasing flash +chips. It's often used to flash BIOS/EFI/coreboot/firmware images in-system +using a supported mainboard, but it also supports flashing of network cards +(NICs), SATA controller cards, and other external devices which can program +flash chips. +.PP +It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and +TSOP40 chips, which use various protocols such as LPC, FWH, parallel flash, +or SPI. +.SH OPTIONS +Please note that the command line interface for flashrom will change before +flashrom 1.0. Do not use flashrom in scripts or other automated tools without +checking that your flashrom version won't interpret options in a different way. +.PP +You can specify one of \-E, \-r, \-w, \-v or no operation. +If no operation is specified, then all that happens +is that flash info is dumped and the flash chip is set to writable. +.TP +.B "\-r, \-\-read " +Read flash ROM contents and save them into the given +.BR . +.TP +.B "\-w, \-\-write " +Write file into flash ROM. +.TP +.B "\-n, \-\-noverify" +Do +.B not +verify the flash ROM contents after writing them to the chip. Using this +option is +.B not +recommended, you should only use it if you know what you are doing and you +feel that the time for verification takes too long. +.sp +Typical usage is: +.B "flashrom -wn file" +.sp +This option is only useful in combination with +.BR \-\-write . +.TP +.B "\-v, \-\-verify " +Verify the flash ROM contents against the given +.BR . +.TP +.B "\-E, \-\-erase" +Erase the flash ROM chip. +.TP +.B "\-V, \-\-verbose" +More verbose output. +.TP +.B "\-c, \-\-chip" +Probe only for specified flash ROM chip. +.sp +flashrom supports ROM layouts. This allows you to flash certain parts of +the flash chip only. A ROM layout file looks like follows: +.sp + 00000000:00008fff gfxrom + 00009000:0003ffff normal + 00040000:0007ffff fallback +.sp + i.e.: + startaddr:endaddr name +.sp +All addresses are offsets within the file, not absolute addresses! +If you only want to update the normal image in a ROM you can say: +.sp +.B " flashrom -w --layout rom.layout --image normal agami_aruma.rom" +.sp +To update normal and fallback but leave the VGA BIOS alone, say: +.sp +.B " flashrom -w -l rom.layout -i normal \" +.br +.B " -i fallback agami_aruma.rom" +.sp +Currently overlapping sections are not supported. +.sp +ROM layouts should replace the \-s and \-e option since they are more +flexible and they should lead to a ROM update file format with the +ROM layout and the ROM image in one file (cpio, zip or something?). +.TP +.B "\-m, \-\-mainboard" <[vendor:]part> +Override mainboard settings. +.sp +flashrom reads the coreboot table to determine the current mainboard. If no +coreboot table could be read or if you want to override these values, you can +specify \-m, e.g.: +.sp +.B " flashrom -w --mainboard AGAMI:ARUMA agami_aruma.rom" +.sp +See the 'Supported mainboards' section in the output of 'flashrom \-L' for +a list of boards which require the specification of the board name, if no +coreboot table is found. +.TP +.B "\-f, \-\-force" +Force write without checking whether the ROM image file is really meant +to be used on this board. +.sp +Note: This check only works while coreboot is running, and only for those +boards where the coreboot code supports it. +.TP +.B "\-l, \-\-layout " +Read ROM layout from +.BR . +.TP +.B "\-i, \-\-image " +Only flash image +.B +from flash layout. +.TP +.B "\-L, \-\-list\-supported" +List the flash chips, chipsets, mainboards, and PCI card "programmers" +supported by flashrom. +.sp +There are many unlisted boards which will work out of the box, without +special support in flashrom. Please let us know if you can verify that +other boards work or do not work out of the box. For verification you have +to test an ERASE and/or WRITE operation, so make sure you only do that +if you have proper means to recover from failure! +.TP +.B "\-z, \-\-list\-supported-wiki" +Same as +.BR \-\-list\-supported , +but outputs the supported hardware in MediaWiki syntax, so that it can be +easily pasted into the wiki page at http://www.flashrom.org/. +.TP +.B "\-p, \-\-programmer " +Specify the programmer device. Currently supported are: +.sp +.BR "* internal" " (default, for in-system flashing in the mainboard)" +.sp +.BR "* dummy" " (just prints all operations and accesses)" +.sp +.BR "* nic3com" " (for flash ROMs on 3COM network cards)" +.sp +.BR "* gfxnvidia" " (for flash ROMs on NVIDIA graphics cards)" +.sp +.BR "* drkaiser" " (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)" +.sp +.BR "* satasii" " (for flash ROMs on Silicon Image SATA/IDE controllers)" +.sp +.BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)" +.sp +.BR "* ft2232spi" " (for flash ROMs attached to a FT2232H/FT4232H based USB SPI programmer)" +.sp +.BR "* serprog" " (for flash ROMs attached to Urja's AVR programmer)" +.sp +.BR "* buspiratespi" " (for flash ROMs attached to a Bus Pirate)" +.sp +The dummy programmer has an optional parameter specifying the bus types it +should support. For that you have to use the +.B "flashrom -p dummy:type" +syntax where +.B type +can be any comma-separated combination of +.B parallel lpc fwh spi all +in any order. +.sp +Example: +.B "flashrom -p dummy:lpc,fwh" +.sp +If you have multiple supported PCI cards which can program flash chips +(NICs, SATA/IDE controllers, etc.) in your system, you must use the +.B "flashrom -p xxxx:bb:dd.f" +syntax to explicitly select one of them, where +.B xxxx +is the name of the programmer +.B bb +is the PCI bus number, +.B dd +is the PCI device number, and +.B f +is the PCI function number of the desired NIC. +.sp +Example: +.B "flashrom -p nic3com:05:04.0" +.sp +Currently the following programmers support this mechanism: +.BR nic3com , +.BR gfxnvidia , +.BR satasii . +.sp +The it87spi programmer has an optional parameter which will set the I/O base +port of the IT87* SPI controller interface to the port specified in the +parameter. For that you have to use the +.B "flashrom -p it87spi:port=portnum" +syntax where +.B portnum +is an I/O port number which must be a multiple of 8. +.sp +The ft2232spi programmer has an optional parameter specifying the controller +type and interface/port it should support. For that you have to use the +.B "flashrom -p ft2232spi:model,port=interface" +syntax where +.B model +can be any of +.B 2232H 4232H +and +.B interface +can be any of +.B A +.BR B . +The default model is +.B 4232H +and the default interface is +.BR B . +.sp +The serprog programmer has an optional parameter specifying either a serial +device/baud combination or an IP/port combination for communication with the +programmer. For serial, you have to use the +.B "flashrom -p serprog:/dev/device:baud" +syntax and for IP, you have to use +.B "flashrom -p serprog:ip:port" +instead. More information about serprog is available in serprog-protocol.txt in +the source distribution. +.sp +The buspiratespi programmer has a required dev parameter specifying the Bus +Pirate device node and an optional spispeed parameter specifying the frequency +of the SPI bus. The parameter delimiter is a comma. Syntax is +.B "flashrom -p buspiratespi:dev=/dev/device,spispeed=frequency" +where +.B frequency +can be any of +.B 30k 125k 250k 1M 2M 2.6M 4M 8M +(in Hz). +.sp +Support for some programmers can be disabled at compile time. +.B "flashrom -h" +lists all supported programmers. +.TP +.B "\-h, \-\-help" +Show a help text and exit. +.TP +.B "\-R, \-\-version" +Show version information and exit. +.SH EXIT STATUS +flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem +(/dev/xsvc on Solaris) can not be opened and with 3 if a call to mmap() fails. +.SH BUGS +Please report any bugs at +.BR http://www.flashrom.org/trac/flashrom/newticket "," +or on the flashrom mailing list +.RB "(" http://www.flashrom.org/mailman/listinfo/flashrom ")." +.SH LICENCE +.B flashrom +is covered by the GNU General Public License (GPL), version 2. Some files are +additionally available under the GPL (version 2, or any later version). +.SH COPYRIGHT +.br +Please see the individual files. +.SH AUTHORS +Carl-Daniel Hailfinger +.br +Claus Gindhart +.br +Dominik Geyer +.br +Eric Biederman +.br +Giampiero Giancipoli +.br +Joe Bao +.br +Luc Verhaegen +.br +Li-Ta Lo +.br +Markus Boas +.br +Nikolay Petukhov +.br +Peter Stuge +.br +Reinder E.N. de Haan +.br +Ronald G. Minnich +.br +Ronald Hoogenboom +.br +Stefan Reinauer +.br +Stefan Wildemann +.br +Steven James +.br +Uwe Hermann +.br +Wang Qingpei +.br +Yinghai Lu +.br +some others +.PP +This manual page was written by Uwe Hermann . +It is licensed under the terms of the GNU GPL (version 2 or later). diff --git a/cli/flashrom.c b/cli/flashrom.c new file mode 100644 index 0000000..8a6bdfe --- /dev/null +++ b/cli/flashrom.c @@ -0,0 +1,1369 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2004 Tyan Corp + * Copyright (C) 2005-2008 coresystems GmbH + * Copyright (C) 2008,2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include "../libflashrom/flash.h" +#include "../libflashrom/flashchips.h" + +const char *flashrom_version = FLASHROM_VERSION; +char *chip_to_probe = NULL; +int verbose = 0; +enum programmer programmer = PROGRAMMER_INTERNAL; +char *programmer_param = NULL; + +const struct programmer_entry programmer_table[] = { + { + .name = "internal", + .init = internal_init, + .shutdown = internal_shutdown, + .map_flash_region = physmap, + .unmap_flash_region = physunmap, + .chip_readb = internal_chip_readb, + .chip_readw = internal_chip_readw, + .chip_readl = internal_chip_readl, + .chip_readn = internal_chip_readn, + .chip_writeb = internal_chip_writeb, + .chip_writew = internal_chip_writew, + .chip_writel = internal_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, + +#if DUMMY_SUPPORT == 1 + { + .name = "dummy", + .init = dummy_init, + .shutdown = dummy_shutdown, + .map_flash_region = dummy_map, + .unmap_flash_region = dummy_unmap, + .chip_readb = dummy_chip_readb, + .chip_readw = dummy_chip_readw, + .chip_readl = dummy_chip_readl, + .chip_readn = dummy_chip_readn, + .chip_writeb = dummy_chip_writeb, + .chip_writew = dummy_chip_writew, + .chip_writel = dummy_chip_writel, + .chip_writen = dummy_chip_writen, + .delay = internal_delay, + }, +#endif + +#if NIC3COM_SUPPORT == 1 + { + .name = "nic3com", + .init = nic3com_init, + .shutdown = nic3com_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = nic3com_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = nic3com_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + +#if GFXNVIDIA_SUPPORT == 1 + { + .name = "gfxnvidia", + .init = gfxnvidia_init, + .shutdown = gfxnvidia_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = gfxnvidia_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = gfxnvidia_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + +#if DRKAISER_SUPPORT == 1 + { + .name = "drkaiser", + .init = drkaiser_init, + .shutdown = drkaiser_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = drkaiser_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = drkaiser_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + +#if SATASII_SUPPORT == 1 + { + .name = "satasii", + .init = satasii_init, + .shutdown = satasii_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = satasii_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = satasii_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + + { + .name = "it87spi", + .init = it87spi_init, + .shutdown = noop_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = noop_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = noop_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, + +#if FT2232_SPI_SUPPORT == 1 + { + .name = "ft2232spi", + .init = ft2232_spi_init, + .shutdown = noop_shutdown, /* Missing shutdown */ + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = noop_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = noop_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + +#if SERPROG_SUPPORT == 1 + { + .name = "serprog", + .init = serprog_init, + .shutdown = serprog_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = serprog_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = serprog_chip_readn, + .chip_writeb = serprog_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = serprog_delay, + }, +#endif + +#if BUSPIRATE_SPI_SUPPORT == 1 + { + .name = "buspiratespi", + .init = buspirate_spi_init, + .shutdown = buspirate_spi_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = noop_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = noop_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + + {}, /* This entry corresponds to PROGRAMMER_INVALID. */ +}; + +int programmer_init(void) +{ + return programmer_table[programmer].init(); +} + +int programmer_shutdown(void) +{ + return programmer_table[programmer].shutdown(); +} + +void *programmer_map_flash_region(const char *descr, unsigned long phys_addr, + size_t len) +{ + return programmer_table[programmer].map_flash_region(descr, + phys_addr, len); +} + +void programmer_unmap_flash_region(void *virt_addr, size_t len) +{ + programmer_table[programmer].unmap_flash_region(virt_addr, len); +} + +void chip_writeb(uint8_t val, chipaddr addr) +{ + programmer_table[programmer].chip_writeb(val, addr); +} + +void chip_writew(uint16_t val, chipaddr addr) +{ + programmer_table[programmer].chip_writew(val, addr); +} + +void chip_writel(uint32_t val, chipaddr addr) +{ + programmer_table[programmer].chip_writel(val, addr); +} + +void chip_writen(uint8_t *buf, chipaddr addr, size_t len) +{ + programmer_table[programmer].chip_writen(buf, addr, len); +} + +uint8_t chip_readb(const chipaddr addr) +{ + return programmer_table[programmer].chip_readb(addr); +} + +uint16_t chip_readw(const chipaddr addr) +{ + return programmer_table[programmer].chip_readw(addr); +} + +uint32_t chip_readl(const chipaddr addr) +{ + return programmer_table[programmer].chip_readl(addr); +} + +void chip_readn(uint8_t *buf, chipaddr addr, size_t len) +{ + programmer_table[programmer].chip_readn(buf, addr, len); +} + +void programmer_delay(int usecs) +{ + programmer_table[programmer].delay(usecs); +} + +void map_flash_registers(struct flashchip *flash) +{ + size_t size = flash->total_size * 1024; + /* Flash registers live 4 MByte below the flash. */ + /* FIXME: This is incorrect for nonstandard flashbase. */ + flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size); +} + +int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + chip_readn(buf, flash->virtual_memory + start, len); + + return 0; +} + +int min(int a, int b) +{ + return (a < b) ? a : b; +} + +int max(int a, int b) +{ + return (a > b) ? a : b; +} + +int bitcount(unsigned long a) +{ + int i = 0; + for (; a != 0; a >>= 1) + if (a & 1) + i++; + return i; +} + +char *strcat_realloc(char *dest, const char *src) +{ + dest = realloc(dest, strlen(dest) + strlen(src) + 1); + if (!dest) + return NULL; + strcat(dest, src); + return dest; +} + +/* This is a somewhat hacked function similar in some ways to strtok(). + * It will look for needle in haystack, return a copy of needle and remove + * everything from the first occurrence of needle to the next delimiter + * from haystack. + */ +char *extract_param(char **haystack, char *needle, char *delim) +{ + char *param_pos, *rest, *tmp; + char *dev = NULL; + int devlen; + + param_pos = strstr(*haystack, needle); + do { + if (!param_pos) + return NULL; + /* Beginning of the string? */ + if (param_pos == *haystack) + break; + /* After a delimiter? */ + if (strchr(delim, *(param_pos - 1))) + break; + /* Continue searching. */ + param_pos++; + param_pos = strstr(param_pos, needle); + } while (1); + + if (param_pos) { + param_pos += strlen(needle); + devlen = strcspn(param_pos, delim); + if (devlen) { + dev = malloc(devlen + 1); + if (!dev) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + strncpy(dev, param_pos, devlen); + dev[devlen] = '\0'; + } + rest = param_pos + devlen; + rest += strspn(rest, delim); + param_pos -= strlen(needle); + memmove(param_pos, rest, strlen(rest) + 1); + tmp = realloc(*haystack, strlen(*haystack) + 1); + if (!tmp) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + *haystack = tmp; + } + + + return dev; +} + +/* start is an offset to the base address of the flash chip */ +int check_erased_range(struct flashchip *flash, int start, int len) +{ + int ret; + uint8_t *cmpbuf = malloc(len); + + if (!cmpbuf) { + fprintf(stderr, "Could not allocate memory!\n"); + exit(1); + } + memset(cmpbuf, 0xff, len); + ret = verify_range(flash, cmpbuf, start, len, "ERASE"); + free(cmpbuf); + return ret; +} + +/** + * @cmpbuf buffer to compare against, cmpbuf[0] is expected to match the + flash content at location start + * @start offset to the base address of the flash chip + * @len length of the verified area + * @message string to print in the "FAILED" message + * @return 0 for success, -1 for failure + */ +int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message) +{ + int i, j, starthere, lenhere, ret = 0; + int page_size = flash->page_size; + uint8_t *readbuf = malloc(page_size); + int failcount = 0; + + if (!len) + goto out_free; + + if (!flash->read) { + fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n"); + return 1; + } + if (!readbuf) { + fprintf(stderr, "Could not allocate memory!\n"); + exit(1); + } + + if (start + len > flash->total_size * 1024) { + fprintf(stderr, "Error: %s called with start 0x%x + len 0x%x >" + " total_size 0x%x\n", __func__, start, len, + flash->total_size * 1024); + ret = -1; + goto out_free; + } + if (!message) + message = "VERIFY"; + + /* Warning: This loop has a very unusual condition and body. + * The loop needs to go through each page with at least one affected + * byte. The lowest page number is (start / page_size) since that + * division rounds down. The highest page number we want is the page + * where the last byte of the range lives. That last byte has the + * address (start + len - 1), thus the highest page number is + * (start + len - 1) / page_size. Since we want to include that last + * page as well, the loop condition uses <=. + */ + for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { + /* Byte position of the first byte in the range in this page. */ + starthere = max(start, i * page_size); + /* Length of bytes in the range in this page. */ + lenhere = min(start + len, (i + 1) * page_size) - starthere; + flash->read(flash, readbuf, starthere, lenhere); + for (j = 0; j < lenhere; j++) { + if (cmpbuf[starthere - start + j] != readbuf[j]) { + /* Only print the first failure. */ + if (!failcount++) + fprintf(stderr, "%s FAILED at 0x%08x! " + "Expected=0x%02x, Read=0x%02x,", + message, starthere + j, + cmpbuf[starthere - start + j], + readbuf[j]); + } + } + } + if (failcount) { + fprintf(stderr, " failed byte count from 0x%08x-0x%08x: 0x%x\n", + start, start + len - 1, failcount); + ret = -1; + } + +out_free: + free(readbuf); + return ret; +} + +/* This function generates various test patterns useful for testing controller + * and chip communication as well as chip behaviour. + * + * If a byte can be written multiple times, each time keeping 0-bits at 0 + * and changing 1-bits to 0 if the new value for that bit is 0, the effect + * is essentially an AND operation. That's also the reason why this function + * provides the result of AND between various patterns. + * + * Below is a list of patterns (and their block length). + * Pattern 0 is 05 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 (16 Bytes) + * Pattern 1 is 0a 1a 2a 3a 4a 5a 6a 7a 8a 9a aa ba ca da ea fa (16 Bytes) + * Pattern 2 is 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f (16 Bytes) + * Pattern 3 is a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af (16 Bytes) + * Pattern 4 is 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 (16 Bytes) + * Pattern 5 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f (16 Bytes) + * Pattern 6 is 00 (1 Byte) + * Pattern 7 is ff (1 Byte) + * Patterns 0-7 have a big-endian block number in the last 2 bytes of each 256 + * byte block. + * + * Pattern 8 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11... (256 B) + * Pattern 9 is ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ef ee... (256 B) + * Pattern 10 is 00 00 00 01 00 02 00 03 00 04... (128 kB big-endian counter) + * Pattern 11 is ff ff ff fe ff fd ff fc ff fb... (128 kB big-endian downwards) + * Pattern 12 is 00 (1 Byte) + * Pattern 13 is ff (1 Byte) + * Patterns 8-13 have no block number. + * + * Patterns 0-3 are created to detect and efficiently diagnose communication + * slips like missed bits or bytes and their repetitive nature gives good visual + * cues to the person inspecting the results. In addition, the following holds: + * AND Pattern 0/1 == Pattern 4 + * AND Pattern 2/3 == Pattern 5 + * AND Pattern 0/1/2/3 == AND Pattern 4/5 == Pattern 6 + * A weakness of pattern 0-5 is the inability to detect swaps/copies between + * any two 16-byte blocks except for the last 16-byte block in a 256-byte bloc. + * They work perfectly for detecting any swaps/aliasing of blocks >= 256 bytes. + * 0x5 and 0xa were picked because they are 0101 and 1010 binary. + * Patterns 8-9 are best for detecting swaps/aliasing of blocks < 256 bytes. + * Besides that, they provide for bit testing of the last two bytes of every + * 256 byte block which contains the block number for patterns 0-6. + * Patterns 10-11 are special purpose for detecting subblock aliasing with + * block sizes >256 bytes (some Dataflash chips etc.) + * AND Pattern 8/9 == Pattern 12 + * AND Pattern 10/11 == Pattern 12 + * Pattern 13 is the completely erased state. + * None of the patterns can detect aliasing at boundaries which are a multiple + * of 16 MBytes (but such chips do not exist anyway for Parallel/LPC/FWH/SPI). + */ +int generate_testpattern(uint8_t *buf, uint32_t size, int variant) +{ + int i; + + if (!buf) { + fprintf(stderr, "Invalid buffer!\n"); + return 1; + } + + switch (variant) { + case 0: + for (i = 0; i < size; i++) + buf[i] = (i & 0xf) << 4 | 0x5; + break; + case 1: + for (i = 0; i < size; i++) + buf[i] = (i & 0xf) << 4 | 0xa; + break; + case 2: + for (i = 0; i < size; i++) + buf[i] = 0x50 | (i & 0xf); + break; + case 3: + for (i = 0; i < size; i++) + buf[i] = 0xa0 | (i & 0xf); + break; + case 4: + for (i = 0; i < size; i++) + buf[i] = (i & 0xf) << 4; + break; + case 5: + for (i = 0; i < size; i++) + buf[i] = i & 0xf; + break; + case 6: + memset(buf, 0x00, size); + break; + case 7: + memset(buf, 0xff, size); + break; + case 8: + for (i = 0; i < size; i++) + buf[i] = i & 0xff; + break; + case 9: + for (i = 0; i < size; i++) + buf[i] = ~(i & 0xff); + break; + case 10: + for (i = 0; i < size % 2; i++) { + buf[i * 2] = (i >> 8) & 0xff; + buf[i * 2 + 1] = i & 0xff; + } + if (size & 0x1) + buf[i * 2] = (i >> 8) & 0xff; + break; + case 11: + for (i = 0; i < size % 2; i++) { + buf[i * 2] = ~((i >> 8) & 0xff); + buf[i * 2 + 1] = ~(i & 0xff); + } + if (size & 0x1) + buf[i * 2] = ~((i >> 8) & 0xff); + break; + case 12: + memset(buf, 0x00, size); + break; + case 13: + memset(buf, 0xff, size); + break; + } + + if ((variant >= 0) && (variant <= 7)) { + /* Write block number in the last two bytes of each 256-byte + * block, big endian for easier reading of the hexdump. + * Note that this wraps around for chips larger than 2^24 bytes + * (16 MB). + */ + for (i = 0; i < size / 256; i++) { + buf[i * 256 + 254] = (i >> 8) & 0xff; + buf[i * 256 + 255] = i & 0xff; + } + } + + return 0; +} + +int check_max_decode(enum chipbustype buses, uint32_t size) +{ + int limitexceeded = 0; + if ((buses & CHIP_BUSTYPE_PARALLEL) && + (max_rom_decode.parallel < size)) { + limitexceeded++; + printf_debug("Chip size %u kB is bigger than supported " + "size %u kB of chipset/board/programmer " + "for %s interface, " + "probe/read/erase/write may fail. ", size / 1024, + max_rom_decode.parallel / 1024, "Parallel"); + } + if ((buses & CHIP_BUSTYPE_LPC) && (max_rom_decode.lpc < size)) { + limitexceeded++; + printf_debug("Chip size %u kB is bigger than supported " + "size %u kB of chipset/board/programmer " + "for %s interface, " + "probe/read/erase/write may fail. ", size / 1024, + max_rom_decode.lpc / 1024, "LPC"); + } + if ((buses & CHIP_BUSTYPE_FWH) && (max_rom_decode.fwh < size)) { + limitexceeded++; + printf_debug("Chip size %u kB is bigger than supported " + "size %u kB of chipset/board/programmer " + "for %s interface, " + "probe/read/erase/write may fail. ", size / 1024, + max_rom_decode.fwh / 1024, "FWH"); + } + if ((buses & CHIP_BUSTYPE_SPI) && (max_rom_decode.spi < size)) { + limitexceeded++; + printf_debug("Chip size %u kB is bigger than supported " + "size %u kB of chipset/board/programmer " + "for %s interface, " + "probe/read/erase/write may fail. ", size / 1024, + max_rom_decode.spi / 1024, "SPI"); + } + if (!limitexceeded) + return 0; + /* Sometimes chip and programmer have more than one bus in common, + * and the limit is not exceeded on all buses. Tell the user. + */ + if (bitcount(buses) > limitexceeded) + printf_debug("There is at least one common chip/programmer " + "interface which can support a chip of this size. " + "You can try --force at your own risk.\n"); + return 1; +} + +struct flashchip *probe_flash(struct flashchip *first_flash, int force) +{ + struct flashchip *flash; + unsigned long base = 0; + uint32_t size; + enum chipbustype buses_common; + char *tmp; + + for (flash = first_flash; flash && flash->name; flash++) { + if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0) + continue; + printf_debug("Probing for %s %s, %d KB: ", + flash->vendor, flash->name, flash->total_size); + if (!flash->probe && !force) { + printf_debug("failed! flashrom has no probe function for this flash chip.\n"); + continue; + } + buses_common = buses_supported & flash->bustype; + if (!buses_common) { + tmp = flashbuses_to_text(buses_supported); + printf_debug("skipped. Host bus type %s ", tmp); + free(tmp); + tmp = flashbuses_to_text(flash->bustype); + printf_debug("and chip bus type %s are incompatible.\n", tmp); + free(tmp); + continue; + } + + size = flash->total_size * 1024; + check_max_decode(buses_common, size); + + base = flashbase ? flashbase : (0xffffffff - size + 1); + flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size); + + if (force) + break; + + if (flash->probe(flash) != 1) + goto notfound; + + if (first_flash == flashchips + || flash->model_id != GENERIC_DEVICE_ID) + break; + +notfound: + programmer_unmap_flash_region((void *)flash->virtual_memory, size); + } + + if (!flash || !flash->name) + return NULL; + + printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n", + flash->vendor, flash->name, flash->total_size, + flashbuses_to_text(flash->bustype), base); + + return flash; +} + +int verify_flash(struct flashchip *flash, uint8_t *buf) +{ + int ret; + int total_size = flash->total_size * 1024; + + printf("Verifying flash... "); + + ret = verify_range(flash, buf, 0, total_size, NULL); + + if (!ret) + printf("VERIFIED. \n"); + + return ret; +} + +int read_flash(struct flashchip *flash, char *filename) +{ + unsigned long numbytes; + FILE *image; + unsigned long size = flash->total_size * 1024; + unsigned char *buf = calloc(size, sizeof(char)); + + if (!filename) { + printf("Error: No filename specified.\n"); + return 1; + } + if ((image = fopen(filename, "w")) == NULL) { + perror(filename); + exit(1); + } + printf("Reading flash... "); + if (!flash->read) { + printf("FAILED!\n"); + fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n"); + return 1; + } else + flash->read(flash, buf, 0, size); + + numbytes = fwrite(buf, 1, size, image); + fclose(image); + free(buf); + printf("%s.\n", numbytes == size ? "done" : "FAILED"); + if (numbytes != size) + return 1; + return 0; +} + +int erase_flash(struct flashchip *flash) +{ + int i, j, k, ret = 0, found = 0; + + printf("Erasing flash chip... "); + for (k = 0; k < NUM_ERASEFUNCTIONS; k++) { + unsigned long done = 0; + struct block_eraser eraser = flash->block_erasers[k]; + + printf_debug("Looking at blockwise erase function %i... ", k); + if (!eraser.block_erase && !eraser.eraseblocks[0].count) { + printf_debug("not defined. " + "Looking for another erase function.\n"); + continue; + } + if (!eraser.block_erase && eraser.eraseblocks[0].count) { + printf_debug("eraseblock layout is known, but no " + "matching block erase function found. " + "Looking for another erase function.\n"); + continue; + } + if (eraser.block_erase && !eraser.eraseblocks[0].count) { + printf_debug("block erase function found, but " + "eraseblock layout is unknown. " + "Looking for another erase function.\n"); + continue; + } + found = 1; + printf_debug("trying... "); + for (i = 0; i < NUM_ERASEREGIONS; i++) { + /* count==0 for all automatically initialized array + * members so the loop below won't be executed for them. + */ + for (j = 0; j < eraser.eraseblocks[i].count; j++) { + ret = eraser.block_erase(flash, done + eraser.eraseblocks[i].size * j, eraser.eraseblocks[i].size); + if (ret) + break; + } + if (ret) + break; + } + /* If everything is OK, don't try another erase function. */ + if (!ret) + break; + } + /* If no block erase function was found or block erase failed, retry. */ + if ((!found || ret) && (flash->erase)) { + found = 1; + printf_debug("Trying whole-chip erase function... "); + ret = flash->erase(flash); + } + if (!found) { + fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n"); + return 1; + } + + if (ret) { + fprintf(stderr, "FAILED!\n"); + } else { + printf("SUCCESS.\n"); + } + return ret; +} + +void emergency_help_message(void) +{ + fprintf(stderr, "Your flash chip is in an unknown state.\n" + "Get help on IRC at irc.freenode.net (channel #flashrom) or\n" + "mail flashrom@flashrom.org!\n--------------------" + "-----------------------------------------------------------\n" + "DO NOT REBOOT OR POWEROFF!\n"); +} + +void usage(const char *name) +{ + const char *pname; + int pnamelen; + int remaining = 0; + enum programmer p; + + printf("usage: %s [-VfLzhR] [-E|-r file|-w file|-v file] [-c chipname]\n" + " [-m [vendor:]part] [-l file] [-i image] [-p programmer]\n\n", name); + + printf("Please note that the command line interface for flashrom will " + "change before\nflashrom 1.0. Do not use flashrom in scripts " + "or other automated tools without\nchecking that your flashrom" + " version won't interpret options in a different way.\n\n"); + + printf + (" -r | --read: read flash and save into file\n" + " -w | --write: write file into flash\n" + " -v | --verify: verify flash against file\n" + " -n | --noverify: don't verify flash against file\n" + " -E | --erase: erase flash device\n" + " -V | --verbose: more verbose output\n" + " -c | --chip : probe only for specified flash chip\n" + " -m | --mainboard <[vendor:]part>: override mainboard settings\n" + " -f | --force: force write without checking image\n" + " -l | --layout : read ROM layout from file\n" + " -i | --image : only flash image name from flash layout\n" + " -L | --list-supported: print supported devices\n" +#if PRINT_WIKI_SUPPORT == 1 + " -z | --list-supported-wiki: print supported devices in wiki syntax\n" +#endif + " -p | --programmer : specify the programmer device"); + + for (p = 0; p < PROGRAMMER_INVALID; p++) { + pname = programmer_table[p].name; + pnamelen = strlen(pname); + if (remaining - pnamelen - 2 < 0) { + printf("\n "); + remaining = 43; + } else { + printf(" "); + remaining--; + } + if (p == 0) { + printf("("); + remaining--; + } + printf("%s", pname); + remaining -= pnamelen; + if (p < PROGRAMMER_INVALID - 1) { + printf(","); + remaining--; + } else { + printf(")\n"); + } + } + + printf( + " -h | --help: print this help text\n" + " -R | --version: print the version (release)\n" + "\nYou can specify one of -E, -r, -w, -v or no operation. If no operation is\n" + "specified, then all that happens is that flash info is dumped.\n\n"); + exit(1); +} + +void print_version(void) +{ + printf("flashrom v%s\n", flashrom_version); +} + +int main(int argc, char *argv[]) +{ + uint8_t *buf; + unsigned long size, numbytes; + FILE *image; + /* Probe for up to three flash chips. */ + struct flashchip *flash, *flashes[3]; + const char *name; + int namelen; + int opt; + int option_index = 0; + int force = 0; + int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; + int dont_verify_it = 0, list_supported = 0; +#if PRINT_WIKI_SUPPORT == 1 + int list_supported_wiki = 0; +#endif + int operation_specified = 0; + int ret = 0, i; + +#if PRINT_WIKI_SUPPORT == 1 + const char *optstring = "rRwvnVEfc:m:l:i:p:Lzh"; +#else + const char *optstring = "rRwvnVEfc:m:l:i:p:Lh"; +#endif + static struct option long_options[] = { + {"read", 0, 0, 'r'}, + {"write", 0, 0, 'w'}, + {"erase", 0, 0, 'E'}, + {"verify", 0, 0, 'v'}, + {"noverify", 0, 0, 'n'}, + {"chip", 1, 0, 'c'}, + {"mainboard", 1, 0, 'm'}, + {"verbose", 0, 0, 'V'}, + {"force", 0, 0, 'f'}, + {"layout", 1, 0, 'l'}, + {"image", 1, 0, 'i'}, + {"list-supported", 0, 0, 'L'}, +#if PRINT_WIKI_SUPPORT == 1 + {"list-supported-wiki", 0, 0, 'z'}, +#endif + {"programmer", 1, 0, 'p'}, + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'R'}, + {0, 0, 0, 0} + }; + + char *filename = NULL; + + char *tempstr = NULL, *tempstr2 = NULL; + + print_version(); + + if (argc > 1) { + /* Yes, print them. */ + int i; + printf_debug("The arguments are:\n"); + for (i = 1; i < argc; ++i) + printf_debug("%s\n", argv[i]); + } + + /* Safety check. */ + if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) { + fprintf(stderr, "Programmer table miscompilation!\n"); + exit(1); + } + if (spi_programmer_count - 1 != SPI_CONTROLLER_INVALID) { + fprintf(stderr, "SPI programmer table miscompilation!\n"); + exit(1); + } +#if BITBANG_SPI_SUPPORT == 1 + if (bitbang_spi_master_count - 1 != BITBANG_SPI_INVALID) { + fprintf(stderr, "Bitbanging SPI master table miscompilation!\n"); + exit(1); + } +#endif + + setbuf(stdout, NULL); + while ((opt = getopt_long(argc, argv, optstring, + long_options, &option_index)) != EOF) { + switch (opt) { + case 'r': + if (++operation_specified > 1) { + fprintf(stderr, "More than one operation " + "specified. Aborting.\n"); + exit(1); + } + read_it = 1; + break; + case 'w': + if (++operation_specified > 1) { + fprintf(stderr, "More than one operation " + "specified. Aborting.\n"); + exit(1); + } + write_it = 1; + break; + case 'v': + //FIXME: gracefully handle superfluous -v + if (++operation_specified > 1) { + fprintf(stderr, "More than one operation " + "specified. Aborting.\n"); + exit(1); + } + if (dont_verify_it) { + fprintf(stderr, "--verify and --noverify are" + "mutually exclusive. Aborting.\n"); + exit(1); + } + verify_it = 1; + break; + case 'n': + if (verify_it) { + fprintf(stderr, "--verify and --noverify are" + "mutually exclusive. Aborting.\n"); + exit(1); + } + dont_verify_it = 1; + break; + case 'c': + chip_to_probe = strdup(optarg); + break; + case 'V': + verbose = 1; + break; + case 'E': + if (++operation_specified > 1) { + fprintf(stderr, "More than one operation " + "specified. Aborting.\n"); + exit(1); + } + erase_it = 1; + break; + case 'm': + tempstr = strdup(optarg); + strtok(tempstr, ":"); + tempstr2 = strtok(NULL, ":"); + if (tempstr2) { + lb_vendor = tempstr; + lb_part = tempstr2; + } else { + lb_vendor = NULL; + lb_part = tempstr; + } + break; + case 'f': + force = 1; + break; + case 'l': + tempstr = strdup(optarg); + if (read_romlayout(tempstr)) + exit(1); + break; + case 'i': + tempstr = strdup(optarg); + find_romentry(tempstr); + break; + case 'L': + list_supported = 1; + break; +#if PRINT_WIKI_SUPPORT == 1 + case 'z': + list_supported_wiki = 1; + break; +#endif + case 'p': + for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) { + name = programmer_table[programmer].name; + namelen = strlen(name); + if (strncmp(optarg, name, namelen) == 0) { + switch (optarg[namelen]) { + case ':': + programmer_param = strdup(optarg + namelen + 1); + break; + case '\0': + break; + default: + /* The continue refers to the + * for loop. It is here to be + * able to differentiate between + * foo and foobar. + */ + continue; + } + break; + } + } + if (programmer == PROGRAMMER_INVALID) { + printf("Error: Unknown programmer %s.\n", optarg); + exit(1); + } + break; + case 'R': + /* print_version() is always called during startup. */ + exit(0); + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + if (list_supported) { + print_supported(); + exit(0); + } + +#if PRINT_WIKI_SUPPORT == 1 + if (list_supported_wiki) { + print_supported_wiki(); + exit(0); + } +#endif + + if (read_it && write_it) { + printf("Error: -r and -w are mutually exclusive.\n"); + usage(argv[0]); + } + + if (optind < argc) + filename = argv[optind++]; + + if (optind < argc) { + printf("Error: Extra parameter found.\n"); + usage(argv[0]); + } + + if (programmer_init()) { + fprintf(stderr, "Error: Programmer initialization failed.\n"); + exit(1); + } + + myusec_calibrate_delay(); + + for (i = 0; i < ARRAY_SIZE(flashes); i++) { + flashes[i] = + probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0); + if (!flashes[i]) + for (i++; i < ARRAY_SIZE(flashes); i++) + flashes[i] = NULL; + } + + if (flashes[1]) { + printf("Multiple flash chips were detected:"); + for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++) + printf(" %s", flashes[i]->name); + printf("\nPlease specify which chip to use with the -c option.\n"); + programmer_shutdown(); + exit(1); + } else if (!flashes[0]) { + printf("No EEPROM/flash device found.\n"); + if (!force || !chip_to_probe) { + printf("If you know which flash chip you have, and if this version of flashrom\n"); + printf("supports a similar flash chip, you can try to force read your chip. Run:\n"); + printf("flashrom -f -r -c similar_supported_flash_chip filename\n"); + printf("\n"); + printf("Note: flashrom can never write when the flash chip isn't found automatically.\n"); + } + if (force && read_it && chip_to_probe) { + printf("Force read (-f -r -c) requested, forcing chip probe success:\n"); + flashes[0] = probe_flash(flashchips, 1); + if (!flashes[0]) { + printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe); + printf("Run flashrom -L to view the hardware supported in this flashrom version.\n"); + exit(1); + } + printf("Please note that forced reads most likely contain garbage.\n"); + return read_flash(flashes[0], filename); + } + // FIXME: flash writes stay enabled! + programmer_shutdown(); + exit(1); + } + + flash = flashes[0]; + + if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) { + printf("===\n"); + if (flash->tested & TEST_BAD_MASK) { + printf("This flash part has status NOT WORKING for operations:"); + if (flash->tested & TEST_BAD_PROBE) + printf(" PROBE"); + if (flash->tested & TEST_BAD_READ) + printf(" READ"); + if (flash->tested & TEST_BAD_ERASE) + printf(" ERASE"); + if (flash->tested & TEST_BAD_WRITE) + printf(" WRITE"); + printf("\n"); + } + if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) || + (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) || + (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) || + (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) { + printf("This flash part has status UNTESTED for operations:"); + if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) + printf(" PROBE"); + if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) + printf(" READ"); + if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) + printf(" ERASE"); + if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE)) + printf(" WRITE"); + printf("\n"); + } + printf("Please email a report to flashrom@flashrom.org if any " + "of the above operations\nwork correctly for you with " + "this flash part. Please include the flashrom\noutput " + "with the additional -V option for all operations you " + "tested (-V, -rV,\n-wV, -EV), and mention which " + "mainboard you tested. Thanks for your help!\n===\n"); + } + + size = flash->total_size * 1024; + if (check_max_decode((buses_supported & flash->bustype), size) && + (!force)) { + fprintf(stderr, "Chip is too big for this programmer " + "(-V gives details). Use --force to override.\n"); + programmer_shutdown(); + return 1; + } + + if (!(read_it | write_it | verify_it | erase_it)) { + printf("No operations were specified.\n"); + // FIXME: flash writes stay enabled! + programmer_shutdown(); + exit(1); + } + + if (!filename && !erase_it) { + printf("Error: No filename specified.\n"); + // FIXME: flash writes stay enabled! + programmer_shutdown(); + exit(1); + } + + /* Always verify write operations unless -n is used. */ + if (write_it && !dont_verify_it) + verify_it = 1; + + buf = (uint8_t *) calloc(size, sizeof(char)); + + if (erase_it) { + if (flash->tested & TEST_BAD_ERASE) { + fprintf(stderr, "Erase is not working on this chip. "); + if (!force) { + fprintf(stderr, "Aborting.\n"); + programmer_shutdown(); + return 1; + } else { + fprintf(stderr, "Continuing anyway.\n"); + } + } + if (erase_flash(flash)) { + emergency_help_message(); + programmer_shutdown(); + return 1; + } + } else if (read_it) { + if (read_flash(flash, filename)) { + programmer_shutdown(); + return 1; + } + } else { + struct stat image_stat; + + if (flash->tested & TEST_BAD_ERASE) { + fprintf(stderr, "Erase is not working on this chip " + "and erase is needed for write. "); + if (!force) { + fprintf(stderr, "Aborting.\n"); + programmer_shutdown(); + return 1; + } else { + fprintf(stderr, "Continuing anyway.\n"); + } + } + if (flash->tested & TEST_BAD_WRITE) { + fprintf(stderr, "Write is not working on this chip. "); + if (!force) { + fprintf(stderr, "Aborting.\n"); + programmer_shutdown(); + return 1; + } else { + fprintf(stderr, "Continuing anyway.\n"); + } + } + if ((image = fopen(filename, "r")) == NULL) { + perror(filename); + programmer_shutdown(); + exit(1); + } + if (fstat(fileno(image), &image_stat) != 0) { + perror(filename); + programmer_shutdown(); + exit(1); + } + if (image_stat.st_size != flash->total_size * 1024) { + fprintf(stderr, "Error: Image size doesn't match\n"); + programmer_shutdown(); + exit(1); + } + + numbytes = fread(buf, 1, size, image); + show_id(buf, size, force); + fclose(image); + if (numbytes != size) { + fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size); + programmer_shutdown(); + return 1; + } + } + + // This should be moved into each flash part's code to do it + // cleanly. This does the job. + handle_romentries(buf, flash); + + // //////////////////////////////////////////////////////////// + + if (write_it) { + printf("Writing flash chip... "); + if (!flash->write) { + fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n"); + programmer_shutdown(); + return 1; + } + ret = flash->write(flash, buf); + if (ret) { + fprintf(stderr, "FAILED!\n"); + emergency_help_message(); + programmer_shutdown(); + return 1; + } else { + printf("COMPLETE.\n"); + } + } + + if (verify_it) { + /* Work around chips which need some time to calm down. */ + if (write_it) + programmer_delay(1000*1000); + ret = verify_flash(flash, buf); + /* If we tried to write, and verification now fails, we + * might have an emergency situation. + */ + if (ret && write_it) + emergency_help_message(); + } + + programmer_shutdown(); + + return ret; +} diff --git a/cli/layout.c b/cli/layout.c new file mode 100644 index 0000000..7610466 --- /dev/null +++ b/cli/layout.c @@ -0,0 +1,229 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2005-2008 coresystems GmbH + * (Written by Stefan Reinauer for coresystems GmbH) + * + * 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 "../libflashrom/flash.h" + +char *mainboard_vendor = NULL; +char *mainboard_part = NULL; +int romimages = 0; + +#define MAX_ROMLAYOUT 16 + +typedef struct { + unsigned int start; + unsigned int end; + unsigned int included; + char name[256]; +} romlayout_t; + +romlayout_t rom_entries[MAX_ROMLAYOUT]; + +static char *def_name = "DEFAULT"; + +int show_id(uint8_t *bios, int size, int force) +{ + unsigned int *walk; + unsigned int mb_part_offset, mb_vendor_offset; + char *mb_part, *mb_vendor; + + mainboard_vendor = def_name; + mainboard_part = def_name; + + walk = (unsigned int *)(bios + size - 0x10); + walk--; + + if ((*walk) == 0 || ((*walk) & 0x3ff) != 0) { + /* We might have an NVIDIA chipset BIOS which stores the ID + * information at a different location. + */ + walk = (unsigned int *)(bios + size - 0x80); + walk--; + } + + /* + * Check if coreboot last image size is 0 or not a multiple of 1k or + * bigger than the chip or if the pointers to vendor ID or mainboard ID + * are outside the image of if the start of ID strings are nonsensical + * (nonprintable and not \0). + */ + mb_part_offset = *(walk - 1); + mb_vendor_offset = *(walk - 2); + if ((*walk) == 0 || ((*walk) & 0x3ff) != 0 || (*walk) > size || + mb_part_offset > size || mb_vendor_offset > size) { + printf("Flash image seems to be a legacy BIOS. Disabling checks.\n"); + return 0; + } + + mb_part = (char *)(bios + size - mb_part_offset); + mb_vendor = (char *)(bios + size - mb_vendor_offset); + if (!isprint((unsigned char)*mb_part) || + !isprint((unsigned char)*mb_vendor)) { + printf("Flash image seems to have garbage in the ID location." + " Disabling checks.\n"); + return 0; + } + + printf_debug("coreboot last image size " + "(not ROM size) is %d bytes.\n", *walk); + + mainboard_part = strdup(mb_part); + mainboard_vendor = strdup(mb_vendor); + printf_debug("Manufacturer: %s\n", mainboard_vendor); + printf_debug("Mainboard ID: %s\n", mainboard_part); + + /* + * If lb_vendor is not set, the coreboot table was + * not found. Nor was -m VENDOR:PART specified. + */ + if (!lb_vendor || !lb_part) { + printf("Note: If the following flash access fails, " + "try -m :.\n"); + return 0; + } + + /* These comparisons are case insensitive to make things + * a little less user^Werror prone. + */ + if (!strcasecmp(mainboard_vendor, lb_vendor) && + !strcasecmp(mainboard_part, lb_part)) { + printf_debug("This firmware image matches this mainboard.\n"); + } else { + if (force) { + printf("WARNING: This firmware image does not " + "seem to fit to this machine - forcing it.\n"); + } else { + printf("ERROR: Your firmware image (%s:%s) does not " + "appear to\n be correct for the detected " + "mainboard (%s:%s)\n\nOverride with --force if you " + "are absolutely sure that you\nare using a correct " + "image for this mainboard or override\nthe detected " + "values with --mainboard :.\n\n", + mainboard_vendor, mainboard_part, lb_vendor, + lb_part); + exit(1); + } + } + + return 0; +} + +int read_romlayout(char *name) +{ + FILE *romlayout; + char tempstr[256]; + int i; + + romlayout = fopen(name, "r"); + + if (!romlayout) { + fprintf(stderr, "ERROR: Could not open ROM layout (%s).\n", + name); + return -1; + } + + while (!feof(romlayout)) { + char *tstr1, *tstr2; + if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name)) + continue; +#if 0 + // fscanf does not like arbitrary comments like that :( later + if (tempstr[0] == '#') { + continue; + } +#endif + tstr1 = strtok(tempstr, ":"); + tstr2 = strtok(NULL, ":"); + if (!tstr1 || !tstr2) { + fprintf(stderr, "Error parsing layout file.\n"); + fclose(romlayout); + return 1; + } + rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16); + rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16); + rom_entries[romimages].included = 0; + romimages++; + } + + for (i = 0; i < romimages; i++) { + printf_debug("romlayout %08x - %08x named %s\n", + rom_entries[i].start, + rom_entries[i].end, rom_entries[i].name); + } + + fclose(romlayout); + + return 0; +} + +int find_romentry(char *name) +{ + int i; + + if (!romimages) + return -1; + + printf("Looking for \"%s\"... ", name); + + for (i = 0; i < romimages; i++) { + if (!strcmp(rom_entries[i].name, name)) { + rom_entries[i].included = 1; + printf("found.\n"); + return i; + } + } + printf("not found.\n"); // Not found. Error. + + return -1; +} + +int handle_romentries(uint8_t *buffer, struct flashchip *flash) +{ + int i; + + // This function does not save flash write cycles. + // + // Also it does not cope with overlapping rom layout + // sections. + // example: + // 00000000:00008fff gfxrom + // 00009000:0003ffff normal + // 00040000:0007ffff fallback + // 00000000:0007ffff all + // + // If you'd specify -i all the included flag of all other + // sections is still 0, so no changes will be made to the + // flash. Same thing if you specify -i normal -i all only + // normal will be updated and the rest will be kept. + + for (i = 0; i < romimages; i++) { + + if (rom_entries[i].included) + continue; + + flash->read(flash, buffer + rom_entries[i].start, + rom_entries[i].start, + rom_entries[i].end - rom_entries[i].start + 1); + } + + return 0; +} diff --git a/cli/physmap.c b/cli/physmap.c new file mode 100644 index 0000000..6b86ba6 --- /dev/null +++ b/cli/physmap.c @@ -0,0 +1,340 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Peter Stuge + * Copyright (C) 2009 coresystems GmbH + * + * 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 "../libflashrom/flash.h" + +#ifdef __DARWIN__ +#include + +#define MEM_DEV "DirectIO" + +void *sys_physmap(unsigned long phys_addr, size_t len) +{ + return map_physical(phys_addr, len); +} + +void physunmap(void *virt_addr, size_t len) +{ + unmap_physical(virt_addr, len); +} + +#else +#include + +#if defined (__sun) && (defined(__i386) || defined(__amd64)) +# define MEM_DEV "/dev/xsvc" +#else +# define MEM_DEV "/dev/mem" +#endif + +static int fd_mem = -1; + +void *sys_physmap(unsigned long phys_addr, size_t len) +{ + void *virt_addr; + + if (-1 == fd_mem) { + /* Open the memory device UNCACHED. Important for MMIO. */ + if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) { + perror("Critical error: open(" MEM_DEV ")"); + exit(2); + } + } + + virt_addr = mmap(0, len, PROT_WRITE | PROT_READ, MAP_SHARED, + fd_mem, (off_t)phys_addr); + return MAP_FAILED == virt_addr ? NULL : virt_addr; +} + +void physunmap(void *virt_addr, size_t len) +{ + if (len == 0) { + printf_debug("Not unmapping zero size at %p\n", virt_addr); + return; + } + + munmap(virt_addr, len); +} +#endif + +void *physmap(const char *descr, unsigned long phys_addr, size_t len) +{ + void *virt_addr; + + if (len == 0) { + printf_debug("Not mapping %s, zero size at 0x%08lx.\n", + descr, phys_addr); + return NULL; + } + + if ((getpagesize() - 1) & len) { + fprintf(stderr, "Mapping %s at 0x%08lx, unaligned size 0x%lx.\n", + descr, phys_addr, (unsigned long)len); + } + + if ((getpagesize() - 1) & phys_addr) { + fprintf(stderr, "Mapping %s, 0x%lx bytes at unaligned 0x%08lx.\n", + descr, (unsigned long)len, phys_addr); + } + + virt_addr = sys_physmap(phys_addr, len); + + if (NULL == virt_addr) { + if (NULL == descr) + descr = "memory"; + fprintf(stderr, "Error accessing %s, 0x%lx bytes at 0x%08lx\n", descr, (unsigned long)len, phys_addr); + perror(MEM_DEV " mmap failed"); + if (EINVAL == errno) { + fprintf(stderr, "In Linux this error can be caused by the CONFIG_NONPROMISC_DEVMEM (<2.6.27),\n"); + fprintf(stderr, "CONFIG_STRICT_DEVMEM (>=2.6.27) and CONFIG_X86_PAT kernel options.\n"); + fprintf(stderr, "Please check if either is enabled in your kernel before reporting a failure.\n"); + fprintf(stderr, "You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n"); + fprintf(stderr, "disabling the other option unfortunately requires a kernel recompile. Sorry!\n"); + } + exit(3); + } + + return virt_addr; +} + +#ifdef __linux__ +/* + * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr, + * which are ring0 privileged instructions so only the kernel can do the + * read/write. This function, therefore, requires that the msr kernel module + * be loaded to access these instructions from user space using device + * /dev/cpu/0/msr. + */ + +static int fd_msr = -1; + +msr_t rdmsr(int addr) +{ + uint32_t buf[2]; + msr_t msr = { 0xffffffff, 0xffffffff }; + + if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) { + perror("Could not lseek() to MSR"); + close(fd_msr); + exit(1); + } + + if (read(fd_msr, buf, 8) == 8) { + msr.lo = buf[0]; + msr.hi = buf[1]; + + return msr; + } + + if (errno != EIO) { + // A severe error. + perror("Could not read() MSR"); + close(fd_msr); + exit(1); + } + + return msr; +} + +int wrmsr(int addr, msr_t msr) +{ + if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) { + perror("Could not lseek() to MSR"); + close(fd_msr); + exit(1); + } + + if (write(fd_msr, &msr, 8) != 8 && errno != EIO) { + perror("Could not write() MSR"); + close(fd_msr); + exit(1); + } + + /* some MSRs must not be written */ + if (errno == EIO) + return -1; + + return 0; +} + +int setup_cpu_msr(int cpu) +{ + char msrfilename[64]; + memset(msrfilename, 0, 64); + sprintf(msrfilename, "/dev/cpu/%d/msr", cpu); + + if (fd_msr != -1) { + printf("MSR was already initialized\n"); + return -1; + } + + fd_msr = open(msrfilename, O_RDWR); + + if (fd_msr < 0) { + perror("Error while opening /dev/cpu/0/msr"); + printf("Did you run 'modprobe msr'?\n"); + return -1; + } + + return 0; +} + +void cleanup_cpu_msr(void) +{ + if (fd_msr == -1) { + printf("No MSR initialized.\n"); + return; + } + + close(fd_msr); + + /* Clear MSR file descriptor */ + fd_msr = -1; +} +#else +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include + +typedef struct { + int msr; + uint64_t data; +} cpu_msr_args_t; +#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t) +#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t) + +static int fd_msr = -1; + +msr_t rdmsr(int addr) +{ + cpu_msr_args_t args; + + msr_t msr = { 0xffffffff, 0xffffffff }; + + args.msr = addr; + + if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) { + perror("CPU_RDMSR"); + close(fd_msr); + exit(1); + } + + msr.lo = args.data & 0xffffffff; + msr.hi = args.data >> 32; + + return msr; +} + +int wrmsr(int addr, msr_t msr) +{ + cpu_msr_args_t args; + + args.msr = addr; + args.data = (((uint64_t)msr.hi) << 32) | msr.lo; + + if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) { + perror("CPU_WRMSR"); + close(fd_msr); + exit(1); + } + + return 0; +} + +int setup_cpu_msr(int cpu) +{ + char msrfilename[64]; + memset(msrfilename, 0, 64); + sprintf(msrfilename, "/dev/cpu%d", cpu); + + if (fd_msr != -1) { + printf("MSR was already initialized\n"); + return -1; + } + + fd_msr = open(msrfilename, O_RDWR); + + if (fd_msr < 0) { + perror("Error while opening /dev/cpu0"); + printf("Did you install ports/sysutils/devcpu?\n"); + return -1; + } + + return 0; +} + +void cleanup_cpu_msr(void) +{ + if (fd_msr == -1) { + printf("No MSR initialized.\n"); + return; + } + + close(fd_msr); + + /* Clear MSR file descriptor */ + fd_msr = -1; +} + +#else + +#ifdef __DARWIN__ +int setup_cpu_msr(int cpu) +{ + // Always succeed for now + return 0; +} + +void cleanup_cpu_msr(void) +{ + // Nothing, yet. +} +#else +msr_t rdmsr(int addr) +{ + msr_t ret = { 0xffffffff, 0xffffffff }; + + return ret; +} + +int wrmsr(int addr, msr_t msr) +{ + return -1; +} + +int setup_cpu_msr(int cpu) +{ + printf("No MSR support for your OS yet.\n"); + return -1; +} + +void cleanup_cpu_msr(void) +{ + // Nothing, yet. +} +#endif +#endif +#endif + diff --git a/cli/print.c b/cli/print.c new file mode 100644 index 0000000..e887334 --- /dev/null +++ b/cli/print.c @@ -0,0 +1,397 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include "../libflashrom/flash.h" +#include "../libflashrom/flashchips.h" + +/* + * Return a string corresponding to the bustype parameter. + * Memory is obtained with malloc() and can be freed with free(). + */ +char *flashbuses_to_text(enum chipbustype bustype) +{ + char *ret = calloc(1, 1); + if (bustype == CHIP_BUSTYPE_UNKNOWN) { + ret = strcat_realloc(ret, "Unknown,"); + /* + * FIXME: Once all chipsets and flash chips have been updated, NONSPI + * will cease to exist and should be eliminated here as well. + */ + } else if (bustype == CHIP_BUSTYPE_NONSPI) { + ret = strcat_realloc(ret, "Non-SPI,"); + } else { + if (bustype & CHIP_BUSTYPE_PARALLEL) + ret = strcat_realloc(ret, "Parallel,"); + if (bustype & CHIP_BUSTYPE_LPC) + ret = strcat_realloc(ret, "LPC,"); + if (bustype & CHIP_BUSTYPE_FWH) + ret = strcat_realloc(ret, "FWH,"); + if (bustype & CHIP_BUSTYPE_SPI) + ret = strcat_realloc(ret, "SPI,"); + if (bustype == CHIP_BUSTYPE_NONE) + ret = strcat_realloc(ret, "None,"); + } + /* Kill last comma. */ + ret[strlen(ret) - 1] = '\0'; + ret = realloc(ret, strlen(ret) + 1); + return ret; +} + +#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0) + +static int digits(int n) +{ + int i; + + if (!n) + return 1; + + for (i = 0; n; ++i) + n /= 10; + + return i; +} + +void print_supported_chips(void) +{ + int okcol = 0, pos = 0, i, chipcount = 0; + struct flashchip *f; + + for (f = flashchips; f->name != NULL; f++) { + if (GENERIC_DEVICE_ID == f->model_id) + continue; + okcol = max(okcol, strlen(f->vendor) + 1 + strlen(f->name)); + } + okcol = (okcol + 7) & ~7; + + for (f = flashchips; f->name != NULL; f++) + chipcount++; + + printf("\nSupported flash chips (total: %d):\n\n", chipcount); + POS_PRINT("Vendor: Device:"); + while (pos < okcol) { + printf("\t"); + pos += 8 - (pos % 8); + } + + printf("Tested OK:\tKnown BAD: Size/KB: Type:\n\n"); + printf("(P = PROBE, R = READ, E = ERASE, W = WRITE)\n\n"); + + for (f = flashchips; f->name != NULL; f++) { + /* Don't print "unknown XXXX SPI chip" entries. */ + if (!strncmp(f->name, "unknown", 7)) + continue; + + printf("%s", f->vendor); + for (i = 0; i < 10 - strlen(f->vendor); i++) + printf(" "); + printf("%s", f->name); + + pos = 10 + strlen(f->name); + while (pos < okcol) { + printf("\t"); + pos += 8 - (pos % 8); + } + if ((f->tested & TEST_OK_MASK)) { + if ((f->tested & TEST_OK_PROBE)) + POS_PRINT("P "); + if ((f->tested & TEST_OK_READ)) + POS_PRINT("R "); + if ((f->tested & TEST_OK_ERASE)) + POS_PRINT("E "); + if ((f->tested & TEST_OK_WRITE)) + POS_PRINT("W "); + } + while (pos < okcol + 9) { + printf("\t"); + pos += 8 - (pos % 8); + } + if ((f->tested & TEST_BAD_MASK)) { + if ((f->tested & TEST_BAD_PROBE)) + printf("P "); + if ((f->tested & TEST_BAD_READ)) + printf("R "); + if ((f->tested & TEST_BAD_ERASE)) + printf("E "); + if ((f->tested & TEST_BAD_WRITE)) + printf("W "); + } + + printf("\t %d", f->total_size); + for (i = 0; i < 10 - digits(f->total_size); i++) + printf(" "); + printf("%s\n", flashbuses_to_text(f->bustype)); + } +} + +void print_supported_chipsets(void) +{ + int i, j, chipsetcount = 0; + const struct penable *c = chipset_enables; + + for (i = 0; c[i].vendor_name != NULL; i++) + chipsetcount++; + + printf("\nSupported chipsets (total: %d):\n\nVendor: " + "Chipset: PCI IDs:\n\n", chipsetcount); + + for (i = 0; c[i].vendor_name != NULL; i++) { + printf("%s", c[i].vendor_name); + for (j = 0; j < 25 - strlen(c[i].vendor_name); j++) + printf(" "); + printf("%s", c[i].device_name); + for (j = 0; j < 25 - strlen(c[i].device_name); j++) + printf(" "); + printf("%04x:%04x%s\n", c[i].vendor_id, c[i].device_id, + (c[i].status == OK) ? "" : " (untested)"); + } +} + +void print_supported_boards_helper(const struct board_info *b, const char *msg) +{ + int i, j, boardcount = 0; + + for (i = 0; b[i].vendor != NULL; i++) + boardcount++; + + printf("\n%s (total: %d):\n\n", msg, boardcount); + + for (i = 0; b[i].vendor != NULL; i++) { + printf("%s", b[i].vendor); + for (j = 0; j < 25 - strlen(b[i].vendor); j++) + printf(" "); + printf("%s", b[i].name); + for (j = 0; j < 28 - strlen(b[i].name); j++) + printf(" "); + printf("\n"); + } +} + +void print_supported_boards(void) +{ + int i, j, boardcount = 0; + struct board_pciid_enable *b = board_pciid_enables; + + for (i = 0; b[i].vendor_name != NULL; i++) + boardcount++; + + printf("\nSupported boards which need write-enable code (total: %d):" + "\n\nVendor: Board: " + "Required option:\n\n", boardcount); + + for (i = 0; b[i].vendor_name != NULL; i++) { + printf("%s", b[i].vendor_name); + for (j = 0; j < 25 - strlen(b[i].vendor_name); j++) + printf(" "); + printf("%s", b[i].board_name); + for (j = 0; j < 30 - strlen(b[i].board_name); j++) + printf(" "); + if (b[i].lb_vendor != NULL) + printf("-m %s:%s\n", b[i].lb_vendor, b[i].lb_part); + else + printf("(none, board is autodetected)\n"); + } + + print_supported_boards_helper(boards_ok, + "Supported boards which don't need write-enable code"); + print_supported_boards_helper(boards_bad, + "Boards which have been verified to NOT work yet"); + print_supported_boards_helper(laptops_ok, + "Laptops which have been verified to work"); + print_supported_boards_helper(laptops_bad, + "Laptops which have been verified to NOT work yet"); +} + +void print_supported(void) +{ + print_supported_chips(); + print_supported_chipsets(); + print_supported_boards(); + printf("\nSupported PCI devices flashrom can use " + "as programmer:\n\n"); +#if NIC3COM_SUPPORT == 1 + print_supported_pcidevs(nics_3com); +#endif +#if GFXNVIDIA_SUPPORT == 1 + print_supported_pcidevs(gfx_nvidia); +#endif +#if DRKAISER_SUPPORT == 1 + print_supported_pcidevs(drkaiser_pcidev); +#endif +#if SATASII_SUPPORT == 1 + print_supported_pcidevs(satas_sii); +#endif +} + + +/* Please keep this list alphabetically ordered by vendor/board. */ +const struct board_info boards_ok[] = { + /* Verified working boards that don't need write-enables. */ + { "Abit", "AX8", }, + { "Abit", "Fatal1ty F-I90HD", }, + { "Advantech", "PCM-5820", }, + { "ASI", "MB-5BLMP", }, + { "ASRock", "A770CrossFire", }, + { "ASRock", "K8S8X", }, + { "ASUS", "A7N8X Deluxe", }, + { "ASUS", "A7N8X-E Deluxe", }, + { "ASUS", "A7V400-MX", }, + { "ASUS", "A7V8X-MX", }, + { "ASUS", "A8N-E", }, + { "ASUS", "A8NE-FM/S", }, + { "ASUS", "A8N-SLI", }, + { "ASUS", "A8N-SLI Premium", }, + { "ASUS", "A8V Deluxe", }, + { "ASUS", "A8V-E Deluxe", }, + { "ASUS", "A8V-E SE", }, + { "ASUS", "K8V", }, + { "ASUS", "K8V SE Deluxe", }, + { "ASUS", "K8V-X SE", }, + { "ASUS", "M2A-MX", }, + { "ASUS", "M2A-VM", }, + { "ASUS", "M2N-E", }, + { "ASUS", "M2V", }, + { "ASUS", "M3A78-EM", }, + { "ASUS", "P2B", }, + { "ASUS", "P2B-D", }, + { "ASUS", "P2B-DS", }, + { "ASUS", "P2B-F", }, + { "ASUS", "P2L97-S", }, + { "ASUS", "P5B-Deluxe", }, + { "ASUS", "P5KC", }, + { "ASUS", "P5L-MX", }, + { "ASUS", "P6T Deluxe V2", }, + { "A-Trend", "ATC-6220", }, + { "BCOM", "WinNET100", }, + { "DFI", "Blood-Iron P35 T2RL", }, + { "Elitegroup", "K7S5A", }, + { "Elitegroup", "P6VAP-A+", }, + { "GIGABYTE", "GA-6BXC", }, + { "GIGABYTE", "GA-6BXDU", }, + { "GIGABYTE", "GA-6ZMA", }, + { "GIGABYTE", "GA-7ZM", }, + { "GIGABYTE", "GA-EP35-DS3L", }, + { "GIGABYTE", "GA-EX58-UD4P", }, + { "GIGABYTE", "GA-MA78GPM-DS2H", }, + { "GIGABYTE", "GA-MA790GP-DS4H", }, + { "GIGABYTE", "GA-MA770T-UD3P", }, + { "Intel", "EP80759", }, + { "Jetway", "J7F4K1G5D-PB", }, + { "MSI", "MS-6153", }, + { "MSI", "MS-6156", }, + { "MSI", "MS-6570 (K7N2)", }, + { "MSI", "MS-7065", }, + { "MSI", "MS-7168 (Orion)", }, + { "MSI", "MS-7236 (945PL Neo3)", }, + { "MSI", "MS-7255 (P4M890M)", }, + { "MSI", "MS-7345 (P35 Neo2-FIR)", }, + { "MSI", "MS-7368 (K9AG Neo2-Digital)", }, + { "NEC", "PowerMate 2000", }, + { "PC Engines", "Alix.1c", }, + { "PC Engines", "Alix.2c2", }, + { "PC Engines", "Alix.2c3", }, + { "PC Engines", "Alix.3c3", }, + { "PC Engines", "Alix.3d3", }, + { "RCA", "RM4100", }, + { "Sun", "Blade x6250", }, + { "Supermicro", "H8QC8", }, + { "Thomson", "IP1000", }, + { "TriGem", "Lomita", }, + { "T-Online", "S-100", }, + { "Tyan", "iS5375-1U", }, + { "Tyan", "S1846", }, + { "Tyan", "S2466", }, + { "Tyan", "S2881", }, + { "Tyan", "S2882", }, + { "Tyan", "S2882-D", }, + { "Tyan", "S2891", }, + { "Tyan", "S2892", }, + { "Tyan", "S2895", }, + { "Tyan", "S3095", }, + { "Tyan", "S5180", }, + { "Tyan", "S5191", }, + { "Tyan", "S5197", }, + { "Tyan", "S5211", }, + { "Tyan", "S5211-1U", }, + { "Tyan", "S5220", }, + { "Tyan", "S5375", }, + { "Tyan", "S5376G2NR/S5376WAG2NR", }, + { "Tyan", "S5377", }, + { "Tyan", "S5397", }, + { "VIA", "EPIA-EX15000G", }, + { "VIA", "EPIA-LN", }, + { "VIA", "EPIA-M700", }, + { "VIA", "EPIA-NX15000G", }, + { "VIA", "NAB74X0", }, + { "VIA", "pc2500e", }, + { "VIA", "VB700X", }, + + {}, +}; + +/* Please keep this list alphabetically ordered by vendor/board. */ +const struct board_info boards_bad[] = { + /* Verified non-working boards (for now). */ + { "Abit", "IS-10", }, + { "ASRock", "K7VT4A+", }, + { "ASUS", "MEW-AM", }, + { "ASUS", "MEW-VM", }, + { "ASUS", "P3B-F", }, + { "ASUS", "P5B", }, + { "ASUS", "P5BV-M", }, + { "Biostar", "M6TBA", }, + { "Boser", "HS-6637", }, + { "DFI", "855GME-MGF", }, + { "FIC", "VA-502", }, + { "MSI", "MS-6178", }, + { "MSI", "MS-7260 (K9N Neo)", }, + { "Soyo", "SY-5VD", }, + { "Sun", "Fire x4150", }, + { "Sun", "Fire x4200", }, + { "Sun", "Fire x4540", }, + { "Sun", "Fire x4600", }, + + {}, +}; + +/* Please keep this list alphabetically ordered by vendor/board. */ +const struct board_info laptops_ok[] = { + /* Verified working laptops. */ + { "Lenovo", "3000 V100 TF05Cxx", }, + + {}, +}; + +/* Please keep this list alphabetically ordered by vendor/board. */ +const struct board_info laptops_bad[] = { + /* Verified non-working laptops (for now). */ + { "Acer", "Aspire One", }, + { "ASUS", "Eee PC 701 4G", }, + { "Dell", "Latitude CPi A366XT", }, + { "HP/Compaq", "nx9010", }, + { "IBM/Lenovo", "Thinkpad T40p", }, + { "IBM/Lenovo", "240", }, + + {}, +}; + diff --git a/cli/print_wiki.c b/cli/print_wiki.c new file mode 100644 index 0000000..86f9510 --- /dev/null +++ b/cli/print_wiki.c @@ -0,0 +1,569 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "../libflashrom/flash.h" +#include "../libflashrom/flashchips.h" + +struct board_info_url { + const char *vendor; + const char *name; + const char *url; +}; + +struct board_info_notes { + const char *vendor; + const char *name; + const char *note; +}; + +const char *wiki_header = "= Supported devices =\n\n\ +
\n\ +Please do '''not''' edit these tables in the wiki directly, they are \ +generated by pasting '''flashrom -z''' output.
\ +'''Last update:''' %s(generated by flashrom %s)\n
\n"; + +const char *chipset_th = "{| border=\"0\" style=\"font-size: smaller\"\n\ +|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ +! align=\"left\" | Southbridge\n! align=\"left\" | PCI IDs\n\ +! align=\"left\" | Status\n\n"; + +const char *board_th = "{| border=\"0\" style=\"font-size: smaller\" \ +valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ +! align=\"left\" | Mainboard\n! align=\"left\" | Status\n\n"; + +const char *board_th2 = "{| border=\"0\" style=\"font-size: smaller\" \ +valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ +! align=\"left\" | Mainboard\n! align=\"left\" | Required option\n\ +! align=\"left\" | Status\n\n"; + +const char *board_intro = "\ +\n== Supported mainboards ==\n\n\ +In general, it is very likely that flashrom works out of the box even if your \ +mainboard is not listed below.\n\nThis is a list of mainboards where we have \ +verified that they either do or do not need any special initialization to \ +make flashrom work (given flashrom supports the respective chipset and flash \ +chip), or that they do not yet work at all. If they do not work, support may \ +or may not be added later.\n\n\ +Mainboards which don't appear in the list may or may not work (we don't \ +know, someone has to give it a try). Please report any further verified \ +mainboards on the [[Mailinglist|mailing list]].\n"; + +const char *chip_th = "{| border=\"0\" style=\"font-size: smaller\" \ +valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ +! align=\"left\" | Device\n! align=\"left\" | Size / KB\n\ +! align=\"left\" | Type\n! align=\"left\" colspan=\"4\" | Status\n\n\ +|- bgcolor=\"#6699ff\"\n| colspan=\"4\" |  \n\ +| Probe\n| Read\n| Write\n| Erase\n\n"; + +const char *programmer_section = "\ +\n== Supported programmers ==\n\nThis is a list \ +of supported PCI devices flashrom can use as programmer:\n\n{| border=\"0\" \ +valign=\"top\"\n| valign=\"top\"|\n\n{| border=\"0\" style=\"font-size: \ +smaller\" valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ +! align=\"left\" | Device\n! align=\"left\" | PCI IDs\n\ +! align=\"left\" | Status\n\n"; + +const char *laptop_intro = "\n== Supported laptops/notebooks ==\n\n\ +In general, flashing laptops is more difficult because laptops\n\n\ +* often use the flash chip for stuff besides the BIOS,\n\ +* often have special protection stuff which has to be handled by flashrom,\n\ +* often use flash translation circuits which need drivers in flashrom.\n\n\ +
\n\ +'''IMPORTANT:''' At this point we recommend to '''not''' use flashrom on \ +untested laptops unless you have a means to recover from a flashing that goes \ +wrong (a working backup flash chip and/or good soldering skills).\n
\n"; + +/* Please keep these lists alphabetically ordered by vendor/board. */ +const struct board_info_url boards_url[] = { + /* Verified working boards that don't need write-enables. */ + { "Abit", "AX8", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?DEFTITLE=Y&fMTYPE=Socket%20939&pMODEL_NAME=AX8" }, + { "Abit", "Fatal1ty F-I90HD", "http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?pMODEL_NAME=Fatal1ty+F-I90HD&fMTYPE=LGA775" }, + { "Advantech", "PCM-5820", "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm" }, + { "ASI", "MB-5BLMP", "http://www.hojerteknik.com/winnet.htm" }, + { "ASRock", "A770CrossFire", "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire&s=AM2\%2b" }, + { "ASRock", "K8S8X", "http://www.asrock.com/mb/overview.asp?Model=K8S8X" }, + { "ASUS", "A7N8X Deluxe", "http://www.asus.com/Product.aspx?P_ID=wAsRYm41KTp78MFC" }, + { "ASUS", "A7N8X-E Deluxe", "http://www.asus.com/products.aspx?l1=3&l2=13&l3=56&l4=0&model=217&modelmenu=1" }, + { "ASUS", "A7V400-MX", "http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=63&l4=0&model=228&modelmenu=1" }, + { "ASUS", "A7V8X-MX", "http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=64&l4=0&model=229&modelmenu=1" }, + { "ASUS", "A8N-E", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=171&l4=0&model=455&modelmenu=2" }, + { "ASUS", "A8NE-FM/S", "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM" }, + { "ASUS", "A8N-SLI", "http://asus.com/product.aspx?P_ID=J9FKa8z2xVId3pDK" }, + { "ASUS", "A8N-SLI Premium", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=148&l4=0&model=539&modelmenu=1" }, + { "ASUS", "A8V Deluxe", "http://www.asus.com/product.aspx?P_ID=tvpdgPNCPaABZRVU" }, + { "ASUS", "A8V-E Deluxe", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=376&modelmenu=1" }, + { "ASUS", "A8V-E SE", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=576&modelmenu=1" }, + { "ASUS", "K8V", "http://www.asus.com/product.aspx?P_ID=fG2KZOWF7v6MRFRm" }, + { "ASUS", "K8V SE Deluxe", "http://www.asus.com/product.aspx?P_ID=65HeDI8XM1u6Uy6o" }, + { "ASUS", "K8V-X SE", "http://asus.com/product.aspx?P_ID=lzDXlbBVHkdckHVr" }, + { "ASUS", "M2A-MX", "http://www.asus.com/products.aspx?l1=3&l2=101&l3=583&l4=0&model=1909&modelmenu=1" }, + { "ASUS", "M2A-VM", "http://www.asus.com.tw/products.aspx?l1=3&l2=101&l3=496&l4=0&model=1568&modelmenu=1" }, + { "ASUS", "M2N-E", "http://www.asus.com/products.aspx?l1=3&l2=101&l3=308&l4=0&model=1181&modelmenu=1" }, + { "ASUS", "M2V", "http://asus.com/Product.aspx?P_ID=OqYlEDFfF6ZqZGvp" }, + { "ASUS", "M3A78-EM", "http://www.asus.com/product.aspx?P_ID=KjpYqzmAd9vsTM2D" }, + { "ASUS", "P2B", "http://www.motherboard.cz/mb/asus/P2B.htm" }, + { "ASUS", "P2B-D", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" }, + { "ASUS", "P2B-DS", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/" }, + { "ASUS", "P2B-F", "http://www.motherboard.cz/mb/asus/P2B-F.htm" }, + { "ASUS", "P2L97-S", "http://www.motherboard.cz/mb/asus/P2L97-S.htm" }, + { "ASUS", "P5B-Deluxe", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-Deluxe/" }, + { "ASUS", "P5KC", "http://www.asus.com/product.aspx?P_ID=fFZ8oUIGmLpwNMjj" }, + { "ASUS", "P5L-MX", "http://www.asus.com/product.aspx?P_ID=X70d3NCzH2DE9vWH" }, + { "ASUS", "P6T Deluxe V2", "http://www.asus.com/product.aspx?P_ID=iRlP8RG9han6saZx" }, + { "A-Trend", "ATC-6220", "http://www.motherboard.cz/mb/atrend/atc6220.htm" }, + { "BCOM", "WinNET100", "http://www.coreboot.org/BCOM_WINNET100" }, + { "DFI", "Blood-Iron P35 T2RL", "http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1" }, + { "Elitegroup", "K7S5A", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=279&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" }, + { "Elitegroup", "P6VAP-A+", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=117&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" }, + { "GIGABYTE", "GA-6BXC", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ClassValue=Motherboard&ProductID=1445&ProductName=GA-6BXC" }, + { "GIGABYTE", "GA-6BXDU", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1429" }, + { "GIGABYTE", "GA-6ZMA", "http://www.gigabyte.de/Support/Motherboard/BIOS_Model.aspx?ProductID=3289" }, + { "GIGABYTE", "GA-EX58-UD4P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2986" }, + { "GIGABYTE", "GA-EP35-DS3L", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2778" }, + { "GIGABYTE", "GA-MA790GP-DS4H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2887" }, + { "GIGABYTE", "GA-MA78GPM-DS2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2859" }, + { "GIGABYTE", "GA-MA770T-UD3P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=3096" }, + { "Intel", "EP80759", NULL }, + { "Jetway", "J7F4K1G5D-PB", "http://www.jetway.com.tw/jetway/system/productshow2.asp?id=389&proname=J7F4K1G5D-P" }, + { "MSI", "MS-6153", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=336" }, + { "MSI", "MS-6156", "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm" }, + { "MSI", "MS-6570 (K7N2)", "http://www.msi-computer.de/index.php?func=proddesc&prod_no=519&maincat_no=1" }, + { "MSI", "MS-7065", "http://browse.geekbench.ca/geekbench2/view/53114" }, + { "MSI", "MS-7168 (Orion)", "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart" }, + { "MSI", "MS-7236 (945PL Neo3)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1173" }, + { "MSI", "MS-7255 (P4M890M)", "http://www.tcsbahamas.com/P4M89.htm" }, + { "MSI", "MS-7345 (P35 Neo2-FIR)","http://www.msi.com/index.php?func=prodcpusupport&maincat_no=1&cat2_no=170&cat3_no=&prod_no=1261" }, + { "MSI", "MS-7368 (K9AG Neo2-Digital)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1241" }, + { "NEC", "PowerMate 2000", "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/" }, + { "PC Engines", "Alix.1c", "http://pcengines.ch/alix1c.htm" }, + { "PC Engines", "Alix.2c2", "http://pcengines.ch/alix2c2.htm" }, + { "PC Engines", "Alix.2c3", "http://pcengines.ch/alix2c3.htm" }, + { "PC Engines", "Alix.3c3", "http://pcengines.ch/alix3c3.htm" }, + { "PC Engines", "Alix.3d3", "http://pcengines.ch/alix3d3.htm" }, + { "RCA", "RM4100", "http://www.settoplinux.org/index.php?title=RCA_RM4100" }, + { "Sun", "Blade x6250", "http://www.sun.com/servers/blades/x6250/" }, + { "Supermicro", "H8QC8", "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm" }, + { "Thomson", "IP1000", "http://www.settoplinux.org/index.php?title=Thomson_IP1000" }, + { "TriGem", "Lomita", "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml" }, + { "T-Online", "S-100", "http://wiki.freifunk-hannover.de/T-Online_S_100" }, + { "Tyan", "iS5375-1U", "http://www.tyan.com/product_board_detail.aspx?pid=610" }, + { "Tyan", "S1846", "http://www.tyan.com/archive/products/html/tsunamiatx.html" }, + { "Tyan", "S2466", "http://www.tyan.com/product_board_detail.aspx?pid=461" }, + { "Tyan", "S2881", "http://www.tyan.com/product_board_detail.aspx?pid=115" }, + { "Tyan", "S2882", "http://www.tyan.com/product_board_detail.aspx?pid=121" }, + { "Tyan", "S2882-D", "http://www.tyan.com/product_board_detail.aspx?pid=127" }, + { "Tyan", "S2891", "http://www.tyan.com/product_board_detail.aspx?pid=144" }, + { "Tyan", "S2892", "http://www.tyan.com/product_board_detail.aspx?pid=145" }, + { "Tyan", "S2895", "http://www.tyan.com/archive/products/html/thunderk8we.html" }, + { "Tyan", "S3095", "http://www.tyan.com/product_board_detail.aspx?pid=181" }, + { "Tyan", "S5180", "http://www.tyan.com/product_board_detail.aspx?pid=456" }, + { "Tyan", "S5191", "http://www.tyan.com/product_board_detail.aspx?pid=343" }, + { "Tyan", "S5197", "http://www.tyan.com/product_board_detail.aspx?pid=349" }, + { "Tyan", "S5211", "http://www.tyan.com/product_board_detail.aspx?pid=591" }, + { "Tyan", "S5211-1U", "http://www.tyan.com/product_board_detail.aspx?pid=593" }, + { "Tyan", "S5220", "http://www.tyan.com/product_board_detail.aspx?pid=597" }, + { "Tyan", "S5375", "http://www.tyan.com/product_board_detail.aspx?pid=566" }, + { "Tyan", "S5376G2NR/S5376WAG2NR","http://www.tyan.com/product_board_detail.aspx?pid=605" }, + { "Tyan", "S5377", "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017" }, + { "Tyan", "S5397", "http://www.tyan.com/product_board_detail.aspx?pid=560" }, + { "VIA", "EPIA-EX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450" }, + { "VIA", "EPIA-LN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473" }, + { "VIA", "EPIA-M700", "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700" }, + { "VIA", "EPIA-NX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470" }, + { "VIA", "NAB74X0", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590" }, + { "VIA", "pc2500e", "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp" }, + { "VIA", "VB700X", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490" }, + + /* Verified working boards that DO need write-enables. */ + { "Abit", "IP35", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=LGA775&pMODEL_NAME=IP35" }, + { "Acorp", "6A815EPD", "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp" }, + { "agami", "Aruma", "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series" }, + { "Albatron", "PM266A Pro", "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56" }, /* FIXME */ + { "AOpen", "vKM400Am-S", "http://usa.aopen.com/products_detail.aspx?Auno=824" }, + { "Artec Group", "DBE61", "http://wiki.thincan.org/DBE61" }, + { "Artec Group", "DBE62", "http://wiki.thincan.org/DBE62" }, + { "ASUS", "A7V600-X", "http://www.asus.com/product.aspx?P_ID=L2XYS0rmtCjeOr4k" }, + { "ASUS", "A7V8X", "http://www.asus.com/product.aspx?P_ID=qfpaGrAy2kLVo0f2" }, + { "ASUS", "A7V8X-MX SE", "http://www.asus.com/product.aspx?P_ID=1guVBT1qV5oqhHyZ" }, + { "ASUS", "P4B266", "http://www.ciao.co.uk/ASUS_Intel_845D_Chipset_P4B266__5409807#productdetail" }, + { "ASUS", "P4P800-E Deluxe", "http://www.asus.com/product.aspx?P_ID=INIJUvLlif7LHp3g" }, + { "ASUS", "P5ND2-SLI Deluxe", "http://www.asus.com/product.aspx?P_ID=WY7XroDuUImVbgp5" }, + { "ASUS", "P5A", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/" }, + { "Biostar", "P4M80-M4", "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4" }, + { "Dell", "PowerEdge 1850", "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm" }, + { "Elitegroup", "K7VTA3", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" }, + { "EPoX", "EP-8K5A2", "http://www.epox.com/product.asp?ID=EP-8K5A2" }, + { "EPoX", "EP-8RDA3+", "http://www.epox.com/product.asp?ID=EP-8RDA3plus" }, + { "EPoX", "EP-BX3", "http://www.epox.com/product.asp?ID=EP-BX3" }, + { "GIGABYTE", "GA-2761GXDK", "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/" }, + { "GIGABYTE", "GA-7VT600", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1666" }, + { "GIGABYTE", "GA-7ZM", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1366" }, + { "GIGABYTE", "GA-K8N-SLI", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1928" }, + { "GIGABYTE", "GA-M57SLI-S4", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2287&ModelName=GA-M57SLI-S4" }, + { "GIGABYTE", "GA-M61P-S3", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2434" }, + { "GIGABYTE", "GA-MA78G-DS3H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2800" }, /* TODO: Rev 1.x or 2.x? */ + { "GIGABYTE", "GA-MA78GM-S2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2758" }, /* TODO: Rev. 1.0, 1.1, or 2.x? */ + { "GIGABYTE", "GA-MA790FX-DQ6", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2690" }, + { "HP", "DL145 G3", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351" }, + { "IBM", "x3455", "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html" }, + { "Intel", "D201GLY", "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm" }, + { "IWILL", "DK8-HTX", "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98" }, + { "Kontron", "986LCD-M", "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html" }, + { "Mitac", "6513WU", "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm" }, + { "MSI", "MS-6590 (KT4 Ultra)", "http://www.msicomputer.com/product/p_spec.asp?model=KT4_Ultra&class=mb" }, + { "MSI", "MS-6702E (K8T Neo2-F)","http://www.msicomputer.com/product/p_spec.asp?model=K8T_Neo2-F&class=mb" }, + { "MSI", "MS-6712 (KT4V)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=505" }, + { "MSI", "MS-7046", "http://www.heimir.de/ms7046/" }, + { "MSI", "MS-7135 (K8N Neo3)", "http://www.msi-computer.de/index.php?func=proddesc&prod_no=170&maincat_no=1" }, + { "Shuttle", "AK38N", "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/" }, + { "Soyo", "SY-7VCA", "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html" }, + { "Tyan", "S2498 (Tomcat K7M)", "http://www.tyan.com/archive/products/html/tomcatk7m.html" }, + { "VIA", "EPIA-CN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400" }, + { "VIA", "EPIA M/MII/...", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202" }, /* EPIA-MII link for now */ + { "VIA", "EPIA-N/NL", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221" }, /* EPIA-N link for now */ + { "VIA", "EPIA SP", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261" }, + { "VIA", "PC3500G", "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp" }, + + /* Verified non-working boards (for now). */ + { "Abit", "IS-10", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?pMODEL_NAME=IS-10&fMTYPE=Socket+478" }, + { "ASRock", "K7VT4A+", "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%%2b&s=" }, + { "ASUS", "MEW-AM", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/" }, + { "ASUS", "MEW-VM", "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm" }, + { "ASUS", "P3B-F", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/" }, + { "ASUS", "P5B", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/" }, + { "ASUS", "P5BV-M", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/" }, + { "Biostar", "M6TBA", "ftp://ftp.biostar-usa.com/manuals/M6TBA/" }, + { "Boser", "HS-6637", "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf" }, + { "DFI", "855GME-MGF", "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433" }, + { "FIC", "VA-502", "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/" }, + { "MSI", "MS-6178", "http://www.msi-technology.de/index.php?func=proddesc&prod_no=343&maincat_no=1" }, + { "MSI", "MS-7260 (K9N Neo)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=255" }, + { "Soyo", "SY-5VD", "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English" }, + { "Sun", "Fire x4540", "http://www.sun.com/servers/x64/x4540/" }, + { "Sun", "Fire x4150", "http://www.sun.com/servers/x64/x4150/" }, + { "Sun", "Fire x4200", "http://www.sun.com/servers/entry/x4200/" }, + { "Sun", "Fire x4600", "http://www.sun.com/servers/x64/x4600/" }, + + /* Verified working laptops. */ + { "Lenovo", "3000 V100 TF05Cxx", "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop" }, + + /* Verified non-working laptops (for now). */ + { "Acer", "Aspire One", NULL }, + { "ASUS", "Eee PC 701 4G", "http://www.asus.com/product.aspx?P_ID=h6SPd3tEzLEsrEiS" }, + { "Dell", "Latitude CPi A366XT", "http://www.coreboot.org/Dell_Latitude_CPi_A366XT" }, + { "HP/Compaq", "nx9010", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514" }, + { "IBM/Lenovo", "Thinkpad T40p", "http://www.thinkwiki.org/wiki/Category:T40p" }, + { "IBM/Lenovo", "240", "http://www.stanford.edu/~bresnan//tp240.html" }, + + { NULL, NULL, 0 }, +}; + +/* Please keep these lists alphabetically ordered by vendor/board. */ +const struct board_info_notes boards_notes[] = { + /* Verified working boards that don't need write-enables. */ + { "ASI", "MB-5BLMP", "Used in the IGEL WinNET III thin client." }, + { "ASRock", "K8S8X", "The Super I/O isn't found on this board. See http://www.flashrom.org/pipermail/flashrom/2009-November/000937.html." }, + { "ASUS", "A8V-E SE", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html." }, + { "ASUS", "M2A-VM", "See http://www.coreboot.org/pipermail/coreboot/2007-September/025281.html." }, + { "BCOM", "WinNET100", "Used in the IGEL-316 thin client." }, + { "GIGABYTE", "GA-7ZM", "Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option." }, + { "ASUS", "M2N-E", "If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See http://www.flashrom.org/pipermail/flashrom/2009-November/000879.html" }, + + /* Verified working boards that DO need write-enables. */ + { "Acer", "Aspire One", "See http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html." }, + + /* Verified non-working boards (for now). */ + { "MSI", "MS-6178", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot." }, + { "MSI", "MS-7260 (K9N Neo)", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot." }, + + /* Verified working laptops. */ + /* None which need comments, yet... */ + + /* Verified non-working laptops (for now). */ + { "Acer", "Aspire One", "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html" }, + { "ASUS", "Eee PC 701 4G", "It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)." }, + { "Dell", "Latitude CPi A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop." }, + { "HP/Compaq", "nx9010", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)." }, + { "IBM/Lenovo", "Thinkpad T40p", "Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later." }, + + { NULL, NULL, 0 }, +}; + +static int url(const char *vendor, const char *board) +{ + int i; + const struct board_info_url *b = boards_url; + + for (i = 0; b[i].vendor != NULL; i++) { + if (!strcmp(vendor, b[i].vendor) && !strcmp(board, b[i].name)) + return i; + } + + return -1; +} + +static int note(const char *vendor, const char *board) +{ + int i; + const struct board_info_notes *n = boards_notes; + + for (i = 0; n[i].vendor != NULL; i++) { + if (!strcmp(vendor, n[i].vendor) && !strcmp(board, n[i].name)) + return i; + } + + return -1; +} + +void print_supported_chipsets_wiki(void) +{ + int i, j, enablescount = 0, color = 1; + const struct penable *e; + + for (e = chipset_enables; e->vendor_name != NULL; e++) + enablescount++; + + printf("\n== Supported chipsets ==\n\nTotal amount of supported " + "chipsets: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n| " + "valign=\"top\"|\n\n%s", enablescount, chipset_th); + + e = chipset_enables; + for (i = 0, j = 0; e[i].vendor_name != NULL; i++, j++) { + /* Alternate colors if the vendor changes. */ + if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name)) + color = !color; + + printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s " + "|| %04x:%04x || %s\n", (color) ? "eeeeee" : "dddddd", + e[i].vendor_name, e[i].device_name, + e[i].vendor_id, e[i].device_id, + (e[i].status == OK) ? "{{OK}}" : "?"); + + /* Split table in three columns. */ + if (j >= (enablescount / 3 + 1)) { + printf("\n|}\n\n| valign=\"top\"|\n\n%s", chipset_th); + j = 0; + } + } + + printf("\n|}\n\n|}\n"); +} + +static void wiki_helper(const char *heading, const char *status, + int cols, const struct board_info boards[]) +{ + int i, j, k, c, boardcount = 0, color = 1, num_notes = 0; + const struct board_info *b; + const struct board_info_url *u = boards_url; + char *notes = calloc(1, 1); + char tmp[900 + 1]; + + for (b = boards; b->vendor != NULL; b++) + boardcount++; + + printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" + "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", + heading, boardcount, board_th); + + for (i = 0, j = 0, b = boards; b[i].vendor != NULL; i++, j++) { + /* Alternate colors if the vendor changes. */ + if (i > 0 && strcmp(b[i].vendor, b[i - 1].vendor)) + color = !color; + + k = url(b[i].vendor, b[i].name); + c = note(b[i].vendor, b[i].name); + + printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s ||" + " {{%s}}", (color) ? "eeeeee" : "dddddd", b[i].vendor, + (k != -1 && u[k].url) ? "[" : "", + (k != -1 && u[k].url) ? u[k].url : "", + b[i].name, (k != -1 && u[k].url) ? "]" : "", status); + + if (c != -1) { + printf("%d\n", num_notes + 1); + snprintf((char *)&tmp, 900, "%d %s
\n", + 1 + num_notes++, boards_notes[c].note); + notes = strcat_realloc(notes, (char *)&tmp); + } else { + printf("\n"); + } + + /* Split table in 'cols' columns. */ + if (j >= (boardcount / cols + 1)) { + printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th); + j = 0; + } + } + + printf("\n|}\n\n|}\n"); + + if (num_notes > 0) + printf("\n\n%s\n", notes); + free(notes); +} + +static void wiki_helper2(const char *heading, int cols) +{ + int i, j, k, boardcount = 0, color = 1; + struct board_pciid_enable *b; + const struct board_info_url *u = boards_url; + + for (b = board_pciid_enables; b->vendor_name != NULL; b++) + boardcount++; + + printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" + "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", + heading, boardcount, board_th2); + + b = board_pciid_enables; + for (i = 0, j = 0; b[i].vendor_name != NULL; i++, j++) { + /* Alternate colors if the vendor changes. */ + if (i > 0 && strcmp(b[i].vendor_name, b[i - 1].vendor_name)) + color = !color; + + k = url(b[i].vendor_name, b[i].board_name); + + printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s " + "|| %s%s%s%s || {{OK}}\n", (color) ? "eeeeee" : "dddddd", + b[i].vendor_name, (k != -1 && u[k].url) ? "[" : "", + (k != -1 && u[k].url) ? u[k].url : "", b[i].board_name, + (k != -1 && u[k].url) ? "]" : "", + (b[i].lb_vendor) ? "-m " : "—", + (b[i].lb_vendor) ? b[i].lb_vendor : "", + (b[i].lb_vendor) ? ":" : "", + (b[i].lb_vendor) ? b[i].lb_part : ""); + + /* Split table in three columns. */ + if (j >= (boardcount / cols + 1)) { + printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th2); + j = 0; + } + } + + printf("\n|}\n\n|}\n"); +} + +void print_supported_boards_wiki(void) +{ + printf("%s", board_intro); + wiki_helper("Known good (worked out of the box)", "OK", 3, boards_ok); + wiki_helper2("Known good (with write-enable code in flashrom)", 3); + wiki_helper("Not supported (yet)", "No", 3, boards_bad); + + printf("%s", laptop_intro); + wiki_helper("Known good (worked out of the box)", "OK", 1, laptops_ok); + wiki_helper("Not supported (yet)", "No", 1, laptops_bad); +} + +void print_supported_chips_wiki(void) +{ + int i = 0, c = 1, chipcount = 0; + struct flashchip *f, *old = NULL; + uint32_t t; + + for (f = flashchips; f->name != NULL; f++) + chipcount++; + + printf("\n== Supported chips ==\n\nTotal amount of supported " + "chips: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n" + "| valign=\"top\"|\n\n%s", chipcount, chip_th); + + for (f = flashchips; f->name != NULL; f++, i++) { + /* Don't print "unknown XXXX SPI chip" entries. */ + if (!strncmp(f->name, "unknown", 7)) + continue; + + /* Alternate colors if the vendor changes. */ + if (old != NULL && strcmp(old->vendor, f->vendor)) + c = !c; + + t = f->tested; + printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || %d " + "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}\n", + (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name, + f->total_size, flashbuses_to_text(f->bustype), + (t & TEST_OK_PROBE) ? "OK" : + (t & TEST_BAD_PROBE) ? "No" : ((c) ? "?2" : "?"), + (t & TEST_OK_READ) ? "OK" : + (t & TEST_BAD_READ) ? "No" : ((c) ? "?2" : "?"), + (t & TEST_OK_ERASE) ? "OK" : + (t & TEST_BAD_ERASE) ? "No" : ((c) ? "?2" : "?"), + (t & TEST_OK_WRITE) ? "OK" : + (t & TEST_BAD_WRITE) ? "No" : ((c) ? "?2" : "?")); + + /* Split table into three columns. */ + if (i >= (chipcount / 3 + 1)) { + printf("\n|}\n\n| valign=\"top\"|\n\n%s", chip_th); + i = 0; + } + + old = f; + } + + printf("\n|}\n\n|}\n"); +} + +void print_supported_pcidevs_wiki(struct pcidev_status *devs) +{ + int i = 0; + static int c = 0; + + /* Alternate colors if the vendor changes. */ + c = !c; + + for (i = 0; devs[i].vendor_name != NULL; i++) { + printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || " + "%04x:%04x || {{%s}}\n", (c) ? "eeeeee" : "dddddd", + devs[i].vendor_name, devs[i].device_name, + devs[i].vendor_id, devs[i].device_id, + (devs[i].status == PCI_NT) ? (c) ? "?2" : "?" : "OK"); + } +} + +void print_supported_wiki(void) +{ + time_t t = time(NULL); + + printf(wiki_header, ctime(&t), flashrom_version); + print_supported_chips_wiki(); + print_supported_chipsets_wiki(); + print_supported_boards_wiki(); + printf("%s", programmer_section); +#if NIC3COM_SUPPORT == 1 + print_supported_pcidevs_wiki(nics_3com); +#endif +#if GFXNVIDIA_SUPPORT == 1 + print_supported_pcidevs_wiki(gfx_nvidia); +#endif +#if DRKAISER_SUPPORT == 1 + print_supported_pcidevs_wiki(drkaiser_pcidev); +#endif +#if SATASII_SUPPORT == 1 + print_supported_pcidevs_wiki(satas_sii); +#endif + printf("\n|}\n"); +} + diff --git a/cli/udelay.c b/cli/udelay.c new file mode 100644 index 0000000..bebe122 --- /dev/null +++ b/cli/udelay.c @@ -0,0 +1,65 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "../libflashrom/flash.h" + +// count to a billion. Time it. If it's < 1 sec, count to 10B, etc. +unsigned long micro = 1; + +void myusec_delay(int usecs) +{ + volatile unsigned long i; + for (i = 0; i < usecs * micro; i++) ; +} + +void myusec_calibrate_delay(void) +{ + int count = 1000; + unsigned long timeusec; + struct timeval start, end; + int ok = 0; + + printf("Calibrating delay loop... "); + + while (!ok) { + gettimeofday(&start, 0); + myusec_delay(count); + gettimeofday(&end, 0); + timeusec = 1000000 * (end.tv_sec - start.tv_sec) + + (end.tv_usec - start.tv_usec); + count *= 2; + if (timeusec < 1000000 / 4) + continue; + ok = 1; + } + + // compute one microsecond. That will be count / time + micro = count / timeusec; + + gettimeofday(&start, 0); + myusec_delay(100); + gettimeofday(&end, 0); + timeusec = 1000000 * (end.tv_sec - start.tv_sec) + + (end.tv_usec - start.tv_usec); + printf_debug("%ldM loops per second, 100 myus = %ld us. ", + (unsigned long)micro, timeusec); + printf("OK.\n"); +} diff --git a/coreboot_tables.h b/coreboot_tables.h deleted file mode 100644 index 6944559..0000000 --- a/coreboot_tables.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2002 Linux Networx - * (Written by Eric Biederman for Linux Networx) - * Copyright (C) 2005-2007 coresystems GmbH - * - * 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 - */ - -#ifndef COREBOOT_TABLES_H -#define COREBOOT_TABLES_H - -#include - -/* The coreboot table information is for conveying information - * from the firmware to the loaded OS image. Primarily this - * is expected to be information that cannot be discovered by - * other means, such as quering the hardware directly. - * - * All of the information should be Position Independent Data. - * That is it should be safe to relocated any of the information - * without it's meaning/correctnes changing. For table that - * can reasonably be used on multiple architectures the data - * size should be fixed. This should ease the transition between - * 32 bit and 64 bit architectures etc. - * - * The completeness test for the information in this table is: - * - Can all of the hardware be detected? - * - Are the per motherboard constants available? - * - Is there enough to allow a kernel to run that was written before - * a particular motherboard is constructed? (Assuming the kernel - * has drivers for all of the hardware but it does not have - * assumptions on how the hardware is connected together). - * - * With this test it should be straight forward to determine if a - * table entry is required or not. This should remove much of the - * long term compatibility burden as table entries which are - * irrelevant or have been replaced by better alternatives may be - * dropped. Of course it is polite and expidite to include extra - * table entries and be backwards compatible, but it is not required. - */ - -/* Since coreboot is usually compiled 32bit, gcc will align 64bit - * types to 32bit boundaries. If the coreboot table is dumped on a - * 64bit system, a uint64_t would be aligned to 64bit boundaries, - * breaking the table format. - * - * lb_uint64 will keep 64bit coreboot table values aligned to 32bit - * to ensure compatibility. They can be accessed with the two functions - * below: unpack_lb64() and pack_lb64() - * - * See also: util/lbtdump/lbtdump.c - */ - -struct lb_uint64 { - uint32_t lo; - uint32_t hi; -}; - -struct lb_header { - uint8_t signature[4]; /* LBIO */ - uint32_t header_bytes; - uint32_t header_checksum; - uint32_t table_bytes; - uint32_t table_checksum; - uint32_t table_entries; -}; - -/* Every entry in the boot enviroment list will correspond to a boot - * info record. Encoding both type and size. The type is obviously - * so you can tell what it is. The size allows you to skip that - * boot enviroment record if you don't know what it easy. This allows - * forward compatibility with records not yet defined. - */ -struct lb_record { - uint32_t tag; /* tag ID */ - uint32_t size; /* size of record (in bytes) */ -}; - -#define LB_TAG_UNUSED 0x0000 - -#define LB_TAG_MEMORY 0x0001 - -struct lb_memory_range { - struct lb_uint64 start; - struct lb_uint64 size; - uint32_t type; -#define LB_MEM_RAM 1 /* Memory anyone can use */ -#define LB_MEM_RESERVED 2 /* Don't use this memory region */ -#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */ -}; - -struct lb_memory { - uint32_t tag; - uint32_t size; - struct lb_memory_range map[0]; -}; - -#define LB_TAG_HWRPB 0x0002 -struct lb_hwrpb { - uint32_t tag; - uint32_t size; - uint64_t hwrpb; -}; - -#define LB_TAG_MAINBOARD 0x0003 -struct lb_mainboard { - uint32_t tag; - uint32_t size; - uint8_t vendor_idx; - uint8_t part_number_idx; - uint8_t strings[0]; -}; - -#define LB_TAG_VERSION 0x0004 -#define LB_TAG_EXTRA_VERSION 0x0005 -#define LB_TAG_BUILD 0x0006 -#define LB_TAG_COMPILE_TIME 0x0007 -#define LB_TAG_COMPILE_BY 0x0008 -#define LB_TAG_COMPILE_HOST 0x0009 -#define LB_TAG_COMPILE_DOMAIN 0x000a -#define LB_TAG_COMPILER 0x000b -#define LB_TAG_LINKER 0x000c -#define LB_TAG_ASSEMBLER 0x000d -struct lb_string { - uint32_t tag; - uint32_t size; - uint8_t string[0]; -}; - -#define LB_TAG_FORWARD 0x0011 -struct lb_forward { - uint32_t tag; - uint32_t size; - uint64_t forward; -}; - -#endif /* COREBOOT_TABLES_H */ diff --git a/drkaiser.c b/drkaiser.c deleted file mode 100644 index f13c13e..0000000 --- a/drkaiser.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Joerg Fischer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" - -#define PCI_VENDOR_ID_DRKAISER 0x1803 - -#define PCI_MAGIC_DRKAISER_ADDR 0x50 -#define PCI_MAGIC_DRKAISER_VALUE 0xa971 - -struct pcidev_status drkaiser_pcidev[] = { - {0x1803, 0x5057, PCI_OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"}, - {}, -}; - -uint8_t *drkaiser_bar; - -int drkaiser_init(void) -{ - uint32_t addr; - - get_io_perms(); - pcidev_init(PCI_VENDOR_ID_DRKAISER, PCI_BASE_ADDRESS_2, - drkaiser_pcidev, programmer_param); - - /* Write magic register to enable flash write. */ - pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, - PCI_MAGIC_DRKAISER_VALUE); - - /* TODO: Mask lower bits? How many? 3? 7? */ - addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) & ~0x03; - - /* Map 128KB flash memory window. */ - drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory", - addr, 128 * 1024); - - buses_supported = CHIP_BUSTYPE_PARALLEL; - return 0; -} - -int drkaiser_shutdown(void) -{ - /* Write protect the flash again. */ - pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, 0); - free(programmer_param); - pci_cleanup(pacc); - release_io_perms(); - return 0; -}; - -void drkaiser_chip_writeb(uint8_t val, chipaddr addr) -{ - mmio_writeb(val, drkaiser_bar + addr); -} - -uint8_t drkaiser_chip_readb(const chipaddr addr) -{ - return mmio_readb(drkaiser_bar + addr); -} diff --git a/dummyflasher.c b/dummyflasher.c deleted file mode 100644 index 903f88b..0000000 --- a/dummyflasher.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include "flash.h" - -int dummy_init(void) -{ - int i; - printf_debug("%s\n", __func__); - - /* "all" is equivalent to specifying no type. */ - if (programmer_param && (!strcmp(programmer_param, "all"))) { - free(programmer_param); - programmer_param = NULL; - } - if (!programmer_param) - programmer_param = strdup("parallel,lpc,fwh,spi"); - /* Convert the parameters to lowercase. */ - for (i = 0; programmer_param[i] != '\0'; i++) - programmer_param[i] = (char)tolower(programmer_param[i]); - - buses_supported = CHIP_BUSTYPE_NONE; - if (strstr(programmer_param, "parallel")) { - buses_supported |= CHIP_BUSTYPE_PARALLEL; - printf_debug("Enabling support for %s flash.\n", "parallel"); - } - if (strstr(programmer_param, "lpc")) { - buses_supported |= CHIP_BUSTYPE_LPC; - printf_debug("Enabling support for %s flash.\n", "LPC"); - } - if (strstr(programmer_param, "fwh")) { - buses_supported |= CHIP_BUSTYPE_FWH; - printf_debug("Enabling support for %s flash.\n", "FWH"); - } - if (strstr(programmer_param, "spi")) { - buses_supported |= CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_DUMMY; - printf_debug("Enabling support for %s flash.\n", "SPI"); - } - if (buses_supported == CHIP_BUSTYPE_NONE) - printf_debug("Support for all flash bus types disabled.\n"); - free(programmer_param); - return 0; -} - -int dummy_shutdown(void) -{ - printf_debug("%s\n", __func__); - return 0; -} - -void *dummy_map(const char *descr, unsigned long phys_addr, size_t len) -{ - printf_debug("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n", - __func__, descr, (unsigned long)len, phys_addr); - return (void *)phys_addr; -} - -void dummy_unmap(void *virt_addr, size_t len) -{ - printf_debug("%s: Unmapping 0x%lx bytes at %p\n", - __func__, (unsigned long)len, virt_addr); -} - -void dummy_chip_writeb(uint8_t val, chipaddr addr) -{ - printf_debug("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val); -} - -void dummy_chip_writew(uint16_t val, chipaddr addr) -{ - printf_debug("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val); -} - -void dummy_chip_writel(uint32_t val, chipaddr addr) -{ - printf_debug("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val); -} - -void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len) -{ - size_t i; - printf_debug("%s: addr=0x%lx, len=0x%08lx, writing data (hex):", - __func__, addr, (unsigned long)len); - for (i = 0; i < len; i++) { - if ((i % 16) == 0) - printf_debug("\n"); - printf_debug("%02x ", buf[i]) - } -} - -uint8_t dummy_chip_readb(const chipaddr addr) -{ - printf_debug("%s: addr=0x%lx, returning 0xff\n", __func__, addr); - return 0xff; -} - -uint16_t dummy_chip_readw(const chipaddr addr) -{ - printf_debug("%s: addr=0x%lx, returning 0xffff\n", __func__, addr); - return 0xffff; -} - -uint32_t dummy_chip_readl(const chipaddr addr) -{ - printf_debug("%s: addr=0x%lx, returning 0xffffffff\n", __func__, addr); - return 0xffffffff; -} - -void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len) -{ - printf_debug("%s: addr=0x%lx, len=0x%lx, returning array of 0xff\n", - __func__, addr, (unsigned long)len); - memset(buf, 0xff, len); - return; -} - -int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - int i; - - printf_debug("%s:", __func__); - - printf_debug(" writing %u bytes:", writecnt); - for (i = 0; i < writecnt; i++) - printf_debug(" 0x%02x", writearr[i]); - - printf_debug(" reading %u bytes:", readcnt); - for (i = 0; i < readcnt; i++) { - printf_debug(" 0xff"); - readarr[i] = 0xff; - } - - printf_debug("\n"); - return 0; -} diff --git a/en29f002a.c b/en29f002a.c deleted file mode 100644 index 020df32..0000000 --- a/en29f002a.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2007 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * EN29F512 has 1C,21 - * EN29F010 has 1C,20 - * EN29F040A has 1C,04 - * EN29LV010 has 1C,6E and uses short F0 reset sequence - * EN29LV040(A) has 1C,4F and uses short F0 reset sequence - */ - -#include "flash.h" - -int probe_en29f512(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x90, bios + 0x555); - - programmer_delay(10); - - id1 = chip_readb(bios + 0x100); - id2 = chip_readb(bios + 0x101); - - /* exit by writing F0 anywhere? or the code below */ - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0xF0, bios + 0x555); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} - -/* - * EN29F002AT has 1C,92 - * EN29F002AB has 1C,97 - */ - -/* This does not seem to function properly for EN29F002NT. */ -int probe_en29f002a(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0xAAA); - chip_writeb(0x90, bios + 0x555); - - programmer_delay(10); - - id1 = chip_readb(bios + 0x100); - id2 = chip_readb(bios + 0x101); - - /* exit by writing F0 anywhere? or the code below */ - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0xAAA); - chip_writeb(0xF0, bios + 0x555); - - printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} diff --git a/flash.h b/flash.h deleted file mode 100644 index 4178d47..0000000 --- a/flash.h +++ /dev/null @@ -1,763 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2000 Ronald G. Minnich - * Copyright (C) 2005-2009 coresystems GmbH - * Copyright (C) 2006-2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FLASH_H__ -#define __FLASH_H__ 1 - -#if defined(__GLIBC__) -#include -#endif -#include -#include -#include -#include - -/* for iopl and outb under Solaris */ -#if defined (__sun) && (defined(__i386) || defined(__amd64)) -#include -#include -#include -#include -#endif - -#if (defined(__MACH__) && defined(__APPLE__)) -#define __DARWIN__ -#endif - -#if defined(__FreeBSD__) || defined(__DragonFly__) - #include - #define off64_t off_t - #define lseek64 lseek - #define OUTB(x, y) do { u_int tmp = (y); outb(tmp, (x)); } while (0) - #define OUTW(x, y) do { u_int tmp = (y); outw(tmp, (x)); } while (0) - #define OUTL(x, y) do { u_int tmp = (y); outl(tmp, (x)); } while (0) - #define INB(x) __extension__ ({ u_int tmp = (x); inb(tmp); }) - #define INW(x) __extension__ ({ u_int tmp = (x); inw(tmp); }) - #define INL(x) __extension__ ({ u_int tmp = (x); inl(tmp); }) -#else -#if defined(__DARWIN__) - #include - #define off64_t off_t - #define lseek64 lseek -#endif -#if defined (__sun) && (defined(__i386) || defined(__amd64)) - /* Note different order for outb */ - #define OUTB(x,y) outb(y, x) - #define OUTW(x,y) outw(y, x) - #define OUTL(x,y) outl(y, x) - #define INB inb - #define INW inw - #define INL inl -#else - #define OUTB outb - #define OUTW outw - #define OUTL outl - #define INB inb - #define INW inw - #define INL inl -#endif -#endif - -typedef unsigned long chipaddr; - -enum programmer { - PROGRAMMER_INTERNAL, -#if DUMMY_SUPPORT == 1 - PROGRAMMER_DUMMY, -#endif -#if NIC3COM_SUPPORT == 1 - PROGRAMMER_NIC3COM, -#endif -#if GFXNVIDIA_SUPPORT == 1 - PROGRAMMER_GFXNVIDIA, -#endif -#if DRKAISER_SUPPORT == 1 - PROGRAMMER_DRKAISER, -#endif -#if SATASII_SUPPORT == 1 - PROGRAMMER_SATASII, -#endif - PROGRAMMER_IT87SPI, -#if FT2232_SPI_SUPPORT == 1 - PROGRAMMER_FT2232SPI, -#endif -#if SERPROG_SUPPORT == 1 - PROGRAMMER_SERPROG, -#endif -#if BUSPIRATE_SPI_SUPPORT == 1 - PROGRAMMER_BUSPIRATESPI, -#endif - PROGRAMMER_INVALID /* This must always be the last entry. */ -}; - -extern enum programmer programmer; - -struct programmer_entry { - const char *vendor; - const char *name; - - int (*init) (void); - int (*shutdown) (void); - - void * (*map_flash_region) (const char *descr, unsigned long phys_addr, - size_t len); - void (*unmap_flash_region) (void *virt_addr, size_t len); - - void (*chip_writeb) (uint8_t val, chipaddr addr); - void (*chip_writew) (uint16_t val, chipaddr addr); - void (*chip_writel) (uint32_t val, chipaddr addr); - void (*chip_writen) (uint8_t *buf, chipaddr addr, size_t len); - uint8_t (*chip_readb) (const chipaddr addr); - uint16_t (*chip_readw) (const chipaddr addr); - uint32_t (*chip_readl) (const chipaddr addr); - void (*chip_readn) (uint8_t *buf, const chipaddr addr, size_t len); - void (*delay) (int usecs); -}; - -extern const struct programmer_entry programmer_table[]; - -int programmer_init(void); -int programmer_shutdown(void); -void *programmer_map_flash_region(const char *descr, unsigned long phys_addr, - size_t len); -void programmer_unmap_flash_region(void *virt_addr, size_t len); -void chip_writeb(uint8_t val, chipaddr addr); -void chip_writew(uint16_t val, chipaddr addr); -void chip_writel(uint32_t val, chipaddr addr); -void chip_writen(uint8_t *buf, chipaddr addr, size_t len); -uint8_t chip_readb(const chipaddr addr); -uint16_t chip_readw(const chipaddr addr); -uint32_t chip_readl(const chipaddr addr); -void chip_readn(uint8_t *buf, const chipaddr addr, size_t len); -void programmer_delay(int usecs); - -enum bitbang_spi_master { - BITBANG_SPI_INVALID /* This must always be the last entry. */ -}; - -extern const int bitbang_spi_master_count; - -extern enum bitbang_spi_master bitbang_spi_master; - -struct bitbang_spi_master_entry { - void (*set_cs) (int val); - void (*set_sck) (int val); - void (*set_mosi) (int val); - int (*get_miso) (void); -}; - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -enum chipbustype { - CHIP_BUSTYPE_NONE = 0, - CHIP_BUSTYPE_PARALLEL = 1 << 0, - CHIP_BUSTYPE_LPC = 1 << 1, - CHIP_BUSTYPE_FWH = 1 << 2, - CHIP_BUSTYPE_SPI = 1 << 3, - CHIP_BUSTYPE_NONSPI = CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, - CHIP_BUSTYPE_UNKNOWN = CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI, -}; - -/* - * How many different contiguous runs of erase blocks with one size each do - * we have for a given erase function? - */ -#define NUM_ERASEREGIONS 5 - -/* - * How many different erase functions do we have per chip? - */ -#define NUM_ERASEFUNCTIONS 5 - -struct flashchip { - const char *vendor; - const char *name; - - enum chipbustype bustype; - - /* - * With 32bit manufacture_id and model_id we can cover IDs up to - * (including) the 4th bank of JEDEC JEP106W Standard Manufacturer's - * Identification code. - */ - uint32_t manufacture_id; - uint32_t model_id; - - int total_size; - int page_size; - - /* - * Indicate if flashrom has been tested with this flash chip and if - * everything worked correctly. - */ - uint32_t tested; - - int (*probe) (struct flashchip *flash); - - /* Delay after "enter/exit ID mode" commands in microseconds. */ - int probe_timing; - int (*erase) (struct flashchip *flash); - - /* - * Erase blocks and associated erase function. The default entry is a - * chip-sized virtual block together with the chip erase function. - */ - struct block_eraser { - struct eraseblock{ - unsigned int size; /* Eraseblock size */ - unsigned int count; /* Number of contiguous blocks with that size */ - } eraseblocks[NUM_ERASEREGIONS]; - int (*block_erase) (struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen); - } block_erasers[NUM_ERASEFUNCTIONS]; - - int (*write) (struct flashchip *flash, uint8_t *buf); - int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len); - - /* Some flash devices have an additional register space. */ - chipaddr virtual_memory; - chipaddr virtual_registers; -}; - -#define TEST_UNTESTED 0 - -#define TEST_OK_PROBE (1 << 0) -#define TEST_OK_READ (1 << 1) -#define TEST_OK_ERASE (1 << 2) -#define TEST_OK_WRITE (1 << 3) -#define TEST_OK_PR (TEST_OK_PROBE | TEST_OK_READ) -#define TEST_OK_PRE (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE) -#define TEST_OK_PRW (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_WRITE) -#define TEST_OK_PREW (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE | TEST_OK_WRITE) -#define TEST_OK_MASK 0x0f - -#define TEST_BAD_PROBE (1 << 4) -#define TEST_BAD_READ (1 << 5) -#define TEST_BAD_ERASE (1 << 6) -#define TEST_BAD_WRITE (1 << 7) -#define TEST_BAD_PREW (TEST_BAD_PROBE | TEST_BAD_READ | TEST_BAD_ERASE | TEST_BAD_WRITE) -#define TEST_BAD_MASK 0xf0 - -/* Timing used in probe routines. ZERO is -2 to differentiate between an unset - * field and zero delay. - * - * SPI devices will always have zero delay and ignore this field. - */ -#define TIMING_FIXME -1 -/* this is intentionally same value as fixme */ -#define TIMING_IGNORED -1 -#define TIMING_ZERO -2 - -extern struct flashchip flashchips[]; - -struct penable { - uint16_t vendor_id; - uint16_t device_id; - int status; - const char *vendor_name; - const char *device_name; - int (*doit) (struct pci_dev *dev, const char *name); -}; - -extern const struct penable chipset_enables[]; - -struct board_pciid_enable { - /* Any device, but make it sensible, like the ISA bridge. */ - uint16_t first_vendor; - uint16_t first_device; - uint16_t first_card_vendor; - uint16_t first_card_device; - - /* Any device, but make it sensible, like - * the host bridge. May be NULL. - */ - uint16_t second_vendor; - uint16_t second_device; - uint16_t second_card_vendor; - uint16_t second_card_device; - - /* The vendor / part name from the coreboot table. */ - const char *lb_vendor; - const char *lb_part; - - const char *vendor_name; - const char *board_name; - - int (*enable) (const char *name); -}; - -extern struct board_pciid_enable board_pciid_enables[]; - -struct board_info { - const char *vendor; - const char *name; -}; - -extern const struct board_info boards_ok[]; -extern const struct board_info boards_bad[]; -extern const struct board_info laptops_ok[]; -extern const struct board_info laptops_bad[]; - -/* udelay.c */ -void myusec_delay(int usecs); -void myusec_calibrate_delay(void); - -/* pcidev.c */ -#define PCI_OK 0 -#define PCI_NT 1 /* Not tested */ - -extern uint32_t io_base_addr; -extern struct pci_access *pacc; -extern struct pci_filter filter; -extern struct pci_dev *pcidev_dev; -struct pcidev_status { - uint16_t vendor_id; - uint16_t device_id; - int status; - const char *vendor_name; - const char *device_name; -}; -uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, struct pcidev_status *devs); -uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, struct pcidev_status *devs, char *pcidev_bdf); - -/* print.c */ -char *flashbuses_to_text(enum chipbustype bustype); -void print_supported(void); -void print_supported_pcidevs(struct pcidev_status *devs); -void print_supported_wiki(void); - -/* board_enable.c */ -void w836xx_ext_enter(uint16_t port); -void w836xx_ext_leave(uint16_t port); -uint8_t sio_read(uint16_t port, uint8_t reg); -void sio_write(uint16_t port, uint8_t reg, uint8_t data); -void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask); -int board_flash_enable(const char *vendor, const char *part); - -struct decode_sizes { - uint32_t parallel; - uint32_t lpc; - uint32_t fwh; - uint32_t spi; -}; - -/* chipset_enable.c */ -extern enum chipbustype buses_supported; -int chipset_flash_enable(void); -extern struct decode_sizes max_rom_decode; - -extern unsigned long flashbase; - -/* physmap.c */ -void *physmap(const char *descr, unsigned long phys_addr, size_t len); -void physunmap(void *virt_addr, size_t len); -int setup_cpu_msr(int cpu); -void cleanup_cpu_msr(void); -#if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(__DragonFly__) -typedef struct { uint32_t hi, lo; } msr_t; -msr_t rdmsr(int addr); -int wrmsr(int addr, msr_t msr); -#endif -#if defined(__FreeBSD__) || defined(__DragonFly__) -/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */ -#undef rdmsr -#undef wrmsr -#define rdmsr freebsd_rdmsr -#define wrmsr freebsd_wrmsr -typedef struct { uint32_t hi, lo; } msr_t; -msr_t freebsd_rdmsr(int addr); -int freebsd_wrmsr(int addr, msr_t msr); -#endif - -/* internal.c */ -struct pci_dev *pci_dev_find_filter(struct pci_filter filter); -struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class); -struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device); -struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device, - uint16_t card_vendor, uint16_t card_device); -void get_io_perms(void); -void release_io_perms(void); -int internal_init(void); -int internal_shutdown(void); -void internal_chip_writeb(uint8_t val, chipaddr addr); -void internal_chip_writew(uint16_t val, chipaddr addr); -void internal_chip_writel(uint32_t val, chipaddr addr); -uint8_t internal_chip_readb(const chipaddr addr); -uint16_t internal_chip_readw(const chipaddr addr); -uint32_t internal_chip_readl(const chipaddr addr); -void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); -void mmio_writeb(uint8_t val, void *addr); -void mmio_writew(uint16_t val, void *addr); -void mmio_writel(uint32_t val, void *addr); -uint8_t mmio_readb(void *addr); -uint16_t mmio_readw(void *addr); -uint32_t mmio_readl(void *addr); -void internal_delay(int usecs); -int noop_shutdown(void); -void *fallback_map(const char *descr, unsigned long phys_addr, size_t len); -void fallback_unmap(void *virt_addr, size_t len); -uint8_t noop_chip_readb(const chipaddr addr); -void noop_chip_writeb(uint8_t val, chipaddr addr); -void fallback_chip_writew(uint16_t val, chipaddr addr); -void fallback_chip_writel(uint32_t val, chipaddr addr); -void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len); -uint16_t fallback_chip_readw(const chipaddr addr); -uint32_t fallback_chip_readl(const chipaddr addr); -void fallback_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); -#if defined(__FreeBSD__) || defined(__DragonFly__) -extern int io_fd; -#endif - -/* dummyflasher.c */ -int dummy_init(void); -int dummy_shutdown(void); -void *dummy_map(const char *descr, unsigned long phys_addr, size_t len); -void dummy_unmap(void *virt_addr, size_t len); -void dummy_chip_writeb(uint8_t val, chipaddr addr); -void dummy_chip_writew(uint16_t val, chipaddr addr); -void dummy_chip_writel(uint32_t val, chipaddr addr); -void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len); -uint8_t dummy_chip_readb(const chipaddr addr); -uint16_t dummy_chip_readw(const chipaddr addr); -uint32_t dummy_chip_readl(const chipaddr addr); -void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); -int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); - -/* nic3com.c */ -int nic3com_init(void); -int nic3com_shutdown(void); -void nic3com_chip_writeb(uint8_t val, chipaddr addr); -uint8_t nic3com_chip_readb(const chipaddr addr); -extern struct pcidev_status nics_3com[]; - -/* gfxnvidia.c */ -int gfxnvidia_init(void); -int gfxnvidia_shutdown(void); -void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr); -uint8_t gfxnvidia_chip_readb(const chipaddr addr); -extern struct pcidev_status gfx_nvidia[]; - -/* drkaiser.c */ -int drkaiser_init(void); -int drkaiser_shutdown(void); -void drkaiser_chip_writeb(uint8_t val, chipaddr addr); -uint8_t drkaiser_chip_readb(const chipaddr addr); -extern struct pcidev_status drkaiser_pcidev[]; - -/* satasii.c */ -int satasii_init(void); -int satasii_shutdown(void); -void satasii_chip_writeb(uint8_t val, chipaddr addr); -uint8_t satasii_chip_readb(const chipaddr addr); -extern struct pcidev_status satas_sii[]; - -/* ft2232_spi.c */ -#define FTDI_FT2232H 0x6010 -#define FTDI_FT4232H 0x6011 -int ft2232_spi_init(void); -int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); -int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf); - -/* bitbang_spi.c */ -extern int bitbang_spi_half_period; -extern const struct bitbang_spi_master_entry bitbang_spi_master_table[]; -int bitbang_spi_init(void); -int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); -int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf); - -/* buspirate_spi.c */ -struct buspirate_spispeeds { - const char *name; - const int speed; -}; -int buspirate_spi_init(void); -int buspirate_spi_shutdown(void); -int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); -int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); - -/* flashrom.c */ -extern char *programmer_param; -extern int verbose; -extern const char *flashrom_version; -#define printf_debug(x...) { if (verbose) printf(x); } -void map_flash_registers(struct flashchip *flash); -int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len); -int erase_flash(struct flashchip *flash); -int min(int a, int b); -int max(int a, int b); -char *extract_param(char **haystack, char *needle, char *delim); -int check_erased_range(struct flashchip *flash, int start, int len); -int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message); -char *strcat_realloc(char *dest, const char *src); - -#define OK 0 -#define NT 1 /* Not tested */ - -/* layout.c */ -int show_id(uint8_t *bios, int size, int force); -int read_romlayout(char *name); -int find_romentry(char *name); -int handle_romentries(uint8_t *buffer, struct flashchip *flash); - -/* cbtable.c */ -int coreboot_init(void); -extern char *lb_part, *lb_vendor; -extern int partvendor_from_cbtable; - -/* spi.c */ -enum spi_controller { - SPI_CONTROLLER_NONE, - SPI_CONTROLLER_ICH7, - SPI_CONTROLLER_ICH9, - SPI_CONTROLLER_IT87XX, - SPI_CONTROLLER_SB600, - SPI_CONTROLLER_VIA, - SPI_CONTROLLER_WBSIO, -#if FT2232_SPI_SUPPORT == 1 - SPI_CONTROLLER_FT2232, -#endif -#if DUMMY_SUPPORT == 1 - SPI_CONTROLLER_DUMMY, -#endif -#if BUSPIRATE_SPI_SUPPORT == 1 - SPI_CONTROLLER_BUSPIRATE, -#endif - SPI_CONTROLLER_INVALID /* This must always be the last entry. */ -}; -extern const int spi_programmer_count; -struct spi_command { - unsigned int writecnt; - unsigned int readcnt; - const unsigned char *writearr; - unsigned char *readarr; -}; -struct spi_programmer { - int (*command)(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); - int (*multicommand)(struct spi_command *cmds); - - /* Optimized functions for this programmer */ - int (*read)(struct flashchip *flash, uint8_t *buf, int start, int len); - int (*write_256)(struct flashchip *flash, uint8_t *buf); -}; - -extern enum spi_controller spi_controller; -extern const struct spi_programmer spi_programmer[]; -extern void *spibar; -int probe_spi_rdid(struct flashchip *flash); -int probe_spi_rdid4(struct flashchip *flash); -int probe_spi_rems(struct flashchip *flash); -int probe_spi_res(struct flashchip *flash); -int spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -int spi_send_multicommand(struct spi_command *cmds); -int spi_write_enable(void); -int spi_write_disable(void); -int spi_chip_erase_60(struct flashchip *flash); -int spi_chip_erase_c7(struct flashchip *flash); -int spi_chip_erase_60_c7(struct flashchip *flash); -int spi_chip_erase_d8(struct flashchip *flash); -int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -int spi_chip_write_1(struct flashchip *flash, uint8_t *buf); -int spi_chip_write_256(struct flashchip *flash, uint8_t *buf); -int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); -uint8_t spi_read_status_register(void); -int spi_disable_blockprotect(void); -int spi_byte_program(int addr, uint8_t byte); -int spi_nbyte_program(int addr, uint8_t *bytes, int len); -int spi_nbyte_read(int addr, uint8_t *bytes, int len); -int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize); -int spi_aai_write(struct flashchip *flash, uint8_t *buf); -uint32_t spi_get_valid_read_addr(void); -int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -int default_spi_send_multicommand(struct spi_command *cmds); - -/* 82802ab.c */ -int probe_82802ab(struct flashchip *flash); -int erase_82802ab(struct flashchip *flash); -int write_82802ab(struct flashchip *flash, uint8_t *buf); - -/* am29f040b.c */ -int probe_29f040b(struct flashchip *flash); -int erase_29f040b(struct flashchip *flash); -int write_29f040b(struct flashchip *flash, uint8_t *buf); - -/* pm29f002.c */ -int write_pm29f002(struct flashchip *flash, uint8_t *buf); - -/* en29f002a.c */ -int probe_en29f002a(struct flashchip *flash); -int erase_en29f002a(struct flashchip *flash); -int write_en29f002a(struct flashchip *flash, uint8_t *buf); - -/* ichspi.c */ -int ich_init_opcodes(void); -int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -int ich_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -int ich_spi_write_256(struct flashchip *flash, uint8_t * buf); -int ich_spi_send_multicommand(struct spi_command *cmds); - -/* it87spi.c */ -extern uint16_t it8716f_flashport; -void enter_conf_mode_ite(uint16_t port); -void exit_conf_mode_ite(uint16_t port); -int it87spi_init(void); -int it87xx_probe_spi_flash(const char *name); -int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); -int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf); - -/* sb600spi.c */ -int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf); -extern uint8_t *sb600_spibar; - -/* jedec.c */ -uint8_t oddparity(uint8_t val); -void toggle_ready_jedec(chipaddr dst); -void data_polling_jedec(chipaddr dst, uint8_t data); -void start_program_jedec(chipaddr bios); -int write_byte_program_jedec(chipaddr bios, uint8_t *src, - chipaddr dst); -int probe_jedec(struct flashchip *flash); -int erase_chip_jedec(struct flashchip *flash); -int write_jedec(struct flashchip *flash, uint8_t *buf); -int write_jedec_1(struct flashchip *flash, uint8_t *buf); -int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize); -int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize); -int write_sector_jedec(chipaddr bios, uint8_t *src, - chipaddr dst, unsigned int page_size); - -/* m29f002.c */ -int erase_m29f002(struct flashchip *flash); -int write_m29f002t(struct flashchip *flash, uint8_t *buf); -int write_m29f002b(struct flashchip *flash, uint8_t *buf); - -/* m29f400bt.c */ -int probe_m29f400bt(struct flashchip *flash); -int erase_m29f400bt(struct flashchip *flash); -int block_erase_m29f400bt(struct flashchip *flash, int start, int len); -int write_m29f400bt(struct flashchip *flash, uint8_t *buf); -int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf); -void toggle_ready_m29f400bt(chipaddr dst); -void data_polling_m29f400bt(chipaddr dst, uint8_t data); -void protect_m29f400bt(chipaddr bios); -void write_page_m29f400bt(chipaddr bios, uint8_t *src, - chipaddr dst, int page_size); - -/* mx29f002.c */ -int probe_29f002(struct flashchip *flash); -int erase_29f002(struct flashchip *flash); -int write_29f002(struct flashchip *flash, uint8_t *buf); - -/* pm49fl00x.c */ -int probe_49fl00x(struct flashchip *flash); -int erase_49fl00x(struct flashchip *flash); -int write_49fl00x(struct flashchip *flash, uint8_t *buf); - -/* sharplhf00l04.c */ -int probe_lhf00l04(struct flashchip *flash); -int erase_lhf00l04(struct flashchip *flash); -int write_lhf00l04(struct flashchip *flash, uint8_t *buf); -void toggle_ready_lhf00l04(chipaddr dst); -void data_polling_lhf00l04(chipaddr dst, uint8_t data); -void protect_lhf00l04(chipaddr bios); - -/* sst28sf040.c */ -int probe_28sf040(struct flashchip *flash); -int erase_28sf040(struct flashchip *flash); -int write_28sf040(struct flashchip *flash, uint8_t *buf); - -/* sst39sf020.c */ -int probe_39sf020(struct flashchip *flash); -int write_39sf020(struct flashchip *flash, uint8_t *buf); - -/* sst49lf040.c */ -int erase_49lf040(struct flashchip *flash); -int write_49lf040(struct flashchip *flash, uint8_t *buf); - -/* sst49lfxxxc.c */ -int probe_49lfxxxc(struct flashchip *flash); -int erase_49lfxxxc(struct flashchip *flash); -int write_49lfxxxc(struct flashchip *flash, uint8_t *buf); - -/* sst_fwhub.c */ -int probe_sst_fwhub(struct flashchip *flash); -int erase_sst_fwhub(struct flashchip *flash); -int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size); -int write_sst_fwhub(struct flashchip *flash, uint8_t *buf); - -/* w39v040c.c */ -int probe_w39v040c(struct flashchip *flash); -int erase_w39v040c(struct flashchip *flash); -int write_w39v040c(struct flashchip *flash, uint8_t *buf); - -/* w39V080fa.c */ -int probe_winbond_fwhub(struct flashchip *flash); -int erase_winbond_fwhub(struct flashchip *flash); -int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf); - -/* w29ee011.c */ -int probe_w29ee011(struct flashchip *flash); - -/* w49f002u.c */ -int write_49f002(struct flashchip *flash, uint8_t *buf); - -/* wbsio_spi.c */ -int wbsio_check_for_spi(const char *name); -int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf); - -/* stm50flw0x0x.c */ -int probe_stm50flw0x0x(struct flashchip *flash); -int erase_stm50flw0x0x(struct flashchip *flash); -int write_stm50flw0x0x(struct flashchip *flash, uint8_t *buf); - -/* serprog.c */ -int serprog_init(void); -int serprog_shutdown(void); -void serprog_chip_writeb(uint8_t val, chipaddr addr); -uint8_t serprog_chip_readb(const chipaddr addr); -void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); -void serprog_delay(int delay); - -/* serial.c */ -void sp_flush_incoming(void); -int sp_openserport(char *dev, unsigned int baud); -void __attribute__((noreturn)) sp_die(char *msg); -extern int sp_fd; - -#endif /* !__FLASH_H__ */ diff --git a/flashchips.c b/flashchips.c deleted file mode 100644 index 5e74ccf..0000000 --- a/flashchips.c +++ /dev/null @@ -1,3435 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2004 Tyan Corp - * Copyright (C) 2005-2008 coresystems GmbH - * Copyright (C) 2006-2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" -#include "flashchips.h" - -/** - * List of supported flash chips. - * - * Please keep the list sorted by vendor name and chip name, so that - * the output of 'flashrom -L' is alphabetically sorted. - */ -struct flashchip flashchips[] = { - - /* - * .vendor = Vendor name - * .name = Chip name - * .bustype = Supported flash bus types (Parallel, LPC...) - * .manufacture_id = Manufacturer chip ID - * .model_id = Model chip ID - * .total_size = Total size in (binary) kbytes - * .page_size = Page or eraseblock(?) size in bytes - * .tested = Test status - * .probe = Probe function - * .probe_timing = Probe function delay - * .erase = Chip erase function - * .block_erasers[] = Array of erase layouts and erase functions - * { - * .eraseblocks[] = Array of { blocksize, blockcount } - * .block_erase = Block erase function - * } - * .write = Chip write function - * .read = Chip read function - */ - - { - .vendor = "AMD", - .name = "Am29F010A/B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F010B, /* Same as Am29F010A */ - .total_size = 128, - .page_size = 16 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_29f040b, - .probe_timing = TIMING_ZERO, - .erase = erase_29f040b, - .write = write_pm29f002, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29F002(N)BB", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F002BB, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, - .erase = erase_chip_jedec, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29F002(N)BT", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F002BT, - .total_size = 256, - .page_size = 256, - .tested = TEST_OK_PRE, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, - .erase = erase_chip_jedec, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29F016D", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F016D, - .total_size = 2048, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_29f040b, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29F040B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_29f040b, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29F080B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F080B, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29LV040B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29LV040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_29f040b, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "AMD", - .name = "Am29LV081B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29LV080B, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_29f040b, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "ASD", - .name = "AE49F2008", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ASD_ID, - .model_id = ASD_AE49F2008, - .total_size = 256, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_FIXME, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "AT25DF021", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF021, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25DF041A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF041A, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25DF081", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF081, - .total_size = 1024, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25DF161", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF161, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25DF321", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF321, - .total_size = 4096, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25DF321A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF321A, - .total_size = 4096, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25DF641", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25DF641, - .total_size = 8192, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25F512B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25F512B, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25FS010", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25FS010, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT25FS040", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_25FS040, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT26DF041", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_26DF041, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL /* Incompatible Page write */, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT26DF081A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_26DF081A, - .total_size = 1024, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT26DF161", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_26DF161, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT26DF161A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_26DF161A, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - /*The AT26DF321 has the same ID as the AT25DF321. */ - /*{ - .vendor = "Atmel", - .name = "AT26DF321", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_26DF321, - .total_size = 4096, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - },*/ - - { - .vendor = "Atmel", - .name = "AT26F004", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_26F004, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = NULL /* Incompatible Page write */, - .read = spi_chip_read, - }, - - { - .vendor = "Atmel", - .name = "AT29C512", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_29C512, - .total_size = 64, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10000, /* 10mS, Enter=Exec */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - - }, - - { - .vendor = "Atmel", - .name = "AT29C010A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_29C010A, - .total_size = 128, - .page_size = 128, - .tested = TEST_OK_PRE, - .probe = probe_jedec, - .probe_timing = 10000, /* 10mS, Enter=Exec */ - .erase = erase_chip_jedec, - .write = write_jedec, /* FIXME */ - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "AT29C020", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_29C020, - .total_size = 256, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10000, /* 10ms */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "AT29C040A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_29C040A, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10000, /* 10 ms */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "AT45CS1282", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45CS1282, - .total_size = 16896 /* No power of two sizes */, - .page_size = 1056 /* No power of two sizes */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL /* Incompatible Page write */, - .read = NULL /* Incompatible read */, - }, - - { - .vendor = "Atmel", - .name = "AT45DB011D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB011D, - .total_size = 128 /* Size can only be determined from status register */, - .page_size = 256 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT45DB021D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB021D, - .total_size = 256 /* Size can only be determined from status register */, - .page_size = 256 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT45DB041D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB041D, - .total_size = 512 /* Size can only be determined from status register */, - .page_size = 256 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT45DB081D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB081D, - .total_size = 1024 /* Size can only be determined from status register */, - .page_size = 256 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT45DB161D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB161D, - .total_size = 2048 /* Size can only be determined from status register */, - .page_size = 512 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT45DB321C", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB321C, - .total_size = 4224 /* No power of two sizes */, - .page_size = 528 /* No power of two sizes */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL /* Incompatible read */, - }, - - { - .vendor = "Atmel", - .name = "AT45DB321D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB321D, - .total_size = 4096 /* Size can only be determined from status register */, - .page_size = 512 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT45DB642D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = AT_45DB642D, - .total_size = 8192 /* Size can only be determined from status register */, - .page_size = 1024 /* Size can only be determined from status register */, - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Atmel", - .name = "AT49BV512", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_49BV512, - .total_size = 64, - .page_size = 64, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "AT49F002(N)", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_49F002N, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "AT49F002(N)T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ATMEL_ID, - .model_id = AT_49F002NT, - .total_size = 256, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "AMIC", - .name = "A25L40P", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = AMIC_ID, - .model_id = AMIC_A25L40P, - .total_size = 512, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid4, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "AMIC", - .name = "A29002B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMIC_ID_NOPREFIX, - .model_id = AMIC_A29002B, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "AMIC", - .name = "A29002T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMIC_ID_NOPREFIX, - .model_id = AMIC_A29002T, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_OK_PRE, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "AMIC", - .name = "A29040B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMIC_ID_NOPREFIX, - .model_id = AMIC_A29040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PR, - .probe = probe_29f040b, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "AMIC", - .name = "A49LF040A", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = AMIC_ID_NOPREFIX, - .model_id = AMIC_A49LF040A, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_49fl00x, - .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ - .erase = erase_49fl00x, - .write = write_49fl00x, - .read = read_memmapped, - }, - - { - .vendor = "EMST", - .name = "F49B002UA", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = EMST_ID, - .model_id = EMST_F49B002UA, - .total_size = 256, - .page_size = 4096, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Eon", - .name = "EN25B05", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B05, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B10", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B10, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B20", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B20, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B40", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B40, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B80", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B80, - .total_size = 1024, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B16", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B16, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B32", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B32, - .total_size = 4096, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25B64", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25B64, - .total_size = 8192, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25D16", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25D16, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F05", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F05, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F10", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F10, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F20", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F20, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F40", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F40, - .total_size = 512, - .page_size = 256, - .tested = TEST_OK_PROBE, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F80", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F80, - .total_size = 1024, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F16", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F16, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Eon", - .name = "EN25F32", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = EN_25F32, - .total_size = 4096, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "EON", - .name = "EN29F002(A)(N)B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = EON_ID, - .model_id = EN_29F002B, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "EON", - .name = "EN29F002(A)(N)T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = EON_ID, - .model_id = EN_29F002T, - .total_size = 256, - .page_size = 256, - .tested = TEST_OK_PRE, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Fujitsu", - .name = "MBM29F004BC", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = FUJITSU_ID, - .model_id = MBM29F004BC, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "Fujitsu", - .name = "MBM29F004TC", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = FUJITSU_ID, - .model_id = MBM29F004TC, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "Fujitsu", - .name = "MBM29F400BC", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = FUJITSU_ID, - .model_id = MBM29F400BC, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_m29f400bt, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ - .erase = erase_m29f400bt, - .write = write_coreboot_m29f400bt, - .read = read_memmapped, - }, - - { - .vendor = "Fujitsu", - .name = "MBM29F400TC", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = FUJITSU_ID, - .model_id = MBM29F400TC, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_m29f400bt, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ - .erase = erase_m29f400bt, - .write = write_coreboot_m29f400bt, - .read = read_memmapped, - }, - - { - .vendor = "Intel", - .name = "28F001BX-B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = INTEL_ID, - .model_id = P28F001BXB, - .total_size = 128, - .page_size = 128 * 1024, /* 8k + 2x4k + 112k */ - .tested = TEST_BAD_ERASE|TEST_BAD_WRITE, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "Intel", - .name = "28F001BX-T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = INTEL_ID, - .model_id = P28F001BXT, - .total_size = 128, - .page_size = 128 * 1024, /* 112k + 2x4k + 8k */ - .tested = TEST_OK_PR|TEST_BAD_ERASE|TEST_BAD_WRITE, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "Intel", - .name = "82802AB", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = INTEL_ID, - .model_id = I_82802AB, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ - .erase = erase_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "Intel", - .name = "82802AC", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = INTEL_ID, - .model_id = I_82802AC, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ - .erase = erase_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "Macronix", - .name = "MX25L512", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L512, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 16} }, - .block_erase = spi_block_erase_20, - }, { - .eraseblocks = { {64 * 1024, 1} }, - .block_erase = spi_block_erase_52, - }, { - .eraseblocks = { {64 * 1024, 1} }, - .block_erase = spi_block_erase_d8, - }, { - .eraseblocks = { {64 * 1024, 1} }, - .block_erase = spi_block_erase_60, - }, { - .eraseblocks = { {64 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - }, - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L1005", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L1005, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 32} }, - .block_erase = spi_block_erase_20, - }, { - .eraseblocks = { {64 * 1024, 2} }, - .block_erase = spi_block_erase_d8, - }, { - .eraseblocks = { {128 * 1024, 1} }, - .block_erase = spi_block_erase_60, - }, { - .eraseblocks = { {128 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - }, - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L2005", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L2005, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 64} }, - .block_erase = spi_block_erase_20, - }, { - .eraseblocks = { {64 * 1024, 4} }, - .block_erase = spi_block_erase_52, - }, { - .eraseblocks = { {64 * 1024, 4} }, - .block_erase = spi_block_erase_d8, - }, { - .eraseblocks = { {256 * 1024, 1} }, - .block_erase = spi_block_erase_60, - }, { - .eraseblocks = { {256 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - }, - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L4005", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L4005, - .total_size = 512, - .page_size = 256, - .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 128} }, - .block_erase = spi_block_erase_20, - }, { - .eraseblocks = { {64 * 1024, 8} }, - .block_erase = spi_block_erase_52, - }, { - .eraseblocks = { {64 * 1024, 8} }, - .block_erase = spi_block_erase_d8, - }, { - .eraseblocks = { {512 * 1024, 1} }, - .block_erase = spi_block_erase_60, - }, { - .eraseblocks = { {512 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - }, - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L8005", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L8005, - .total_size = 1024, - .page_size = 256, - .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 256} }, - .block_erase = spi_block_erase_20, - }, { - .eraseblocks = { {64 * 1024, 16} }, - .block_erase = spi_block_erase_52, - }, { - .eraseblocks = { {64 * 1024, 16} }, - .block_erase = spi_block_erase_d8, - }, { - .eraseblocks = { {1024 * 1024, 1} }, - .block_erase = spi_block_erase_60, - }, { - .eraseblocks = { {1024 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - }, - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L1605", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L1605, - .total_size = 2048, - .page_size = 256, - .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 512} }, - .block_erase = spi_block_erase_20, /* This erase function has 64k blocksize for eLiteFlash */ - }, { - .eraseblocks = { {64 * 1024, 32} }, /* Not supported in MX25L1605 (eLiteFlash) and MX25L1605D */ - .block_erase = spi_block_erase_52, - }, { - .eraseblocks = { {64 * 1024, 32} }, - .block_erase = spi_block_erase_d8, - }, { - .eraseblocks = { {2 * 1024 * 1024, 1} }, - .block_erase = spi_block_erase_60, - }, { - .eraseblocks = { {2 * 1024 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - }, - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L1635D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L1635D, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L3205", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L3205, - .total_size = 4096, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L3235D", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L3235D, - .total_size = 4096, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L6405", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L6405, - .total_size = 8192, - .page_size = 256, - .tested = TEST_OK_PROBE, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX25L12805", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = MX_25L12805, - .total_size = 16384, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Macronix", - .name = "MX29F001B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = MX_ID, - .model_id = MX_29F001B, - .total_size = 128, - .page_size = 32 * 1024, - .tested = TEST_OK_PRE, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Macronix", - .name = "MX29F001T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = MX_ID, - .model_id = MX_29F001T, - .total_size = 128, - .page_size = 32 * 1024, - .tested = TEST_OK_PRE, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Macronix", - .name = "MX29F002B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = MX_ID, - .model_id = MX_29F002B, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Macronix", - .name = "MX29F002T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = MX_ID, - .model_id = MX_29F002T, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_OK_PRE, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Macronix", - .name = "MX29LV040", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = MX_ID, - .model_id = MX_29LV040, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PR, - .probe = probe_29f002, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ - .erase = erase_29f002, - .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Numonyx", - .name = "M25PE10", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25PE10, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_d8, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Numonyx", - .name = "M25PE20", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25PE20, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_d8, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Numonyx", - .name = "M25PE40", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25PE40, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_d8, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Numonyx", - .name = "M25PE80", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25PE80, - .total_size = 1024, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_d8, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Numonyx", - .name = "M25PE16", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25PE16, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_d8, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm25LV010", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = PMC_25LV010, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm25LV016B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = PMC_25LV016B, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm25LV020", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = PMC_25LV020, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm25LV040", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = PMC_25LV040, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm25LV080B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = PMC_25LV080B, - .total_size = 1024, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm25LV512", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = PMC_25LV512, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", - .name = "Pm29F0002T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_29F002T, - .total_size = 256, - .page_size = 8192, - .tested = TEST_OK_PREW, - .probe = probe_29f040b, - .probe_timing = TIMING_FIXME, - .erase = erase_29f040b, - .write = write_pm29f002, - .read = read_memmapped, - }, - - { - .vendor = "PMC", - .name = "Pm29F0002B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_29F002B, - .total_size = 256, - .page_size = 8192, - .tested = TEST_UNTESTED, - .probe = probe_29f040b, - .probe_timing = TIMING_FIXME, - .erase = erase_29f040b, - .write = write_pm29f002, - .read = read_memmapped, - }, - - { - .vendor = "PMC", - .name = "Pm39LV010", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_39F010, - .total_size = 128, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "PMC", - .name = "Pm49FL002", - .bustype = CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/ - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_49FL002, - .total_size = 256, - .page_size = 16 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_49fl00x, - .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ - .erase = erase_49fl00x, - .write = write_49fl00x, - .read = read_memmapped, - }, - - { - .vendor = "PMC", - .name = "Pm49FL004", - .bustype = CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/ - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_49FL004, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_49fl00x, - .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ - .erase = erase_49fl00x, - .write = write_49fl00x, - .read = read_memmapped, - }, - - { - .vendor = "Sanyo", - .name = "LF25FW203A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SANYO_ID, - .model_id = SANYO_LE25FW203A, - .total_size = 2048, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Sharp", - .name = "LHF00L04", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = SHARP_ID, - .model_id = SHARP_LHF00L04, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_lhf00l04, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sharplhf00l04.c) */ - .erase = erase_lhf00l04, - .write = write_lhf00l04, - .read = read_memmapped, - }, - - { - .vendor = "Spansion", - .name = "S25FL016A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SPANSION_ID, - .model_id = SPANSION_S25FL016A, - .total_size = 2048, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST25VF016B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = SST_25VF016B, - .total_size = 2048, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST25VF032B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = SST_25VF032B, - .total_size = 4096, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST25VF040B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = SST_25VF040B, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST25VF040.REMS", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = SST_25VF040_REMS, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_OK_PR, - .probe = probe_spi_rems, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST25VF040B.REMS", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = SST_25VF040B_REMS, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_OK_PR, - .probe = probe_spi_rems, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST25VF080B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = SST_25VF080B, - .total_size = 1024, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", - .name = "SST28SF040A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_28SF040, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_28sf040, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst28sf040.c) */ - .erase = erase_28sf040, - .write = write_28sf040, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST29EE010", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_29EE010, - .total_size = 128, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST29LE010", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_29LE010, - .total_size = 128, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST29EE020A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_29EE020A, - .total_size = 256, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST29LE020", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_29LE020, - .total_size = 256, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39SF010A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39SF010, - .total_size = 128, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39SF020A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39SF020, - .total_size = 256, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39SF040", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39SF040, - .total_size = 512, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39VF512", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39VF512, - .total_size = 64, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns*/ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39VF010", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39VF010, - .total_size = 128, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39VF020", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39VF020, - .total_size = 256, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39VF040", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39VF040, - .total_size = 512, - .page_size = 4096, - .tested = TEST_OK_PROBE, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST39VF080", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39VF080, - .total_size = 1024, - .page_size = 4096, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF002A/B", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = SST_ID, - .model_id = SST_49LF002A, - .total_size = 256, - .page_size = 16 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_sst_fwhub, - .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ - .erase = erase_sst_fwhub, - .write = write_sst_fwhub, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF003A/B", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = SST_ID, - .model_id = SST_49LF003A, - .total_size = 384, - .page_size = 64 * 1024, - .tested = TEST_OK_PR, - .probe = probe_sst_fwhub, - .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ - .erase = erase_sst_fwhub, - .write = write_sst_fwhub, - .read = read_memmapped, - }, - - { - /* Contrary to the data sheet, TBL# on the SST49LF004B affects the top 128kB (instead of 64kB) - * and is only honored for 64k block erase, but not 4k sector erase. - */ - .vendor = "SST", - .name = "SST49LF004A/B", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = SST_ID, - .model_id = SST_49LF004A, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_sst_fwhub, - .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ - .erase = NULL, - .block_erasers = - { - { - .eraseblocks = { {4 * 1024, 128} }, - .block_erase = erase_sector_jedec, /* missing unlock */ - }, { - .eraseblocks = { {64 * 1024, 8} }, - .block_erase = erase_sst_fwhub_block, /* same as erase_block_jedec, but with unlock */ - }, { - .eraseblocks = { {512 * 1024, 1} }, - .block_erase = NULL, /* AA 55 80 AA 55 10, only in PP mode */ - }, - }, - .write = write_sst_fwhub, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF004C", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = SST_ID, - .model_id = SST_49LF004C, - .total_size = 512, - .page_size = 4 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_49lfxxxc, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ - .erase = erase_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF008A", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = SST_ID, - .model_id = SST_49LF008A, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_sst_fwhub, - .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ - .erase = erase_sst_fwhub, - .write = write_sst_fwhub, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF008C", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = SST_ID, - .model_id = SST_49LF008C, - .total_size = 1024, - .page_size = 4 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_49lfxxxc, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ - .erase = erase_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF016C", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = SST_ID, - .model_id = SST_49LF016C, - .total_size = 2048, - .page_size = 4 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_49lfxxxc, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ - .erase = erase_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF020", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = SST_ID, - .model_id = SST_49LF020, - .total_size = 256, - .page_size = 16 * 1024, - .tested = TEST_OK_PR, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_49lf040, - .write = write_49lf040, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF020A", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = SST_ID, - .model_id = SST_49LF020A, - .total_size = 256, - .page_size = 4 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_49lf040, - .write = write_49lf040, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF040", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = SST_ID, - .model_id = SST_49LF040, - .total_size = 512, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ - .erase = erase_49lf040, - .write = write_49lf040, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF040B", - .bustype = CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = SST_ID, - .model_id = SST_49LF040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_sst_fwhub, - .probe_timing = 1, /* 150ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ - .erase = erase_sst_fwhub, - .write = write_sst_fwhub, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF080A", - .bustype = CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = SST_ID, - .model_id = SST_49LF080A, - .total_size = 1024, - .page_size = 4096, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = TIMING_FIXME, - .erase = erase_49lf040, - .write = write_49lf040, - .read = read_memmapped, - }, - - { - .vendor = "SST", - .name = "SST49LF160C", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = SST_ID, - .model_id = SST_49LF160C, - .total_size = 2048, - .page_size = 4 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_49lfxxxc, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ - .erase = erase_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M25P05-A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P05A, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - /* The ST M25P05 is a bit of a problem. It has the same ID as the - * ST M25P05-A in RES mode, but supports only 128 byte writes instead - * of 256 byte writes. We rely heavily on the fact that probe_spi_res - * only is successful if RDID does not work. - */ - { - .vendor = "ST", - .name = "M25P05.RES", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P05_RES, - .total_size = 64, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_res, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_1, /* 128 */ - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P10-A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P10A, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - /* The ST M25P10 has the same problem as the M25P05. */ - { - .vendor = "ST", - .name = "M25P10.RES", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P10_RES, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_res, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_1, /* 128 */ - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P20", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P20, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P40", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P40, - .total_size = 512, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P40-old", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P40_RES, - .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_res, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P80", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P80, - .total_size = 1024, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P16", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P16, - .total_size = 2048, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P32", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P32, - .total_size = 4096, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P64", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P64, - .total_size = 8192, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M25P128", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25P128, - .total_size = 16384, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "ST", - .name = "M29F002B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ST_ID, - .model_id = ST_M29F002B, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_m29f002, - .write = write_m29f002b, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M29F002T/NT", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ST_ID, - .model_id = ST_M29F002T, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_m29f002, - .write = write_m29f002t, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M29F040B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ST_ID, - .model_id = ST_M29F040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_29f040b, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ - .erase = erase_29f040b, - .write = write_29f040b, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M29F400BT", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ST_ID, - .model_id = ST_M29F400BT, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_m29f400bt, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ - .erase = erase_m29f400bt, - .write = write_coreboot_m29f400bt, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M29W010B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ST_ID, - .model_id = ST_M29W010B, - .total_size = 128, - .page_size = 16 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M29W040B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = ST_ID, - .model_id = ST_M29W040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW040A", - .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW040A, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_stm50flw0x0x, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ - .erase = erase_stm50flw0x0x, - .write = write_stm50flw0x0x, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW040B", - .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW040B, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_stm50flw0x0x, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ - .erase = erase_stm50flw0x0x, - .write = write_stm50flw0x0x, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW080A", - .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW080A, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_stm50flw0x0x, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ - .erase = erase_stm50flw0x0x, - .write = write_stm50flw0x0x, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW080B", - .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW080B, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_stm50flw0x0x, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ - .erase = erase_stm50flw0x0x, - .write = write_stm50flw0x0x, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FW002", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FW002, - .total_size = 256, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_49lfxxxc, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FW016", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FW016, - .total_size = 2048, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ - .erase = erase_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FW040", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FW040, - .total_size = 512, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ - .erase = erase_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FW080", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FW080, - .total_size = 1024, - .page_size = 64 * 1024, - .tested = TEST_OK_PREW, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ - .erase = erase_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50LPW116", - .bustype = CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50LPW116, - .total_size = 2048, - .page_size = 64 * 1024, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "SyncMOS", - .name = "S29C31004T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SYNCMOS_ID, - .model_id = S29C31004T, - .total_size = 512, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SyncMOS", - .name = "S29C51001T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SYNCMOS_ID, - .model_id = S29C51001T, - .total_size = 128, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SyncMOS", - .name = "S29C51002T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SYNCMOS_ID, - .model_id = S29C51002T, - .total_size = 256, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "SyncMOS", - .name = "S29C51004T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SYNCMOS_ID, - .model_id = S29C51004T, - .total_size = 512, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "TI", - .name = "TMS29F002RB", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = TI_OLD_ID, - .model_id = TI_TMS29F002RB, - .total_size = 256, - .page_size = 16384, /* Non-uniform sectors */ - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "TI", - .name = "TMS29F002RT", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = TI_OLD_ID, - .model_id = TI_TMS29F002RT, - .total_size = 256, - .page_size = 16384, /* Non-uniform sectors */ - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ - .erase = NULL, - .write = NULL, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W25x10", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X10, - .total_size = 128, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W25x20", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X20, - .total_size = 256, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W25x40", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X40, - .total_size = 512, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W25x80", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X80, - .total_size = 1024, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W25x16", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X16, - .total_size = 2048, - .page_size = 256, - .tested = TEST_OK_PR, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W25x32", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X32, - .total_size = 4096, - .page_size = 256, - .tested = TEST_OK_PROBE, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W25x64", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, - .model_id = W_25X64, - .total_size = 8192, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = spi_chip_erase_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "Winbond", - .name = "W29C011", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = WINBOND_ID, - .model_id = W_29C011, - .total_size = 128, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, /* used datasheet for the W29C011A */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W29C020C", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = WINBOND_ID, - .model_id = W_29C020C, - .total_size = 256, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W29C040P", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = WINBOND_ID, - .model_id = W_29C040P, - .total_size = 512, - .page_size = 256, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W29EE011", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = WINBOND_ID, - .model_id = W_29C011, - .total_size = 128, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_w29ee011, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w29ee011.c) */ - .erase = erase_chip_jedec, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V040A", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = WINBOND_ID, - .model_id = W_39V040A, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V040B", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = WINBOND_ID, - .model_id = W_39V040B, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_OK_PR | TEST_BAD_ERASE | TEST_BAD_WRITE, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V040C", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = WINBOND_ID, - .model_id = W_39V040C, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_OK_PREW, - .probe = probe_w39v040c, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v040c.c) */ - .erase = erase_w39v040c, - .write = write_w39v040c, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V040FA", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = WINBOND_ID, - .model_id = W_39V040FA, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V080A", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = WINBOND_ID, - .model_id = W_39V080A, - .total_size = 1024, - .page_size = 64*1024, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W49F002U", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = WINBOND_ID, - .model_id = W_49F002U, - .total_size = 256, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W49V002A", - .bustype = CHIP_BUSTYPE_LPC, - .manufacture_id = WINBOND_ID, - .model_id = W_49V002A, - .total_size = 256, - .page_size = 128, - .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W49V002FA", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = WINBOND_ID, - .model_id = W_49V002FA, - .total_size = 256, - .page_size = 128, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, - .erase = erase_chip_jedec, - .write = write_49f002, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V080FA", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = WINBOND_ID, - .model_id = W_39V080FA, - .total_size = 1024, - .page_size = 64*1024, - .tested = TEST_OK_PREW, - .probe = probe_winbond_fwhub, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */ - .erase = erase_winbond_fwhub, - .write = write_winbond_fwhub, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", - .name = "W39V080FA (dual mode)", - .bustype = CHIP_BUSTYPE_FWH, - .manufacture_id = WINBOND_ID, - .model_id = W_39V080FA_DM, - .total_size = 512, - .page_size = 64*1024, - .tested = TEST_UNTESTED, - .probe = probe_winbond_fwhub, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */ - .erase = erase_winbond_fwhub, - .write = write_winbond_fwhub, - .read = read_memmapped, - }, - - { - .vendor = "Atmel", - .name = "unknown Atmel SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ATMEL_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "EON", - .name = "unknown EON SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = EON_ID_NOPREFIX, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Macronix", - .name = "unknown Macronix SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = MX_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "PMC", - .name = "unknown PMC SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = PMC_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "SST", - .name = "unknown SST SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "ST", - .name = "unknown ST SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Sanyo", - .name = "unknown Sanyo SPI chip", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SANYO_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, - .erase = NULL, - .write = NULL, - .read = NULL, - }, - - { - .vendor = "Generic", - .name = "unknown SPI chip (RDID)", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = GENERIC_MANUF_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .erase = NULL, - .write = NULL, - }, - { - .vendor = "Generic", - .name = "unknown SPI chip (REMS)", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = GENERIC_MANUF_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 0, - .page_size = 256, - .tested = TEST_BAD_PREW, - .probe = probe_spi_rems, - .erase = NULL, - .write = NULL, - }, - - { NULL } -}; diff --git a/flashchips.h b/flashchips.h deleted file mode 100644 index 684b8b9..0000000 --- a/flashchips.h +++ /dev/null @@ -1,501 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2000 Ronald G. Minnich - * Copyright (C) 2005-2007 coresystems GmbH - * Copyright (C) 2006-2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FLASHCHIPS_H__ -#define __FLASHCHIPS_H__ 1 - -/* - * Please keep this list sorted alphabetically by manufacturer. The first - * entry of each section should be the manufacturer ID, followed by the - * list of devices from that manufacturer (sorted by device IDs). - * - * All LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no - * continuation code. - * SPI parts have 16-bit device IDs if they support RDID. - */ - -#define GENERIC_MANUF_ID 0xffff /* Check if there is a vendor ID */ -#define GENERIC_DEVICE_ID 0xffff /* Only match the vendor ID */ - -#define ALLIANCE_ID 0x52 /* Alliance Semiconductor */ - -#define AMD_ID 0x01 /* AMD */ -#define AM_29DL400BT 0x0C -#define AM_29DL400BB 0x0F -#define AM_29DL800BT 0x4A -#define AM_29DL800BB 0xCB -#define AM_29F002BB 0x34 /* Same as Am29F002NBB */ -#define AM_29F002BT 0xB0 /* Same as Am29F002NBT */ -#define AM_29F004BB 0x7B -#define AM_29F004BT 0x77 -#define AM_29F016D 0xAD -#define AM_29F010B 0x20 /* Same as Am29F010A */ -#define AM_29F040B 0xA4 -#define AM_29F080B 0xD5 -#define AM_29F200BB 0x57 -#define AM_29F200BT 0x51 -#define AM_29F400BB 0xAB -#define AM_29F400BT 0x23 -#define AM_29F800BB 0x58 -#define AM_29F800BT 0xD6 -#define AM_29LV002BB 0xC2 -#define AM_29LV002BT 0x40 -#define AM_29LV004BB 0xB6 -#define AM_29LV004BT 0xB5 -#define AM_29LV008BB 0x37 -#define AM_29LV008BT 0x3E -#define AM_29LV040B 0x4F -#define AM_29LV080B 0x38 /* Same as Am29LV081B */ -#define AM_29LV200BB 0xBF -#define AM_29LV200BT 0x3B -#define AM_29LV800BB 0x5B /* Same as Am29LV800DB */ -#define AM_29LV400BT 0xB9 -#define AM_29LV400BB 0xBA -#define AM_29LV800BT 0xDA /* Same as Am29LV800DT */ - -#define AMIC_ID 0x7F37 /* AMIC */ -#define AMIC_ID_NOPREFIX 0x37 /* AMIC */ -#define AMIC_A25L40P 0x2013 -#define AMIC_A29002B 0x0d -#define AMIC_A29002T 0x8C /* Same as A290021T */ -#define AMIC_A29040B 0x86 -#define AMIC_A29400T 0xB0 /* Same as 294001T */ -#define AMIC_A29400U 0x31 /* Same as A294001U */ -#define AMIC_A29800T 0x0E -#define AMIC_A29800U 0x8F -#define AMIC_A29L004T 0x34 /* Same as A29L400T */ -#define AMIC_A29L004U 0xB5 /* Same as A29L400U */ -#define AMIC_A29L008T 0x1A /* Same as A29L800T */ -#define AMIC_A29L008U 0x9B /* Same as A29L800U */ -#define AMIC_A29L040 0x92 -#define AMIC_A49LF040A 0x9d - -/* This chip vendor/device ID is probably a misinterpreted LHA header. */ -#define ASD_ID 0x25 /* ASD, not listed in JEP106W */ -#define ASD_AE49F2008 0x52 - -#define ATMEL_ID 0x1F /* Atmel */ -#define AT_25DF021 0x4300 -#define AT_25DF041A 0x4401 -#define AT_25DF081 0x4502 -#define AT_25DF161 0x4602 -#define AT_25DF321 0x4700 /* Same as 26DF321 */ -#define AT_25DF321A 0x4701 -#define AT_25DF641 0x4800 -#define AT_25F512A 0x65 /* Needs special RDID. AT25F512A_RDID 15 1d */ -#define AT_25F512B 0x6500 -#define AT_25FS010 0x6601 -#define AT_25FS040 0x6604 -#define AT_26DF041 0x4400 -#define AT_26DF081 0x4500 /* guessed, no datasheet available */ -#define AT_26DF081A 0x4501 -#define AT_26DF161 0x4600 -#define AT_26DF161A 0x4601 -#define AT_26DF321 0x4700 /* Same as 25DF321 */ -#define AT_26F004 0x0400 -#define AT_29C040A 0xA4 -#define AT_29C010A 0xD5 -#define AT_29C020 0xDA -#define AT_29C512 0x5D -#define AT_45BR3214B /* No ID available */ -#define AT_45CS1282 0x2920 -#define AT_45D011 /* No ID available */ -#define AT_45D021A /* No ID available */ -#define AT_45D041A /* No ID available */ -#define AT_45D081A /* No ID available */ -#define AT_45D161 /* No ID available */ -#define AT_45DB011 /* No ID available */ -#define AT_45DB011B /* No ID available */ -#define AT_45DB011D 0x2200 -#define AT_45DB021A /* No ID available */ -#define AT_45DB021B /* No ID available */ -#define AT_45DB021D 0x2300 -#define AT_45DB041A /* No ID available */ -#define AT_45DB041D 0x2400 -#define AT_45DB081A /* No ID available */ -#define AT_45DB081D 0x2500 -#define AT_45DB161 /* No ID available */ -#define AT_45DB161B /* No ID available */ -#define AT_45DB161D 0x2600 -#define AT_45DB321 /* No ID available */ -#define AT_45DB321B /* No ID available */ -#define AT_45DB321C 0x2700 -#define AT_45DB321D 0x2701 /* Buggy data sheet */ -#define AT_45DB642 /* No ID available */ -#define AT_45DB642D 0x2800 -#define AT_49BV512 0x03 -#define AT_49F002N 0x07 /* for AT49F002(N) */ -#define AT_49F002NT 0x08 /* for AT49F002(N)T */ - -#define CATALYST_ID 0x31 /* Catalyst */ - -#define EMST_ID 0x8C /* EMST / EFST Elite Flash Storage */ -#define EMST_F49B002UA 0x00 - -/* - * EN25 chips are SPI, first byte of device ID is memory type, - * second byte of device ID is log(bitsize)-9. - * Vendor and device ID of EN29 series are both prefixed with 0x7F, which - * is the continuation code for IDs in bank 2. - * Vendor ID of EN25 series is NOT prefixed with 0x7F, this results in - * a collision with Mitsubishi. Mitsubishi once manufactured flash chips. - * Let's hope they are not manufacturing SPI flash chips as well. - */ -#define EON_ID 0x7F1C /* EON Silicon Devices */ -#define EON_ID_NOPREFIX 0x1C /* EON, missing 0x7F prefix */ -#define EN_25B05 0x2010 /* Same as P05, 2^19 kbit or 2^16 kByte */ -#define EN_25B10 0x2011 /* Same as P10 */ -#define EN_25B20 0x2012 /* Same as P20 */ -#define EN_25B40 0x2013 /* Same as P40 */ -#define EN_25B80 0x2014 /* Same as P80 */ -#define EN_25B16 0x2015 /* Same as P16 */ -#define EN_25B32 0x2016 /* Same as P32 */ -#define EN_25B64 0x2017 /* Same as P64 */ -#define EN_25D16 0x3015 -#define EN_25F05 0x3110 -#define EN_25F10 0x3111 -#define EN_25F20 0x3112 -#define EN_25F40 0x3113 -#define EN_25F80 0x3114 -#define EN_25F16 0x3115 -#define EN_25F32 0x3116 -#define EN_29F512 0x7F21 -#define EN_29F010 0x7F20 -#define EN_29F040A 0x7F04 -#define EN_29LV010 0x7F6E -#define EN_29LV040A 0x7F4F /* EN_29LV040(A) */ -#define EN_29F002T 0x7F92 /* Same as EN29F002A */ -#define EN_29F002B 0x7F97 /* Same as EN29F002AN */ - -#define FUJITSU_ID 0x04 /* Fujitsu */ -#define MBM29DL400BC 0x0F -#define MBM29DL400TC 0x0C -#define MBM29DL800BA 0xCB -#define MBM29DL800TA 0x4A -#define MBM29F002BC 0x34 -#define MBM29F002TC 0xB0 -#define MBM29F004BC 0x7B -#define MBM29F004TC 0x77 -#define MBM29F040C 0xA4 -#define MBM29F080A 0xD5 -#define MBM29F200BC 0x57 -#define MBM29F200TC 0x51 -#define MBM29F400BC 0xAB -#define MBM29F400TC 0x23 -#define MBM29F800BA 0x58 -#define MBM29F800TA 0xD6 -#define MBM29LV002BC 0xC2 -#define MBM29LV002TC 0x40 -#define MBM29LV004BC 0xB6 -#define MBM29LV004TC 0xB5 -#define MBM29LV008BA 0x37 -#define MBM29LV008TA 0x3E -#define MBM29LV080A 0x38 -#define MBM29LV200BC 0xBF -#define MBM29LV200TC 0x3B -#define MBM29LV400BC 0xBA -#define MBM29LV400TC 0xB9 -#define MBM29LV800BA 0x5B /* Same as MBM29LV800BE */ -#define MBM29LV800TA 0xDA /* Same as MBM29LV800TE */ - -#define HYUNDAI_ID 0xAD /* Hyundai */ -#define HY_29F400T 0x23 /* Same as HY_29F400AT */ -#define HY_29F800B 0x58 /* Same as HY_29F800AB */ -#define HY_29LV800B 0x5B -#define HY_29F040A 0xA4 -#define HY_29F400B 0xAB /* Same as HY_29F400AB */ -#define HY_29F002 0xB0 -#define HY_29LV400T 0xB9 -#define HY_29LV400B 0xBA -#define HY_29F080 0xD5 -#define HY_29F800T 0xD6 /* Same as HY_29F800AT */ -#define HY_29LV800T 0xDA - -#define IMT_ID 0x7F1F /* Integrated Memory Technologies */ -#define IM_29F004B 0xAE -#define IM_29F004T 0xAF - -#define INTEL_ID 0x89 /* Intel */ -#define I_82802AB 0xAD -#define I_82802AC 0xAC -#define P28F001BXT 0x94 /* 28F001BX-T */ -#define P28F001BXB 0x95 /* 28F001BX-B */ -#define SHARP_LH28F008SA 0xA2 /* Sharp chip, Intel Vendor ID */ -#define SHARP_LH28F008SC 0xA6 /* Sharp chip, Intel Vendor ID */ - -#define ISSI_ID 0xD5 /* ISSI Integrated Silicon Solutions */ - -/* - * MX25 chips are SPI, first byte of device ID is memory type, - * second byte of device ID is log(bitsize)-9. - * Generalplus SPI chips seem to be compatible with Macronix - * and use the same set of IDs. - */ -#define MX_ID 0xC2 /* Macronix (MX) */ -#define MX_25L512 0x2010 /* Same as MX25V512 */ -#define MX_25L1005 0x2011 -#define MX_25L2005 0x2012 -#define MX_25L4005 0x2013 /* MX25L4005{,A} */ -#define MX_25L8005 0x2014 /* Same as MX25V8005 */ -#define MX_25L1605 0x2015 /* MX25L1605{,A,D} */ -#define MX_25L3205 0x2016 /* MX25L3205{,A} */ -#define MX_25L6405 0x2017 /* MX25L3205{,D} */ -#define MX_25L12805 0x2018 /* MX25L12805 */ -#define MX_25L1635D 0x2415 -#define MX_25L3235D 0x5E16 /* MX25L3225D/MX25L3235D/MX25L3237D */ -#define MX_29F001B 0x19 -#define MX_29F001T 0x18 -#define MX_29F002B 0x34 /* Same as MX29F002NB */ -#define MX_29F002T 0xB0 /* Same as MX29F002NT */ -#define MX_29F004B 0x46 -#define MX_29F004T 0x45 -#define MX_29F022T 0x36 /* Same as MX29F022NT */ -#define MX_29F040 0xA4 /* Same as MX29F040C */ -#define MX_29F080 0xD5 -#define MX_29F200B 0x57 /* Same as MX29F200CB */ -#define MX_29F200T 0x51 /* Same as MX29F200CT */ -#define MX_29F400B 0xAB /* Same as MX29F400CB */ -#define MX_29F400T 0x23 /* Same as MX29F400CT */ -#define MX_29F800B 0x58 -#define MX_29F800T 0xD6 -#define MX_29LV002CB 0x5A -#define MX_29LV002CT 0x59 -#define MX_29LV004B 0xB6 /* Same as MX29LV004CB */ -#define MX_29LV004T 0xB5 /* Same as MX29LV004CT */ -#define MX_29LV008B 0x37 /* Same as MX29LV008CB */ -#define MX_29LV008T 0x3E /* Same as MX29LV008CT */ -#define MX_29LV040 0x4F /* Same as MX29LV040C */ -#define MX_29LV081 0x38 -#define MX_29LV128DB 0x7A -#define MX_29LV128DT 0x7E -#define MX_29LV160DB 0x49 /* Same as MX29LV161DB/MX29LV160CB */ -#define MX_29LV160DT 0xC4 /* Same as MX29LV161DT/MX29LV160CT */ -#define MX_29LV320DB 0xA8 /* Same as MX29LV321DB */ -#define MX_29LV320DT 0xA7 /* Same as MX29LV321DT */ -#define MX_29LV400B 0xBA /* Same as MX29LV400CB */ -#define MX_29LV400T 0xB9 /* Same as MX29LV400CT */ -#define MX_29LV640DB 0xCB /* Same as MX29LV640EB */ -#define MX_29LV640DT 0xC9 /* Same as MX29LV640ET */ -#define MX_29LV800B 0x5B /* Same as MX29LV800CB */ -#define MX_29LV800T 0xDA /* Same as MX29LV800CT */ -#define MX_29SL402CB 0xF1 -#define MX_29SL402CT 0x70 -#define MX_29SL800CB 0x6B /* Same as MX29SL802CB */ -#define MX_29SL800CT 0xEA /* Same as MX29SL802CT */ - -/* - * Programmable Micro Corp is listed in JEP106W in bank 2, so it should - * have a 0x7F continuation code prefix. - */ -#define PMC_ID 0x7F9D /* PMC */ -#define PMC_ID_NOPREFIX 0x9D /* PMC, missing 0x7F prefix */ -#define PMC_25LV512 0x7B -#define PMC_25LV010 0x7C -#define PMC_25LV020 0x7D -#define PMC_25LV040 0x7E -#define PMC_25LV080B 0x13 -#define PMC_25LV016B 0x14 -#define PMC_29F002T 0x1D -#define PMC_29F002B 0x2D -#define PMC_39LV512 0x1B -#define PMC_39F010 0x1C /* Same as Pm39LV010 */ -#define PMC_39LV020 0x3D -#define PMC_39LV040 0x3E -#define PMC_39F020 0x4D -#define PMC_39F040 0x4E -#define PMC_49FL002 0x6D -#define PMC_49FL004 0x6E - -/* - * The Sanyo chip found so far uses SPI, first byte is manufacture code, - * second byte is the device code, - * third byte is a dummy byte. - */ -#define SANYO_ID 0x62 -#define SANYO_LE25FW203A 0x1600 - -#define SHARP_ID 0xB0 /* Sharp */ -#define SHARP_LH28F008BJxxPT 0xEC -#define SHARP_LH28F008BJxxPB 0xED -#define SHARP_LH28F800BVxxBTL 0x4B -#define SHARP_LH28F800BVxxBV 0x4D -#define SHARP_LH28F800BVxxTV 0x4C -#define SHARP_LHF00L02 0xC9 /* Same as LHF00L06/LHF00L07 */ -#define SHARP_LHF00L04 0xCF /* Same as LHF00L03/LHF00L05 */ - -/* - * Spansion was previously a joint venture of AMD and Fujitsu. - * S25 chips are SPI. The first device ID byte is memory type and - * the second device ID byte is memory capacity. - */ -#define SPANSION_ID 0x01 /* Spansion, same ID as AMD */ -#define SPANSION_S25FL016A 0x0214 - -/* - * SST25 chips are SPI, first byte of device ID is memory type, second - * byte of device ID is related to log(bitsize) at least for some chips. - */ -#define SST_ID 0xBF /* SST */ -#define SST_25WF512 0x2501 -#define SST_25WF010 0x2502 -#define SST_25WF020 0x2503 -#define SST_25WF040 0x2504 -#define SST_25VF512A_REMS 0x48 /* REMS or RES opcode */ -#define SST_25VF010_REMS 0x49 /* REMS or RES opcode */ -#define SST_25VF020_REMS 0x43 /* REMS or RES opcode */ -#define SST_25VF040_REMS 0x44 /* REMS or RES opcode */ -#define SST_25VF040B 0x258D -#define SST_25VF040B_REMS 0x8D /* REMS or RES opcode */ -#define SST_25VF080_REMS 0x80 /* REMS or RES opcode */ -#define SST_25VF080B 0x258E -#define SST_25VF080B_REMS 0x8E /* REMS or RES opcode */ -#define SST_25VF016B 0x2541 -#define SST_25VF032B 0x254A -#define SST_25VF032B_REMS 0x4A /* REMS or RES opcode */ -#define SST_26VF016 0x2601 -#define SST_26VF032 0x2602 -#define SST_27SF512 0xA4 -#define SST_27SF010 0xA5 -#define SST_27SF020 0xA6 -#define SST_27VF010 0xA9 -#define SST_27VF020 0xAA -#define SST_28SF040 0x04 -#define SST_29EE512 0x5D -#define SST_29EE010 0x07 -#define SST_29LE010 0x08 /* Same as SST29VE010 */ -#define SST_29EE020A 0x10 /* Same as SST29EE020 */ -#define SST_29LE020 0x12 /* Same as SST29VE020 */ -#define SST_29SF020 0x24 -#define SST_29VF020 0x25 -#define SST_29SF040 0x13 -#define SST_29VF040 0x14 -#define SST_39SF010 0xB5 -#define SST_39SF020 0xB6 /* Same as 39SF020A */ -#define SST_39SF040 0xB7 -#define SST_39VF512 0xD4 -#define SST_39VF010 0xD5 -#define SST_39VF020 0xD6 /* Same as 39LF020 */ -#define SST_39VF040 0xD7 /* Same as 39LF040 */ -#define SST_39VF080 0xD8 /* Same as 39LF080/39VF080/39VF088 */ -#define SST_49LF040B 0x50 -#define SST_49LF040 0x51 -#define SST_49LF020 0x61 -#define SST_49LF020A 0x52 -#define SST_49LF030A 0x1C -#define SST_49LF080A 0x5B -#define SST_49LF002A 0x57 -#define SST_49LF003A 0x1B -#define SST_49LF004A 0x60 /* Same as 49LF004B */ -#define SST_49LF008A 0x5A -#define SST_49LF004C 0x54 -#define SST_49LF008C 0x59 -#define SST_49LF016C 0x5C -#define SST_49LF160C 0x4C - -/* - * ST25P chips are SPI, first byte of device ID is memory type, second - * byte of device ID is related to log(bitsize) at least for some chips. - */ -#define ST_ID 0x20 /* ST / SGS/Thomson */ -#define ST_M25P05A 0x2010 -#define ST_M25P05_RES 0x10 /* Same code as M25P10. */ -#define ST_M25P10A 0x2011 -#define ST_M25P10_RES 0x10 /* Same code as M25P05. */ -#define ST_M25P20 0x2012 -#define ST_M25P40 0x2013 -#define ST_M25P40_RES 0x12 -#define ST_M25P80 0x2014 -#define ST_M25P16 0x2015 -#define ST_M25P32 0x2016 -#define ST_M25P64 0x2017 -#define ST_M25P128 0x2018 -#define ST_M25PE10 0x8011 -#define ST_M25PE20 0x8012 -#define ST_M25PE40 0x8013 -#define ST_M25PE80 0x8014 -#define ST_M25PE16 0x8015 -#define ST_M50FLW040A 0x08 -#define ST_M50FLW040B 0x28 -#define ST_M50FLW080A 0x80 -#define ST_M50FLW080B 0x81 -#define ST_M50FW002 0x29 -#define ST_M50FW040 0x2C -#define ST_M50FW080 0x2D -#define ST_M50FW016 0x2E -#define ST_M50LPW116 0x30 -#define ST_M29F002B 0x34 /* Same as M29F002BB */ -#define ST_M29F002T 0xB0 /* Same as M29F002BT/M29F002NT/M29F002BNT */ -#define ST_M29F040B 0xE2 /* Same as M29F040 */ -#define ST_M29F080 0xF1 -#define ST_M29F200BT 0xD3 -#define ST_M29F200BB 0xD4 -#define ST_M29F400BT 0xD5 /* Same as M29F400T */ -#define ST_M29F400BB 0xD6 /* Same as M29F400B */ -#define ST_M29F800DB 0x58 -#define ST_M29F800DT 0xEC -#define ST_M29W010B 0x23 -#define ST_M29W040B 0xE3 - -#define SYNCMOS_ID 0x40 /* SyncMOS and Mosel Vitelic */ -#define S29C51001T 0x01 -#define S29C51002T 0x02 -#define S29C51004T 0x03 -#define S29C31004T 0x63 - -#define TI_ID 0x97 /* Texas Instruments */ -#define TI_OLD_ID 0x01 /* TI chips from last century */ -#define TI_TMS29F002RT 0xB0 -#define TI_TMS29F002RB 0x34 - -/* - * W25X chips are SPI, first byte of device ID is memory type, second - * byte of device ID is related to log(bitsize). - */ -#define WINBOND_ID 0xDA /* Winbond */ -#define WINBOND_NEX_ID 0xEF /* Winbond (ex Nexcom) serial flashes */ -#define W_25X10 0x3011 -#define W_25X20 0x3012 -#define W_25X40 0x3013 -#define W_25X80 0x3014 -#define W_25X16 0x3015 -#define W_25X32 0x3016 -#define W_25X64 0x3017 -#define W_29C011 0xC1 -#define W_29C020C 0x45 /* Same as W29C020 and ASD AE29F2008 */ -#define W_29C040P 0x46 /* Same as W29C040 */ -#define W_29EE011 0xC1 -#define W_39L020 0xB5 -#define W_39L040 0xB6 -#define W_39V040FA 0x34 -#define W_39V040A 0x3D -#define W_39V040B 0x54 -#define W_39V040C 0x50 -#define W_39V080A 0xD0 -#define W_39V080FA 0xD3 -#define W_39V080FA_DM 0x93 -#define W_49F002U 0x0B -#define W_49F020 0x8C -#define W_49V002A 0xB0 -#define W_49V002FA 0x32 - -#endif /* !FLASHCHIPS_H */ diff --git a/flashrom.8 b/flashrom.8 deleted file mode 100644 index 011840c..0000000 --- a/flashrom.8 +++ /dev/null @@ -1,302 +0,0 @@ -.TH FLASHROM 8 "May 21, 2009" -.SH NAME -flashrom \- detect, read, write, verify and erase flash chips -.SH SYNOPSIS -.B flashrom \fR[\fB\-VfLzhRn\fR] [\fB\-E\fR|\fB\-r\fR file|\fB\-w\fR file|\fB\-v\fR file] [\fB\-c\fR chipname] - [\fB\-m\fR [vendor:]part] [\fB\-l\fR file] [\fB\-i\fR image] [\fB\-p\fR programmer] -.SH DESCRIPTION -.B flashrom -is a utility for detecting, reading, writing, verifying and erasing flash -chips. It's often used to flash BIOS/EFI/coreboot/firmware images in-system -using a supported mainboard, but it also supports flashing of network cards -(NICs), SATA controller cards, and other external devices which can program -flash chips. -.PP -It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and -TSOP40 chips, which use various protocols such as LPC, FWH, parallel flash, -or SPI. -.SH OPTIONS -Please note that the command line interface for flashrom will change before -flashrom 1.0. Do not use flashrom in scripts or other automated tools without -checking that your flashrom version won't interpret options in a different way. -.PP -You can specify one of \-E, \-r, \-w, \-v or no operation. -If no operation is specified, then all that happens -is that flash info is dumped and the flash chip is set to writable. -.TP -.B "\-r, \-\-read " -Read flash ROM contents and save them into the given -.BR . -.TP -.B "\-w, \-\-write " -Write file into flash ROM. -.TP -.B "\-n, \-\-noverify" -Do -.B not -verify the flash ROM contents after writing them to the chip. Using this -option is -.B not -recommended, you should only use it if you know what you are doing and you -feel that the time for verification takes too long. -.sp -Typical usage is: -.B "flashrom -wn file" -.sp -This option is only useful in combination with -.BR \-\-write . -.TP -.B "\-v, \-\-verify " -Verify the flash ROM contents against the given -.BR . -.TP -.B "\-E, \-\-erase" -Erase the flash ROM chip. -.TP -.B "\-V, \-\-verbose" -More verbose output. -.TP -.B "\-c, \-\-chip" -Probe only for specified flash ROM chip. -.sp -flashrom supports ROM layouts. This allows you to flash certain parts of -the flash chip only. A ROM layout file looks like follows: -.sp - 00000000:00008fff gfxrom - 00009000:0003ffff normal - 00040000:0007ffff fallback -.sp - i.e.: - startaddr:endaddr name -.sp -All addresses are offsets within the file, not absolute addresses! -If you only want to update the normal image in a ROM you can say: -.sp -.B " flashrom -w --layout rom.layout --image normal agami_aruma.rom" -.sp -To update normal and fallback but leave the VGA BIOS alone, say: -.sp -.B " flashrom -w -l rom.layout -i normal \" -.br -.B " -i fallback agami_aruma.rom" -.sp -Currently overlapping sections are not supported. -.sp -ROM layouts should replace the \-s and \-e option since they are more -flexible and they should lead to a ROM update file format with the -ROM layout and the ROM image in one file (cpio, zip or something?). -.TP -.B "\-m, \-\-mainboard" <[vendor:]part> -Override mainboard settings. -.sp -flashrom reads the coreboot table to determine the current mainboard. If no -coreboot table could be read or if you want to override these values, you can -specify \-m, e.g.: -.sp -.B " flashrom -w --mainboard AGAMI:ARUMA agami_aruma.rom" -.sp -See the 'Supported mainboards' section in the output of 'flashrom \-L' for -a list of boards which require the specification of the board name, if no -coreboot table is found. -.TP -.B "\-f, \-\-force" -Force write without checking whether the ROM image file is really meant -to be used on this board. -.sp -Note: This check only works while coreboot is running, and only for those -boards where the coreboot code supports it. -.TP -.B "\-l, \-\-layout " -Read ROM layout from -.BR . -.TP -.B "\-i, \-\-image " -Only flash image -.B -from flash layout. -.TP -.B "\-L, \-\-list\-supported" -List the flash chips, chipsets, mainboards, and PCI card "programmers" -supported by flashrom. -.sp -There are many unlisted boards which will work out of the box, without -special support in flashrom. Please let us know if you can verify that -other boards work or do not work out of the box. For verification you have -to test an ERASE and/or WRITE operation, so make sure you only do that -if you have proper means to recover from failure! -.TP -.B "\-z, \-\-list\-supported-wiki" -Same as -.BR \-\-list\-supported , -but outputs the supported hardware in MediaWiki syntax, so that it can be -easily pasted into the wiki page at http://www.flashrom.org/. -.TP -.B "\-p, \-\-programmer " -Specify the programmer device. Currently supported are: -.sp -.BR "* internal" " (default, for in-system flashing in the mainboard)" -.sp -.BR "* dummy" " (just prints all operations and accesses)" -.sp -.BR "* nic3com" " (for flash ROMs on 3COM network cards)" -.sp -.BR "* gfxnvidia" " (for flash ROMs on NVIDIA graphics cards)" -.sp -.BR "* drkaiser" " (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)" -.sp -.BR "* satasii" " (for flash ROMs on Silicon Image SATA/IDE controllers)" -.sp -.BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)" -.sp -.BR "* ft2232spi" " (for flash ROMs attached to a FT2232H/FT4232H based USB SPI programmer)" -.sp -.BR "* serprog" " (for flash ROMs attached to Urja's AVR programmer)" -.sp -.BR "* buspiratespi" " (for flash ROMs attached to a Bus Pirate)" -.sp -The dummy programmer has an optional parameter specifying the bus types it -should support. For that you have to use the -.B "flashrom -p dummy:type" -syntax where -.B type -can be any comma-separated combination of -.B parallel lpc fwh spi all -in any order. -.sp -Example: -.B "flashrom -p dummy:lpc,fwh" -.sp -If you have multiple supported PCI cards which can program flash chips -(NICs, SATA/IDE controllers, etc.) in your system, you must use the -.B "flashrom -p xxxx:bb:dd.f" -syntax to explicitly select one of them, where -.B xxxx -is the name of the programmer -.B bb -is the PCI bus number, -.B dd -is the PCI device number, and -.B f -is the PCI function number of the desired NIC. -.sp -Example: -.B "flashrom -p nic3com:05:04.0" -.sp -Currently the following programmers support this mechanism: -.BR nic3com , -.BR gfxnvidia , -.BR satasii . -.sp -The it87spi programmer has an optional parameter which will set the I/O base -port of the IT87* SPI controller interface to the port specified in the -parameter. For that you have to use the -.B "flashrom -p it87spi:port=portnum" -syntax where -.B portnum -is an I/O port number which must be a multiple of 8. -.sp -The ft2232spi programmer has an optional parameter specifying the controller -type and interface/port it should support. For that you have to use the -.B "flashrom -p ft2232spi:model,port=interface" -syntax where -.B model -can be any of -.B 2232H 4232H -and -.B interface -can be any of -.B A -.BR B . -The default model is -.B 4232H -and the default interface is -.BR B . -.sp -The serprog programmer has an optional parameter specifying either a serial -device/baud combination or an IP/port combination for communication with the -programmer. For serial, you have to use the -.B "flashrom -p serprog:/dev/device:baud" -syntax and for IP, you have to use -.B "flashrom -p serprog:ip:port" -instead. More information about serprog is available in serprog-protocol.txt in -the source distribution. -.sp -The buspiratespi programmer has a required dev parameter specifying the Bus -Pirate device node and an optional spispeed parameter specifying the frequency -of the SPI bus. The parameter delimiter is a comma. Syntax is -.B "flashrom -p buspiratespi:dev=/dev/device,spispeed=frequency" -where -.B frequency -can be any of -.B 30k 125k 250k 1M 2M 2.6M 4M 8M -(in Hz). -.sp -Support for some programmers can be disabled at compile time. -.B "flashrom -h" -lists all supported programmers. -.TP -.B "\-h, \-\-help" -Show a help text and exit. -.TP -.B "\-R, \-\-version" -Show version information and exit. -.SH EXIT STATUS -flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem -(/dev/xsvc on Solaris) can not be opened and with 3 if a call to mmap() fails. -.SH BUGS -Please report any bugs at -.BR http://www.flashrom.org/trac/flashrom/newticket "," -or on the flashrom mailing list -.RB "(" http://www.flashrom.org/mailman/listinfo/flashrom ")." -.SH LICENCE -.B flashrom -is covered by the GNU General Public License (GPL), version 2. Some files are -additionally available under the GPL (version 2, or any later version). -.SH COPYRIGHT -.br -Please see the individual files. -.SH AUTHORS -Carl-Daniel Hailfinger -.br -Claus Gindhart -.br -Dominik Geyer -.br -Eric Biederman -.br -Giampiero Giancipoli -.br -Joe Bao -.br -Luc Verhaegen -.br -Li-Ta Lo -.br -Markus Boas -.br -Nikolay Petukhov -.br -Peter Stuge -.br -Reinder E.N. de Haan -.br -Ronald G. Minnich -.br -Ronald Hoogenboom -.br -Stefan Reinauer -.br -Stefan Wildemann -.br -Steven James -.br -Uwe Hermann -.br -Wang Qingpei -.br -Yinghai Lu -.br -some others -.PP -This manual page was written by Uwe Hermann . -It is licensed under the terms of the GNU GPL (version 2 or later). diff --git a/flashrom.c b/flashrom.c deleted file mode 100644 index 64a6835..0000000 --- a/flashrom.c +++ /dev/null @@ -1,1369 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2004 Tyan Corp - * Copyright (C) 2005-2008 coresystems GmbH - * Copyright (C) 2008,2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include "flash.h" -#include "flashchips.h" - -const char *flashrom_version = FLASHROM_VERSION; -char *chip_to_probe = NULL; -int verbose = 0; -enum programmer programmer = PROGRAMMER_INTERNAL; -char *programmer_param = NULL; - -const struct programmer_entry programmer_table[] = { - { - .name = "internal", - .init = internal_init, - .shutdown = internal_shutdown, - .map_flash_region = physmap, - .unmap_flash_region = physunmap, - .chip_readb = internal_chip_readb, - .chip_readw = internal_chip_readw, - .chip_readl = internal_chip_readl, - .chip_readn = internal_chip_readn, - .chip_writeb = internal_chip_writeb, - .chip_writew = internal_chip_writew, - .chip_writel = internal_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, - -#if DUMMY_SUPPORT == 1 - { - .name = "dummy", - .init = dummy_init, - .shutdown = dummy_shutdown, - .map_flash_region = dummy_map, - .unmap_flash_region = dummy_unmap, - .chip_readb = dummy_chip_readb, - .chip_readw = dummy_chip_readw, - .chip_readl = dummy_chip_readl, - .chip_readn = dummy_chip_readn, - .chip_writeb = dummy_chip_writeb, - .chip_writew = dummy_chip_writew, - .chip_writel = dummy_chip_writel, - .chip_writen = dummy_chip_writen, - .delay = internal_delay, - }, -#endif - -#if NIC3COM_SUPPORT == 1 - { - .name = "nic3com", - .init = nic3com_init, - .shutdown = nic3com_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = nic3com_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = nic3com_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -#endif - -#if GFXNVIDIA_SUPPORT == 1 - { - .name = "gfxnvidia", - .init = gfxnvidia_init, - .shutdown = gfxnvidia_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = gfxnvidia_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = gfxnvidia_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -#endif - -#if DRKAISER_SUPPORT == 1 - { - .name = "drkaiser", - .init = drkaiser_init, - .shutdown = drkaiser_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = drkaiser_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = drkaiser_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -#endif - -#if SATASII_SUPPORT == 1 - { - .name = "satasii", - .init = satasii_init, - .shutdown = satasii_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = satasii_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = satasii_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -#endif - - { - .name = "it87spi", - .init = it87spi_init, - .shutdown = noop_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = noop_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = noop_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, - -#if FT2232_SPI_SUPPORT == 1 - { - .name = "ft2232spi", - .init = ft2232_spi_init, - .shutdown = noop_shutdown, /* Missing shutdown */ - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = noop_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = noop_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -#endif - -#if SERPROG_SUPPORT == 1 - { - .name = "serprog", - .init = serprog_init, - .shutdown = serprog_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = serprog_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = serprog_chip_readn, - .chip_writeb = serprog_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = serprog_delay, - }, -#endif - -#if BUSPIRATE_SPI_SUPPORT == 1 - { - .name = "buspiratespi", - .init = buspirate_spi_init, - .shutdown = buspirate_spi_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .chip_readb = noop_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = noop_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -#endif - - {}, /* This entry corresponds to PROGRAMMER_INVALID. */ -}; - -int programmer_init(void) -{ - return programmer_table[programmer].init(); -} - -int programmer_shutdown(void) -{ - return programmer_table[programmer].shutdown(); -} - -void *programmer_map_flash_region(const char *descr, unsigned long phys_addr, - size_t len) -{ - return programmer_table[programmer].map_flash_region(descr, - phys_addr, len); -} - -void programmer_unmap_flash_region(void *virt_addr, size_t len) -{ - programmer_table[programmer].unmap_flash_region(virt_addr, len); -} - -void chip_writeb(uint8_t val, chipaddr addr) -{ - programmer_table[programmer].chip_writeb(val, addr); -} - -void chip_writew(uint16_t val, chipaddr addr) -{ - programmer_table[programmer].chip_writew(val, addr); -} - -void chip_writel(uint32_t val, chipaddr addr) -{ - programmer_table[programmer].chip_writel(val, addr); -} - -void chip_writen(uint8_t *buf, chipaddr addr, size_t len) -{ - programmer_table[programmer].chip_writen(buf, addr, len); -} - -uint8_t chip_readb(const chipaddr addr) -{ - return programmer_table[programmer].chip_readb(addr); -} - -uint16_t chip_readw(const chipaddr addr) -{ - return programmer_table[programmer].chip_readw(addr); -} - -uint32_t chip_readl(const chipaddr addr) -{ - return programmer_table[programmer].chip_readl(addr); -} - -void chip_readn(uint8_t *buf, chipaddr addr, size_t len) -{ - programmer_table[programmer].chip_readn(buf, addr, len); -} - -void programmer_delay(int usecs) -{ - programmer_table[programmer].delay(usecs); -} - -void map_flash_registers(struct flashchip *flash) -{ - size_t size = flash->total_size * 1024; - /* Flash registers live 4 MByte below the flash. */ - /* FIXME: This is incorrect for nonstandard flashbase. */ - flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size); -} - -int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - chip_readn(buf, flash->virtual_memory + start, len); - - return 0; -} - -int min(int a, int b) -{ - return (a < b) ? a : b; -} - -int max(int a, int b) -{ - return (a > b) ? a : b; -} - -int bitcount(unsigned long a) -{ - int i = 0; - for (; a != 0; a >>= 1) - if (a & 1) - i++; - return i; -} - -char *strcat_realloc(char *dest, const char *src) -{ - dest = realloc(dest, strlen(dest) + strlen(src) + 1); - if (!dest) - return NULL; - strcat(dest, src); - return dest; -} - -/* This is a somewhat hacked function similar in some ways to strtok(). - * It will look for needle in haystack, return a copy of needle and remove - * everything from the first occurrence of needle to the next delimiter - * from haystack. - */ -char *extract_param(char **haystack, char *needle, char *delim) -{ - char *param_pos, *rest, *tmp; - char *dev = NULL; - int devlen; - - param_pos = strstr(*haystack, needle); - do { - if (!param_pos) - return NULL; - /* Beginning of the string? */ - if (param_pos == *haystack) - break; - /* After a delimiter? */ - if (strchr(delim, *(param_pos - 1))) - break; - /* Continue searching. */ - param_pos++; - param_pos = strstr(param_pos, needle); - } while (1); - - if (param_pos) { - param_pos += strlen(needle); - devlen = strcspn(param_pos, delim); - if (devlen) { - dev = malloc(devlen + 1); - if (!dev) { - fprintf(stderr, "Out of memory!\n"); - exit(1); - } - strncpy(dev, param_pos, devlen); - dev[devlen] = '\0'; - } - rest = param_pos + devlen; - rest += strspn(rest, delim); - param_pos -= strlen(needle); - memmove(param_pos, rest, strlen(rest) + 1); - tmp = realloc(*haystack, strlen(*haystack) + 1); - if (!tmp) { - fprintf(stderr, "Out of memory!\n"); - exit(1); - } - *haystack = tmp; - } - - - return dev; -} - -/* start is an offset to the base address of the flash chip */ -int check_erased_range(struct flashchip *flash, int start, int len) -{ - int ret; - uint8_t *cmpbuf = malloc(len); - - if (!cmpbuf) { - fprintf(stderr, "Could not allocate memory!\n"); - exit(1); - } - memset(cmpbuf, 0xff, len); - ret = verify_range(flash, cmpbuf, start, len, "ERASE"); - free(cmpbuf); - return ret; -} - -/** - * @cmpbuf buffer to compare against, cmpbuf[0] is expected to match the - flash content at location start - * @start offset to the base address of the flash chip - * @len length of the verified area - * @message string to print in the "FAILED" message - * @return 0 for success, -1 for failure - */ -int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message) -{ - int i, j, starthere, lenhere, ret = 0; - int page_size = flash->page_size; - uint8_t *readbuf = malloc(page_size); - int failcount = 0; - - if (!len) - goto out_free; - - if (!flash->read) { - fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n"); - return 1; - } - if (!readbuf) { - fprintf(stderr, "Could not allocate memory!\n"); - exit(1); - } - - if (start + len > flash->total_size * 1024) { - fprintf(stderr, "Error: %s called with start 0x%x + len 0x%x >" - " total_size 0x%x\n", __func__, start, len, - flash->total_size * 1024); - ret = -1; - goto out_free; - } - if (!message) - message = "VERIFY"; - - /* Warning: This loop has a very unusual condition and body. - * The loop needs to go through each page with at least one affected - * byte. The lowest page number is (start / page_size) since that - * division rounds down. The highest page number we want is the page - * where the last byte of the range lives. That last byte has the - * address (start + len - 1), thus the highest page number is - * (start + len - 1) / page_size. Since we want to include that last - * page as well, the loop condition uses <=. - */ - for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { - /* Byte position of the first byte in the range in this page. */ - starthere = max(start, i * page_size); - /* Length of bytes in the range in this page. */ - lenhere = min(start + len, (i + 1) * page_size) - starthere; - flash->read(flash, readbuf, starthere, lenhere); - for (j = 0; j < lenhere; j++) { - if (cmpbuf[starthere - start + j] != readbuf[j]) { - /* Only print the first failure. */ - if (!failcount++) - fprintf(stderr, "%s FAILED at 0x%08x! " - "Expected=0x%02x, Read=0x%02x,", - message, starthere + j, - cmpbuf[starthere - start + j], - readbuf[j]); - } - } - } - if (failcount) { - fprintf(stderr, " failed byte count from 0x%08x-0x%08x: 0x%x\n", - start, start + len - 1, failcount); - ret = -1; - } - -out_free: - free(readbuf); - return ret; -} - -/* This function generates various test patterns useful for testing controller - * and chip communication as well as chip behaviour. - * - * If a byte can be written multiple times, each time keeping 0-bits at 0 - * and changing 1-bits to 0 if the new value for that bit is 0, the effect - * is essentially an AND operation. That's also the reason why this function - * provides the result of AND between various patterns. - * - * Below is a list of patterns (and their block length). - * Pattern 0 is 05 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 (16 Bytes) - * Pattern 1 is 0a 1a 2a 3a 4a 5a 6a 7a 8a 9a aa ba ca da ea fa (16 Bytes) - * Pattern 2 is 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f (16 Bytes) - * Pattern 3 is a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af (16 Bytes) - * Pattern 4 is 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 (16 Bytes) - * Pattern 5 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f (16 Bytes) - * Pattern 6 is 00 (1 Byte) - * Pattern 7 is ff (1 Byte) - * Patterns 0-7 have a big-endian block number in the last 2 bytes of each 256 - * byte block. - * - * Pattern 8 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11... (256 B) - * Pattern 9 is ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ef ee... (256 B) - * Pattern 10 is 00 00 00 01 00 02 00 03 00 04... (128 kB big-endian counter) - * Pattern 11 is ff ff ff fe ff fd ff fc ff fb... (128 kB big-endian downwards) - * Pattern 12 is 00 (1 Byte) - * Pattern 13 is ff (1 Byte) - * Patterns 8-13 have no block number. - * - * Patterns 0-3 are created to detect and efficiently diagnose communication - * slips like missed bits or bytes and their repetitive nature gives good visual - * cues to the person inspecting the results. In addition, the following holds: - * AND Pattern 0/1 == Pattern 4 - * AND Pattern 2/3 == Pattern 5 - * AND Pattern 0/1/2/3 == AND Pattern 4/5 == Pattern 6 - * A weakness of pattern 0-5 is the inability to detect swaps/copies between - * any two 16-byte blocks except for the last 16-byte block in a 256-byte bloc. - * They work perfectly for detecting any swaps/aliasing of blocks >= 256 bytes. - * 0x5 and 0xa were picked because they are 0101 and 1010 binary. - * Patterns 8-9 are best for detecting swaps/aliasing of blocks < 256 bytes. - * Besides that, they provide for bit testing of the last two bytes of every - * 256 byte block which contains the block number for patterns 0-6. - * Patterns 10-11 are special purpose for detecting subblock aliasing with - * block sizes >256 bytes (some Dataflash chips etc.) - * AND Pattern 8/9 == Pattern 12 - * AND Pattern 10/11 == Pattern 12 - * Pattern 13 is the completely erased state. - * None of the patterns can detect aliasing at boundaries which are a multiple - * of 16 MBytes (but such chips do not exist anyway for Parallel/LPC/FWH/SPI). - */ -int generate_testpattern(uint8_t *buf, uint32_t size, int variant) -{ - int i; - - if (!buf) { - fprintf(stderr, "Invalid buffer!\n"); - return 1; - } - - switch (variant) { - case 0: - for (i = 0; i < size; i++) - buf[i] = (i & 0xf) << 4 | 0x5; - break; - case 1: - for (i = 0; i < size; i++) - buf[i] = (i & 0xf) << 4 | 0xa; - break; - case 2: - for (i = 0; i < size; i++) - buf[i] = 0x50 | (i & 0xf); - break; - case 3: - for (i = 0; i < size; i++) - buf[i] = 0xa0 | (i & 0xf); - break; - case 4: - for (i = 0; i < size; i++) - buf[i] = (i & 0xf) << 4; - break; - case 5: - for (i = 0; i < size; i++) - buf[i] = i & 0xf; - break; - case 6: - memset(buf, 0x00, size); - break; - case 7: - memset(buf, 0xff, size); - break; - case 8: - for (i = 0; i < size; i++) - buf[i] = i & 0xff; - break; - case 9: - for (i = 0; i < size; i++) - buf[i] = ~(i & 0xff); - break; - case 10: - for (i = 0; i < size % 2; i++) { - buf[i * 2] = (i >> 8) & 0xff; - buf[i * 2 + 1] = i & 0xff; - } - if (size & 0x1) - buf[i * 2] = (i >> 8) & 0xff; - break; - case 11: - for (i = 0; i < size % 2; i++) { - buf[i * 2] = ~((i >> 8) & 0xff); - buf[i * 2 + 1] = ~(i & 0xff); - } - if (size & 0x1) - buf[i * 2] = ~((i >> 8) & 0xff); - break; - case 12: - memset(buf, 0x00, size); - break; - case 13: - memset(buf, 0xff, size); - break; - } - - if ((variant >= 0) && (variant <= 7)) { - /* Write block number in the last two bytes of each 256-byte - * block, big endian for easier reading of the hexdump. - * Note that this wraps around for chips larger than 2^24 bytes - * (16 MB). - */ - for (i = 0; i < size / 256; i++) { - buf[i * 256 + 254] = (i >> 8) & 0xff; - buf[i * 256 + 255] = i & 0xff; - } - } - - return 0; -} - -int check_max_decode(enum chipbustype buses, uint32_t size) -{ - int limitexceeded = 0; - if ((buses & CHIP_BUSTYPE_PARALLEL) && - (max_rom_decode.parallel < size)) { - limitexceeded++; - printf_debug("Chip size %u kB is bigger than supported " - "size %u kB of chipset/board/programmer " - "for %s interface, " - "probe/read/erase/write may fail. ", size / 1024, - max_rom_decode.parallel / 1024, "Parallel"); - } - if ((buses & CHIP_BUSTYPE_LPC) && (max_rom_decode.lpc < size)) { - limitexceeded++; - printf_debug("Chip size %u kB is bigger than supported " - "size %u kB of chipset/board/programmer " - "for %s interface, " - "probe/read/erase/write may fail. ", size / 1024, - max_rom_decode.lpc / 1024, "LPC"); - } - if ((buses & CHIP_BUSTYPE_FWH) && (max_rom_decode.fwh < size)) { - limitexceeded++; - printf_debug("Chip size %u kB is bigger than supported " - "size %u kB of chipset/board/programmer " - "for %s interface, " - "probe/read/erase/write may fail. ", size / 1024, - max_rom_decode.fwh / 1024, "FWH"); - } - if ((buses & CHIP_BUSTYPE_SPI) && (max_rom_decode.spi < size)) { - limitexceeded++; - printf_debug("Chip size %u kB is bigger than supported " - "size %u kB of chipset/board/programmer " - "for %s interface, " - "probe/read/erase/write may fail. ", size / 1024, - max_rom_decode.spi / 1024, "SPI"); - } - if (!limitexceeded) - return 0; - /* Sometimes chip and programmer have more than one bus in common, - * and the limit is not exceeded on all buses. Tell the user. - */ - if (bitcount(buses) > limitexceeded) - printf_debug("There is at least one common chip/programmer " - "interface which can support a chip of this size. " - "You can try --force at your own risk.\n"); - return 1; -} - -struct flashchip *probe_flash(struct flashchip *first_flash, int force) -{ - struct flashchip *flash; - unsigned long base = 0; - uint32_t size; - enum chipbustype buses_common; - char *tmp; - - for (flash = first_flash; flash && flash->name; flash++) { - if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0) - continue; - printf_debug("Probing for %s %s, %d KB: ", - flash->vendor, flash->name, flash->total_size); - if (!flash->probe && !force) { - printf_debug("failed! flashrom has no probe function for this flash chip.\n"); - continue; - } - buses_common = buses_supported & flash->bustype; - if (!buses_common) { - tmp = flashbuses_to_text(buses_supported); - printf_debug("skipped. Host bus type %s ", tmp); - free(tmp); - tmp = flashbuses_to_text(flash->bustype); - printf_debug("and chip bus type %s are incompatible.\n", tmp); - free(tmp); - continue; - } - - size = flash->total_size * 1024; - check_max_decode(buses_common, size); - - base = flashbase ? flashbase : (0xffffffff - size + 1); - flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size); - - if (force) - break; - - if (flash->probe(flash) != 1) - goto notfound; - - if (first_flash == flashchips - || flash->model_id != GENERIC_DEVICE_ID) - break; - -notfound: - programmer_unmap_flash_region((void *)flash->virtual_memory, size); - } - - if (!flash || !flash->name) - return NULL; - - printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n", - flash->vendor, flash->name, flash->total_size, - flashbuses_to_text(flash->bustype), base); - - return flash; -} - -int verify_flash(struct flashchip *flash, uint8_t *buf) -{ - int ret; - int total_size = flash->total_size * 1024; - - printf("Verifying flash... "); - - ret = verify_range(flash, buf, 0, total_size, NULL); - - if (!ret) - printf("VERIFIED. \n"); - - return ret; -} - -int read_flash(struct flashchip *flash, char *filename) -{ - unsigned long numbytes; - FILE *image; - unsigned long size = flash->total_size * 1024; - unsigned char *buf = calloc(size, sizeof(char)); - - if (!filename) { - printf("Error: No filename specified.\n"); - return 1; - } - if ((image = fopen(filename, "w")) == NULL) { - perror(filename); - exit(1); - } - printf("Reading flash... "); - if (!flash->read) { - printf("FAILED!\n"); - fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n"); - return 1; - } else - flash->read(flash, buf, 0, size); - - numbytes = fwrite(buf, 1, size, image); - fclose(image); - free(buf); - printf("%s.\n", numbytes == size ? "done" : "FAILED"); - if (numbytes != size) - return 1; - return 0; -} - -int erase_flash(struct flashchip *flash) -{ - int i, j, k, ret = 0, found = 0; - - printf("Erasing flash chip... "); - for (k = 0; k < NUM_ERASEFUNCTIONS; k++) { - unsigned long done = 0; - struct block_eraser eraser = flash->block_erasers[k]; - - printf_debug("Looking at blockwise erase function %i... ", k); - if (!eraser.block_erase && !eraser.eraseblocks[0].count) { - printf_debug("not defined. " - "Looking for another erase function.\n"); - continue; - } - if (!eraser.block_erase && eraser.eraseblocks[0].count) { - printf_debug("eraseblock layout is known, but no " - "matching block erase function found. " - "Looking for another erase function.\n"); - continue; - } - if (eraser.block_erase && !eraser.eraseblocks[0].count) { - printf_debug("block erase function found, but " - "eraseblock layout is unknown. " - "Looking for another erase function.\n"); - continue; - } - found = 1; - printf_debug("trying... "); - for (i = 0; i < NUM_ERASEREGIONS; i++) { - /* count==0 for all automatically initialized array - * members so the loop below won't be executed for them. - */ - for (j = 0; j < eraser.eraseblocks[i].count; j++) { - ret = eraser.block_erase(flash, done + eraser.eraseblocks[i].size * j, eraser.eraseblocks[i].size); - if (ret) - break; - } - if (ret) - break; - } - /* If everything is OK, don't try another erase function. */ - if (!ret) - break; - } - /* If no block erase function was found or block erase failed, retry. */ - if ((!found || ret) && (flash->erase)) { - found = 1; - printf_debug("Trying whole-chip erase function... "); - ret = flash->erase(flash); - } - if (!found) { - fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n"); - return 1; - } - - if (ret) { - fprintf(stderr, "FAILED!\n"); - } else { - printf("SUCCESS.\n"); - } - return ret; -} - -void emergency_help_message(void) -{ - fprintf(stderr, "Your flash chip is in an unknown state.\n" - "Get help on IRC at irc.freenode.net (channel #flashrom) or\n" - "mail flashrom@flashrom.org!\n--------------------" - "-----------------------------------------------------------\n" - "DO NOT REBOOT OR POWEROFF!\n"); -} - -void usage(const char *name) -{ - const char *pname; - int pnamelen; - int remaining = 0; - enum programmer p; - - printf("usage: %s [-VfLzhR] [-E|-r file|-w file|-v file] [-c chipname]\n" - " [-m [vendor:]part] [-l file] [-i image] [-p programmer]\n\n", name); - - printf("Please note that the command line interface for flashrom will " - "change before\nflashrom 1.0. Do not use flashrom in scripts " - "or other automated tools without\nchecking that your flashrom" - " version won't interpret options in a different way.\n\n"); - - printf - (" -r | --read: read flash and save into file\n" - " -w | --write: write file into flash\n" - " -v | --verify: verify flash against file\n" - " -n | --noverify: don't verify flash against file\n" - " -E | --erase: erase flash device\n" - " -V | --verbose: more verbose output\n" - " -c | --chip : probe only for specified flash chip\n" - " -m | --mainboard <[vendor:]part>: override mainboard settings\n" - " -f | --force: force write without checking image\n" - " -l | --layout : read ROM layout from file\n" - " -i | --image : only flash image name from flash layout\n" - " -L | --list-supported: print supported devices\n" -#if PRINT_WIKI_SUPPORT == 1 - " -z | --list-supported-wiki: print supported devices in wiki syntax\n" -#endif - " -p | --programmer : specify the programmer device"); - - for (p = 0; p < PROGRAMMER_INVALID; p++) { - pname = programmer_table[p].name; - pnamelen = strlen(pname); - if (remaining - pnamelen - 2 < 0) { - printf("\n "); - remaining = 43; - } else { - printf(" "); - remaining--; - } - if (p == 0) { - printf("("); - remaining--; - } - printf("%s", pname); - remaining -= pnamelen; - if (p < PROGRAMMER_INVALID - 1) { - printf(","); - remaining--; - } else { - printf(")\n"); - } - } - - printf( - " -h | --help: print this help text\n" - " -R | --version: print the version (release)\n" - "\nYou can specify one of -E, -r, -w, -v or no operation. If no operation is\n" - "specified, then all that happens is that flash info is dumped.\n\n"); - exit(1); -} - -void print_version(void) -{ - printf("flashrom v%s\n", flashrom_version); -} - -int main(int argc, char *argv[]) -{ - uint8_t *buf; - unsigned long size, numbytes; - FILE *image; - /* Probe for up to three flash chips. */ - struct flashchip *flash, *flashes[3]; - const char *name; - int namelen; - int opt; - int option_index = 0; - int force = 0; - int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; - int dont_verify_it = 0, list_supported = 0; -#if PRINT_WIKI_SUPPORT == 1 - int list_supported_wiki = 0; -#endif - int operation_specified = 0; - int ret = 0, i; - -#if PRINT_WIKI_SUPPORT == 1 - const char *optstring = "rRwvnVEfc:m:l:i:p:Lzh"; -#else - const char *optstring = "rRwvnVEfc:m:l:i:p:Lh"; -#endif - static struct option long_options[] = { - {"read", 0, 0, 'r'}, - {"write", 0, 0, 'w'}, - {"erase", 0, 0, 'E'}, - {"verify", 0, 0, 'v'}, - {"noverify", 0, 0, 'n'}, - {"chip", 1, 0, 'c'}, - {"mainboard", 1, 0, 'm'}, - {"verbose", 0, 0, 'V'}, - {"force", 0, 0, 'f'}, - {"layout", 1, 0, 'l'}, - {"image", 1, 0, 'i'}, - {"list-supported", 0, 0, 'L'}, -#if PRINT_WIKI_SUPPORT == 1 - {"list-supported-wiki", 0, 0, 'z'}, -#endif - {"programmer", 1, 0, 'p'}, - {"help", 0, 0, 'h'}, - {"version", 0, 0, 'R'}, - {0, 0, 0, 0} - }; - - char *filename = NULL; - - char *tempstr = NULL, *tempstr2 = NULL; - - print_version(); - - if (argc > 1) { - /* Yes, print them. */ - int i; - printf_debug("The arguments are:\n"); - for (i = 1; i < argc; ++i) - printf_debug("%s\n", argv[i]); - } - - /* Safety check. */ - if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) { - fprintf(stderr, "Programmer table miscompilation!\n"); - exit(1); - } - if (spi_programmer_count - 1 != SPI_CONTROLLER_INVALID) { - fprintf(stderr, "SPI programmer table miscompilation!\n"); - exit(1); - } -#if BITBANG_SPI_SUPPORT == 1 - if (bitbang_spi_master_count - 1 != BITBANG_SPI_INVALID) { - fprintf(stderr, "Bitbanging SPI master table miscompilation!\n"); - exit(1); - } -#endif - - setbuf(stdout, NULL); - while ((opt = getopt_long(argc, argv, optstring, - long_options, &option_index)) != EOF) { - switch (opt) { - case 'r': - if (++operation_specified > 1) { - fprintf(stderr, "More than one operation " - "specified. Aborting.\n"); - exit(1); - } - read_it = 1; - break; - case 'w': - if (++operation_specified > 1) { - fprintf(stderr, "More than one operation " - "specified. Aborting.\n"); - exit(1); - } - write_it = 1; - break; - case 'v': - //FIXME: gracefully handle superfluous -v - if (++operation_specified > 1) { - fprintf(stderr, "More than one operation " - "specified. Aborting.\n"); - exit(1); - } - if (dont_verify_it) { - fprintf(stderr, "--verify and --noverify are" - "mutually exclusive. Aborting.\n"); - exit(1); - } - verify_it = 1; - break; - case 'n': - if (verify_it) { - fprintf(stderr, "--verify and --noverify are" - "mutually exclusive. Aborting.\n"); - exit(1); - } - dont_verify_it = 1; - break; - case 'c': - chip_to_probe = strdup(optarg); - break; - case 'V': - verbose = 1; - break; - case 'E': - if (++operation_specified > 1) { - fprintf(stderr, "More than one operation " - "specified. Aborting.\n"); - exit(1); - } - erase_it = 1; - break; - case 'm': - tempstr = strdup(optarg); - strtok(tempstr, ":"); - tempstr2 = strtok(NULL, ":"); - if (tempstr2) { - lb_vendor = tempstr; - lb_part = tempstr2; - } else { - lb_vendor = NULL; - lb_part = tempstr; - } - break; - case 'f': - force = 1; - break; - case 'l': - tempstr = strdup(optarg); - if (read_romlayout(tempstr)) - exit(1); - break; - case 'i': - tempstr = strdup(optarg); - find_romentry(tempstr); - break; - case 'L': - list_supported = 1; - break; -#if PRINT_WIKI_SUPPORT == 1 - case 'z': - list_supported_wiki = 1; - break; -#endif - case 'p': - for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) { - name = programmer_table[programmer].name; - namelen = strlen(name); - if (strncmp(optarg, name, namelen) == 0) { - switch (optarg[namelen]) { - case ':': - programmer_param = strdup(optarg + namelen + 1); - break; - case '\0': - break; - default: - /* The continue refers to the - * for loop. It is here to be - * able to differentiate between - * foo and foobar. - */ - continue; - } - break; - } - } - if (programmer == PROGRAMMER_INVALID) { - printf("Error: Unknown programmer %s.\n", optarg); - exit(1); - } - break; - case 'R': - /* print_version() is always called during startup. */ - exit(0); - break; - case 'h': - default: - usage(argv[0]); - break; - } - } - - if (list_supported) { - print_supported(); - exit(0); - } - -#if PRINT_WIKI_SUPPORT == 1 - if (list_supported_wiki) { - print_supported_wiki(); - exit(0); - } -#endif - - if (read_it && write_it) { - printf("Error: -r and -w are mutually exclusive.\n"); - usage(argv[0]); - } - - if (optind < argc) - filename = argv[optind++]; - - if (optind < argc) { - printf("Error: Extra parameter found.\n"); - usage(argv[0]); - } - - if (programmer_init()) { - fprintf(stderr, "Error: Programmer initialization failed.\n"); - exit(1); - } - - myusec_calibrate_delay(); - - for (i = 0; i < ARRAY_SIZE(flashes); i++) { - flashes[i] = - probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0); - if (!flashes[i]) - for (i++; i < ARRAY_SIZE(flashes); i++) - flashes[i] = NULL; - } - - if (flashes[1]) { - printf("Multiple flash chips were detected:"); - for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++) - printf(" %s", flashes[i]->name); - printf("\nPlease specify which chip to use with the -c option.\n"); - programmer_shutdown(); - exit(1); - } else if (!flashes[0]) { - printf("No EEPROM/flash device found.\n"); - if (!force || !chip_to_probe) { - printf("If you know which flash chip you have, and if this version of flashrom\n"); - printf("supports a similar flash chip, you can try to force read your chip. Run:\n"); - printf("flashrom -f -r -c similar_supported_flash_chip filename\n"); - printf("\n"); - printf("Note: flashrom can never write when the flash chip isn't found automatically.\n"); - } - if (force && read_it && chip_to_probe) { - printf("Force read (-f -r -c) requested, forcing chip probe success:\n"); - flashes[0] = probe_flash(flashchips, 1); - if (!flashes[0]) { - printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe); - printf("Run flashrom -L to view the hardware supported in this flashrom version.\n"); - exit(1); - } - printf("Please note that forced reads most likely contain garbage.\n"); - return read_flash(flashes[0], filename); - } - // FIXME: flash writes stay enabled! - programmer_shutdown(); - exit(1); - } - - flash = flashes[0]; - - if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) { - printf("===\n"); - if (flash->tested & TEST_BAD_MASK) { - printf("This flash part has status NOT WORKING for operations:"); - if (flash->tested & TEST_BAD_PROBE) - printf(" PROBE"); - if (flash->tested & TEST_BAD_READ) - printf(" READ"); - if (flash->tested & TEST_BAD_ERASE) - printf(" ERASE"); - if (flash->tested & TEST_BAD_WRITE) - printf(" WRITE"); - printf("\n"); - } - if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) || - (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) || - (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) || - (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) { - printf("This flash part has status UNTESTED for operations:"); - if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) - printf(" PROBE"); - if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) - printf(" READ"); - if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) - printf(" ERASE"); - if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE)) - printf(" WRITE"); - printf("\n"); - } - printf("Please email a report to flashrom@flashrom.org if any " - "of the above operations\nwork correctly for you with " - "this flash part. Please include the flashrom\noutput " - "with the additional -V option for all operations you " - "tested (-V, -rV,\n-wV, -EV), and mention which " - "mainboard you tested. Thanks for your help!\n===\n"); - } - - size = flash->total_size * 1024; - if (check_max_decode((buses_supported & flash->bustype), size) && - (!force)) { - fprintf(stderr, "Chip is too big for this programmer " - "(-V gives details). Use --force to override.\n"); - programmer_shutdown(); - return 1; - } - - if (!(read_it | write_it | verify_it | erase_it)) { - printf("No operations were specified.\n"); - // FIXME: flash writes stay enabled! - programmer_shutdown(); - exit(1); - } - - if (!filename && !erase_it) { - printf("Error: No filename specified.\n"); - // FIXME: flash writes stay enabled! - programmer_shutdown(); - exit(1); - } - - /* Always verify write operations unless -n is used. */ - if (write_it && !dont_verify_it) - verify_it = 1; - - buf = (uint8_t *) calloc(size, sizeof(char)); - - if (erase_it) { - if (flash->tested & TEST_BAD_ERASE) { - fprintf(stderr, "Erase is not working on this chip. "); - if (!force) { - fprintf(stderr, "Aborting.\n"); - programmer_shutdown(); - return 1; - } else { - fprintf(stderr, "Continuing anyway.\n"); - } - } - if (erase_flash(flash)) { - emergency_help_message(); - programmer_shutdown(); - return 1; - } - } else if (read_it) { - if (read_flash(flash, filename)) { - programmer_shutdown(); - return 1; - } - } else { - struct stat image_stat; - - if (flash->tested & TEST_BAD_ERASE) { - fprintf(stderr, "Erase is not working on this chip " - "and erase is needed for write. "); - if (!force) { - fprintf(stderr, "Aborting.\n"); - programmer_shutdown(); - return 1; - } else { - fprintf(stderr, "Continuing anyway.\n"); - } - } - if (flash->tested & TEST_BAD_WRITE) { - fprintf(stderr, "Write is not working on this chip. "); - if (!force) { - fprintf(stderr, "Aborting.\n"); - programmer_shutdown(); - return 1; - } else { - fprintf(stderr, "Continuing anyway.\n"); - } - } - if ((image = fopen(filename, "r")) == NULL) { - perror(filename); - programmer_shutdown(); - exit(1); - } - if (fstat(fileno(image), &image_stat) != 0) { - perror(filename); - programmer_shutdown(); - exit(1); - } - if (image_stat.st_size != flash->total_size * 1024) { - fprintf(stderr, "Error: Image size doesn't match\n"); - programmer_shutdown(); - exit(1); - } - - numbytes = fread(buf, 1, size, image); - show_id(buf, size, force); - fclose(image); - if (numbytes != size) { - fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size); - programmer_shutdown(); - return 1; - } - } - - // This should be moved into each flash part's code to do it - // cleanly. This does the job. - handle_romentries(buf, flash); - - // //////////////////////////////////////////////////////////// - - if (write_it) { - printf("Writing flash chip... "); - if (!flash->write) { - fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n"); - programmer_shutdown(); - return 1; - } - ret = flash->write(flash, buf); - if (ret) { - fprintf(stderr, "FAILED!\n"); - emergency_help_message(); - programmer_shutdown(); - return 1; - } else { - printf("COMPLETE.\n"); - } - } - - if (verify_it) { - /* Work around chips which need some time to calm down. */ - if (write_it) - programmer_delay(1000*1000); - ret = verify_flash(flash, buf); - /* If we tried to write, and verification now fails, we - * might have an emergency situation. - */ - if (ret && write_it) - emergency_help_message(); - } - - programmer_shutdown(); - - return ret; -} diff --git a/ft2232_spi.c b/ft2232_spi.c deleted file mode 100644 index d565a6f..0000000 --- a/ft2232_spi.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Paul Fox - * Copyright (C) 2009 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 - */ - -#if FT2232_SPI_SUPPORT == 1 - -#include -#include -#include -#include -#include -#include "flash.h" -#include "spi.h" -#include - -/* - * The 'H' chips can run internally at either 12MHz or 60MHz. - * The non-H chips can only run at 12MHz. - */ -#define CLOCK_5X 1 - -/* - * In either case, the divisor is a simple integer clock divider. - * If CLOCK_5X is set, this divisor divides 30MHz, else it divides 6MHz. - */ -#define DIVIDE_BY 3 /* e.g. '3' will give either 10MHz or 2MHz SPI clock. */ - -#define BITMODE_BITBANG_NORMAL 1 -#define BITMODE_BITBANG_SPI 2 - -static struct ftdi_context ftdic_context; - -int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) -{ - int r; - r = ftdi_write_data(ftdic, (unsigned char *) buf, size); - if (r < 0) { - fprintf(stderr, "ftdi_write_data: %d, %s\n", r, - ftdi_get_error_string(ftdic)); - return 1; - } - return 0; -} - -int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) -{ - int r; - r = ftdi_read_data(ftdic, (unsigned char *) buf, size); - if (r < 0) { - fprintf(stderr, "ftdi_read_data: %d, %s\n", r, - ftdi_get_error_string(ftdic)); - return 1; - } - return 0; -} - -int ft2232_spi_init(void) -{ - int f; - struct ftdi_context *ftdic = &ftdic_context; - unsigned char buf[512]; - char *portpos = NULL; - int ft2232_type = FTDI_FT4232H; - enum ftdi_interface ft2232_interface = INTERFACE_B; - - if (ftdi_init(ftdic) < 0) { - fprintf(stderr, "ftdi_init failed\n"); - return EXIT_FAILURE; // TODO - } - - if (programmer_param && !strlen(programmer_param)) { - free(programmer_param); - programmer_param = NULL; - } - if (programmer_param) { - if (strstr(programmer_param, "2232")) - ft2232_type = FTDI_FT2232H; - if (strstr(programmer_param, "4232")) - ft2232_type = FTDI_FT4232H; - portpos = strstr(programmer_param, "port="); - if (portpos) { - portpos += 5; - switch (toupper(*portpos)) { - case 'A': - ft2232_interface = INTERFACE_A; - break; - case 'B': - ft2232_interface = INTERFACE_B; - break; - default: - fprintf(stderr, "Invalid interface specified, " - "using default.\n"); - } - } - free(programmer_param); - } - printf_debug("Using device type %s ", - (ft2232_type == FTDI_FT2232H) ? "2232H" : "4232H"); - printf_debug("interface %s\n", - (ft2232_interface == INTERFACE_A) ? "A" : "B"); - - f = ftdi_usb_open(ftdic, 0x0403, ft2232_type); - - if (f < 0 && f != -5) { - fprintf(stderr, "Unable to open FTDI device: %d (%s)\n", f, - ftdi_get_error_string(ftdic)); - exit(-1); // TODO - } - - if (ftdi_set_interface(ftdic, ft2232_interface) < 0) { - fprintf(stderr, "Unable to select interface: %s\n", - ftdic->error_str); - } - - if (ftdi_usb_reset(ftdic) < 0) { - fprintf(stderr, "Unable to reset FTDI device\n"); - } - - if (ftdi_set_latency_timer(ftdic, 2) < 0) { - fprintf(stderr, "Unable to set latency timer\n"); - } - - if (ftdi_write_data_set_chunksize(ftdic, 512)) { - fprintf(stderr, "Unable to set chunk size\n"); - } - - if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) { - fprintf(stderr, "Unable to set bitmode to SPI\n"); - } - -#if CLOCK_5X - printf_debug("Disable divide-by-5 front stage\n"); - buf[0] = 0x8a; /* Disable divide-by-5. */ - if (send_buf(ftdic, buf, 1)) - return -1; -#define MPSSE_CLK 60.0 - -#else - -#define MPSSE_CLK 12.0 - -#endif - printf_debug("Set clock divisor\n"); - buf[0] = 0x86; /* command "set divisor" */ - /* valueL/valueH are (desired_divisor - 1) */ - buf[1] = (DIVIDE_BY - 1) & 0xff; - buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff; - if (send_buf(ftdic, buf, 3)) - return -1; - - printf("SPI clock is %fMHz\n", - (double)(MPSSE_CLK / (((DIVIDE_BY - 1) + 1) * 2))); - - /* Disconnect TDI/DO to TDO/DI for loopback. */ - printf_debug("No loopback of TDI/DO TDO/DI\n"); - buf[0] = 0x85; - if (send_buf(ftdic, buf, 1)) - return -1; - - printf_debug("Set data bits\n"); - /* Set data bits low-byte command: - * value: 0x08 CS=high, DI=low, DO=low, SK=low - * dir: 0x0b CS=output, DI=input, DO=output, SK=output - */ -#define CS_BIT 0x08 - buf[0] = SET_BITS_LOW; - buf[1] = CS_BIT; - buf[2] = 0x0b; - if (send_buf(ftdic, buf, 3)) - return -1; - - // printf_debug("\nft2232 chosen\n"); - - buses_supported = CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_FT2232; - - return 0; -} - -int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - struct ftdi_context *ftdic = &ftdic_context; - static unsigned char *buf = NULL; - /* failed is special. We use bitwise ops, but it is essentially bool. */ - int i = 0, ret = 0, failed = 0; - int bufsize; - static int oldbufsize = 0; - - if (writecnt > 65536 || readcnt > 65536) - return SPI_INVALID_LENGTH; - - /* buf is not used for the response from the chip. */ - bufsize = max(writecnt + 9, 260 + 9); - /* Never shrink. realloc() calls are expensive. */ - if (bufsize > oldbufsize) { - buf = realloc(buf, bufsize); - if (!buf) { - fprintf(stderr, "Out of memory!\n"); - exit(1); - } - oldbufsize = bufsize; - } - - /* - * Minimize USB transfers by packing as many commands as possible - * together. If we're not expecting to read, we can assert CS#, write, - * and deassert CS# all in one shot. If reading, we do three separate - * operations. - */ - printf_debug("Assert CS#\n"); - buf[i++] = SET_BITS_LOW; - buf[i++] = 0 & ~CS_BIT; /* assertive */ - buf[i++] = 0x0b; - - if (writecnt) { - buf[i++] = 0x11; - buf[i++] = (writecnt - 1) & 0xff; - buf[i++] = ((writecnt - 1) >> 8) & 0xff; - memcpy(buf + i, writearr, writecnt); - i += writecnt; - } - - /* - * Optionally terminate this batch of commands with a - * read command, then do the fetch of the results. - */ - if (readcnt) { - buf[i++] = 0x20; - buf[i++] = (readcnt - 1) & 0xff; - buf[i++] = ((readcnt - 1) >> 8) & 0xff; - ret = send_buf(ftdic, buf, i); - failed = ret; - /* We can't abort here, we still have to deassert CS#. */ - if (ret) - fprintf(stderr, "send_buf failed before read: %i\n", - ret); - i = 0; - if (ret == 0) { - /* - * FIXME: This is unreliable. There's no guarantee that - * we read the response directly after sending the read - * command. We may be scheduled out etc. - */ - ret = get_buf(ftdic, readarr, readcnt); - failed |= ret; - /* We can't abort here either. */ - if (ret) - fprintf(stderr, "get_buf failed: %i\n", ret); - } - } - - printf_debug("De-assert CS#\n"); - buf[i++] = SET_BITS_LOW; - buf[i++] = CS_BIT; - buf[i++] = 0x0b; - ret = send_buf(ftdic, buf, i); - failed |= ret; - if (ret) - fprintf(stderr, "send_buf failed at end: %i\n", ret); - - return failed ? -1 : 0; -} - -int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - /* Maximum read length is 64k bytes. */ - return spi_read_chunked(flash, buf, start, len, 64 * 1024); -} - -int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) -{ - int total_size = 1024 * flash->total_size; - int i; - - spi_disable_blockprotect(); - /* Erase first. */ - printf("Erasing flash before programming... "); - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("done.\n"); - printf_debug("total_size is %d\n", total_size); - for (i = 0; i < total_size; i += 256) { - int l, r; - if (i + 256 <= total_size) - l = 256; - else - l = total_size - i; - - if ((r = spi_nbyte_program(i, &buf[i], l))) { - fprintf(stderr, "%s: write fail %d\n", __func__, r); - return 1; - } - - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - /* loop */; - } - - return 0; -} - -#endif diff --git a/gfxnvidia.c b/gfxnvidia.c deleted file mode 100644 index 1e9b679..0000000 --- a/gfxnvidia.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Uwe Hermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" - -#define PCI_VENDOR_ID_NVIDIA 0x10de - -uint8_t *nvidia_bar; - -struct pcidev_status gfx_nvidia[] = { - {0x10de, 0x0010, PCI_NT, "NVIDIA", "Mutara V08 [NV2]" }, - {0x10de, 0x0018, PCI_NT, "NVIDIA", "RIVA 128" }, - {0x10de, 0x0020, PCI_NT, "NVIDIA", "RIVA TNT" }, - {0x10de, 0x0028, PCI_NT, "NVIDIA", "RIVA TNT2/TNT2 Pro" }, - {0x10de, 0x0029, PCI_NT, "NVIDIA", "RIVA TNT2 Ultra" }, - {0x10de, 0x002c, PCI_NT, "NVIDIA", "Vanta/Vanta LT" }, - {0x10de, 0x002d, PCI_OK, "NVIDIA", "RIVA TNT2 Model 64/Model 64 Pro" }, - {0x10de, 0x00a0, PCI_NT, "NVIDIA", "Aladdin TNT2" }, - {0x10de, 0x0100, PCI_NT, "NVIDIA", "GeForce 256" }, - {0x10de, 0x0101, PCI_NT, "NVIDIA", "GeForce DDR" }, - {0x10de, 0x0103, PCI_NT, "NVIDIA", "Quadro" }, - {0x10de, 0x0110, PCI_NT, "NVIDIA", "GeForce2 MX" }, - {0x10de, 0x0111, PCI_NT, "NVIDIA", "GeForce2 MX" }, - {0x10de, 0x0112, PCI_NT, "NVIDIA", "GeForce2 GO" }, - {0x10de, 0x0113, PCI_NT, "NVIDIA", "Quadro2 MXR" }, - {0x10de, 0x0150, PCI_NT, "NVIDIA", "GeForce2 GTS/Pro" }, - {0x10de, 0x0151, PCI_NT, "NVIDIA", "GeForce2 GTS" }, - {0x10de, 0x0152, PCI_NT, "NVIDIA", "GeForce2 Ultra" }, - {0x10de, 0x0153, PCI_NT, "NVIDIA", "Quadro2 Pro" }, - {0x10de, 0x0200, PCI_NT, "NVIDIA", "GeForce 3 nFX" }, - {0x10de, 0x0201, PCI_NT, "NVIDIA", "GeForce 3 nFX" }, - {0x10de, 0x0202, PCI_NT, "NVIDIA", "GeForce 3 nFX Ultra" }, - {0x10de, 0x0203, PCI_NT, "NVIDIA", "Quadro 3 DDC" }, - - {}, -}; - -int gfxnvidia_init(void) -{ - uint32_t reg32; - - get_io_perms(); - - io_base_addr = pcidev_init(PCI_VENDOR_ID_NVIDIA, PCI_BASE_ADDRESS_0, - gfx_nvidia, programmer_param); - io_base_addr += 0x300000; - printf("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr); - - /* Allow access to flash interface (will disable screen). */ - reg32 = pci_read_long(pcidev_dev, 0x50); - reg32 &= ~(1 << 0); - pci_write_long(pcidev_dev, 0x50, reg32); - - nvidia_bar = physmap("NVIDIA", io_base_addr, 16 * 1024 * 1024); - - buses_supported = CHIP_BUSTYPE_PARALLEL; - - return 0; -} - -int gfxnvidia_shutdown(void) -{ - uint32_t reg32; - - /* Disallow access to flash interface (and re-enable screen). */ - reg32 = pci_read_long(pcidev_dev, 0x50); - reg32 |= (1 << 0); - pci_write_long(pcidev_dev, 0x50, reg32); - - free(programmer_param); - pci_cleanup(pacc); - release_io_perms(); - return 0; -} - -void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr) -{ - mmio_writeb(val, nvidia_bar + addr); -} - -uint8_t gfxnvidia_chip_readb(const chipaddr addr) -{ - return mmio_readb(nvidia_bar + addr); -} diff --git a/ichspi.c b/ichspi.c deleted file mode 100644 index cd02b96..0000000 --- a/ichspi.c +++ /dev/null @@ -1,763 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Stefan Wildemann - * Copyright (C) 2008 Claus Gindhart - * Copyright (C) 2008 Dominik Geyer - * Copyright (C) 2008 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * This module is designed for supporting the devices - * ST M25P40 - * ST M25P80 - * ST M25P16 - * ST M25P32 already tested - * ST M25P64 - * AT 25DF321 already tested - * - */ - -#include -#include "flash.h" -#include "spi.h" - -/* ICH9 controller register definition */ -#define ICH9_REG_FADDR 0x08 /* 32 Bits */ -#define ICH9_REG_FDATA0 0x10 /* 64 Bytes */ - -#define ICH9_REG_SSFS 0x90 /* 08 Bits */ -#define SSFS_SCIP 0x00000001 -#define SSFS_CDS 0x00000004 -#define SSFS_FCERR 0x00000008 -#define SSFS_AEL 0x00000010 - -#define ICH9_REG_SSFC 0x91 /* 24 Bits */ -#define SSFC_SCGO 0x00000200 -#define SSFC_ACS 0x00000400 -#define SSFC_SPOP 0x00000800 -#define SSFC_COP 0x00001000 -#define SSFC_DBC 0x00010000 -#define SSFC_DS 0x00400000 -#define SSFC_SME 0x00800000 -#define SSFC_SCF 0x01000000 -#define SSFC_SCF_20MHZ 0x00000000 -#define SSFC_SCF_33MHZ 0x01000000 - -#define ICH9_REG_PREOP 0x94 /* 16 Bits */ -#define ICH9_REG_OPTYPE 0x96 /* 16 Bits */ -#define ICH9_REG_OPMENU 0x98 /* 64 Bits */ - -// ICH9R SPI commands -#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0 -#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1 -#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2 -#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3 - -// ICH7 registers -#define ICH7_REG_SPIS 0x00 /* 16 Bits */ -#define SPIS_SCIP 0x00000001 -#define SPIS_CDS 0x00000004 -#define SPIS_FCERR 0x00000008 - -/* VIA SPI is compatible with ICH7, but maxdata - to transfer is 16 bytes. - - DATA byte count on ICH7 is 8:13, on VIA 8:11 - - bit 12 is port select CS0 CS1 - bit 13 is FAST READ enable - bit 7 is used with fast read and one shot controls CS de-assert? -*/ - -#define ICH7_REG_SPIC 0x02 /* 16 Bits */ -#define SPIC_SCGO 0x0002 -#define SPIC_ACS 0x0004 -#define SPIC_SPOP 0x0008 -#define SPIC_DS 0x4000 - -#define ICH7_REG_SPIA 0x04 /* 32 Bits */ -#define ICH7_REG_SPID0 0x08 /* 64 Bytes */ -#define ICH7_REG_PREOP 0x54 /* 16 Bits */ -#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */ -#define ICH7_REG_OPMENU 0x58 /* 64 Bits */ - -/* ICH SPI configuration lock-down. May be set during chipset enabling. */ -int ichspi_lock = 0; - -typedef struct _OPCODE { - uint8_t opcode; //This commands spi opcode - uint8_t spi_type; //This commands spi type - uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1 -} OPCODE; - -/* Opcode definition: - * Preop 1: Write Enable - * Preop 2: Write Status register enable - * - * OP 0: Write address - * OP 1: Read Address - * OP 2: ERASE block - * OP 3: Read Status register - * OP 4: Read ID - * OP 5: Write Status register - * OP 6: chip private (read JDEC id) - * OP 7: Chip erase - */ -typedef struct _OPCODES { - uint8_t preop[2]; - OPCODE opcode[8]; -} OPCODES; - -static OPCODES *curopcodes = NULL; - -/* HW access functions */ -static uint32_t REGREAD32(int X) -{ - return mmio_readl(spibar + X); -} - -static uint16_t REGREAD16(int X) -{ - return mmio_readw(spibar + X); -} - -#define REGWRITE32(X,Y) mmio_writel(Y, spibar+X) -#define REGWRITE16(X,Y) mmio_writew(Y, spibar+X) -#define REGWRITE8(X,Y) mmio_writeb(Y, spibar+X) - -/* Common SPI functions */ -static int find_opcode(OPCODES *op, uint8_t opcode); -static int find_preop(OPCODES *op, uint8_t preop); -static int generate_opcodes(OPCODES * op); -static int program_opcodes(OPCODES * op); -static int run_opcode(OPCODE op, uint32_t offset, - uint8_t datalength, uint8_t * data); -static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes, - int offset, int maxdata); - -/* for pairing opcodes with their required preop */ -struct preop_opcode_pair { - uint8_t preop; - uint8_t opcode; -}; - -struct preop_opcode_pair pops[] = { - {JEDEC_WREN, JEDEC_BYTE_PROGRAM}, - {JEDEC_WREN, JEDEC_SE}, /* sector erase */ - {JEDEC_WREN, JEDEC_BE_52}, /* block erase */ - {JEDEC_WREN, JEDEC_BE_D8}, /* block erase */ - {JEDEC_WREN, JEDEC_CE_60}, /* chip erase */ - {JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */ - {JEDEC_EWSR, JEDEC_WRSR}, - {0,} -}; - -OPCODES O_ST_M25P = { - { - JEDEC_WREN, - 0}, - { - {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte - {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data - {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector - {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg - {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature - {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register - {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID - {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase - } -}; - -OPCODES O_EXISTING = {}; - -static int find_opcode(OPCODES *op, uint8_t opcode) -{ - int a; - - for (a = 0; a < 8; a++) { - if (op->opcode[a].opcode == opcode) - return a; - } - - return -1; -} - -static int find_preop(OPCODES *op, uint8_t preop) -{ - int a; - - for (a = 0; a < 2; a++) { - if (op->preop[a] == preop) - return a; - } - - return -1; -} - -static int generate_opcodes(OPCODES * op) -{ - int a, b, i; - uint16_t preop, optype; - uint32_t opmenu[2]; - - if (op == NULL) { - printf_debug("\n%s: null OPCODES pointer!\n", __func__); - return -1; - } - - switch (spi_controller) { - case SPI_CONTROLLER_ICH7: - case SPI_CONTROLLER_VIA: - preop = REGREAD16(ICH7_REG_PREOP); - optype = REGREAD16(ICH7_REG_OPTYPE); - opmenu[0] = REGREAD32(ICH7_REG_OPMENU); - opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4); - break; - case SPI_CONTROLLER_ICH9: - preop = REGREAD16(ICH9_REG_PREOP); - optype = REGREAD16(ICH9_REG_OPTYPE); - opmenu[0] = REGREAD32(ICH9_REG_OPMENU); - opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4); - break; - default: - printf_debug("%s: unsupported chipset\n", __func__); - return -1; - } - - op->preop[0] = (uint8_t) preop; - op->preop[1] = (uint8_t) (preop >> 8); - - for (a = 0; a < 8; a++) { - op->opcode[a].spi_type = (uint8_t) (optype & 0x3); - optype >>= 2; - } - - for (a = 0; a < 4; a++) { - op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff); - opmenu[0] >>= 8; - } - - for (a = 4; a < 8; a++) { - op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff); - opmenu[1] >>= 8; - } - - /* atomic (link opcode with required pre-op) */ - for (a = 4; a < 8; a++) - op->opcode[a].atomic = 0; - - for (i = 0; pops[i].opcode; i++) { - a = find_opcode(op, pops[i].opcode); - b = find_preop(op, pops[i].preop); - if ((a != -1) && (b != -1)) - op->opcode[a].atomic = (uint8_t) ++b; - } - - return 0; -} - -int program_opcodes(OPCODES * op) -{ - uint8_t a; - uint16_t preop, optype; - uint32_t opmenu[2]; - - /* Program Prefix Opcodes */ - /* 0:7 Prefix Opcode 1 */ - preop = (op->preop[0]); - /* 8:16 Prefix Opcode 2 */ - preop |= ((uint16_t) op->preop[1]) << 8; - - /* Program Opcode Types 0 - 7 */ - optype = 0; - for (a = 0; a < 8; a++) { - optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2); - } - - /* Program Allowable Opcodes 0 - 3 */ - opmenu[0] = 0; - for (a = 0; a < 4; a++) { - opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8); - } - - /*Program Allowable Opcodes 4 - 7 */ - opmenu[1] = 0; - for (a = 4; a < 8; a++) { - opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8); - } - - printf_debug("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]); - switch (spi_controller) { - case SPI_CONTROLLER_ICH7: - case SPI_CONTROLLER_VIA: - REGWRITE16(ICH7_REG_PREOP, preop); - REGWRITE16(ICH7_REG_OPTYPE, optype); - REGWRITE32(ICH7_REG_OPMENU, opmenu[0]); - REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]); - break; - case SPI_CONTROLLER_ICH9: - REGWRITE16(ICH9_REG_PREOP, preop); - REGWRITE16(ICH9_REG_OPTYPE, optype); - REGWRITE32(ICH9_REG_OPMENU, opmenu[0]); - REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]); - break; - default: - printf_debug("%s: unsupported chipset\n", __func__); - return -1; - } - - return 0; -} - -/* This function generates OPCODES from or programs OPCODES to ICH according to - * the chipset's SPI configuration lock. - * - * It should be called before ICH sends any spi command. - */ -int ich_init_opcodes(void) -{ - int rc = 0; - OPCODES *curopcodes_done; - - if (curopcodes) - return 0; - - if (ichspi_lock) { - printf_debug("Generating OPCODES... "); - curopcodes_done = &O_EXISTING; - rc = generate_opcodes(curopcodes_done); - } else { - printf_debug("Programming OPCODES... "); - curopcodes_done = &O_ST_M25P; - rc = program_opcodes(curopcodes_done); - } - - if (rc) { - curopcodes = NULL; - printf_debug("failed\n"); - return 1; - } else { - curopcodes = curopcodes_done; - printf_debug("done\n"); - return 0; - } -} - -static int ich7_run_opcode(OPCODE op, uint32_t offset, - uint8_t datalength, uint8_t * data, int maxdata) -{ - int write_cmd = 0; - int timeout; - uint32_t temp32 = 0; - uint16_t temp16; - uint32_t a; - uint64_t opmenu; - int opcode_index; - - /* Is it a write command? */ - if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) - || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) { - write_cmd = 1; - } - - /* Programm Offset in Flash into FADDR */ - REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */ - - /* Program data into FDATA0 to N */ - if (write_cmd && (datalength != 0)) { - temp32 = 0; - for (a = 0; a < datalength; a++) { - if ((a % 4) == 0) { - temp32 = 0; - } - - temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8); - - if ((a % 4) == 3) { - REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)), - temp32); - } - } - if (((a - 1) % 4) != 3) { - REGWRITE32(ICH7_REG_SPID0 + - ((a - 1) - ((a - 1) % 4)), temp32); - } - - } - - /* Assemble SPIS */ - temp16 = 0; - /* clear error status registers */ - temp16 |= (SPIS_CDS + SPIS_FCERR); - REGWRITE16(ICH7_REG_SPIS, temp16); - - /* Assemble SPIC */ - temp16 = 0; - - if (datalength != 0) { - temp16 |= SPIC_DS; - temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8; - } - - /* Select opcode */ - opmenu = REGREAD32(ICH7_REG_OPMENU); - opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32; - - for (opcode_index = 0; opcode_index < 8; opcode_index++) { - if ((opmenu & 0xff) == op.opcode) { - break; - } - opmenu >>= 8; - } - if (opcode_index == 8) { - printf_debug("Opcode %x not found.\n", op.opcode); - return 1; - } - temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4; - - /* Handle Atomic */ - if (op.atomic != 0) { - /* Select atomic command */ - temp16 |= SPIC_ACS; - /* Select prefix opcode */ - if ((op.atomic - 1) == 1) { - /*Select prefix opcode 2 */ - temp16 |= SPIC_SPOP; - } - } - - /* Start */ - temp16 |= SPIC_SCGO; - - /* write it */ - REGWRITE16(ICH7_REG_SPIC, temp16); - - /* wait for cycle complete */ - timeout = 100 * 1000 * 60; // 60s is a looong timeout. - while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) { - programmer_delay(10); - } - if (!timeout) { - printf_debug("timeout\n"); - } - - if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) { - printf_debug("Transaction error!\n"); - return 1; - } - - if ((!write_cmd) && (datalength != 0)) { - for (a = 0; a < datalength; a++) { - if ((a % 4) == 0) { - temp32 = REGREAD32(ICH7_REG_SPID0 + (a)); - } - - data[a] = - (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) - >> ((a % 4) * 8); - } - } - - return 0; -} - -static int ich9_run_opcode(OPCODE op, uint32_t offset, - uint8_t datalength, uint8_t * data) -{ - int write_cmd = 0; - int timeout; - uint32_t temp32; - uint32_t a; - uint64_t opmenu; - int opcode_index; - - /* Is it a write command? */ - if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) - || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) { - write_cmd = 1; - } - - /* Programm Offset in Flash into FADDR */ - REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */ - - /* Program data into FDATA0 to N */ - if (write_cmd && (datalength != 0)) { - temp32 = 0; - for (a = 0; a < datalength; a++) { - if ((a % 4) == 0) { - temp32 = 0; - } - - temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8); - - if ((a % 4) == 3) { - REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)), - temp32); - } - } - if (((a - 1) % 4) != 3) { - REGWRITE32(ICH9_REG_FDATA0 + - ((a - 1) - ((a - 1) % 4)), temp32); - } - } - - /* Assemble SSFS + SSFC */ - temp32 = 0; - - /* clear error status registers */ - temp32 |= (SSFS_CDS + SSFS_FCERR); - /* USE 20 MhZ */ - temp32 |= SSFC_SCF_20MHZ; - - if (datalength != 0) { - uint32_t datatemp; - temp32 |= SSFC_DS; - datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8); - temp32 |= datatemp; - } - - /* Select opcode */ - opmenu = REGREAD32(ICH9_REG_OPMENU); - opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32; - - for (opcode_index = 0; opcode_index < 8; opcode_index++) { - if ((opmenu & 0xff) == op.opcode) { - break; - } - opmenu >>= 8; - } - if (opcode_index == 8) { - printf_debug("Opcode %x not found.\n", op.opcode); - return 1; - } - temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4); - - /* Handle Atomic */ - if (op.atomic != 0) { - /* Select atomic command */ - temp32 |= SSFC_ACS; - /* Selct prefix opcode */ - if ((op.atomic - 1) == 1) { - /*Select prefix opcode 2 */ - temp32 |= SSFC_SPOP; - } - } - - /* Start */ - temp32 |= SSFC_SCGO; - - /* write it */ - REGWRITE32(ICH9_REG_SSFS, temp32); - - /*wait for cycle complete */ - timeout = 100 * 1000 * 60; // 60s is a looong timeout. - while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) { - programmer_delay(10); - } - if (!timeout) { - printf_debug("timeout\n"); - } - - if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) { - printf_debug("Transaction error!\n"); - return 1; - } - - if ((!write_cmd) && (datalength != 0)) { - for (a = 0; a < datalength; a++) { - if ((a % 4) == 0) { - temp32 = REGREAD32(ICH9_REG_FDATA0 + (a)); - } - - data[a] = - (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) - >> ((a % 4) * 8); - } - } - - return 0; -} - -static int run_opcode(OPCODE op, uint32_t offset, - uint8_t datalength, uint8_t * data) -{ - switch (spi_controller) { - case SPI_CONTROLLER_VIA: - if (datalength > 16) - return SPI_INVALID_LENGTH; - return ich7_run_opcode(op, offset, datalength, data, 16); - case SPI_CONTROLLER_ICH7: - if (datalength > 64) - return SPI_INVALID_LENGTH; - return ich7_run_opcode(op, offset, datalength, data, 64); - case SPI_CONTROLLER_ICH9: - if (datalength > 64) - return SPI_INVALID_LENGTH; - return ich9_run_opcode(op, offset, datalength, data); - default: - printf_debug("%s: unsupported chipset\n", __func__); - } - - /* If we ever get here, something really weird happened */ - return -1; -} - -static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes, - int offset, int maxdata) -{ - int page_size = flash->page_size; - uint32_t remaining = page_size; - int towrite; - - printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n", - offset, page_size, bytes); - - for (; remaining > 0; remaining -= towrite) { - towrite = min(remaining, maxdata); - if (spi_nbyte_program(offset + (page_size - remaining), - &bytes[page_size - remaining], towrite)) { - printf_debug("Error writing"); - return 1; - } - } - - return 0; -} - -int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len) -{ - int maxdata = 64; - - if (spi_controller == SPI_CONTROLLER_VIA) - maxdata = 16; - - return spi_read_chunked(flash, buf, start, len, maxdata); -} - -int ich_spi_write_256(struct flashchip *flash, uint8_t * buf) -{ - int i, j, rc = 0; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - int erase_size = 64 * 1024; - int maxdata = 64; - - spi_disable_blockprotect(); - /* Erase first */ - printf("Erasing flash before programming... "); - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("done.\n"); - - printf("Programming page: \n"); - for (i = 0; i < total_size / erase_size; i++) { - if (spi_controller == SPI_CONTROLLER_VIA) - maxdata = 16; - - for (j = 0; j < erase_size / page_size; j++) { - ich_spi_write_page(flash, - (void *)(buf + (i * erase_size) + (j * page_size)), - (i * erase_size) + (j * page_size), maxdata); - } - } - - printf("\n"); - - return rc; -} - -int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - int a; - int result; - int opcode_index = -1; - const unsigned char cmd = *writearr; - OPCODE *opcode; - uint32_t addr = 0; - uint8_t *data; - int count; - - /* find cmd in opcodes-table */ - for (a = 0; a < 8; a++) { - if ((curopcodes->opcode[a]).opcode == cmd) { - opcode_index = a; - break; - } - } - - /* unknown / not programmed command */ - if (opcode_index == -1) { - printf_debug("Invalid OPCODE 0x%02x\n", cmd); - return SPI_INVALID_OPCODE; - } - - opcode = &(curopcodes->opcode[opcode_index]); - - /* if opcode-type requires an address */ - if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS || - opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) { - addr = (writearr[1] << 16) | - (writearr[2] << 8) | (writearr[3] << 0); - } - - /* translate read/write array/count */ - if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) { - data = (uint8_t *) (writearr + 1); - count = writecnt - 1; - } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) { - data = (uint8_t *) (writearr + 4); - count = writecnt - 4; - } else { - data = (uint8_t *) readarr; - count = readcnt; - } - - result = run_opcode(*opcode, addr, count, data); - if (result) { - printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode); - } - - return result; -} - -int ich_spi_send_multicommand(struct spi_command *cmds) -{ - int ret = 0; - int oppos, preoppos; - for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) { - /* Is the next command valid or a terminator? */ - if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) { - preoppos = find_preop(curopcodes, cmds->writearr[0]); - oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]); - /* Is the opcode of the current command listed in the - * ICH struct OPCODES as associated preopcode for the - * opcode of the next command? - */ - if ((oppos != -1) && (preoppos != -1) && - ((curopcodes->opcode[oppos].atomic - 1) == preoppos)) - continue; - } - - ret = ich_spi_send_command(cmds->writecnt, cmds->readcnt, - cmds->writearr, cmds->readarr); - } - return ret; -} diff --git a/internal.c b/internal.c deleted file mode 100644 index fc662c5..0000000 --- a/internal.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include "flash.h" - -#if defined(__FreeBSD__) || defined(__DragonFly__) -int io_fd; -#endif - -struct pci_dev *pci_dev_find_filter(struct pci_filter filter) -{ - struct pci_dev *temp; - - for (temp = pacc->devices; temp; temp = temp->next) - if (pci_filter_match(&filter, temp)) - return temp; - - return NULL; -} - -struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class) -{ - struct pci_dev *temp; - struct pci_filter filter; - uint16_t tmp2; - - pci_filter_init(NULL, &filter); - filter.vendor = vendor; - - for (temp = pacc->devices; temp; temp = temp->next) - if (pci_filter_match(&filter, temp)) { - /* Read PCI class */ - tmp2 = pci_read_word(temp, 0x0a); - if (tmp2 == class) - return temp; - } - - return NULL; -} - -struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device) -{ - struct pci_dev *temp; - struct pci_filter filter; - - pci_filter_init(NULL, &filter); - filter.vendor = vendor; - filter.device = device; - - for (temp = pacc->devices; temp; temp = temp->next) - if (pci_filter_match(&filter, temp)) - return temp; - - return NULL; -} - -struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device, - uint16_t card_vendor, uint16_t card_device) -{ - struct pci_dev *temp; - struct pci_filter filter; - - pci_filter_init(NULL, &filter); - filter.vendor = vendor; - filter.device = device; - - for (temp = pacc->devices; temp; temp = temp->next) - if (pci_filter_match(&filter, temp)) { - if ((card_vendor == - pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID)) - && (card_device == - pci_read_word(temp, PCI_SUBSYSTEM_ID))) - return temp; - } - - return NULL; -} - -void get_io_perms(void) -{ -#if defined (__sun) && (defined(__i386) || defined(__amd64)) - if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) { -#elif defined(__FreeBSD__) || defined (__DragonFly__) - if ((io_fd = open("/dev/io", O_RDWR)) < 0) { -#else - if (iopl(3) != 0) { -#endif - fprintf(stderr, "ERROR: Could not get I/O privileges (%s).\n" - "You need to be root.\n", strerror(errno)); - exit(1); - } -} - -void release_io_perms(void) -{ -#if defined(__FreeBSD__) || defined(__DragonFly__) - close(io_fd); -#endif -} - -int internal_init(void) -{ - int ret = 0; - - get_io_perms(); - - /* Initialize PCI access for flash enables */ - pacc = pci_alloc(); /* Get the pci_access structure */ - /* Set all options you want -- here we stick with the defaults */ - pci_init(pacc); /* Initialize the PCI library */ - pci_scan_bus(pacc); /* We want to get the list of devices */ - - /* We look at the lbtable first to see if we need a - * mainboard specific flash enable sequence. - */ - coreboot_init(); - - /* try to enable it. Failure IS an option, since not all motherboards - * really need this to be done, etc., etc. - */ - ret = chipset_flash_enable(); - if (ret == -2) { - printf("WARNING: No chipset found. Flash detection " - "will most likely fail.\n"); - } - - board_flash_enable(lb_vendor, lb_part); - - /* Even if chipset init returns an error code, we don't want to abort. - * The error code might have been a warning only. - * Besides that, we don't check the board enable return code either. - */ - return 0; -} - -int internal_shutdown(void) -{ - release_io_perms(); - - return 0; -} - -void internal_chip_writeb(uint8_t val, chipaddr addr) -{ - mmio_writeb(val, (void *) addr); -} - -void internal_chip_writew(uint16_t val, chipaddr addr) -{ - mmio_writew(val, (void *) addr); -} - -void internal_chip_writel(uint32_t val, chipaddr addr) -{ - mmio_writel(val, (void *) addr); -} - -uint8_t internal_chip_readb(const chipaddr addr) -{ - return mmio_readb((void *) addr); -} - -uint16_t internal_chip_readw(const chipaddr addr) -{ - return mmio_readw((void *) addr); -} - -uint32_t internal_chip_readl(const chipaddr addr) -{ - return mmio_readl((void *) addr); -} - -void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len) -{ - memcpy(buf, (void *)addr, len); - return; -} - -void mmio_writeb(uint8_t val, void *addr) -{ - *(volatile uint8_t *) addr = val; -} - -void mmio_writew(uint16_t val, void *addr) -{ - *(volatile uint16_t *) addr = val; -} - -void mmio_writel(uint32_t val, void *addr) -{ - *(volatile uint32_t *) addr = val; -} - -uint8_t mmio_readb(void *addr) -{ - return *(volatile uint8_t *) addr; -} - -uint16_t mmio_readw(void *addr) -{ - return *(volatile uint16_t *) addr; -} - -uint32_t mmio_readl(void *addr) -{ - return *(volatile uint32_t *) addr; -} - -void internal_delay(int usecs) -{ - /* If the delay is >1 s, use usleep because timing does not need to - * be so precise. - */ - if (usecs > 1000000) { - usleep(usecs); - } else { - myusec_delay(usecs); - } -} - -/* No-op shutdown() for programmers which don't need special handling */ -int noop_shutdown(void) -{ - return 0; -} - -/* Fallback map() for programmers which don't need special handling */ -void *fallback_map(const char *descr, unsigned long phys_addr, size_t len) -{ - /* FIXME: Should return phys_addr. */ - return 0; -} - -/* No-op/fallback unmap() for programmers which don't need special handling */ -void fallback_unmap(void *virt_addr, size_t len) -{ -} - -/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ -uint8_t noop_chip_readb(const chipaddr addr) -{ - return 0xff; -} - -/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ -void noop_chip_writeb(uint8_t val, chipaddr addr) -{ -} - -/* Little-endian fallback for drivers not supporting 16 bit accesses */ -void fallback_chip_writew(uint16_t val, chipaddr addr) -{ - chip_writeb(val & 0xff, addr); - chip_writeb((val >> 8) & 0xff, addr + 1); -} - -/* Little-endian fallback for drivers not supporting 16 bit accesses */ -uint16_t fallback_chip_readw(const chipaddr addr) -{ - uint16_t val; - val = chip_readb(addr); - val |= chip_readb(addr + 1) << 8; - return val; -} - -/* Little-endian fallback for drivers not supporting 32 bit accesses */ -void fallback_chip_writel(uint32_t val, chipaddr addr) -{ - chip_writew(val & 0xffff, addr); - chip_writew((val >> 16) & 0xffff, addr + 2); -} - -/* Little-endian fallback for drivers not supporting 32 bit accesses */ -uint32_t fallback_chip_readl(const chipaddr addr) -{ - uint32_t val; - val = chip_readw(addr); - val |= chip_readw(addr + 2) << 16; - return val; -} - -void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len) -{ - size_t i; - for (i = 0; i < len; i++) - chip_writeb(buf[i], addr + i); - return; -} - -void fallback_chip_readn(uint8_t *buf, chipaddr addr, size_t len) -{ - size_t i; - for (i = 0; i < len; i++) - buf[i] = chip_readb(addr + i); - return; -} diff --git a/it87spi.c b/it87spi.c deleted file mode 100644 index a5dc06e..0000000 --- a/it87spi.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger - * Copyright (C) 2008 Ronald Hoogenboom - * Copyright (C) 2008 coresystems GmbH - * - * 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 - */ - -/* - * Contains the ITE IT87* SPI specific routines - */ - -#include -#include -#include "flash.h" -#include "spi.h" - -#define ITE_SUPERIO_PORT1 0x2e -#define ITE_SUPERIO_PORT2 0x4e - -uint16_t it8716f_flashport = 0; -/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ -int fast_spi = 1; - -/* Helper functions for most recent ITE IT87xx Super I/O chips */ -#define CHIP_ID_BYTE1_REG 0x20 -#define CHIP_ID_BYTE2_REG 0x21 -void enter_conf_mode_ite(uint16_t port) -{ - OUTB(0x87, port); - OUTB(0x01, port); - OUTB(0x55, port); - if (port == ITE_SUPERIO_PORT1) - OUTB(0x55, port); - else - OUTB(0xaa, port); -} - -void exit_conf_mode_ite(uint16_t port) -{ - sio_write(port, 0x02, 0x02); -} - -static uint16_t find_ite_spi_flash_port(uint16_t port) -{ - uint8_t tmp = 0; - char *portpos = NULL; - uint16_t id, flashport = 0; - - enter_conf_mode_ite(port); - - id = sio_read(port, CHIP_ID_BYTE1_REG) << 8; - id |= sio_read(port, CHIP_ID_BYTE2_REG); - - /* TODO: Handle more IT87xx if they support flash translation */ - if (0x8716 == id || 0x8718 == id) { - /* NOLDN, reg 0x24, mask out lowest bit (suspend) */ - tmp = sio_read(port, 0x24) & 0xFE; - printf("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis"); - printf("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis"); - printf("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis"); - printf("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis"); - printf("LPC write to serial flash %sabled\n", - (tmp & 1 << 4) ? "en" : "dis"); - /* The LPC->SPI force write enable below only makes sense for - * non-programmer mode. - */ - /* If any serial flash segment is enabled, enable writing. */ - if ((tmp & 0xe) && (!(tmp & 1 << 4))) { - printf("Enabling LPC write to serial flash\n"); - tmp |= 1 << 4; - sio_write(port, 0x24, tmp); - } - printf("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); - /* LDN 0x7, reg 0x64/0x65 */ - sio_write(port, 0x07, 0x7); - flashport = sio_read(port, 0x64) << 8; - flashport |= sio_read(port, 0x65); - printf("Serial flash port 0x%04x\n", flashport); - if (programmer_param && !strlen(programmer_param)) { - free(programmer_param); - programmer_param = NULL; - } - if (programmer_param && (portpos = strstr(programmer_param, "port="))) { - portpos += 5; - flashport = strtol(portpos, (char **)NULL, 0); - printf("Forcing serial flash port 0x%04x\n", flashport); - sio_write(port, 0x64, (flashport >> 8)); - sio_write(port, 0x65, (flashport & 0xff)); - } - } - exit_conf_mode_ite(port); - return flashport; -} - -int it87spi_common_init(void) -{ - it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT1); - - if (!it8716f_flashport) - it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT2); - - if (it8716f_flashport) - spi_controller = SPI_CONTROLLER_IT87XX; - - return (!it8716f_flashport); -} - - -int it87spi_init(void) -{ - int ret; - - get_io_perms(); - ret = it87spi_common_init(); - if (!ret) { - buses_supported = CHIP_BUSTYPE_SPI; - } else { - buses_supported = CHIP_BUSTYPE_NONE; - } - return ret; -} - -int it87xx_probe_spi_flash(const char *name) -{ - int ret; - - ret = it87spi_common_init(); - if (!ret) - buses_supported |= CHIP_BUSTYPE_SPI; - return ret; -} - -/* - * The IT8716F only supports commands with length 1,2,4,5 bytes including - * command byte and can not read more than 3 bytes from the device. - * - * This function expects writearr[0] to be the first byte sent to the device, - * whereas the IT8716F splits commands internally into address and non-address - * commands with the address in inverse wire order. That's why the register - * ordering in case 4 and 5 may seem strange. - */ -int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - uint8_t busy, writeenc; - int i; - - do { - busy = INB(it8716f_flashport) & 0x80; - } while (busy); - if (readcnt > 3) { - printf("%s called with unsupported readcnt %i.\n", - __func__, readcnt); - return SPI_INVALID_LENGTH; - } - switch (writecnt) { - case 1: - OUTB(writearr[0], it8716f_flashport + 1); - writeenc = 0x0; - break; - case 2: - OUTB(writearr[0], it8716f_flashport + 1); - OUTB(writearr[1], it8716f_flashport + 7); - writeenc = 0x1; - break; - case 4: - OUTB(writearr[0], it8716f_flashport + 1); - OUTB(writearr[1], it8716f_flashport + 4); - OUTB(writearr[2], it8716f_flashport + 3); - OUTB(writearr[3], it8716f_flashport + 2); - writeenc = 0x2; - break; - case 5: - OUTB(writearr[0], it8716f_flashport + 1); - OUTB(writearr[1], it8716f_flashport + 4); - OUTB(writearr[2], it8716f_flashport + 3); - OUTB(writearr[3], it8716f_flashport + 2); - OUTB(writearr[4], it8716f_flashport + 7); - writeenc = 0x3; - break; - default: - printf("%s called with unsupported writecnt %i.\n", - __func__, writecnt); - return SPI_INVALID_LENGTH; - } - /* - * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes. - * Note: - * We can't use writecnt directly, but have to use a strange encoding. - */ - OUTB(((0x4 + (fast_spi ? 1 : 0)) << 4) - | ((readcnt & 0x3) << 2) | (writeenc), it8716f_flashport); - - if (readcnt > 0) { - do { - busy = INB(it8716f_flashport) & 0x80; - } while (busy); - - for (i = 0; i < readcnt; i++) - readarr[i] = INB(it8716f_flashport + 5 + i); - } - - return 0; -} - -/* Page size is usually 256 bytes */ -static int it8716f_spi_page_program(struct flashchip *flash, int block, uint8_t *buf) -{ - int i; - int result; - chipaddr bios = flash->virtual_memory; - - result = spi_write_enable(); - if (result) - return result; - /* FIXME: The command below seems to be redundant or wrong. */ - OUTB(0x06, it8716f_flashport + 1); - OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport); - for (i = 0; i < 256; i++) { - chip_writeb(buf[256 * block + i], bios + 256 * block + i); - } - OUTB(0, it8716f_flashport); - /* Wait until the Write-In-Progress bit is cleared. - * This usually takes 1-10 ms, so wait in 1 ms steps. - */ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(1000); - return 0; -} - -/* - * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles - * Need to read this big flash using firmware cycles 3 byte at a time. - */ -int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - int total_size = 1024 * flash->total_size; - fast_spi = 0; - - if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) { - spi_read_chunked(flash, buf, start, len, 3); - } else { - read_memmapped(flash, buf, start, len); - } - - return 0; -} - -int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf) -{ - int total_size = 1024 * flash->total_size; - int i; - - /* - * IT8716F only allows maximum of 512 kb SPI chip size for memory - * mapped access. - */ - if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) { - spi_chip_write_1(flash, buf); - } else { - spi_disable_blockprotect(); - /* Erase first */ - printf("Erasing flash before programming... "); - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("done.\n"); - for (i = 0; i < total_size / 256; i++) { - it8716f_spi_page_program(flash, i, buf); - } - } - - return 0; -} diff --git a/jedec.c b/jedec.c deleted file mode 100644 index 83a0b83..0000000 --- a/jedec.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2006 Giampiero Giancipoli - * Copyright (C) 2006 coresystems GmbH - * Copyright (C) 2007 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -#define MAX_REFLASH_TRIES 0x10 - -/* Check one byte for odd parity */ -uint8_t oddparity(uint8_t val) -{ - val = (val ^ (val >> 4)) & 0xf; - val = (val ^ (val >> 2)) & 0x3; - return (val ^ (val >> 1)) & 0x1; -} - -void toggle_ready_jedec(chipaddr dst) -{ - unsigned int i = 0; - uint8_t tmp1, tmp2; - - tmp1 = chip_readb(dst) & 0x40; - - while (i++ < 0xFFFFFFF) { - tmp2 = chip_readb(dst) & 0x40; - if (tmp1 == tmp2) { - break; - } - tmp1 = tmp2; - } -} - -void data_polling_jedec(chipaddr dst, uint8_t data) -{ - unsigned int i = 0; - uint8_t tmp; - - data &= 0x80; - - while (i++ < 0xFFFFFFF) { - tmp = chip_readb(dst) & 0x80; - if (tmp == data) { - break; - } - } -} - -void start_program_jedec(chipaddr bios) -{ - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0xA0, bios + 0x5555); -} - -int probe_jedec(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - uint32_t largeid1, largeid2; - uint32_t flashcontent1, flashcontent2; - int probe_timing_enter, probe_timing_exit; - - if (flash->probe_timing > 0) - probe_timing_enter = probe_timing_exit = flash->probe_timing; - else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */ - probe_timing_enter = probe_timing_exit = 0; - } else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */ - printf_debug("Chip lacks correct probe timing information, " - "using default 10mS/40uS. "); - probe_timing_enter = 10000; - probe_timing_exit = 40; - } else { - printf("Chip has negative value in probe_timing, failing " - "without chip access\n"); - return 0; - } - - /* Issue JEDEC Product ID Entry command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x90, bios + 0x5555); - programmer_delay(probe_timing_enter); - - /* Read product ID */ - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - largeid1 = id1; - largeid2 = id2; - - /* Check if it is a continuation ID, this should be a while loop. */ - if (id1 == 0x7F) { - largeid1 <<= 8; - id1 = chip_readb(bios + 0x100); - largeid1 |= id1; - } - if (id2 == 0x7F) { - largeid2 <<= 8; - id2 = chip_readb(bios + 0x101); - largeid2 |= id2; - } - - /* Issue JEDEC Product ID Exit command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(probe_timing_exit); - - printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2); - if (!oddparity(id1)) - printf_debug(", id1 parity violation"); - - /* Read the product ID location again. We should now see normal flash contents. */ - flashcontent1 = chip_readb(bios); - flashcontent2 = chip_readb(bios + 0x01); - - /* Check if it is a continuation ID, this should be a while loop. */ - if (flashcontent1 == 0x7F) { - flashcontent1 <<= 8; - flashcontent1 |= chip_readb(bios + 0x100); - } - if (flashcontent2 == 0x7F) { - flashcontent2 <<= 8; - flashcontent2 |= chip_readb(bios + 0x101); - } - - if (largeid1 == flashcontent1) - printf_debug(", id1 is normal flash content"); - if (largeid2 == flashcontent2) - printf_debug(", id2 is normal flash content"); - - printf_debug("\n"); - if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id) - return 1; - - return 0; -} - -int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize) -{ - chipaddr bios = flash->virtual_memory; - - /* Issue the Sector Erase command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x80, bios + 0x5555); - programmer_delay(10); - - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x30, bios + page); - programmer_delay(10); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios); - - if (check_erased_range(flash, page, pagesize)) { - fprintf(stderr,"ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int erase_block_jedec(struct flashchip *flash, unsigned int block, unsigned int blocksize) -{ - chipaddr bios = flash->virtual_memory; - - /* Issue the Sector Erase command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x80, bios + 0x5555); - programmer_delay(10); - - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x50, bios + block); - programmer_delay(10); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios); - - if (check_erased_range(flash, block, blocksize)) { - fprintf(stderr,"ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int erase_chip_jedec(struct flashchip *flash) -{ - int total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory; - - /* Issue the JEDEC Chip Erase command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x80, bios + 0x5555); - programmer_delay(10); - - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x10, bios + 0x5555); - programmer_delay(10); - - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, total_size)) { - fprintf(stderr,"ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int write_page_write_jedec(struct flashchip *flash, uint8_t *src, - int start, int page_size) -{ - int i, tried = 0, failed; - uint8_t *s = src; - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios + start; - chipaddr d = dst; - -retry: - /* Issue JEDEC Data Unprotect comand */ - start_program_jedec(bios); - - /* transfer data from source to destination */ - for (i = 0; i < page_size; i++) { - /* If the data is 0xFF, don't program it */ - if (*src != 0xFF) - chip_writeb(*src, dst); - dst++; - src++; - } - - toggle_ready_jedec(dst - 1); - - dst = d; - src = s; - failed = verify_range(flash, src, start, page_size, NULL); - - if (failed && tried++ < MAX_REFLASH_TRIES) { - fprintf(stderr, "retrying.\n"); - goto retry; - } - if (failed) { - fprintf(stderr, " page 0x%lx failed!\n", - (d - bios) / page_size); - } - return failed; -} - -int write_byte_program_jedec(chipaddr bios, uint8_t *src, - chipaddr dst) -{ - int tried = 0, failed = 0; - - /* If the data is 0xFF, don't program it and don't complain. */ - if (*src == 0xFF) { - return 0; - } - -retry: - /* Issue JEDEC Byte Program command */ - start_program_jedec(bios); - - /* transfer data from source to destination */ - chip_writeb(*src, dst); - toggle_ready_jedec(bios); - - if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) { - goto retry; - } - - if (tried >= MAX_REFLASH_TRIES) - failed = 1; - - return failed; -} - -int write_sector_jedec(chipaddr bios, uint8_t *src, - chipaddr dst, unsigned int page_size) -{ - int i, failed = 0; - chipaddr olddst; - - olddst = dst; - for (i = 0; i < page_size; i++) { - if (write_byte_program_jedec(bios, src, dst)) - failed = 1; - dst++, src++; - } - if (failed) - fprintf(stderr, " writing sector at 0x%lx failed!\n", olddst); - - return failed; -} - -int write_jedec(struct flashchip *flash, uint8_t *buf) -{ - int i, failed = 0; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - - if (erase_chip_jedec(flash)) { - fprintf(stderr,"ERASE FAILED!\n"); - return -1; - } - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - printf("%04d at address: 0x%08x", i, i * page_size); - if (write_page_write_jedec(flash, buf + i * page_size, - i * page_size, page_size)) - failed = 1; - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - return failed; -} - -int write_jedec_1(struct flashchip *flash, uint8_t * buf) -{ - int i; - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios; - - programmer_delay(10); - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - printf("Programming page: "); - for (i = 0; i < flash->total_size; i++) { - if ((i & 0x3) == 0) - printf("address: 0x%08lx", (unsigned long)i * 1024); - - write_sector_jedec(bios, buf + i * 1024, dst + i * 1024, 1024); - - if ((i & 0x3) == 0) - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - - printf("\n"); - return 0; -} diff --git a/layout.c b/layout.c deleted file mode 100644 index c432ebe..0000000 --- a/layout.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2005-2008 coresystems GmbH - * (Written by Stefan Reinauer for coresystems GmbH) - * - * 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 "flash.h" - -char *mainboard_vendor = NULL; -char *mainboard_part = NULL; -int romimages = 0; - -#define MAX_ROMLAYOUT 16 - -typedef struct { - unsigned int start; - unsigned int end; - unsigned int included; - char name[256]; -} romlayout_t; - -romlayout_t rom_entries[MAX_ROMLAYOUT]; - -static char *def_name = "DEFAULT"; - -int show_id(uint8_t *bios, int size, int force) -{ - unsigned int *walk; - unsigned int mb_part_offset, mb_vendor_offset; - char *mb_part, *mb_vendor; - - mainboard_vendor = def_name; - mainboard_part = def_name; - - walk = (unsigned int *)(bios + size - 0x10); - walk--; - - if ((*walk) == 0 || ((*walk) & 0x3ff) != 0) { - /* We might have an NVIDIA chipset BIOS which stores the ID - * information at a different location. - */ - walk = (unsigned int *)(bios + size - 0x80); - walk--; - } - - /* - * Check if coreboot last image size is 0 or not a multiple of 1k or - * bigger than the chip or if the pointers to vendor ID or mainboard ID - * are outside the image of if the start of ID strings are nonsensical - * (nonprintable and not \0). - */ - mb_part_offset = *(walk - 1); - mb_vendor_offset = *(walk - 2); - if ((*walk) == 0 || ((*walk) & 0x3ff) != 0 || (*walk) > size || - mb_part_offset > size || mb_vendor_offset > size) { - printf("Flash image seems to be a legacy BIOS. Disabling checks.\n"); - return 0; - } - - mb_part = (char *)(bios + size - mb_part_offset); - mb_vendor = (char *)(bios + size - mb_vendor_offset); - if (!isprint((unsigned char)*mb_part) || - !isprint((unsigned char)*mb_vendor)) { - printf("Flash image seems to have garbage in the ID location." - " Disabling checks.\n"); - return 0; - } - - printf_debug("coreboot last image size " - "(not ROM size) is %d bytes.\n", *walk); - - mainboard_part = strdup(mb_part); - mainboard_vendor = strdup(mb_vendor); - printf_debug("Manufacturer: %s\n", mainboard_vendor); - printf_debug("Mainboard ID: %s\n", mainboard_part); - - /* - * If lb_vendor is not set, the coreboot table was - * not found. Nor was -m VENDOR:PART specified. - */ - if (!lb_vendor || !lb_part) { - printf("Note: If the following flash access fails, " - "try -m :.\n"); - return 0; - } - - /* These comparisons are case insensitive to make things - * a little less user^Werror prone. - */ - if (!strcasecmp(mainboard_vendor, lb_vendor) && - !strcasecmp(mainboard_part, lb_part)) { - printf_debug("This firmware image matches this mainboard.\n"); - } else { - if (force) { - printf("WARNING: This firmware image does not " - "seem to fit to this machine - forcing it.\n"); - } else { - printf("ERROR: Your firmware image (%s:%s) does not " - "appear to\n be correct for the detected " - "mainboard (%s:%s)\n\nOverride with --force if you " - "are absolutely sure that you\nare using a correct " - "image for this mainboard or override\nthe detected " - "values with --mainboard :.\n\n", - mainboard_vendor, mainboard_part, lb_vendor, - lb_part); - exit(1); - } - } - - return 0; -} - -int read_romlayout(char *name) -{ - FILE *romlayout; - char tempstr[256]; - int i; - - romlayout = fopen(name, "r"); - - if (!romlayout) { - fprintf(stderr, "ERROR: Could not open ROM layout (%s).\n", - name); - return -1; - } - - while (!feof(romlayout)) { - char *tstr1, *tstr2; - if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name)) - continue; -#if 0 - // fscanf does not like arbitrary comments like that :( later - if (tempstr[0] == '#') { - continue; - } -#endif - tstr1 = strtok(tempstr, ":"); - tstr2 = strtok(NULL, ":"); - if (!tstr1 || !tstr2) { - fprintf(stderr, "Error parsing layout file.\n"); - fclose(romlayout); - return 1; - } - rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16); - rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16); - rom_entries[romimages].included = 0; - romimages++; - } - - for (i = 0; i < romimages; i++) { - printf_debug("romlayout %08x - %08x named %s\n", - rom_entries[i].start, - rom_entries[i].end, rom_entries[i].name); - } - - fclose(romlayout); - - return 0; -} - -int find_romentry(char *name) -{ - int i; - - if (!romimages) - return -1; - - printf("Looking for \"%s\"... ", name); - - for (i = 0; i < romimages; i++) { - if (!strcmp(rom_entries[i].name, name)) { - rom_entries[i].included = 1; - printf("found.\n"); - return i; - } - } - printf("not found.\n"); // Not found. Error. - - return -1; -} - -int handle_romentries(uint8_t *buffer, struct flashchip *flash) -{ - int i; - - // This function does not save flash write cycles. - // - // Also it does not cope with overlapping rom layout - // sections. - // example: - // 00000000:00008fff gfxrom - // 00009000:0003ffff normal - // 00040000:0007ffff fallback - // 00000000:0007ffff all - // - // If you'd specify -i all the included flag of all other - // sections is still 0, so no changes will be made to the - // flash. Same thing if you specify -i normal -i all only - // normal will be updated and the rest will be kept. - - for (i = 0; i < romimages; i++) { - - if (rom_entries[i].included) - continue; - - flash->read(flash, buffer + rom_entries[i].start, - rom_entries[i].start, - rom_entries[i].end - rom_entries[i].start + 1); - } - - return 0; -} diff --git a/libflashrom/82802ab.c b/libflashrom/82802ab.c new file mode 100644 index 0000000..58d3467 --- /dev/null +++ b/libflashrom/82802ab.c @@ -0,0 +1,196 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Datasheet: + * - Name: Intel 82802AB/82802AC Firmware Hub (FWH) + * - URL: http://www.intel.com/design/chipsets/datashts/290658.htm + * - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf + * - Order number: 290658-004 + */ + +#include +#include +#include "flash.h" + +// I need that Berkeley bit-map printer +void print_82802ab_status(uint8_t status) +{ + printf_debug("%s", status & 0x80 ? "Ready:" : "Busy:"); + printf_debug("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); + printf_debug("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); + printf_debug("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); + printf_debug("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); + printf_debug("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); + printf_debug("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); +} + +int probe_82802ab(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + /* Reset to get a clean state */ + chip_writeb(0xFF, bios); + programmer_delay(10); + + /* Enter ID mode */ + chip_writeb(0x90, bios); + programmer_delay(10); + + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + + /* Leave ID mode */ + chip_writeb(0xFF, bios); + + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (id1 != flash->manufacture_id || id2 != flash->model_id) + return 0; + + map_flash_registers(flash); + + return 1; +} + +uint8_t wait_82802ab(chipaddr bios) +{ + uint8_t status; + + chip_writeb(0x70, bios); + if ((chip_readb(bios) & 0x80) == 0) { // it's busy + while ((chip_readb(bios) & 0x80) == 0) ; + } + + status = chip_readb(bios); + + /* Reset to get a clean state */ + chip_writeb(0xFF, bios); + + return status; +} + +int erase_82802ab_block(struct flashchip *flash, int offset) +{ + chipaddr bios = flash->virtual_memory + offset; + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t status; + + // clear status register + chip_writeb(0x50, bios); + + // clear write protect + chip_writeb(0, wrprotect); + + // now start it + chip_writeb(0x20, bios); + chip_writeb(0xd0, bios); + programmer_delay(10); + + // now let's see what the register is + status = wait_82802ab(flash->virtual_memory); + print_82802ab_status(status); + + if (check_erased_range(flash, offset, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("DONE BLOCK 0x%x\n", offset); + + return 0; +} + +int erase_82802ab(struct flashchip *flash) +{ + int i; + unsigned int total_size = flash->total_size * 1024; + + printf("total_size is %d; flash->page_size is %d\n", + total_size, flash->page_size); + for (i = 0; i < total_size; i += flash->page_size) + if (erase_82802ab_block(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("DONE ERASE\n"); + + return 0; +} + +void write_page_82802ab(chipaddr bios, uint8_t *src, + chipaddr dst, int page_size) +{ + int i; + + for (i = 0; i < page_size; i++) { + /* transfer data from source to destination */ + chip_writeb(0x40, dst); + chip_writeb(*src++, dst++); + wait_82802ab(bios); + } +} + +int write_82802ab(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + uint8_t *tmpbuf = malloc(page_size); + + if (!tmpbuf) { + printf("Could not allocate memory!\n"); + exit(1); + } + printf("Programming page: \n"); + for (i = 0; i < total_size / page_size; i++) { + printf + ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%04d at address: 0x%08x", i, i * page_size); + + /* Auto Skip Blocks, which already contain the desired data + * Faster, because we only write, what has changed + * More secure, because blocks, which are excluded + * (with the exclude or layout feature) + * or not erased and rewritten; their data is retained also in + * sudden power off situations + */ + chip_readn(tmpbuf, bios + i * page_size, page_size); + if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) { + printf("SKIPPED\n"); + continue; + } + + /* erase block by block and write block by block; this is the most secure way */ + if (erase_82802ab_block(flash, i * page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_82802ab(bios, buf + i * page_size, + bios + i * page_size, page_size); + } + printf("\n"); + free(tmpbuf); + + return 0; +} diff --git a/libflashrom/am29f040b.c b/libflashrom/am29f040b.c new file mode 100644 index 0000000..46a5ef4 --- /dev/null +++ b/libflashrom/am29f040b.c @@ -0,0 +1,144 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +/* FIMXE: check that the 2 second delay is really needed. + Use erase_sector_jedec if not? */ +static int erase_sector_29f040b(struct flashchip *flash, unsigned long address) +{ + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x80, bios + 0x555); + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x30, bios + address); + + programmer_delay(2 * 1000 * 1000); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios + address); + + if (check_erased_range(flash, address, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +/* FIXME: use write_sector_jedec? */ +static int write_sector_29f040b(chipaddr bios, uint8_t *src, chipaddr dst, + unsigned int page_size) +{ + int i; + + for (i = 0; i < page_size; i++) { + if ((i & 0xfff) == 0xfff) + printf("0x%08lx", dst - bios); + + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0xA0, bios + 0x555); + chip_writeb(*src++, dst++); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios); + + if ((i & 0xfff) == 0xfff) + printf("\b\b\b\b\b\b\b\b\b\b"); + } + + return 0; +} + +int probe_29f040b(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x90, bios + 0x555); + + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + + chip_writeb(0xF0, bios); + + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} + +/* FIXME: use erase_chip_jedec? */ +int erase_29f040b(struct flashchip *flash) +{ + int total_size = flash->total_size * 1024; + chipaddr bios = flash->virtual_memory; + + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x80, bios + 0x555); + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x10, bios + 0x555); + + programmer_delay(10); + toggle_ready_jedec(bios); + + if (check_erased_range(flash, 0, total_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int write_29f040b(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + printf("Programming page "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page before programming */ + if (erase_sector_29f040b(flash, i * page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* write to the sector */ + printf("%04d at address: ", i); + write_sector_29f040b(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/bitbang_spi.c b/libflashrom/bitbang_spi.c new file mode 100644 index 0000000..abf5530 --- /dev/null +++ b/libflashrom/bitbang_spi.c @@ -0,0 +1,164 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 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 "flash.h" +#include "spi.h" + +/* Length of half a clock period in usecs */ +int bitbang_spi_half_period = 0; + +enum bitbang_spi_master bitbang_spi_master = BITBANG_SPI_INVALID; + +const struct bitbang_spi_master_entry bitbang_spi_master_table[] = { + {}, /* This entry corresponds to BITBANG_SPI_INVALID. */ +}; + +const int bitbang_spi_master_count = ARRAY_SIZE(bitbang_spi_master_table); + +void bitbang_spi_set_cs(int val) +{ + bitbang_spi_master_table[bitbang_spi_master].set_cs(val); +} + +void bitbang_spi_set_sck(int val) +{ + bitbang_spi_master_table[bitbang_spi_master].set_sck(val); +} + +void bitbang_spi_set_mosi(int val) +{ + bitbang_spi_master_table[bitbang_spi_master].set_mosi(val); +} + +int bitbang_spi_get_miso(void) +{ + return bitbang_spi_master_table[bitbang_spi_master].get_miso(); +} + +int bitbang_spi_init(void) +{ + bitbang_spi_set_cs(1); + bitbang_spi_set_sck(0); + buses_supported = CHIP_BUSTYPE_SPI; + return 0; +} + +uint8_t bitbang_spi_readwrite_byte(uint8_t val) +{ + uint8_t ret = 0; + int i; + + for (i = 7; i >= 0; i--) { + bitbang_spi_set_mosi((val >> i) & 1); + programmer_delay(bitbang_spi_half_period); + bitbang_spi_set_sck(1); + ret <<= 1; + ret |= bitbang_spi_get_miso(); + programmer_delay(bitbang_spi_half_period); + bitbang_spi_set_sck(0); + } + return ret; +} + +int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + static unsigned char *bufout = NULL; + static unsigned char *bufin = NULL; + static int oldbufsize = 0; + int bufsize; + int i; + + /* Arbitrary size limitation here. We're only constrained by memory. */ + if (writecnt > 65536 || readcnt > 65536) + return SPI_INVALID_LENGTH; + + bufsize = max(writecnt + readcnt, 260); + /* Never shrink. realloc() calls are expensive. */ + if (bufsize > oldbufsize) { + bufout = realloc(bufout, bufsize); + if (!bufout) { + fprintf(stderr, "Out of memory!\n"); + if (bufin) + free(bufin); + exit(1); + } + bufin = realloc(bufout, bufsize); + if (!bufin) { + fprintf(stderr, "Out of memory!\n"); + if (bufout) + free(bufout); + exit(1); + } + oldbufsize = bufsize; + } + + memcpy(bufout, writearr, writecnt); + /* Shift out 0x00 while reading data. */ + memset(bufout + writecnt, 0x00, readcnt); + /* Make sure any non-read data is 0xff. */ + memset(bufin + writecnt, 0xff, readcnt); + + bitbang_spi_set_cs(0); + for (i = 0; i < readcnt + writecnt; i++) { + bufin[i] = bitbang_spi_readwrite_byte(bufout[i]); + } + programmer_delay(bitbang_spi_half_period); + bitbang_spi_set_cs(1); + programmer_delay(bitbang_spi_half_period); + memcpy(readarr, bufin + writecnt, readcnt); + + return 0; +} + +int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* Maximum read length is unlimited, use 64k bytes. */ + return spi_read_chunked(flash, buf, start, len, 64 * 1024); +} + +int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i; + + printf_debug("total_size is %d\n", total_size); + for (i = 0; i < total_size; i += 256) { + int l, r; + if (i + 256 <= total_size) + l = 256; + else + l = total_size - i; + + if ((r = spi_nbyte_program(i, &buf[i], l))) { + fprintf(stderr, "%s: write fail %d\n", __func__, r); + return 1; + } + + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + /* loop */; + } + + return 0; +} diff --git a/libflashrom/board_enable.c b/libflashrom/board_enable.c new file mode 100644 index 0000000..769b402 --- /dev/null +++ b/libflashrom/board_enable.c @@ -0,0 +1,1326 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2005-2007 coresystems GmbH + * Copyright (C) 2006 Uwe Hermann + * Copyright (C) 2007-2009 Luc Verhaegen + * Copyright (C) 2007 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 + */ + +/* + * Contains the board specific flash enables. + */ + +#include +#include +#include "flash.h" + +/* + * Helper functions for many Winbond Super I/Os of the W836xx range. + */ +/* Enter extended functions */ +void w836xx_ext_enter(uint16_t port) +{ + OUTB(0x87, port); + OUTB(0x87, port); +} + +/* Leave extended functions */ +void w836xx_ext_leave(uint16_t port) +{ + OUTB(0xAA, port); +} + +/* Generic Super I/O helper functions */ +uint8_t sio_read(uint16_t port, uint8_t reg) +{ + OUTB(reg, port); + return INB(port + 1); +} + +void sio_write(uint16_t port, uint8_t reg, uint8_t data) +{ + OUTB(reg, port); + OUTB(data, port + 1); +} + +void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask) +{ + uint8_t tmp; + + OUTB(reg, port); + tmp = INB(port + 1) & ~mask; + OUTB(tmp | (data & mask), port + 1); +} + +/** + * Winbond W83627HF: Raise GPIO24. + * + * Suited for: + * - Agami Aruma + * - IWILL DK8-HTX + */ +static int w83627hf_gpio24_raise(uint16_t port, const char *name) +{ + w836xx_ext_enter(port); + + /* Is this the W83627HF? */ + if (sio_read(port, 0x20) != 0x52) { /* Super I/O device ID reg. */ + fprintf(stderr, "\nERROR: %s: W83627HF: Wrong ID: 0x%02X.\n", + name, sio_read(port, 0x20)); + w836xx_ext_leave(port); + return -1; + } + + /* PIN89S: WDTO/GP24 multiplex -> GPIO24 */ + sio_mask(port, 0x2B, 0x10, 0x10); + + /* Select logical device 8: GPIO port 2 */ + sio_write(port, 0x07, 0x08); + + sio_mask(port, 0x30, 0x01, 0x01); /* Activate logical device. */ + sio_mask(port, 0xF0, 0x00, 0x10); /* GPIO24 -> output */ + sio_mask(port, 0xF2, 0x00, 0x10); /* Clear GPIO24 inversion */ + sio_mask(port, 0xF1, 0x10, 0x10); /* Raise GPIO24 */ + + w836xx_ext_leave(port); + + return 0; +} + +static int w83627hf_gpio24_raise_2e(const char *name) +{ + return w83627hf_gpio24_raise(0x2e, name); +} + +/** + * Winbond W83627THF: GPIO 4, bit 4 + * + * Suited for: + * - MSI K8T Neo2-F + * - MSI K8N-NEO3 + */ +static int w83627thf_gpio4_4_raise(uint16_t port, const char *name) +{ + w836xx_ext_enter(port); + + /* Is this the W83627THF? */ + if (sio_read(port, 0x20) != 0x82) { /* Super I/O device ID reg. */ + fprintf(stderr, "\nERROR: %s: W83627THF: Wrong ID: 0x%02X.\n", + name, sio_read(port, 0x20)); + w836xx_ext_leave(port); + return -1; + } + + /* PINxxxxS: GPIO4/bit 4 multiplex -> GPIOXXX */ + + sio_write(port, 0x07, 0x09); /* Select LDN 9: GPIO port 4 */ + sio_mask(port, 0x30, 0x02, 0x02); /* Activate logical device. */ + sio_mask(port, 0xF4, 0x00, 0x10); /* GPIO4 bit 4 -> output */ + sio_mask(port, 0xF6, 0x00, 0x10); /* Clear GPIO4 bit 4 inversion */ + sio_mask(port, 0xF5, 0x10, 0x10); /* Raise GPIO4 bit 4 */ + + w836xx_ext_leave(port); + + return 0; +} + +static int w83627thf_gpio4_4_raise_2e(const char *name) +{ + return w83627thf_gpio4_4_raise(0x2e, name); +} + +static int w83627thf_gpio4_4_raise_4e(const char *name) +{ + return w83627thf_gpio4_4_raise(0x4e, name); +} + +/** + * w83627: Enable MEMW# and set ROM size to max. + */ +static void w836xx_memw_enable(uint16_t port) +{ + w836xx_ext_enter(port); + if (!(sio_read(port, 0x24) & 0x02)) { /* Flash ROM enabled? */ + /* Enable MEMW# and set ROM size select to max. (4M). */ + sio_mask(port, 0x24, 0x28, 0x28); + } + w836xx_ext_leave(port); +} + +/** + * Common routine for several VT823x based boards. + */ +static void vt823x_set_all_writes_to_lpc(struct pci_dev *dev) +{ + uint8_t val; + + /* All memory cycles, not just ROM ones, go to LPC. */ + val = pci_read_byte(dev, 0x59); + val &= ~0x80; + pci_write_byte(dev, 0x59, val); +} + +/** + * VT823x: Set one of the GPIO pins. + */ +static void vt823x_gpio_set(struct pci_dev *dev, uint8_t gpio, int raise) +{ + uint16_t base; + uint8_t val, bit, offset; + + if ((gpio >= 12) && (gpio <= 15)) { + /* GPIO12-15 -> output */ + val = pci_read_byte(dev, 0xE4); + val |= 0x10; + pci_write_byte(dev, 0xE4, val); + } else if (gpio == 9) { + /* GPIO9 -> Output */ + val = pci_read_byte(dev, 0xE4); + val |= 0x20; + pci_write_byte(dev, 0xE4, val); + } else if (gpio == 5) { + val = pci_read_byte(dev, 0xE4); + val |= 0x01; + pci_write_byte(dev, 0xE4, val); + } else { + fprintf(stderr, "\nERROR: " + "VT823x GPIO%02d is not implemented.\n", gpio); + return; + } + + /* We need the I/O Base Address for this board's flash enable. */ + base = pci_read_word(dev, 0x88) & 0xff80; + + offset = 0x4C + gpio / 8; + bit = 0x01 << (gpio % 8); + + val = INB(base + offset); + if (raise) + val |= bit; + else + val &= ~bit; + OUTB(val, base + offset); +} + +/** + * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs. + * + * We don't need to do this when using coreboot, GPIO15 is never lowered there. + */ +static int board_via_epia_m(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n"); + return -1; + } + + /* GPIO15 is connected to write protect. */ + vt823x_gpio_set(dev, 15, 1); + + return 0; +} + +/** + * Suited for: + * - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235 + * - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237. + */ +static int board_asus_a7v8x_mx(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ + if (!dev) + dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); + return -1; + } + + vt823x_set_all_writes_to_lpc(dev); + w836xx_memw_enable(0x2E); + + return 0; +} + +/** + * Suited for VIAs EPIA SP and EPIA CN. + */ +static int board_via_epia_sp(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3227); /* VT8237R ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n"); + return -1; + } + + vt823x_set_all_writes_to_lpc(dev); + + return 0; +} + +/** + * Suited for VIAs EPIA N & NL. + */ +static int board_via_epia_n(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3227); /* VT8237R ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n"); + return -1; + } + + /* All memory cycles, not just ROM ones, go to LPC */ + vt823x_set_all_writes_to_lpc(dev); + + /* GPIO9 -> output */ + vt823x_gpio_set(dev, 9, 1); + + return 0; +} + +/** + * Suited for: + * - EPoX EP-8K5A2: VIA KT333 + VT8235. + * - Albatron PM266A Pro: VIA P4M266A + VT8235. + * - Shuttle AK31 (all versions): VIA KT266 + VT8233. + */ +static int w836xx_memw_enable_2e(const char *name) +{ + w836xx_memw_enable(0x2E); + + return 0; +} + +/** + * Suited for ASUS P5A. + * + * This is rather nasty code, but there's no way to do this cleanly. + * We're basically talking to some unknown device on SMBus, my guess + * is that it is the Winbond W83781D that lives near the DIP BIOS. + */ +static int board_asus_p5a(const char *name) +{ + uint8_t tmp; + int i; + +#define ASUSP5A_LOOP 5000 + + OUTB(0x00, 0xE807); + OUTB(0xEF, 0xE803); + + OUTB(0xFF, 0xE800); + + for (i = 0; i < ASUSP5A_LOOP; i++) { + OUTB(0xE1, 0xFF); + if (INB(0xE800) & 0x04) + break; + } + + if (i == ASUSP5A_LOOP) { + printf("%s: Unable to contact device.\n", name); + return -1; + } + + OUTB(0x20, 0xE801); + OUTB(0x20, 0xE1); + + OUTB(0xFF, 0xE802); + + for (i = 0; i < ASUSP5A_LOOP; i++) { + tmp = INB(0xE800); + if (tmp & 0x70) + break; + } + + if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) { + printf("%s: failed to read device.\n", name); + return -1; + } + + tmp = INB(0xE804); + tmp &= ~0x02; + + OUTB(0x00, 0xE807); + OUTB(0xEE, 0xE803); + + OUTB(tmp, 0xE804); + + OUTB(0xFF, 0xE800); + OUTB(0xE1, 0xFF); + + OUTB(0x20, 0xE801); + OUTB(0x20, 0xE1); + + OUTB(0xFF, 0xE802); + + for (i = 0; i < ASUSP5A_LOOP; i++) { + tmp = INB(0xE800); + if (tmp & 0x70) + break; + } + + if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) { + printf("%s: failed to write to device.\n", name); + return -1; + } + + return 0; +} + +/* + * Set GPIO lines in the Broadcom HT-1000 southbridge. + * + * It's not a Super I/O but it uses the same index/data port method. + */ +static int board_hp_dl145_g3_enable(const char *name) +{ + /* GPIO 0 reg from PM regs */ + /* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */ + sio_mask(0xcd6, 0x44, 0x24, 0x24); + + return 0; +} + +static int board_ibm_x3455(const char *name) +{ + /* raise gpio13 */ + sio_mask(0xcd6, 0x45, 0x20, 0x20); + + return 0; +} + +/** + * Suited for Shuttle FN25 (SN25P): AMD S939 + Nvidia CK804 (nForce4). + */ +static int board_shuttle_fn25(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x10DE, 0x0050); /* NVIDIA CK804 ISA Bridge. */ + if (!dev) { + fprintf(stderr, + "\nERROR: NVIDIA nForce4 ISA bridge not found.\n"); + return -1; + } + + /* one of those bits seems to be connected to TBL#, but -ENOINFO. */ + pci_write_byte(dev, 0x92, 0); + + return 0; +} + +/** + * Very similar to AMD 8111 IO Hub. + */ +static int nvidia_mcp_gpio_set(int gpio, int raise) +{ + struct pci_dev *dev; + uint16_t base; + uint8_t tmp; + + if ((gpio < 0) || (gpio > 31)) { + fprintf(stderr, "\nERROR: unsupported GPIO: %d.\n", gpio); + return -1; + } + + dev = pci_dev_find_vendorclass(0x10DE, 0x0C05); + switch (dev->device_id) { + case 0x0030: /* CK804 */ + case 0x0050: /* MCP04 */ + case 0x0060: /* MCP2 */ + break; + default: + fprintf(stderr, "\nERROR: no nVidia SMBus controller found.\n"); + return -1; + } + + base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */ + base += 0xC0; + + tmp = INB(base + gpio); + tmp &= ~0x0F; /* null lower nibble */ + tmp |= 0x04; /* gpio -> output. */ + if (raise) + tmp |= 0x01; + OUTB(tmp, base + gpio); + + return 0; +} + +/** + * Suited for ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04. + */ +static int nvidia_mcp_gpio10_raise(const char *name) +{ + return nvidia_mcp_gpio_set(0x10, 1); +} + +/** + * Suited for the Gigabyte GA-K8N-SLI: CK804 southbridge. + */ +static int nvidia_mcp_gpio21_raise(const char *name) +{ + return nvidia_mcp_gpio_set(0x21, 0x01); +} + +/** + * Suited for EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2. + */ +static int nvidia_mcp_gpio31_raise(const char *name) +{ + return nvidia_mcp_gpio_set(0x31, 0x01); +} + +/** + * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards. + */ +static int board_epox_ep_bx3(const char *name) +{ + uint8_t tmp; + + /* Raise GPIO22. */ + tmp = INB(0x4036); + OUTB(tmp, 0xEB); + + tmp |= 0x40; + + OUTB(tmp, 0x4036); + OUTB(tmp, 0xEB); + + return 0; +} + +/** + * Suited for Artec Group DBE61 and DBE62. + */ +static int board_artecgroup_dbe6x(const char *name) +{ +#define DBE6x_MSR_DIVIL_BALL_OPTS 0x51400015 +#define DBE6x_PRI_BOOT_LOC_SHIFT (2) +#define DBE6x_BOOT_OP_LATCHED_SHIFT (8) +#define DBE6x_SEC_BOOT_LOC_SHIFT (10) +#define DBE6x_PRI_BOOT_LOC (3 << DBE6x_PRI_BOOT_LOC_SHIFT) +#define DBE6x_BOOT_OP_LATCHED (3 << DBE6x_BOOT_OP_LATCHED_SHIFT) +#define DBE6x_SEC_BOOT_LOC (3 << DBE6x_SEC_BOOT_LOC_SHIFT) +#define DBE6x_BOOT_LOC_FLASH (2) +#define DBE6x_BOOT_LOC_FWHUB (3) + + msr_t msr; + unsigned long boot_loc; + + /* Geode only has a single core */ + if (setup_cpu_msr(0)) + return -1; + + msr = rdmsr(DBE6x_MSR_DIVIL_BALL_OPTS); + + if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) == + (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT)) + boot_loc = DBE6x_BOOT_LOC_FWHUB; + else + boot_loc = DBE6x_BOOT_LOC_FLASH; + + msr.lo &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC); + msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) | + (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT)); + + wrmsr(DBE6x_MSR_DIVIL_BALL_OPTS, msr); + + cleanup_cpu_msr(); + + return 0; +} + +/** + * Set a GPIO line on a given intel ICH LPC controller. + */ +static int intel_ich_gpio_set(int gpio, int raise) +{ + /* table mapping the different intel ICH LPC chipsets. */ + static struct { + uint16_t id; + uint8_t base_reg; + uint32_t bank0; + uint32_t bank1; + uint32_t bank2; + } intel_ich_gpio_table[] = { + {0x2410, 0x58, 0x0FE30000, 0, 0}, /* 82801AA (ICH) */ + {0x2420, 0x58, 0x0FE30000, 0, 0}, /* 82801AB (ICH0) */ + {0x2440, 0x58, 0x1BFF391B, 0, 0}, /* 82801BA (ICH2) */ + {0x244C, 0x58, 0x1A23399B, 0, 0}, /* 82801BAM (ICH2M) */ + {0x2450, 0x58, 0x1BFF0000, 0, 0}, /* 82801E (C-ICH) */ + {0x2480, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801CA (ICH3-S) */ + {0x248C, 0x58, 0x1A230000, 0x00000FFF, 0}, /* 82801CAM (ICH3-M) */ + {0x24C0, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801DB/DBL (ICH4/ICH4-L) */ + {0x24CC, 0x58, 0x1A030000, 0x00000FFF, 0}, /* 82801DBM (ICH4-M) */ + {0x24D0, 0x58, 0x1BFF0000, 0x00030305, 0}, /* 82801EB/ER (ICH5/ICH5R) */ + {0x2640, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FB/FR (ICH6/ICH6R) */ + {0x2641, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FBM (ICH6M) */ + {0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GB/GR (ICH7 Family) */ + {0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GBM (ICH7-M) */ + {0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GHM (ICH7-M DH) */ + {0x2810, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HB/HR (ICH8/R) */ + {0x2811, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HBM (ICH8M-E) */ + {0x2812, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HH (ICH8DH) */ + {0x2814, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HO (ICH8DO) */ + {0x2815, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HEM (ICH8M) */ + {0x2912, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IH (ICH9DH) */ + {0x2914, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IO (ICH9DO) */ + {0x2916, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IR (ICH9R) */ + {0x2917, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IEM (ICH9M-E) */ + {0x2918, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IB (ICH9) */ + {0x2919, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IBM (ICH9M) */ + {0x3A14, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JDO (ICH10DO) */ + {0x3A16, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIR (ICH10R) */ + {0x3A18, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIB (ICH10) */ + {0x3A1A, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JD (ICH10D) */ + {0, 0, 0, 0, 0} /* end marker */ + }; + + struct pci_dev *dev; + uint16_t base; + uint32_t tmp; + int i, allowed; + + /* First, look for a known LPC bridge */ + for (dev = pacc->devices; dev; dev = dev->next) + if ((dev->vendor_id == 0x8086) && + (dev->device_class == 0x0601)) { /* ISA Bridge */ + /* Is this device in our list? */ + for (i = 0; intel_ich_gpio_table[i].id; i++) + if (dev->device_id == intel_ich_gpio_table[i].id) + break; + + if (intel_ich_gpio_table[i].id) + break; + } + + if (!dev) { + fprintf(stderr, "\nERROR: No Known Intel LPC Bridge found.\n"); + return -1; + } + + /* According to the datasheets, all intel ICHs have the gpio bar 5:1 + strapped to zero. From some mobile ich9 version on, this becomes + 6:1. The mask below catches all. */ + base = pci_read_word(dev, intel_ich_gpio_table[i].base_reg) & 0xFFC0; + + /* check whether the line is allowed */ + if (gpio < 32) + allowed = (intel_ich_gpio_table[i].bank0 >> gpio) & 0x01; + else if (gpio < 64) + allowed = (intel_ich_gpio_table[i].bank1 >> (gpio - 32)) & 0x01; + else + allowed = (intel_ich_gpio_table[i].bank2 >> (gpio - 64)) & 0x01; + + if (!allowed) { + fprintf(stderr, "\nERROR: This Intel LPC Bridge does not allow" + " setting GPIO%02d\n", gpio); + return -1; + } + + printf("\nIntel ICH LPC Bridge: %sing GPIO%02d.\n", + raise ? "Rais" : "Dropp", gpio); + + if (gpio < 32) { + /* Set line to GPIO */ + tmp = INL(base); + /* ICH/ICH0 multiplexes 27/28 on the line set. */ + if ((gpio == 28) && + ((dev->device_id == 0x2410) || (dev->device_id == 0x2420))) + tmp |= 1 << 27; + else + tmp |= 1 << gpio; + OUTL(tmp, base); + + /* As soon as we are talking to ICH8 and above, this register + decides whether we can set the gpio or not. */ + if (dev->device_id > 0x2800) { + tmp = INL(base); + if (!(tmp & (1 << gpio))) { + fprintf(stderr, "\nERROR: This Intel LPC Bridge" + " does not allow setting GPIO%02d\n", + gpio); + return -1; + } + } + + /* Set GPIO to OUTPUT */ + tmp = INL(base + 0x04); + tmp &= ~(1 << gpio); + OUTL(tmp, base + 0x04); + + /* Raise GPIO line */ + tmp = INL(base + 0x0C); + if (raise) + tmp |= 1 << gpio; + else + tmp &= ~(1 << gpio); + OUTL(tmp, base + 0x0C); + } else if (gpio < 64) { + gpio -= 32; + + /* Set line to GPIO */ + tmp = INL(base + 0x30); + tmp |= 1 << gpio; + OUTL(tmp, base + 0x30); + + /* As soon as we are talking to ICH8 and above, this register + decides whether we can set the gpio or not. */ + if (dev->device_id > 0x2800) { + tmp = INL(base + 30); + if (!(tmp & (1 << gpio))) { + fprintf(stderr, "\nERROR: This Intel LPC Bridge" + " does not allow setting GPIO%02d\n", + gpio + 32); + return -1; + } + } + + /* Set GPIO to OUTPUT */ + tmp = INL(base + 0x34); + tmp &= ~(1 << gpio); + OUTL(tmp, base + 0x34); + + /* Raise GPIO line */ + tmp = INL(base + 0x38); + if (raise) + tmp |= 1 << gpio; + else + tmp &= ~(1 << gpio); + OUTL(tmp, base + 0x38); + } else { + gpio -= 64; + + /* Set line to GPIO */ + tmp = INL(base + 0x40); + tmp |= 1 << gpio; + OUTL(tmp, base + 0x40); + + tmp = INL(base + 40); + if (!(tmp & (1 << gpio))) { + fprintf(stderr, "\nERROR: This Intel LPC Bridge does " + "not allow setting GPIO%02d\n", gpio + 64); + return -1; + } + + /* Set GPIO to OUTPUT */ + tmp = INL(base + 0x44); + tmp &= ~(1 << gpio); + OUTL(tmp, base + 0x44); + + /* Raise GPIO line */ + tmp = INL(base + 0x48); + if (raise) + tmp |= 1 << gpio; + else + tmp &= ~(1 << gpio); + OUTL(tmp, base + 0x48); + } + + return 0; +} + +/** + * Suited for Abit IP35: Intel P35 + ICH9R. + */ +static int intel_ich_gpio16_raise(const char *name) +{ + return intel_ich_gpio_set(16, 1); +} + +/** + * Suited for MSI MS-7046: LGA775 + 915P + ICH6. + */ +static int intel_ich_gpio19_raise(const char *name) +{ + return intel_ich_gpio_set(19, 1); +} + +/** + * Suited for: + * - Asus P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2. + * - Asus P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R. + */ +static int intel_ich_gpio21_raise(const char *name) +{ + return intel_ich_gpio_set(21, 1); +} + +/** + * Suited for ASUS P4B266: socket478 + intel 845D + ICH2. + */ +static int intel_ich_gpio22_raise(const char *name) +{ + return intel_ich_gpio_set(22, 1); +} + +/** + * Suited for: + * - Dell Poweredge 1850: Intel PPGA604 + E7520 + ICH5R. + * - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R. + */ +static int intel_ich_gpio23_raise(const char *name) +{ + return intel_ich_gpio_set(23, 1); +} + +/** + * Suited for Acorp 6A815EPD: socket 370 + intel 815 + ICH2. + */ +static int board_acorp_6a815epd(const char *name) +{ + int ret; + + /* Lower Blocks Lock -- pin 7 of PLCC32 */ + ret = intel_ich_gpio_set(22, 1); + if (!ret) /* Top Block Lock -- pin 8 of PLCC32 */ + ret = intel_ich_gpio_set(23, 1); + + return ret; +} + +/** + * Suited for Kontron 986LCD-M: socket478 + 915GM + ICH7R. + */ +static int board_kontron_986lcd_m(const char *name) +{ + int ret; + + ret = intel_ich_gpio_set(34, 1); /* #TBL */ + if (!ret) + ret = intel_ich_gpio_set(35, 1); /* #WP */ + + return ret; +} + +/** + * Suited for: + * - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF + * - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705 + * + * SIS950 superio probably requires the same flash write enable. + */ +static int it8705_rom_write_enable(const char *name) +{ + /* enter IT87xx conf mode */ + enter_conf_mode_ite(0x2e); + + /* select right flash chip */ + sio_mask(0x2e, 0x22, 0x80, 0x80); + + /* bit 3: flash chip write enable + * bit 7: map flash chip at 1MB-128K (why though? ignoring this.) + */ + sio_mask(0x2e, 0x24, 0x04, 0x04); + + /* exit IT87xx conf mode */ + exit_conf_mode_ite(0x2e); + + return 0; +} + +/** + * Suited for AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F. + */ +static int board_aopen_vkm400(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8237 ISA bridge not found.\n"); + return -1; + } + + vt823x_set_all_writes_to_lpc(dev); + + return it8705_rom_write_enable(name); +} + +/** + * Winbond W83697HF Super I/O + VIA VT8235 southbridge + * + * Suited for: + * - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235 + * - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235 + */ +static int board_msi_kt4v(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); + return -1; + } + + vt823x_set_all_writes_to_lpc(dev); + + vt823x_gpio_set(dev, 12, 1); + w836xx_memw_enable(0x2E); + + return 0; +} + +/** + * Suited for Soyo SY-7VCA: Pro133A + VT82C686. + */ +static int board_soyo_sy_7vca(const char *name) +{ + struct pci_dev *dev; + uint32_t base; + uint8_t tmp; + + /* VT82C686 Power management */ + dev = pci_dev_find(0x1106, 0x3057); + if (!dev) { + fprintf(stderr, "\nERROR: VT82C686 PM device not found.\n"); + return -1; + } + + /* GPO0 output from PM IO base + 0x4C */ + tmp = pci_read_byte(dev, 0x54); + tmp &= ~0x03; + pci_write_byte(dev, 0x54, tmp); + + /* PM IO base */ + base = pci_read_long(dev, 0x48) & 0x0000FF00; + + /* Drop GPO0 */ + tmp = INB(base + 0x4C); + tmp &= ~0x01; + OUTB(tmp, base + 0x4C); + + return 0; +} + +static int it8705f_write_enable(uint8_t port, const char *name) +{ + enter_conf_mode_ite(port); + sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */ + exit_conf_mode_ite(port); + + return 0; +} + +/** + * Suited for: + * - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F + * - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F + */ +static int it8705f_write_enable_2e(const char *name) +{ + return it8705f_write_enable(0x2e, name); +} + +/** + * Find the runtime registers of an SMSC Super I/O, after verifying its + * chip ID. + * + * Returns the base port of the runtime register block, or 0 on error. + */ +static uint16_t smsc_find_runtime(uint16_t sio_port, uint16_t chip_id, + uint8_t logical_device) +{ + uint16_t rt_port = 0; + + /* Verify the chip ID. */ + OUTB(0x55, sio_port); /* Enable configuration. */ + if (sio_read(sio_port, 0x20) != chip_id) { + fprintf(stderr, "\nERROR: SMSC Super I/O not found.\n"); + goto out; + } + + /* If the runtime block is active, get its address. */ + sio_write(sio_port, 0x07, logical_device); + if (sio_read(sio_port, 0x30) & 1) { + rt_port = (sio_read(sio_port, 0x60) << 8) + | sio_read(sio_port, 0x61); + } + + if (rt_port == 0) { + fprintf(stderr, "\nERROR: " + "Super I/O runtime interface not available.\n"); + } +out: + OUTB(0xaa, sio_port); /* Disable configuration. */ + return rt_port; +} + +/** + * Disable write protection on the Mitac 6513WU. WP# on the FWH is + * connected to GP30 on the Super I/O, and TBL# is always high. + */ +static int board_mitac_6513wu(const char *name) +{ + struct pci_dev *dev; + uint16_t rt_port; + uint8_t val; + + dev = pci_dev_find(0x8086, 0x2410); /* Intel 82801AA ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: Intel 82801AA ISA bridge not found.\n"); + return -1; + } + + rt_port = smsc_find_runtime(0x4e, 0x54 /* LPC47U33x */, 0xa); + if (rt_port == 0) + return -1; + + /* Configure the GPIO pin. */ + val = INB(rt_port + 0x33); /* GP30 config */ + val &= ~0x87; /* Output, non-inverted, GPIO, push/pull */ + OUTB(val, rt_port + 0x33); + + /* Disable write protection. */ + val = INB(rt_port + 0x4d); /* GP3 values */ + val |= 0x01; /* Set GP30 high. */ + OUTB(val, rt_port + 0x4d); + + return 0; +} + +/** + * Suited for Asus A7V8X: VIA KT400 + VT8235 + IT8703F-A + */ +static int board_asus_a7v8x(const char *name) +{ + uint16_t id, base; + uint8_t tmp; + + /* find the IT8703F */ + w836xx_ext_enter(0x2E); + id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21); + w836xx_ext_leave(0x2E); + + if (id != 0x8701) { + fprintf(stderr, "\nERROR: IT8703F SuperIO not found.\n"); + return -1; + } + + /* Get the GP567 IO base */ + w836xx_ext_enter(0x2E); + sio_write(0x2E, 0x07, 0x0C); + base = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61); + w836xx_ext_leave(0x2E); + + if (!base) { + fprintf(stderr, "\nERROR: Failed to read IT8703F SuperIO GPIO" + " Base.\n"); + return -1; + } + + /* Raise GP51. */ + tmp = INB(base); + tmp |= 0x02; + OUTB(tmp, base); + + return 0; +} + +/* + * General routine for raising/dropping GPIO lines on the ITE IT8712F. + * There is only some limited checking on the port numbers. + */ +static int +it8712f_gpio_set(unsigned int line, int raise) +{ + unsigned int port; + uint16_t id, base; + uint8_t tmp; + + port = line / 10; + port--; + line %= 10; + + /* Check line */ + if ((port > 4) || /* also catches unsigned -1 */ + ((port < 4) && (line > 7)) || ((port == 4) && (line > 5))) { + fprintf(stderr, + "\nERROR: Unsupported IT8712F GPIO Line %02d.\n", line); + return -1; + } + + /* find the IT8712F */ + enter_conf_mode_ite(0x2E); + id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21); + exit_conf_mode_ite(0x2E); + + if (id != 0x8712) { + fprintf(stderr, "\nERROR: IT8712F SuperIO not found.\n"); + return -1; + } + + /* Get the GPIO base */ + enter_conf_mode_ite(0x2E); + sio_write(0x2E, 0x07, 0x07); + base = (sio_read(0x2E, 0x62) << 8) | sio_read(0x2E, 0x63); + exit_conf_mode_ite(0x2E); + + if (!base) { + fprintf(stderr, "\nERROR: Failed to read IT8712F SuperIO GPIO" + " Base.\n"); + return -1; + } + + /* set GPIO. */ + tmp = INB(base + port); + if (raise) + tmp |= 1 << line; + else + tmp &= ~(1 << line); + OUTB(tmp, base + port); + + return 0; +} + +/** + * Suited for Asus A7V600-X: VIA KT600 + VT8237 + IT8712F + */ +static int board_asus_a7v600x(const char *name) +{ + return it8712f_gpio_set(32, 1); +} + +/** + * Suited for Asus M2V-MX: VIA K8M890 + VT8237A + IT8716F + */ +static int board_asus_m2v_mx(const char *name) +{ + struct pci_dev *dev; + + dev = pci_dev_find(0x1106, 0x3337); /* VT8237A ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8237A ISA bridge not found.\n"); + return -1; + } + + /* GPO5 is connected to WP# and TBL#. */ + vt823x_gpio_set(dev, 5, 1); + + return 0; +} + + +/** + * Below is the list of boards which need a special "board enable" code in + * flashrom before their ROM chip can be accessed/written to. + * + * NOTE: Please add boards that _don't_ need such enables or don't work yet + * to the respective tables in print.c. Thanks! + * + * We use 2 sets of IDs here, you're free to choose which is which. This + * is to provide a very high degree of certainty when matching a board on + * the basis of subsystem/card IDs. As not every vendor handles + * subsystem/card IDs in a sane manner. + * + * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs + * NULLed if they don't identify the board fully. But please take care to + * provide an as complete set of pci ids as possible; autodetection is the + * preferred behaviour and we would like to make sure that matches are unique. + * + * The coreboot ids are used two fold. When running with a coreboot firmware, + * the ids uniquely matches the coreboot board identification string. When a + * legacy bios is installed and when autodetection is not possible, these ids + * can be used to identify the board through the -m command line argument. + * + * When a board is identified through its coreboot ids (in both cases), the + * main pci ids are still required to match, as a safeguard. + */ + +/* Please keep this list alphabetically ordered by vendor/board name. */ +struct board_pciid_enable board_pciid_enables[] = { + /* first pci-id set [4], second pci-id set [4], coreboot id [2], vendor name board name flash enable */ + {0x8086, 0x2926, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, "Abit", "IP35", intel_ich_gpio16_raise}, + {0x105a, 0x0d30, 0x105a, 0x4d33, 0x8086, 0x1130, 0x8086, 0, NULL, NULL, "Acorp", "6A815EPD", board_acorp_6a815epd}, + {0x8086, 0x24D4, 0x1849, 0x24D0, 0x8086, 0x24D5, 0x1849, 0x9739, NULL, NULL, "ASRock", "P4i65GV", intel_ich_gpio23_raise}, + {0x1022, 0x746B, 0, 0, 0, 0, 0, 0, "AGAMI", "ARUMA", "agami", "Aruma", w83627hf_gpio24_raise_2e}, + {0x1106, 0x3177, 0x17F2, 0x3177, 0x1106, 0x3148, 0x17F2, 0x3148, NULL, NULL, "Albatron", "PM266A", w836xx_memw_enable_2e}, + {0x1106, 0x3205, 0x1106, 0x3205, 0x10EC, 0x8139, 0xA0A0, 0x0477, NULL, NULL, "AOpen", "vKM400Am-S", board_aopen_vkm400}, + {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, "artecgroup", "dbe61", "Artec Group", "DBE61", board_artecgroup_dbe6x}, + {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, "artecgroup", "dbe62", "Artec Group", "DBE62", board_artecgroup_dbe6x}, + {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, "ASUS", "A7V600-X", board_asus_a7v600x}, + {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, "ASUS", "A7V8X", board_asus_a7v8x}, + {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, "ASUS", "A7V8X-MX SE", board_asus_a7v8x_mx}, + {0x1106, 0x1336, 0x1043, 0x80ed, 0x1106, 0x3288, 0x1043, 0x8249, NULL, NULL, "ASUS", "M2V-MX", board_asus_m2v_mx}, + {0x8086, 0x1a30, 0x1043, 0x8070, 0x8086, 0x244b, 0x1043, 0x8028, NULL, NULL, "ASUS", "P4B266", intel_ich_gpio22_raise}, + {0x8086, 0x1A30, 0x1043, 0x8025, 0x8086, 0x244B, 0x104D, 0x80F0, NULL, NULL, "ASUS", "P4B266-LM", intel_ich_gpio21_raise}, + {0x8086, 0x2570, 0x1043, 0x80F2, 0x105A, 0x3373, 0x1043, 0x80F5, NULL, NULL, "ASUS", "P4P800-E Deluxe", intel_ich_gpio21_raise}, + {0x10B9, 0x1541, 0, 0, 0x10B9, 0x1533, 0, 0, "asus", "p5a", "ASUS", "P5A", board_asus_p5a}, + {0x10DE, 0x0030, 0x1043, 0x818a, 0x8086, 0x100E, 0x1043, 0x80EE, NULL, NULL, "ASUS", "P5ND2-SLI Deluxe", nvidia_mcp_gpio10_raise}, + {0x1106, 0x3149, 0x1565, 0x3206, 0x1106, 0x3344, 0x1565, 0x1202, NULL, NULL, "Biostar", "P4M80-M4", it8705_rom_write_enable}, + {0x8086, 0x3590, 0x1028, 0x016c, 0x1000, 0x0030, 0x1028, 0x016c, NULL, NULL, "Dell", "PowerEdge 1850", intel_ich_gpio23_raise}, + {0x1106, 0x3038, 0x1019, 0x0996, 0x1106, 0x3177, 0x1019, 0x0996, NULL, NULL, "Elitegroup", "K7VTA3", it8705f_write_enable_2e}, + {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3059, 0x1695, 0x3005, NULL, NULL, "EPoX", "EP-8K5A2", w836xx_memw_enable_2e}, + {0x10EC, 0x8139, 0x1695, 0x9001, 0x11C1, 0x5811, 0x1695, 0x9015, NULL, NULL, "EPoX", "EP-8RDA3+", nvidia_mcp_gpio31_raise}, + {0x8086, 0x7110, 0, 0, 0x8086, 0x7190, 0, 0, "epox", "ep-bx3", "EPoX", "EP-BX3", board_epox_ep_bx3}, + {0x1039, 0x0761, 0, 0, 0x10EC, 0x8168, 0, 0, "gigabyte", "2761gxdk", "GIGABYTE", "GA-2761GXDK", it87xx_probe_spi_flash}, + {0x1106, 0x3227, 0x1458, 0x5001, 0x10ec, 0x8139, 0x1458, 0xe000, NULL, NULL, "GIGABYTE", "GA-7VT600", it8705_rom_write_enable}, + {0x10DE, 0x0050, 0x1458, 0x0C11, 0x10DE, 0x005e, 0x1458, 0x5000, NULL, NULL, "GIGABYTE", "GA-K8N-SLI", nvidia_mcp_gpio21_raise}, + {0x10DE, 0x0360, 0x1458, 0x0C11, 0x10DE, 0x0369, 0x1458, 0x5001, "gigabyte", "m57sli", "GIGABYTE", "GA-M57SLI-S4", it87xx_probe_spi_flash}, + {0x10de, 0x03e0, 0, 0, 0x10DE, 0x03D0, 0, 0, NULL, NULL, "GIGABYTE", "GA-M61P-S3", it87xx_probe_spi_flash}, + {0x1002, 0x4398, 0x1458, 0x5004, 0x1002, 0x4391, 0x1458, 0xb000, NULL, NULL, "GIGABYTE", "GA-MA78G-DS3H", it87xx_probe_spi_flash}, + {0x1002, 0x4398, 0x1458, 0x5004, 0x1002, 0x4391, 0x1458, 0xb002, NULL, NULL, "GIGABYTE", "GA-MA78GM-S2H", it87xx_probe_spi_flash}, + {0x1002, 0x438d, 0x1458, 0x5001, 0x1002, 0x5956, 0x1002, 0x5956, NULL, NULL, "GIGABYTE", "GA-MA790FX-DQ6", it87xx_probe_spi_flash}, + {0x1166, 0x0223, 0x103c, 0x320d, 0x102b, 0x0522, 0x103c, 0x31fa, "hp", "dl145_g3", "HP", "DL145 G3", board_hp_dl145_g3_enable}, + {0x1166, 0x0205, 0x1014, 0x0347, 0x1002, 0x515E, 0x1014, 0x0325, NULL, NULL, "IBM", "x3455", board_ibm_x3455}, + {0x1039, 0x5513, 0x8086, 0xd61f, 0x1039, 0x6330, 0x8086, 0xd61f, NULL, NULL, "Intel", "D201GLY", wbsio_check_for_spi}, + {0x1022, 0x7468, 0, 0, 0, 0, 0, 0, "iwill", "dk8_htx", "IWILL", "DK8-HTX", w83627hf_gpio24_raise_2e}, + {0x8086, 0x27A0, 0, 0, 0x8086, 0x27b8, 0, 0, "kontron", "986lcd-m", "Kontron", "986LCD-M", board_kontron_986lcd_m}, + {0x8086, 0x2411, 0x8086, 0x2411, 0x8086, 0x7125, 0x0e11, 0xb165, NULL, NULL, "Mitac", "6513WU", board_mitac_6513wu}, + {0x13f6, 0x0111, 0x1462, 0x5900, 0x1106, 0x3177, 0x1106, 0, NULL, NULL, "MSI", "MS-6590 (KT4 Ultra)",board_msi_kt4v}, + {0x1106, 0x3149, 0x1462, 0x7094, 0x10ec, 0x8167, 0x1462, 0x094c, NULL, NULL, "MSI", "MS-6702E (K8T Neo2-F)",w83627thf_gpio4_4_raise_2e}, + {0x1106, 0x0571, 0x1462, 0x7120, 0x1106, 0x3065, 0x1462, 0x7120, NULL, NULL, "MSI", "MS-6712 (KT4V)", board_msi_kt4v}, + {0x8086, 0x2658, 0x1462, 0x7046, 0x1106, 0x3044, 0x1462, 0x046d, NULL, NULL, "MSI", "MS-7046", intel_ich_gpio19_raise}, + {0x10DE, 0x005E, 0x1462, 0x7135, 0x10DE, 0x0050, 0x1462, 0x7135, "msi", "k8n-neo3", "MSI", "MS-7135 (K8N Neo3)", w83627thf_gpio4_4_raise_4e}, + {0x1106, 0x3099, 0, 0, 0x1106, 0x3074, 0, 0, "shuttle", "ak31", "Shuttle", "AK31", w836xx_memw_enable_2e}, + {0x1106, 0x3104, 0x1297, 0xa238, 0x1106, 0x3059, 0x1297, 0xc063, NULL, NULL, "Shuttle", "AK38N", it8705f_write_enable_2e}, + {0x10DE, 0x0050, 0x1297, 0x5036, 0x1412, 0x1724, 0x1297, 0x5036, NULL, NULL, "Shuttle", "FN25", board_shuttle_fn25}, + {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x3058, 0x15DD, 0x7609, NULL, NULL, "Soyo", "SY-7VCA", board_soyo_sy_7vca}, + {0x8086, 0x1076, 0x8086, 0x1176, 0x1106, 0x3059, 0x10f1, 0x2498, NULL, NULL, "Tyan", "S2498 (Tomcat K7M)", board_asus_a7v8x_mx}, + {0x1106, 0x0314, 0x1106, 0xaa08, 0x1106, 0x3227, 0x1106, 0xAA08, NULL, NULL, "VIA", "EPIA-CN", board_via_epia_sp}, + {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, "VIA", "EPIA M/MII/...", board_via_epia_m}, + {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, NULL, NULL, "VIA", "EPIA-N/NL", board_via_epia_n}, + {0x1106, 0x3227, 0x1106, 0xAA01, 0x1106, 0x0259, 0x1106, 0xAA01, NULL, NULL, "VIA", "EPIA SP", board_via_epia_sp}, + {0x1106, 0x5337, 0x1458, 0xb003, 0x1106, 0x287e, 0x1106, 0x337e, NULL, NULL, "VIA", "PC3500G", it87xx_probe_spi_flash}, + + { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}, /* end marker */ +}; + +/** + * Match boards on coreboot table gathered vendor and part name. + * Require main PCI IDs to match too as extra safety. + */ +static struct board_pciid_enable *board_match_coreboot_name(const char *vendor, + const char *part) +{ + struct board_pciid_enable *board = board_pciid_enables; + struct board_pciid_enable *partmatch = NULL; + + for (; board->vendor_name; board++) { + if (vendor && (!board->lb_vendor + || strcasecmp(board->lb_vendor, vendor))) + continue; + + if (!board->lb_part || strcasecmp(board->lb_part, part)) + continue; + + if (!pci_dev_find(board->first_vendor, board->first_device)) + continue; + + if (board->second_vendor && + !pci_dev_find(board->second_vendor, board->second_device)) + continue; + + if (vendor) + return board; + + if (partmatch) { + /* a second entry has a matching part name */ + printf("AMBIGUOUS BOARD NAME: %s\n", part); + printf("At least vendors '%s' and '%s' match.\n", + partmatch->lb_vendor, board->lb_vendor); + printf("Please use the full -m vendor:part syntax.\n"); + return NULL; + } + partmatch = board; + } + + if (partmatch) + return partmatch; + + if (!partvendor_from_cbtable) { + /* Only warn if the mainboard type was not gathered from the + * coreboot table. If it was, the coreboot implementor is + * expected to fix flashrom, too. + */ + printf("\nUnknown vendor:board from -m option: %s:%s\n\n", + vendor, part); + } + return NULL; +} + +/** + * Match boards on PCI IDs and subsystem IDs. + * Second set of IDs can be main only or missing completely. + */ +static struct board_pciid_enable *board_match_pci_card_ids(void) +{ + struct board_pciid_enable *board = board_pciid_enables; + + for (; board->vendor_name; board++) { + if (!board->first_card_vendor || !board->first_card_device) + continue; + + if (!pci_card_find(board->first_vendor, board->first_device, + board->first_card_vendor, + board->first_card_device)) + continue; + + if (board->second_vendor) { + if (board->second_card_vendor) { + if (!pci_card_find(board->second_vendor, + board->second_device, + board->second_card_vendor, + board->second_card_device)) + continue; + } else { + if (!pci_dev_find(board->second_vendor, + board->second_device)) + continue; + } + } + + return board; + } + + return NULL; +} + +int board_flash_enable(const char *vendor, const char *part) +{ + struct board_pciid_enable *board = NULL; + int ret = 0; + + if (part) + board = board_match_coreboot_name(vendor, part); + + if (!board) + board = board_match_pci_card_ids(); + + if (board) { + printf("Disabling flash write protection for board \"%s %s\"... ", + board->vendor_name, board->board_name); + + ret = board->enable(board->vendor_name); + if (ret) + printf("FAILED!\n"); + else + printf("OK.\n"); + } + + return ret; +} diff --git a/libflashrom/buspirate_spi.c b/libflashrom/buspirate_spi.c new file mode 100644 index 0000000..a1c8265 --- /dev/null +++ b/libflashrom/buspirate_spi.c @@ -0,0 +1,372 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 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 "flash.h" +#include "spi.h" + +/* Change this to #define if you want to test without a serial implementation */ +#undef FAKE_COMMUNICATION + +#ifndef FAKE_COMMUNICATION +int buspirate_serialport_setup(char *dev) +{ + /* 115200bps, 8 databits, no parity, 1 stopbit */ + sp_fd = sp_openserport(dev, 115200); + return 0; +} + +int buspirate_serialport_shutdown(void) +{ + close(sp_fd); + return 0; +} + +int serialport_write(unsigned char *buf, unsigned int writecnt) +{ + int tmp = 0; + + while (tmp != writecnt) { + tmp = write(sp_fd, buf + tmp, writecnt - tmp); + if (tmp == -1) + return 1; + if (!tmp) + printf_debug("Empty write\n"); + } + + return 0; +} + +int serialport_read(unsigned char *buf, unsigned int readcnt) +{ + int tmp = 0; + + while (tmp != readcnt) { + tmp = read(sp_fd, buf + tmp, readcnt - tmp); + if (tmp == -1) + return 1; + if (!tmp) + printf_debug("Empty read\n"); + } + + return 0; +} + +int buspirate_discard_read(void) +{ + int flags; + + printf_debug("%s\n", __func__); + flags = fcntl(sp_fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(sp_fd, F_SETFL, flags); + sp_flush_incoming(); + flags &= ~O_NONBLOCK; + fcntl(sp_fd, F_SETFL, flags); + + return 0; +} +#else +#define buspirate_serialport_setup(...) 0 +#define buspirate_serialport_shutdown(...) 0 +#define serialport_write(...) 0 +#define serialport_read(...) 0 +#define buspirate_discard_read(...) 0 +#endif + +int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt) +{ + int i, ret = 0; + + printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt); + if (!writecnt && !readcnt) { + fprintf(stderr, "Zero length command!\n"); + return 1; + } + printf_debug("Sending"); + for (i = 0; i < writecnt; i++) + printf_debug(" 0x%02x", buf[i]); +#ifdef FAKE_COMMUNICATION + /* Placate the caller for now. */ + if (readcnt) { + buf[0] = 0x01; + memset(buf + 1, 0xff, readcnt - 1); + } + ret = 0; +#else + if (writecnt) + ret = serialport_write(buf, writecnt); + if (ret) + return ret; + if (readcnt) + ret = serialport_read(buf, readcnt); + if (ret) + return ret; +#endif + printf_debug(", receiving"); + for (i = 0; i < readcnt; i++) + printf_debug(" 0x%02x", buf[i]); + printf_debug("\n"); + return 0; +} + +static const struct buspirate_spispeeds spispeeds[] = { + {"30k", 0x0}, + {"125k", 0x1}, + {"250k", 0x2}, + {"1M", 0x3}, + {"2M", 0x4}, + {"2.6M", 0x5}, + {"4M", 0x6}, + {"8M", 0x7}, + {NULL, 0x0} +}; + +int buspirate_spi_init(void) +{ + unsigned char buf[512]; + int ret = 0; + int i; + char *dev = NULL; + char *speed = NULL; + int spispeed = 0x7; + + if (programmer_param && !strlen(programmer_param)) { + free(programmer_param); + programmer_param = NULL; + } + if (programmer_param) { + dev = extract_param(&programmer_param, "dev=", ",:"); + speed = extract_param(&programmer_param, "spispeed=", ",:"); + if (strlen(programmer_param)) + fprintf(stderr, "Unhandled programmer parameters: %s\n", + programmer_param); + free(programmer_param); + programmer_param = NULL; + } + if (!dev) { + fprintf(stderr, "No serial device given. Use flashrom -p " + "buspiratespi:dev=/dev/ttyUSB0\n"); + return 1; + } + if (speed) { + for (i = 0; spispeeds[i].name; i++) + if (!strncasecmp(spispeeds[i].name, speed, + strlen(spispeeds[i].name))) { + spispeed = spispeeds[i].speed; + break; + } + if (!spispeeds[i].name) + fprintf(stderr, "Invalid SPI speed, using default.\n"); + } + /* This works because speeds numbering starts at 0 and is contiguous. */ + printf_debug("SPI speed is %sHz\n", spispeeds[spispeed].name); + + ret = buspirate_serialport_setup(dev); + if (ret) + return ret; + + /* This is the brute force version, but it should work. */ + for (i = 0; i < 19; i++) { + /* Enter raw bitbang mode */ + buf[0] = 0x00; + /* Send the command, don't read the response. */ + ret = buspirate_sendrecv(buf, 1, 0); + if (ret) + return ret; + /* Read any response and discard it. */ + ret = buspirate_discard_read(); + if (ret) + return ret; + } + /* Enter raw bitbang mode */ + buf[0] = 0x00; + ret = buspirate_sendrecv(buf, 1, 5); + if (ret) + return ret; + if (memcmp(buf, "BBIO", 4)) { + fprintf(stderr, "Entering raw bitbang mode failed!\n"); + return 1; + } + printf_debug("Raw bitbang mode version %c\n", buf[4]); + if (buf[4] != '1') { + fprintf(stderr, "Can't handle raw bitbang mode version %c!\n", + buf[4]); + return 1; + } + /* Enter raw SPI mode */ + buf[0] = 0x01; + ret = buspirate_sendrecv(buf, 1, 4); + if (memcmp(buf, "SPI", 3)) { + fprintf(stderr, "Entering raw SPI mode failed!\n"); + return 1; + } + printf_debug("Raw SPI mode version %c\n", buf[3]); + if (buf[3] != '1') { + fprintf(stderr, "Can't handle raw SPI mode version %c!\n", + buf[3]); + return 1; + } + + /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */ + buf[0] = 0x40 | 0xb; + ret = buspirate_sendrecv(buf, 1, 1); + if (ret) + return 1; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while setting power/CS/AUX!\n"); + return 1; + } + + /* Set SPI speed */ + buf[0] = 0x60 | spispeed; + ret = buspirate_sendrecv(buf, 1, 1); + if (ret) + return 1; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while setting SPI speed!\n"); + return 1; + } + + /* Set SPI config: output type, idle, clock edge, sample */ + buf[0] = 0x80 | 0xa; + ret = buspirate_sendrecv(buf, 1, 1); + if (ret) + return 1; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while setting SPI config!\n"); + return 1; + } + + /* De-assert CS# */ + buf[0] = 0x03; + ret = buspirate_sendrecv(buf, 1, 1); + if (ret) + return 1; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while raising CS#!\n"); + return 1; + } + + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_BUSPIRATE; + + return 0; +} + +int buspirate_spi_shutdown(void) +{ + unsigned char buf[5]; + int ret = 0; + + /* Exit raw SPI mode (enter raw bitbang mode) */ + buf[0] = 0x00; + ret = buspirate_sendrecv(buf, 1, 5); + if (ret) + return ret; + if (memcmp(buf, "BBIO", 4)) { + fprintf(stderr, "Entering raw bitbang mode failed!\n"); + return 1; + } + printf_debug("Raw bitbang mode version %c\n", buf[4]); + if (buf[4] != '1') { + fprintf(stderr, "Can't handle raw bitbang mode version %c!\n", + buf[4]); + return 1; + } + /* Reset Bus Pirate (return to user terminal) */ + buf[0] = 0x0f; + ret = buspirate_sendrecv(buf, 1, 0); + if (ret) + return ret; + + /* Shut down serial port communication */ + ret = buspirate_serialport_shutdown(); + if (ret) + return ret; + printf_debug("Bus Pirate shutdown completed.\n"); + + return 0; +} + +int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + static unsigned char *buf = NULL; + int i = 0, ret = 0; + + if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16) + return SPI_INVALID_LENGTH; + + /* +2 is pretty arbitrary. */ + buf = realloc(buf, writecnt + readcnt + 2); + if (!buf) { + fprintf(stderr, "Out of memory!\n"); + exit(1); // -1 + } + + /* Assert CS# */ + buf[i++] = 0x02; + ret = buspirate_sendrecv(buf, 1, 1); + if (ret) + return SPI_GENERIC_ERROR; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while lowering CS#!\n"); + return SPI_GENERIC_ERROR; + } + + i = 0; + buf[i++] = 0x10 | (writecnt + readcnt - 1); + memcpy(buf + i, writearr, writecnt); + i += writecnt; + memset(buf + i, 0, readcnt); + ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt); + if (ret) + return SPI_GENERIC_ERROR; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while reading/writing SPI!\n"); + return SPI_GENERIC_ERROR; + } + memcpy(readarr, buf + i, readcnt); + + i = 0; + /* De-assert CS# */ + buf[i++] = 0x03; + ret = buspirate_sendrecv(buf, 1, 1); + if (ret) + return SPI_GENERIC_ERROR; + if (buf[0] != 0x01) { + fprintf(stderr, "Protocol error while raising CS#!\n"); + return SPI_GENERIC_ERROR; + } + + return ret; +} + +int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + return spi_read_chunked(flash, buf, start, len, 12); +} + +/* We could do 12-byte writes, but for now we use the generic 1-byte code. */ diff --git a/libflashrom/chipset_enable.c b/libflashrom/chipset_enable.c new file mode 100644 index 0000000..3bdd7d0 --- /dev/null +++ b/libflashrom/chipset_enable.c @@ -0,0 +1,1202 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2005-2009 coresystems GmbH + * Copyright (C) 2006 Uwe Hermann + * + * 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 + */ + +/* + * Contains the chipset specific flash enables. + */ + +#define _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include "flash.h" + +unsigned long flashbase = 0; + +/** + * flashrom defaults to Parallel/LPC/FWH flash devices. If a known host + * controller is found, the init routine sets the buses_supported bitfield to + * contain the supported buses for that controller. + */ + +enum chipbustype buses_supported = CHIP_BUSTYPE_NONSPI; + +/** + * Programmers supporting multiple buses can have differing size limits on + * each bus. Store the limits for each bus in a common struct. + */ +struct decode_sizes max_rom_decode = { + .parallel = 0xffffffff, + .lpc = 0xffffffff, + .fwh = 0xffffffff, + .spi = 0xffffffff +}; + +extern int ichspi_lock; + +static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name) +{ + uint8_t tmp; + + /* + * ROM Write enable, 0xFFFC0000-0xFFFDFFFF and + * 0xFFFE0000-0xFFFFFFFF ROM select enable. + */ + tmp = pci_read_byte(dev, 0x47); + tmp |= 0x46; + pci_write_byte(dev, 0x47, tmp); + + return 0; +} + +static int enable_flash_sis85c496(struct pci_dev *dev, const char *name) +{ + uint8_t tmp; + + tmp = pci_read_byte(dev, 0xd0); + tmp |= 0xf8; + pci_write_byte(dev, 0xd0, tmp); + + return 0; +} + +static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name) +{ + uint8_t new, newer; + + /* Extended BIOS enable = 1, Lower BIOS Enable = 1 */ + /* This is 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */ + new = pci_read_byte(dev, 0x40); + new &= (~0x04); /* No idea why we clear bit 2. */ + new |= 0xb; /* 0x3 for some chipsets, bit 7 seems to be don't care. */ + pci_write_byte(dev, 0x40, new); + newer = pci_read_byte(dev, 0x40); + if (newer != new) { + printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name); + printf_debug("Stuck at 0x%x\n", newer); + return -1; + } + return 0; +} + +static struct pci_dev *find_southbridge(uint16_t vendor, const char *name) +{ + struct pci_dev *sbdev; + + sbdev = pci_dev_find_vendorclass(vendor, 0x0601); + if (!sbdev) + sbdev = pci_dev_find_vendorclass(vendor, 0x0680); + if (!sbdev) + sbdev = pci_dev_find_vendorclass(vendor, 0x0000); + if (!sbdev) + fprintf(stderr, "No southbridge found for %s!\n", name); + if (sbdev) + printf_debug("Found southbridge %04x:%04x at %02x:%02x:%01x\n", + sbdev->vendor_id, sbdev->device_id, + sbdev->bus, sbdev->dev, sbdev->func); + return sbdev; +} + +static int enable_flash_sis501(struct pci_dev *dev, const char *name) +{ + uint8_t tmp; + int ret = 0; + struct pci_dev *sbdev; + + sbdev = find_southbridge(dev->vendor_id, name); + if (!sbdev) + return -1; + + ret = enable_flash_sis_mapping(sbdev, name); + + tmp = sio_read(0x22, 0x80); + tmp &= (~0x20); + tmp |= 0x4; + sio_write(0x22, 0x80, tmp); + + tmp = sio_read(0x22, 0x70); + tmp &= (~0x20); + tmp |= 0x4; + sio_write(0x22, 0x70, tmp); + + return ret; +} + +static int enable_flash_sis5511(struct pci_dev *dev, const char *name) +{ + uint8_t tmp; + int ret = 0; + struct pci_dev *sbdev; + + sbdev = find_southbridge(dev->vendor_id, name); + if (!sbdev) + return -1; + + ret = enable_flash_sis_mapping(sbdev, name); + + tmp = sio_read(0x22, 0x50); + tmp &= (~0x20); + tmp |= 0x4; + sio_write(0x22, 0x50, tmp); + + return ret; +} + +static int enable_flash_sis5596(struct pci_dev *dev, const char *name) +{ + int ret; + + ret = enable_flash_sis5511(dev, name); + + /* FIXME: Needs same superio handling as enable_flash_sis630 */ + return ret; +} + +static int enable_flash_sis530(struct pci_dev *dev, const char *name) +{ + uint8_t new, newer; + int ret = 0; + struct pci_dev *sbdev; + + sbdev = find_southbridge(dev->vendor_id, name); + if (!sbdev) + return -1; + + ret = enable_flash_sis_mapping(sbdev, name); + + new = pci_read_byte(sbdev, 0x45); + new &= (~0x20); + new |= 0x4; + pci_write_byte(sbdev, 0x45, new); + newer = pci_read_byte(dev, 0x45); + if (newer != new) { + printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); + printf_debug("Stuck at 0x%x\n", newer); + ret = -1; + } + + return ret; +} + +static int enable_flash_sis540(struct pci_dev *dev, const char *name) +{ + uint8_t new, newer; + int ret = 0; + struct pci_dev *sbdev; + + sbdev = find_southbridge(dev->vendor_id, name); + if (!sbdev) + return -1; + + ret = enable_flash_sis_mapping(sbdev, name); + + new = pci_read_byte(sbdev, 0x45); + new &= (~0x80); + new |= 0x40; + pci_write_byte(sbdev, 0x45, new); + newer = pci_read_byte(dev, 0x45); + if (newer != new) { + printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); + printf_debug("Stuck at 0x%x\n", newer); + ret = -1; + } + + return ret; +} + +/* Datasheet: + * - Name: 82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4) + * - URL: http://www.intel.com/design/intarch/datashts/290562.htm + * - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf + * - Order Number: 290562-001 + */ +static int enable_flash_piix4(struct pci_dev *dev, const char *name) +{ + uint16_t old, new; + uint16_t xbcs = 0x4e; /* X-Bus Chip Select register. */ + + buses_supported = CHIP_BUSTYPE_PARALLEL; + + old = pci_read_word(dev, xbcs); + + /* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to + * FFF00000-FFF7FFFF are forwarded to ISA). + * Note: This bit is reserved on PIIX/PIIX3/MPIIX. + * Set bit 7: Extended BIOS Enable (PCI master accesses to + * FFF80000-FFFDFFFF are forwarded to ISA). + * Set bit 6: Lower BIOS Enable (PCI master, or ISA master accesses to + * the lower 64-Kbyte BIOS block (E0000-EFFFF) at the top + * of 1 Mbyte, or the aliases at the top of 4 Gbyte + * (FFFE0000-FFFEFFFF) result in the generation of BIOSCS#. + * Note: Accesses to FFFF0000-FFFFFFFF are always forwarded to ISA. + * Set bit 2: BIOSCS# Write Enable (1=enable, 0=disable). + */ + if (dev->device_id == 0x122e || dev->device_id == 0x7000 + || dev->device_id == 0x1234) + new = old | 0x00c4; /* PIIX/PIIX3/MPIIX: Bit 9 is reserved. */ + else + new = old | 0x02c4; + + if (new == old) + return 0; + + pci_write_word(dev, xbcs, new); + + if (pci_read_word(dev, xbcs) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", xbcs, new, name); + return -1; + } + + return 0; +} + +/* + * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet" + * http://download.intel.com/design/chipsets/datashts/30701303.pdf + */ +static int enable_flash_ich(struct pci_dev *dev, const char *name, + int bios_cntl) +{ + uint8_t old, new; + + /* + * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, but + * just treating it as 8 bit wide seems to work fine in practice. + */ + old = pci_read_byte(dev, bios_cntl); + + printf_debug("\nBIOS Lock Enable: %sabled, ", + (old & (1 << 1)) ? "en" : "dis"); + printf_debug("BIOS Write Enable: %sabled, ", + (old & (1 << 0)) ? "en" : "dis"); + printf_debug("BIOS_CNTL is 0x%x\n", old); + + new = old | 1; + + if (new == old) + return 0; + + pci_write_byte(dev, bios_cntl, new); + + if (pci_read_byte(dev, bios_cntl) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", bios_cntl, new, name); + return -1; + } + + return 0; +} + +static int enable_flash_ich_4e(struct pci_dev *dev, const char *name) +{ + /* + * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and + * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and + * FB_DEC_EN2. + */ + return enable_flash_ich(dev, name, 0x4e); +} + +static int enable_flash_ich_dc(struct pci_dev *dev, const char *name) +{ + uint32_t fwh_conf; + int i; + char *idsel = NULL; + + /* Ignore all legacy ranges below 1 MB. */ + /* FWH_SEL1 */ + fwh_conf = pci_read_long(dev, 0xd0); + for (i = 7; i >= 0; i--) + printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x", + (0x1ff8 + i) * 0x80000, + (0x1ff0 + i) * 0x80000, + (fwh_conf >> (i * 4)) & 0xf); + /* FWH_SEL2 */ + fwh_conf = pci_read_word(dev, 0xd4); + for (i = 3; i >= 0; i--) + printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x", + (0xff4 + i) * 0x100000, + (0xff0 + i) * 0x100000, + (fwh_conf >> (i * 4)) & 0xf); + /* FWH_DEC_EN1 */ + fwh_conf = pci_read_word(dev, 0xd8); + for (i = 7; i >= 0; i--) + printf_debug("\n0x%08x/0x%08x FWH decode %sabled", + (0x1ff8 + i) * 0x80000, + (0x1ff0 + i) * 0x80000, + (fwh_conf >> (i + 0x8)) & 0x1 ? "en" : "dis"); + for (i = 3; i >= 0; i--) + printf_debug("\n0x%08x/0x%08x FWH decode %sabled", + (0xff4 + i) * 0x100000, + (0xff0 + i) * 0x100000, + (fwh_conf >> i) & 0x1 ? "en" : "dis"); + + if (programmer_param) + idsel = strstr(programmer_param, "fwh_idsel="); + + if (idsel) { + idsel += strlen("fwh_idsel="); + fwh_conf = (uint32_t)strtoul(idsel, NULL, 0); + + /* FIXME: Need to undo this on shutdown. */ + printf("\nSetting IDSEL=0x%x for top 16 MB", fwh_conf); + pci_write_long(dev, 0xd0, fwh_conf); + pci_write_word(dev, 0xd4, fwh_conf); + } + + return enable_flash_ich(dev, name, 0xdc); +} + +#define ICH_STRAP_RSVD 0x00 +#define ICH_STRAP_SPI 0x01 +#define ICH_STRAP_PCI 0x02 +#define ICH_STRAP_LPC 0x03 + +static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name) +{ + uint32_t mmio_base; + + mmio_base = (pci_read_long(dev, 0xbc)) << 8; + printf_debug("MMIO base at = 0x%x\n", mmio_base); + spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70); + + printf_debug("0x6c: 0x%04x (CLOCK/DEBUG)\n", + mmio_readw(spibar + 0x6c)); + + /* Not sure if it speaks all these bus protocols. */ + buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_VIA; + ich_init_opcodes(); + + return 0; +} + +static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + int ich_generation) +{ + int ret, i; + uint8_t old, new, bbs, buc; + uint16_t spibar_offset, tmp2; + uint32_t tmp, gcs; + void *rcrb; + //TODO: These names are incorrect for EP80579. For that, the solution would look like the commented line + //static const char *straps_names[] = {"SPI", "reserved", "reserved", "LPC" }; + static const char *straps_names[] = { "reserved", "SPI", "PCI", "LPC" }; + + /* Enable Flash Writes */ + ret = enable_flash_ich_dc(dev, name); + + /* Get physical address of Root Complex Register Block */ + tmp = pci_read_long(dev, 0xf0) & 0xffffc000; + printf_debug("\nRoot Complex Register Block address = 0x%x\n", tmp); + + /* Map RCBA to virtual memory */ + rcrb = physmap("ICH RCRB", tmp, 0x4000); + + gcs = mmio_readl(rcrb + 0x3410); + printf_debug("GCS = 0x%x: ", gcs); + printf_debug("BIOS Interface Lock-Down: %sabled, ", + (gcs & 0x1) ? "en" : "dis"); + bbs = (gcs >> 10) & 0x3; + printf_debug("BOOT BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]); + + buc = mmio_readb(rcrb + 0x3414); + printf_debug("Top Swap : %s\n", + (buc & 1) ? "enabled (A16 inverted)" : "not enabled"); + + /* It seems the ICH7 does not support SPI and LPC chips at the same + * time. At least not with our current code. So we prevent searching + * on ICH7 when the southbridge is strapped to LPC + */ + + if (ich_generation == 7 && bbs == ICH_STRAP_LPC) { + /* Not sure if it speaks LPC as well. */ + buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH; + /* No further SPI initialization required */ + return ret; + } + + switch (ich_generation) { + case 7: + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_ICH7; + spibar_offset = 0x3020; + break; + case 8: + /* Not sure if it speaks LPC as well. */ + buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_ICH9; + spibar_offset = 0x3020; + break; + case 9: + case 10: + default: /* Future version might behave the same */ + /* Not sure if it speaks LPC as well. */ + buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_ICH9; + spibar_offset = 0x3800; + break; + } + + /* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */ + printf_debug("SPIBAR = 0x%x + 0x%04x\n", tmp, spibar_offset); + + /* Assign Virtual Address */ + spibar = rcrb + spibar_offset; + + switch (spi_controller) { + case SPI_CONTROLLER_ICH7: + printf_debug("0x00: 0x%04x (SPIS)\n", + mmio_readw(spibar + 0)); + printf_debug("0x02: 0x%04x (SPIC)\n", + mmio_readw(spibar + 2)); + printf_debug("0x04: 0x%08x (SPIA)\n", + mmio_readl(spibar + 4)); + for (i = 0; i < 8; i++) { + int offs; + offs = 8 + (i * 8); + printf_debug("0x%02x: 0x%08x (SPID%d)\n", offs, + mmio_readl(spibar + offs), i); + printf_debug("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4, + mmio_readl(spibar + offs + 4), i); + } + printf_debug("0x50: 0x%08x (BBAR)\n", + mmio_readl(spibar + 0x50)); + printf_debug("0x54: 0x%04x (PREOP)\n", + mmio_readw(spibar + 0x54)); + printf_debug("0x56: 0x%04x (OPTYPE)\n", + mmio_readw(spibar + 0x56)); + printf_debug("0x58: 0x%08x (OPMENU)\n", + mmio_readl(spibar + 0x58)); + printf_debug("0x5c: 0x%08x (OPMENU+4)\n", + mmio_readl(spibar + 0x5c)); + for (i = 0; i < 4; i++) { + int offs; + offs = 0x60 + (i * 4); + printf_debug("0x%02x: 0x%08x (PBR%d)\n", offs, + mmio_readl(spibar + offs), i); + } + printf_debug("\n"); + if (mmio_readw(spibar) & (1 << 15)) { + printf("WARNING: SPI Configuration Lockdown activated.\n"); + ichspi_lock = 1; + } + ich_init_opcodes(); + break; + case SPI_CONTROLLER_ICH9: + tmp2 = mmio_readw(spibar + 4); + printf_debug("0x04: 0x%04x (HSFS)\n", tmp2); + printf_debug("FLOCKDN %i, ", (tmp2 >> 15 & 1)); + printf_debug("FDV %i, ", (tmp2 >> 14) & 1); + printf_debug("FDOPSS %i, ", (tmp2 >> 13) & 1); + printf_debug("SCIP %i, ", (tmp2 >> 5) & 1); + printf_debug("BERASE %i, ", (tmp2 >> 3) & 3); + printf_debug("AEL %i, ", (tmp2 >> 2) & 1); + printf_debug("FCERR %i, ", (tmp2 >> 1) & 1); + printf_debug("FDONE %i\n", (tmp2 >> 0) & 1); + + tmp = mmio_readl(spibar + 0x50); + printf_debug("0x50: 0x%08x (FRAP)\n", tmp); + printf_debug("BMWAG %i, ", (tmp >> 24) & 0xff); + printf_debug("BMRAG %i, ", (tmp >> 16) & 0xff); + printf_debug("BRWA %i, ", (tmp >> 8) & 0xff); + printf_debug("BRRA %i\n", (tmp >> 0) & 0xff); + + printf_debug("0x54: 0x%08x (FREG0)\n", + mmio_readl(spibar + 0x54)); + printf_debug("0x58: 0x%08x (FREG1)\n", + mmio_readl(spibar + 0x58)); + printf_debug("0x5C: 0x%08x (FREG2)\n", + mmio_readl(spibar + 0x5C)); + printf_debug("0x60: 0x%08x (FREG3)\n", + mmio_readl(spibar + 0x60)); + printf_debug("0x64: 0x%08x (FREG4)\n", + mmio_readl(spibar + 0x64)); + printf_debug("0x74: 0x%08x (PR0)\n", + mmio_readl(spibar + 0x74)); + printf_debug("0x78: 0x%08x (PR1)\n", + mmio_readl(spibar + 0x78)); + printf_debug("0x7C: 0x%08x (PR2)\n", + mmio_readl(spibar + 0x7C)); + printf_debug("0x80: 0x%08x (PR3)\n", + mmio_readl(spibar + 0x80)); + printf_debug("0x84: 0x%08x (PR4)\n", + mmio_readl(spibar + 0x84)); + printf_debug("0x90: 0x%08x (SSFS, SSFC)\n", + mmio_readl(spibar + 0x90)); + printf_debug("0x94: 0x%04x (PREOP)\n", + mmio_readw(spibar + 0x94)); + printf_debug("0x96: 0x%04x (OPTYPE)\n", + mmio_readw(spibar + 0x96)); + printf_debug("0x98: 0x%08x (OPMENU)\n", + mmio_readl(spibar + 0x98)); + printf_debug("0x9C: 0x%08x (OPMENU+4)\n", + mmio_readl(spibar + 0x9C)); + printf_debug("0xA0: 0x%08x (BBAR)\n", + mmio_readl(spibar + 0xA0)); + printf_debug("0xB0: 0x%08x (FDOC)\n", + mmio_readl(spibar + 0xB0)); + if (tmp2 & (1 << 15)) { + printf("WARNING: SPI Configuration Lockdown activated.\n"); + ichspi_lock = 1; + } + ich_init_opcodes(); + break; + default: + /* Nothing */ + break; + } + + old = pci_read_byte(dev, 0xdc); + printf_debug("SPI Read Configuration: "); + new = (old >> 2) & 0x3; + switch (new) { + case 0: + case 1: + case 2: + printf_debug("prefetching %sabled, caching %sabled, ", + (new & 0x2) ? "en" : "dis", + (new & 0x1) ? "dis" : "en"); + break; + default: + printf_debug("invalid prefetching/caching settings, "); + break; + } + + return ret; +} + +static int enable_flash_ich7(struct pci_dev *dev, const char *name) +{ + return enable_flash_ich_dc_spi(dev, name, 7); +} + +static int enable_flash_ich8(struct pci_dev *dev, const char *name) +{ + return enable_flash_ich_dc_spi(dev, name, 8); +} + +static int enable_flash_ich9(struct pci_dev *dev, const char *name) +{ + return enable_flash_ich_dc_spi(dev, name, 9); +} + +static int enable_flash_ich10(struct pci_dev *dev, const char *name) +{ + return enable_flash_ich_dc_spi(dev, name, 10); +} + +static int enable_flash_vt823x(struct pci_dev *dev, const char *name) +{ + uint8_t val; + + /* enable ROM decode range (1MB) FFC00000 - FFFFFFFF */ + pci_write_byte(dev, 0x41, 0x7f); + + /* ROM write enable */ + val = pci_read_byte(dev, 0x40); + val |= 0x10; + pci_write_byte(dev, 0x40, val); + + if (pci_read_byte(dev, 0x40) != val) { + printf("\nWARNING: Failed to enable flash write on \"%s\"\n", + name); + return -1; + } + + return 0; +} + +static int enable_flash_cs5530(struct pci_dev *dev, const char *name) +{ + uint8_t reg8; + +#define DECODE_CONTROL_REG2 0x5b /* F0 index 0x5b */ +#define ROM_AT_LOGIC_CONTROL_REG 0x52 /* F0 index 0x52 */ + +#define LOWER_ROM_ADDRESS_RANGE (1 << 0) +#define ROM_WRITE_ENABLE (1 << 1) +#define UPPER_ROM_ADDRESS_RANGE (1 << 2) +#define BIOS_ROM_POSITIVE_DECODE (1 << 5) + + /* Decode 0x000E0000-0x000FFFFF (128 KB), not just 64 KB, and + * decode 0xFF000000-0xFFFFFFFF (16 MB), not just 256 KB. + * Make the configured ROM areas writable. + */ + reg8 = pci_read_byte(dev, ROM_AT_LOGIC_CONTROL_REG); + reg8 |= LOWER_ROM_ADDRESS_RANGE; + reg8 |= UPPER_ROM_ADDRESS_RANGE; + reg8 |= ROM_WRITE_ENABLE; + pci_write_byte(dev, ROM_AT_LOGIC_CONTROL_REG, reg8); + + /* Set positive decode on ROM. */ + reg8 = pci_read_byte(dev, DECODE_CONTROL_REG2); + reg8 |= BIOS_ROM_POSITIVE_DECODE; + pci_write_byte(dev, DECODE_CONTROL_REG2, reg8); + + return 0; +} + +/** + * Geode systems write protect the BIOS via RCONFs (cache settings similar + * to MTRRs). To unlock, change MSR 0x1808 top byte to 0x22. + * + * Geode systems also write protect the NOR flash chip itself via MSR_NORF_CTL. + * To enable write to NOR Boot flash for the benefit of systems that have such + * a setup, raise MSR 0x51400018 WE_CS3 (write enable Boot Flash Chip Select). + */ +static int enable_flash_cs5536(struct pci_dev *dev, const char *name) +{ +#define MSR_RCONF_DEFAULT 0x1808 +#define MSR_NORF_CTL 0x51400018 + + msr_t msr; + + /* Geode only has a single core */ + if (setup_cpu_msr(0)) + return -1; + + msr = rdmsr(MSR_RCONF_DEFAULT); + if ((msr.hi >> 24) != 0x22) { + msr.hi &= 0xfbffffff; + wrmsr(MSR_RCONF_DEFAULT, msr); + } + + msr = rdmsr(MSR_NORF_CTL); + /* Raise WE_CS3 bit. */ + msr.lo |= 0x08; + wrmsr(MSR_NORF_CTL, msr); + + cleanup_cpu_msr(); + +#undef MSR_RCONF_DEFAULT +#undef MSR_NORF_CTL + return 0; +} + +static int enable_flash_sc1100(struct pci_dev *dev, const char *name) +{ + uint8_t new; + + pci_write_byte(dev, 0x52, 0xee); + + new = pci_read_byte(dev, 0x52); + + if (new != 0xee) { + printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x52, new, name); + return -1; + } + + return 0; +} + +/* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */ +static int enable_flash_amd8111(struct pci_dev *dev, const char *name) +{ + uint8_t old, new; + + /* Enable decoding at 0xffb00000 to 0xffffffff. */ + old = pci_read_byte(dev, 0x43); + new = old | 0xC0; + if (new != old) { + pci_write_byte(dev, 0x43, new); + if (pci_read_byte(dev, 0x43) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x43, new, name); + } + } + + /* Enable 'ROM write' bit. */ + old = pci_read_byte(dev, 0x40); + new = old | 0x01; + if (new == old) + return 0; + pci_write_byte(dev, 0x40, new); + + if (pci_read_byte(dev, 0x40) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name); + return -1; + } + + return 0; +} + +static int enable_flash_sb600(struct pci_dev *dev, const char *name) +{ + uint32_t tmp, prot; + uint8_t reg; + struct pci_dev *smbus_dev; + int has_spi = 1; + + /* Clear ROM protect 0-3. */ + for (reg = 0x50; reg < 0x60; reg += 4) { + prot = pci_read_long(dev, reg); + /* No protection flags for this region?*/ + if ((prot & 0x3) == 0) + continue; + printf_debug("SB600 %s%sprotected from %u to %u\n", + (prot & 0x1) ? "write " : "", + (prot & 0x2) ? "read " : "", + (prot & 0xfffffc00), + (prot & 0xfffffc00) + ((prot & 0x3ff) << 8)); + prot &= 0xfffffffc; + pci_write_byte(dev, reg, prot); + prot = pci_read_long(dev, reg); + if (prot & 0x3) + printf("SB600 %s%sunprotect failed from %u to %u\n", + (prot & 0x1) ? "write " : "", + (prot & 0x2) ? "read " : "", + (prot & 0xfffffc00), + (prot & 0xfffffc00) + ((prot & 0x3ff) << 8)); + } + + /* Read SPI_BaseAddr */ + tmp = pci_read_long(dev, 0xa0); + tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */ + printf_debug("SPI base address is at 0x%x\n", tmp); + + /* If the BAR has address 0, it is unlikely SPI is used. */ + if (!tmp) + has_spi = 0; + + if (has_spi) { + /* Physical memory has to be mapped at page (4k) boundaries. */ + sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000, + 0x1000); + /* The low bits of the SPI base address are used as offset into + * the mapped page. + */ + sb600_spibar += tmp & 0xfff; + + tmp = pci_read_long(dev, 0xa0); + printf_debug("AltSpiCSEnable=%i, SpiRomEnable=%i, " + "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1, + (tmp & 0x4) >> 2); + tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2; + printf_debug("PrefetchEnSPIFromIMC=%i, ", tmp); + + tmp = pci_read_byte(dev, 0xbb); + printf_debug("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n", + tmp & 0x1, (tmp & 0x20) >> 5); + tmp = mmio_readl(sb600_spibar); + printf_debug("SpiArbEnable=%i, SpiAccessMacRomEn=%i, " + "SpiHostAccessRomEn=%i, ArbWaitCount=%i, " + "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n", + (tmp >> 19) & 0x1, (tmp >> 22) & 0x1, + (tmp >> 23) & 0x1, (tmp >> 24) & 0x7, + (tmp >> 27) & 0x1, (tmp >> 28) & 0x1); + } + + /* Look for the SMBus device. */ + smbus_dev = pci_dev_find(0x1002, 0x4385); + + if (has_spi && !smbus_dev) { + fprintf(stderr, "ERROR: SMBus device not found. Not enabling SPI.\n"); + has_spi = 0; + } + if (has_spi) { + /* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */ + /* GPIO11/SPI_DO and GPIO12/SPI_DI status */ + reg = pci_read_byte(smbus_dev, 0xAB); + reg &= 0xC0; + printf_debug("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO"); + printf_debug("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI"); + if (reg != 0x00) + has_spi = 0; + /* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */ + reg = pci_read_byte(smbus_dev, 0x83); + reg &= 0xC0; + printf_debug("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD"); + printf_debug("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS"); + /* SPI_HOLD is not used on all boards, filter it out. */ + if ((reg & 0x80) != 0x00) + has_spi = 0; + /* GPIO47/SPI_CLK status */ + reg = pci_read_byte(smbus_dev, 0xA7); + reg &= 0x40; + printf_debug("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK"); + if (reg != 0x00) + has_spi = 0; + } + + buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH; + if (has_spi) { + buses_supported |= CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_SB600; + } + + /* Read ROM strap override register. */ + OUTB(0x8f, 0xcd6); + reg = INB(0xcd7); + reg &= 0x0e; + printf_debug("ROM strap override is %sactive", (reg & 0x02) ? "" : "not "); + if (reg & 0x02) { + switch ((reg & 0x0c) >> 2) { + case 0x00: + printf_debug(": LPC"); + break; + case 0x01: + printf_debug(": PCI"); + break; + case 0x02: + printf_debug(": FWH"); + break; + case 0x03: + printf_debug(": SPI"); + break; + } + } + printf_debug("\n"); + + /* Force enable SPI ROM in SB600 PM register. + * If we enable SPI ROM here, we have to disable it after we leave. + * But how can we know which ROM we are going to handle? So we have + * to trade off. We only access LPC ROM if we boot via LPC ROM. And + * only SPI ROM if we boot via SPI ROM. If you want to access SPI on + * boards with LPC straps, you have to use the code below. + */ + /* + OUTB(0x8f, 0xcd6); + OUTB(0x0e, 0xcd7); + */ + + return 0; +} + +static int enable_flash_nvidia_nforce2(struct pci_dev *dev, const char *name) +{ + uint8_t tmp; + + pci_write_byte(dev, 0x92, 0); + + tmp = pci_read_byte(dev, 0x6d); + tmp |= 0x01; + pci_write_byte(dev, 0x6d, tmp); + + return 0; +} + +static int enable_flash_ck804(struct pci_dev *dev, const char *name) +{ + uint8_t old, new; + + old = pci_read_byte(dev, 0x88); + new = old | 0xc0; + if (new != old) { + pci_write_byte(dev, 0x88, new); + if (pci_read_byte(dev, 0x88) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x88, new, name); + } + } + + old = pci_read_byte(dev, 0x6d); + new = old | 0x01; + if (new == old) + return 0; + pci_write_byte(dev, 0x6d, new); + + if (pci_read_byte(dev, 0x6d) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name); + return -1; + } + + return 0; +} + +/* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */ +static int enable_flash_sb400(struct pci_dev *dev, const char *name) +{ + uint8_t tmp; + struct pci_dev *smbusdev; + + /* Look for the SMBus device. */ + smbusdev = pci_dev_find(0x1002, 0x4372); + + if (!smbusdev) { + fprintf(stderr, "ERROR: SMBus device not found. Aborting.\n"); + exit(1); + } + + /* Enable some SMBus stuff. */ + tmp = pci_read_byte(smbusdev, 0x79); + tmp |= 0x01; + pci_write_byte(smbusdev, 0x79, tmp); + + /* Change southbridge. */ + tmp = pci_read_byte(dev, 0x48); + tmp |= 0x21; + pci_write_byte(dev, 0x48, tmp); + + /* Now become a bit silly. */ + tmp = INB(0xc6f); + OUTB(tmp, 0xeb); + OUTB(tmp, 0xeb); + tmp |= 0x40; + OUTB(tmp, 0xc6f); + OUTB(tmp, 0xeb); + OUTB(tmp, 0xeb); + + return 0; +} + +static int enable_flash_mcp55(struct pci_dev *dev, const char *name) +{ + uint8_t old, new, byte; + uint16_t word; + + /* Set the 0-16 MB enable bits. */ + byte = pci_read_byte(dev, 0x88); + byte |= 0xff; /* 256K */ + pci_write_byte(dev, 0x88, byte); + byte = pci_read_byte(dev, 0x8c); + byte |= 0xff; /* 1M */ + pci_write_byte(dev, 0x8c, byte); + word = pci_read_word(dev, 0x90); + word |= 0x7fff; /* 16M */ + pci_write_word(dev, 0x90, word); + + old = pci_read_byte(dev, 0x6d); + new = old | 0x01; + if (new == old) + return 0; + pci_write_byte(dev, 0x6d, new); + + if (pci_read_byte(dev, 0x6d) != new) { + printf_debug("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name); + return -1; + } + + return 0; +} + +static int enable_flash_ht1000(struct pci_dev *dev, const char *name) +{ + uint8_t byte; + + /* Set the 4MB enable bit. */ + byte = pci_read_byte(dev, 0x41); + byte |= 0x0e; + pci_write_byte(dev, 0x41, byte); + + byte = pci_read_byte(dev, 0x43); + byte |= (1 << 4); + pci_write_byte(dev, 0x43, byte); + + return 0; +} + +/** + * Usually on the x86 architectures (and on other PC-like platforms like some + * Alphas or Itanium) the system flash is mapped right below 4G. On the AMD + * Elan SC520 only a small piece of the system flash is mapped there, but the + * complete flash is mapped somewhere below 1G. The position can be determined + * by the BOOTCS PAR register. + */ +static int get_flashbase_sc520(struct pci_dev *dev, const char *name) +{ + int i, bootcs_found = 0; + uint32_t parx = 0; + void *mmcr; + + /* 1. Map MMCR */ + mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize()); + + /* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for + * BOOTCS region (PARx[31:29] = 100b)e + */ + for (i = 0x88; i <= 0xc4; i += 4) { + parx = mmio_readl(mmcr + i); + if ((parx >> 29) == 4) { + bootcs_found = 1; + break; /* BOOTCS found */ + } + } + + /* 3. PARx[25] = 1b --> flashbase[29:16] = PARx[13:0] + * PARx[25] = 0b --> flashbase[29:12] = PARx[17:0] + */ + if (bootcs_found) { + if (parx & (1 << 25)) { + parx &= (1 << 14) - 1; /* Mask [13:0] */ + flashbase = parx << 16; + } else { + parx &= (1 << 18) - 1; /* Mask [17:0] */ + flashbase = parx << 12; + } + } else { + printf("AMD Elan SC520 detected, but no BOOTCS. Assuming flash at 4G\n"); + } + + /* 4. Clean up */ + physunmap(mmcr, getpagesize()); + return 0; +} + +/* Please keep this list alphabetically sorted by vendor/device. */ +const struct penable chipset_enables[] = { + {0x10B9, 0x1533, OK, "ALi", "M1533", enable_flash_ali_m1533}, + {0x1022, 0x7440, OK, "AMD", "AMD-768", enable_flash_amd8111}, + {0x1022, 0x7468, OK, "AMD", "AMD8111", enable_flash_amd8111}, + {0x1078, 0x0100, OK, "AMD", "CS5530(A)", enable_flash_cs5530}, + {0x1022, 0x2080, OK, "AMD", "CS5536", enable_flash_cs5536}, + {0x1022, 0x2090, OK, "AMD", "CS5536", enable_flash_cs5536}, + {0x1022, 0x3000, OK, "AMD", "Elan SC520", get_flashbase_sc520}, + {0x1002, 0x438D, OK, "AMD", "SB600", enable_flash_sb600}, + {0x1002, 0x439d, OK, "AMD", "SB700/SB710/SB750", enable_flash_sb600}, + {0x100b, 0x0510, NT, "AMD", "SC1100", enable_flash_sc1100}, + {0x1002, 0x4377, OK, "ATI", "SB400", enable_flash_sb400}, + {0x1166, 0x0205, OK, "Broadcom", "HT-1000", enable_flash_ht1000}, + {0x8086, 0x3b00, NT, "Intel", "3400 Desktop", enable_flash_ich10}, + {0x8086, 0x3b01, NT, "Intel", "3400 Mobile", enable_flash_ich10}, + {0x8086, 0x3b0d, NT, "Intel", "3400 Mobile SFF", enable_flash_ich10}, + {0x8086, 0x7198, OK, "Intel", "440MX", enable_flash_piix4}, + {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich_4e}, + {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc}, + {0x8086, 0x5031, OK, "Intel", "EP80579", enable_flash_ich7}, + {0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich_4e}, + {0x8086, 0x3a18, OK, "Intel", "ICH10", enable_flash_ich10}, + {0x8086, 0x3a1a, OK, "Intel", "ICH10D", enable_flash_ich10}, + {0x8086, 0x3a14, OK, "Intel", "ICH10DO", enable_flash_ich10}, + {0x8086, 0x3a16, OK, "Intel", "ICH10R", enable_flash_ich10}, + {0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich_4e}, + {0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich_4e}, + {0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich_4e}, + {0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich_4e}, + {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich_4e}, + {0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich_4e}, + {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich_4e}, + {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich_dc}, + {0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich_dc}, + {0x8086, 0x27b0, OK, "Intel", "ICH7DH", enable_flash_ich7}, + {0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R", enable_flash_ich7}, + {0x8086, 0x27b9, OK, "Intel", "ICH7M", enable_flash_ich7}, + {0x8086, 0x27bd, OK, "Intel", "ICH7MDH", enable_flash_ich7}, + {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich_4e}, + {0x8086, 0x2812, OK, "Intel", "ICH8DH", enable_flash_ich8}, + {0x8086, 0x2814, OK, "Intel", "ICH8DO", enable_flash_ich8}, + {0x8086, 0x2810, OK, "Intel", "ICH8/ICH8R", enable_flash_ich8}, + {0x8086, 0x2815, OK, "Intel", "ICH8M", enable_flash_ich8}, + {0x8086, 0x2811, OK, "Intel", "ICH8M-E", enable_flash_ich8}, + {0x8086, 0x2918, OK, "Intel", "ICH9", enable_flash_ich9}, + {0x8086, 0x2912, OK, "Intel", "ICH9DH", enable_flash_ich9}, + {0x8086, 0x2914, OK, "Intel", "ICH9DO", enable_flash_ich9}, + {0x8086, 0x2919, OK, "Intel", "ICH9M", enable_flash_ich9}, + {0x8086, 0x2917, OK, "Intel", "ICH9M-E", enable_flash_ich9}, + {0x8086, 0x2916, OK, "Intel", "ICH9R", enable_flash_ich9}, + {0x8086, 0x2910, OK, "Intel", "ICH9 Engineering Sample", enable_flash_ich9}, + {0x8086, 0x1234, NT, "Intel", "MPIIX", enable_flash_piix4}, + {0x8086, 0x7000, OK, "Intel", "PIIX3", enable_flash_piix4}, + {0x8086, 0x7110, OK, "Intel", "PIIX4/4E/4M", enable_flash_piix4}, + {0x8086, 0x122e, OK, "Intel", "PIIX", enable_flash_piix4}, + {0x10de, 0x0030, OK, "NVIDIA", "nForce4/MCP4", enable_flash_nvidia_nforce2}, + {0x10de, 0x0050, OK, "NVIDIA", "CK804", enable_flash_ck804}, /* LPC */ + {0x10de, 0x0051, OK, "NVIDIA", "CK804", enable_flash_ck804}, /* Pro */ + {0x10de, 0x0060, OK, "NVIDIA", "NForce2", enable_flash_nvidia_nforce2}, + /* Slave, should not be here, to fix known bug for A01. */ + {0x10de, 0x00d3, OK, "NVIDIA", "CK804", enable_flash_ck804}, + {0x10de, 0x0260, NT, "NVIDIA", "MCP51", enable_flash_ck804}, + {0x10de, 0x0261, NT, "NVIDIA", "MCP51", enable_flash_ck804}, + {0x10de, 0x0262, NT, "NVIDIA", "MCP51", enable_flash_ck804}, + {0x10de, 0x0263, NT, "NVIDIA", "MCP51", enable_flash_ck804}, + {0x10de, 0x0360, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* M57SLI*/ + {0x10de, 0x0361, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ + {0x10de, 0x0362, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ + {0x10de, 0x0363, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ + {0x10de, 0x0364, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ + {0x10de, 0x0365, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ + {0x10de, 0x0366, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ + {0x10de, 0x0367, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* Pro */ + {0x10de, 0x0548, OK, "NVIDIA", "MCP67", enable_flash_mcp55}, + {0x1039, 0x0496, NT, "SiS", "85C496+497", enable_flash_sis85c496}, + {0x1039, 0x0406, NT, "SiS", "501/5101/5501", enable_flash_sis501}, + {0x1039, 0x5511, NT, "SiS", "5511", enable_flash_sis5511}, + {0x1039, 0x5596, NT, "SiS", "5596", enable_flash_sis5596}, + {0x1039, 0x5571, NT, "SiS", "5571", enable_flash_sis530}, + {0x1039, 0x5591, NT, "SiS", "5591/5592", enable_flash_sis530}, + {0x1039, 0x5597, NT, "SiS", "5597/5598/5581/5120", enable_flash_sis530}, + {0x1039, 0x0530, NT, "SiS", "530", enable_flash_sis530}, + {0x1039, 0x5600, NT, "SiS", "600", enable_flash_sis530}, + {0x1039, 0x0620, NT, "SiS", "620", enable_flash_sis530}, + {0x1039, 0x0540, NT, "SiS", "540", enable_flash_sis540}, + {0x1039, 0x0630, NT, "SiS", "630", enable_flash_sis540}, + {0x1039, 0x0635, NT, "SiS", "635", enable_flash_sis540}, + {0x1039, 0x0640, NT, "SiS", "640", enable_flash_sis540}, + {0x1039, 0x0645, NT, "SiS", "645", enable_flash_sis540}, + {0x1039, 0x0646, NT, "SiS", "645DX", enable_flash_sis540}, + {0x1039, 0x0648, NT, "SiS", "648", enable_flash_sis540}, + {0x1039, 0x0650, NT, "SiS", "650", enable_flash_sis540}, + {0x1039, 0x0651, NT, "SiS", "651", enable_flash_sis540}, + {0x1039, 0x0655, NT, "SiS", "655", enable_flash_sis540}, + {0x1039, 0x0730, NT, "SiS", "730", enable_flash_sis540}, + {0x1039, 0x0733, NT, "SiS", "733", enable_flash_sis540}, + {0x1039, 0x0735, OK, "SiS", "735", enable_flash_sis540}, + {0x1039, 0x0740, NT, "SiS", "740", enable_flash_sis540}, + {0x1039, 0x0745, NT, "SiS", "745", enable_flash_sis540}, + {0x1039, 0x0746, NT, "SiS", "746", enable_flash_sis540}, + {0x1039, 0x0748, NT, "SiS", "748", enable_flash_sis540}, + {0x1039, 0x0755, NT, "SiS", "755", enable_flash_sis540}, + {0x1106, 0x8324, OK, "VIA", "CX700", enable_flash_vt823x}, + {0x1106, 0x8231, NT, "VIA", "VT8231", enable_flash_vt823x}, + {0x1106, 0x3074, NT, "VIA", "VT8233", enable_flash_vt823x}, + {0x1106, 0x3177, OK, "VIA", "VT8235", enable_flash_vt823x}, + {0x1106, 0x3227, OK, "VIA", "VT8237", enable_flash_vt823x}, + {0x1106, 0x3337, OK, "VIA", "VT8237A", enable_flash_vt823x}, + {0x1106, 0x3372, OK, "VIA", "VT8237S", enable_flash_vt8237s_spi}, + {0x1106, 0x8353, OK, "VIA", "VX800", enable_flash_vt8237s_spi}, + {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_amd8111}, + {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_amd8111}, + {0x1106, 0x0686, NT, "VIA", "VT82C686A/B", enable_flash_amd8111}, + + {}, +}; + +int chipset_flash_enable(void) +{ + struct pci_dev *dev = 0; + int ret = -2; /* Nothing! */ + int i; + + /* Now let's try to find the chipset we have... */ + for (i = 0; chipset_enables[i].vendor_name != NULL; i++) { + dev = pci_dev_find(chipset_enables[i].vendor_id, + chipset_enables[i].device_id); + if (dev) + break; + } + + if (dev) { + printf("Found chipset \"%s %s\", enabling flash write... ", + chipset_enables[i].vendor_name, + chipset_enables[i].device_name); + + ret = chipset_enables[i].doit(dev, + chipset_enables[i].device_name); + if (ret) + printf("FAILED!\n"); + else + printf("OK.\n"); + } + printf("This chipset supports the following protocols: %s.\n", + flashbuses_to_text(buses_supported)); + + return ret; +} diff --git a/libflashrom/drkaiser.c b/libflashrom/drkaiser.c new file mode 100644 index 0000000..f13c13e --- /dev/null +++ b/libflashrom/drkaiser.c @@ -0,0 +1,79 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Joerg Fischer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "flash.h" + +#define PCI_VENDOR_ID_DRKAISER 0x1803 + +#define PCI_MAGIC_DRKAISER_ADDR 0x50 +#define PCI_MAGIC_DRKAISER_VALUE 0xa971 + +struct pcidev_status drkaiser_pcidev[] = { + {0x1803, 0x5057, PCI_OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"}, + {}, +}; + +uint8_t *drkaiser_bar; + +int drkaiser_init(void) +{ + uint32_t addr; + + get_io_perms(); + pcidev_init(PCI_VENDOR_ID_DRKAISER, PCI_BASE_ADDRESS_2, + drkaiser_pcidev, programmer_param); + + /* Write magic register to enable flash write. */ + pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, + PCI_MAGIC_DRKAISER_VALUE); + + /* TODO: Mask lower bits? How many? 3? 7? */ + addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) & ~0x03; + + /* Map 128KB flash memory window. */ + drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory", + addr, 128 * 1024); + + buses_supported = CHIP_BUSTYPE_PARALLEL; + return 0; +} + +int drkaiser_shutdown(void) +{ + /* Write protect the flash again. */ + pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, 0); + free(programmer_param); + pci_cleanup(pacc); + release_io_perms(); + return 0; +}; + +void drkaiser_chip_writeb(uint8_t val, chipaddr addr) +{ + mmio_writeb(val, drkaiser_bar + addr); +} + +uint8_t drkaiser_chip_readb(const chipaddr addr) +{ + return mmio_readb(drkaiser_bar + addr); +} diff --git a/libflashrom/dummyflasher.c b/libflashrom/dummyflasher.c new file mode 100644 index 0000000..903f88b --- /dev/null +++ b/libflashrom/dummyflasher.c @@ -0,0 +1,158 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "flash.h" + +int dummy_init(void) +{ + int i; + printf_debug("%s\n", __func__); + + /* "all" is equivalent to specifying no type. */ + if (programmer_param && (!strcmp(programmer_param, "all"))) { + free(programmer_param); + programmer_param = NULL; + } + if (!programmer_param) + programmer_param = strdup("parallel,lpc,fwh,spi"); + /* Convert the parameters to lowercase. */ + for (i = 0; programmer_param[i] != '\0'; i++) + programmer_param[i] = (char)tolower(programmer_param[i]); + + buses_supported = CHIP_BUSTYPE_NONE; + if (strstr(programmer_param, "parallel")) { + buses_supported |= CHIP_BUSTYPE_PARALLEL; + printf_debug("Enabling support for %s flash.\n", "parallel"); + } + if (strstr(programmer_param, "lpc")) { + buses_supported |= CHIP_BUSTYPE_LPC; + printf_debug("Enabling support for %s flash.\n", "LPC"); + } + if (strstr(programmer_param, "fwh")) { + buses_supported |= CHIP_BUSTYPE_FWH; + printf_debug("Enabling support for %s flash.\n", "FWH"); + } + if (strstr(programmer_param, "spi")) { + buses_supported |= CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_DUMMY; + printf_debug("Enabling support for %s flash.\n", "SPI"); + } + if (buses_supported == CHIP_BUSTYPE_NONE) + printf_debug("Support for all flash bus types disabled.\n"); + free(programmer_param); + return 0; +} + +int dummy_shutdown(void) +{ + printf_debug("%s\n", __func__); + return 0; +} + +void *dummy_map(const char *descr, unsigned long phys_addr, size_t len) +{ + printf_debug("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n", + __func__, descr, (unsigned long)len, phys_addr); + return (void *)phys_addr; +} + +void dummy_unmap(void *virt_addr, size_t len) +{ + printf_debug("%s: Unmapping 0x%lx bytes at %p\n", + __func__, (unsigned long)len, virt_addr); +} + +void dummy_chip_writeb(uint8_t val, chipaddr addr) +{ + printf_debug("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val); +} + +void dummy_chip_writew(uint16_t val, chipaddr addr) +{ + printf_debug("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val); +} + +void dummy_chip_writel(uint32_t val, chipaddr addr) +{ + printf_debug("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val); +} + +void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len) +{ + size_t i; + printf_debug("%s: addr=0x%lx, len=0x%08lx, writing data (hex):", + __func__, addr, (unsigned long)len); + for (i = 0; i < len; i++) { + if ((i % 16) == 0) + printf_debug("\n"); + printf_debug("%02x ", buf[i]) + } +} + +uint8_t dummy_chip_readb(const chipaddr addr) +{ + printf_debug("%s: addr=0x%lx, returning 0xff\n", __func__, addr); + return 0xff; +} + +uint16_t dummy_chip_readw(const chipaddr addr) +{ + printf_debug("%s: addr=0x%lx, returning 0xffff\n", __func__, addr); + return 0xffff; +} + +uint32_t dummy_chip_readl(const chipaddr addr) +{ + printf_debug("%s: addr=0x%lx, returning 0xffffffff\n", __func__, addr); + return 0xffffffff; +} + +void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len) +{ + printf_debug("%s: addr=0x%lx, len=0x%lx, returning array of 0xff\n", + __func__, addr, (unsigned long)len); + memset(buf, 0xff, len); + return; +} + +int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int i; + + printf_debug("%s:", __func__); + + printf_debug(" writing %u bytes:", writecnt); + for (i = 0; i < writecnt; i++) + printf_debug(" 0x%02x", writearr[i]); + + printf_debug(" reading %u bytes:", readcnt); + for (i = 0; i < readcnt; i++) { + printf_debug(" 0xff"); + readarr[i] = 0xff; + } + + printf_debug("\n"); + return 0; +} diff --git a/libflashrom/en29f002a.c b/libflashrom/en29f002a.c new file mode 100644 index 0000000..020df32 --- /dev/null +++ b/libflashrom/en29f002a.c @@ -0,0 +1,89 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2007 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * EN29F512 has 1C,21 + * EN29F010 has 1C,20 + * EN29F040A has 1C,04 + * EN29LV010 has 1C,6E and uses short F0 reset sequence + * EN29LV040(A) has 1C,4F and uses short F0 reset sequence + */ + +#include "flash.h" + +int probe_en29f512(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x90, bios + 0x555); + + programmer_delay(10); + + id1 = chip_readb(bios + 0x100); + id2 = chip_readb(bios + 0x101); + + /* exit by writing F0 anywhere? or the code below */ + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0xF0, bios + 0x555); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} + +/* + * EN29F002AT has 1C,92 + * EN29F002AB has 1C,97 + */ + +/* This does not seem to function properly for EN29F002NT. */ +int probe_en29f002a(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0xAAA); + chip_writeb(0x90, bios + 0x555); + + programmer_delay(10); + + id1 = chip_readb(bios + 0x100); + id2 = chip_readb(bios + 0x101); + + /* exit by writing F0 anywhere? or the code below */ + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0xAAA); + chip_writeb(0xF0, bios + 0x555); + + printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); + + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} diff --git a/libflashrom/flash.h b/libflashrom/flash.h new file mode 100644 index 0000000..4178d47 --- /dev/null +++ b/libflashrom/flash.h @@ -0,0 +1,763 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2000 Ronald G. Minnich + * Copyright (C) 2005-2009 coresystems GmbH + * Copyright (C) 2006-2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __FLASH_H__ +#define __FLASH_H__ 1 + +#if defined(__GLIBC__) +#include +#endif +#include +#include +#include +#include + +/* for iopl and outb under Solaris */ +#if defined (__sun) && (defined(__i386) || defined(__amd64)) +#include +#include +#include +#include +#endif + +#if (defined(__MACH__) && defined(__APPLE__)) +#define __DARWIN__ +#endif + +#if defined(__FreeBSD__) || defined(__DragonFly__) + #include + #define off64_t off_t + #define lseek64 lseek + #define OUTB(x, y) do { u_int tmp = (y); outb(tmp, (x)); } while (0) + #define OUTW(x, y) do { u_int tmp = (y); outw(tmp, (x)); } while (0) + #define OUTL(x, y) do { u_int tmp = (y); outl(tmp, (x)); } while (0) + #define INB(x) __extension__ ({ u_int tmp = (x); inb(tmp); }) + #define INW(x) __extension__ ({ u_int tmp = (x); inw(tmp); }) + #define INL(x) __extension__ ({ u_int tmp = (x); inl(tmp); }) +#else +#if defined(__DARWIN__) + #include + #define off64_t off_t + #define lseek64 lseek +#endif +#if defined (__sun) && (defined(__i386) || defined(__amd64)) + /* Note different order for outb */ + #define OUTB(x,y) outb(y, x) + #define OUTW(x,y) outw(y, x) + #define OUTL(x,y) outl(y, x) + #define INB inb + #define INW inw + #define INL inl +#else + #define OUTB outb + #define OUTW outw + #define OUTL outl + #define INB inb + #define INW inw + #define INL inl +#endif +#endif + +typedef unsigned long chipaddr; + +enum programmer { + PROGRAMMER_INTERNAL, +#if DUMMY_SUPPORT == 1 + PROGRAMMER_DUMMY, +#endif +#if NIC3COM_SUPPORT == 1 + PROGRAMMER_NIC3COM, +#endif +#if GFXNVIDIA_SUPPORT == 1 + PROGRAMMER_GFXNVIDIA, +#endif +#if DRKAISER_SUPPORT == 1 + PROGRAMMER_DRKAISER, +#endif +#if SATASII_SUPPORT == 1 + PROGRAMMER_SATASII, +#endif + PROGRAMMER_IT87SPI, +#if FT2232_SPI_SUPPORT == 1 + PROGRAMMER_FT2232SPI, +#endif +#if SERPROG_SUPPORT == 1 + PROGRAMMER_SERPROG, +#endif +#if BUSPIRATE_SPI_SUPPORT == 1 + PROGRAMMER_BUSPIRATESPI, +#endif + PROGRAMMER_INVALID /* This must always be the last entry. */ +}; + +extern enum programmer programmer; + +struct programmer_entry { + const char *vendor; + const char *name; + + int (*init) (void); + int (*shutdown) (void); + + void * (*map_flash_region) (const char *descr, unsigned long phys_addr, + size_t len); + void (*unmap_flash_region) (void *virt_addr, size_t len); + + void (*chip_writeb) (uint8_t val, chipaddr addr); + void (*chip_writew) (uint16_t val, chipaddr addr); + void (*chip_writel) (uint32_t val, chipaddr addr); + void (*chip_writen) (uint8_t *buf, chipaddr addr, size_t len); + uint8_t (*chip_readb) (const chipaddr addr); + uint16_t (*chip_readw) (const chipaddr addr); + uint32_t (*chip_readl) (const chipaddr addr); + void (*chip_readn) (uint8_t *buf, const chipaddr addr, size_t len); + void (*delay) (int usecs); +}; + +extern const struct programmer_entry programmer_table[]; + +int programmer_init(void); +int programmer_shutdown(void); +void *programmer_map_flash_region(const char *descr, unsigned long phys_addr, + size_t len); +void programmer_unmap_flash_region(void *virt_addr, size_t len); +void chip_writeb(uint8_t val, chipaddr addr); +void chip_writew(uint16_t val, chipaddr addr); +void chip_writel(uint32_t val, chipaddr addr); +void chip_writen(uint8_t *buf, chipaddr addr, size_t len); +uint8_t chip_readb(const chipaddr addr); +uint16_t chip_readw(const chipaddr addr); +uint32_t chip_readl(const chipaddr addr); +void chip_readn(uint8_t *buf, const chipaddr addr, size_t len); +void programmer_delay(int usecs); + +enum bitbang_spi_master { + BITBANG_SPI_INVALID /* This must always be the last entry. */ +}; + +extern const int bitbang_spi_master_count; + +extern enum bitbang_spi_master bitbang_spi_master; + +struct bitbang_spi_master_entry { + void (*set_cs) (int val); + void (*set_sck) (int val); + void (*set_mosi) (int val); + int (*get_miso) (void); +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +enum chipbustype { + CHIP_BUSTYPE_NONE = 0, + CHIP_BUSTYPE_PARALLEL = 1 << 0, + CHIP_BUSTYPE_LPC = 1 << 1, + CHIP_BUSTYPE_FWH = 1 << 2, + CHIP_BUSTYPE_SPI = 1 << 3, + CHIP_BUSTYPE_NONSPI = CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, + CHIP_BUSTYPE_UNKNOWN = CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI, +}; + +/* + * How many different contiguous runs of erase blocks with one size each do + * we have for a given erase function? + */ +#define NUM_ERASEREGIONS 5 + +/* + * How many different erase functions do we have per chip? + */ +#define NUM_ERASEFUNCTIONS 5 + +struct flashchip { + const char *vendor; + const char *name; + + enum chipbustype bustype; + + /* + * With 32bit manufacture_id and model_id we can cover IDs up to + * (including) the 4th bank of JEDEC JEP106W Standard Manufacturer's + * Identification code. + */ + uint32_t manufacture_id; + uint32_t model_id; + + int total_size; + int page_size; + + /* + * Indicate if flashrom has been tested with this flash chip and if + * everything worked correctly. + */ + uint32_t tested; + + int (*probe) (struct flashchip *flash); + + /* Delay after "enter/exit ID mode" commands in microseconds. */ + int probe_timing; + int (*erase) (struct flashchip *flash); + + /* + * Erase blocks and associated erase function. The default entry is a + * chip-sized virtual block together with the chip erase function. + */ + struct block_eraser { + struct eraseblock{ + unsigned int size; /* Eraseblock size */ + unsigned int count; /* Number of contiguous blocks with that size */ + } eraseblocks[NUM_ERASEREGIONS]; + int (*block_erase) (struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen); + } block_erasers[NUM_ERASEFUNCTIONS]; + + int (*write) (struct flashchip *flash, uint8_t *buf); + int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len); + + /* Some flash devices have an additional register space. */ + chipaddr virtual_memory; + chipaddr virtual_registers; +}; + +#define TEST_UNTESTED 0 + +#define TEST_OK_PROBE (1 << 0) +#define TEST_OK_READ (1 << 1) +#define TEST_OK_ERASE (1 << 2) +#define TEST_OK_WRITE (1 << 3) +#define TEST_OK_PR (TEST_OK_PROBE | TEST_OK_READ) +#define TEST_OK_PRE (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE) +#define TEST_OK_PRW (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_WRITE) +#define TEST_OK_PREW (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE | TEST_OK_WRITE) +#define TEST_OK_MASK 0x0f + +#define TEST_BAD_PROBE (1 << 4) +#define TEST_BAD_READ (1 << 5) +#define TEST_BAD_ERASE (1 << 6) +#define TEST_BAD_WRITE (1 << 7) +#define TEST_BAD_PREW (TEST_BAD_PROBE | TEST_BAD_READ | TEST_BAD_ERASE | TEST_BAD_WRITE) +#define TEST_BAD_MASK 0xf0 + +/* Timing used in probe routines. ZERO is -2 to differentiate between an unset + * field and zero delay. + * + * SPI devices will always have zero delay and ignore this field. + */ +#define TIMING_FIXME -1 +/* this is intentionally same value as fixme */ +#define TIMING_IGNORED -1 +#define TIMING_ZERO -2 + +extern struct flashchip flashchips[]; + +struct penable { + uint16_t vendor_id; + uint16_t device_id; + int status; + const char *vendor_name; + const char *device_name; + int (*doit) (struct pci_dev *dev, const char *name); +}; + +extern const struct penable chipset_enables[]; + +struct board_pciid_enable { + /* Any device, but make it sensible, like the ISA bridge. */ + uint16_t first_vendor; + uint16_t first_device; + uint16_t first_card_vendor; + uint16_t first_card_device; + + /* Any device, but make it sensible, like + * the host bridge. May be NULL. + */ + uint16_t second_vendor; + uint16_t second_device; + uint16_t second_card_vendor; + uint16_t second_card_device; + + /* The vendor / part name from the coreboot table. */ + const char *lb_vendor; + const char *lb_part; + + const char *vendor_name; + const char *board_name; + + int (*enable) (const char *name); +}; + +extern struct board_pciid_enable board_pciid_enables[]; + +struct board_info { + const char *vendor; + const char *name; +}; + +extern const struct board_info boards_ok[]; +extern const struct board_info boards_bad[]; +extern const struct board_info laptops_ok[]; +extern const struct board_info laptops_bad[]; + +/* udelay.c */ +void myusec_delay(int usecs); +void myusec_calibrate_delay(void); + +/* pcidev.c */ +#define PCI_OK 0 +#define PCI_NT 1 /* Not tested */ + +extern uint32_t io_base_addr; +extern struct pci_access *pacc; +extern struct pci_filter filter; +extern struct pci_dev *pcidev_dev; +struct pcidev_status { + uint16_t vendor_id; + uint16_t device_id; + int status; + const char *vendor_name; + const char *device_name; +}; +uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, struct pcidev_status *devs); +uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, struct pcidev_status *devs, char *pcidev_bdf); + +/* print.c */ +char *flashbuses_to_text(enum chipbustype bustype); +void print_supported(void); +void print_supported_pcidevs(struct pcidev_status *devs); +void print_supported_wiki(void); + +/* board_enable.c */ +void w836xx_ext_enter(uint16_t port); +void w836xx_ext_leave(uint16_t port); +uint8_t sio_read(uint16_t port, uint8_t reg); +void sio_write(uint16_t port, uint8_t reg, uint8_t data); +void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask); +int board_flash_enable(const char *vendor, const char *part); + +struct decode_sizes { + uint32_t parallel; + uint32_t lpc; + uint32_t fwh; + uint32_t spi; +}; + +/* chipset_enable.c */ +extern enum chipbustype buses_supported; +int chipset_flash_enable(void); +extern struct decode_sizes max_rom_decode; + +extern unsigned long flashbase; + +/* physmap.c */ +void *physmap(const char *descr, unsigned long phys_addr, size_t len); +void physunmap(void *virt_addr, size_t len); +int setup_cpu_msr(int cpu); +void cleanup_cpu_msr(void); +#if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(__DragonFly__) +typedef struct { uint32_t hi, lo; } msr_t; +msr_t rdmsr(int addr); +int wrmsr(int addr, msr_t msr); +#endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */ +#undef rdmsr +#undef wrmsr +#define rdmsr freebsd_rdmsr +#define wrmsr freebsd_wrmsr +typedef struct { uint32_t hi, lo; } msr_t; +msr_t freebsd_rdmsr(int addr); +int freebsd_wrmsr(int addr, msr_t msr); +#endif + +/* internal.c */ +struct pci_dev *pci_dev_find_filter(struct pci_filter filter); +struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class); +struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device); +struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device, + uint16_t card_vendor, uint16_t card_device); +void get_io_perms(void); +void release_io_perms(void); +int internal_init(void); +int internal_shutdown(void); +void internal_chip_writeb(uint8_t val, chipaddr addr); +void internal_chip_writew(uint16_t val, chipaddr addr); +void internal_chip_writel(uint32_t val, chipaddr addr); +uint8_t internal_chip_readb(const chipaddr addr); +uint16_t internal_chip_readw(const chipaddr addr); +uint32_t internal_chip_readl(const chipaddr addr); +void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); +void mmio_writeb(uint8_t val, void *addr); +void mmio_writew(uint16_t val, void *addr); +void mmio_writel(uint32_t val, void *addr); +uint8_t mmio_readb(void *addr); +uint16_t mmio_readw(void *addr); +uint32_t mmio_readl(void *addr); +void internal_delay(int usecs); +int noop_shutdown(void); +void *fallback_map(const char *descr, unsigned long phys_addr, size_t len); +void fallback_unmap(void *virt_addr, size_t len); +uint8_t noop_chip_readb(const chipaddr addr); +void noop_chip_writeb(uint8_t val, chipaddr addr); +void fallback_chip_writew(uint16_t val, chipaddr addr); +void fallback_chip_writel(uint32_t val, chipaddr addr); +void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len); +uint16_t fallback_chip_readw(const chipaddr addr); +uint32_t fallback_chip_readl(const chipaddr addr); +void fallback_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); +#if defined(__FreeBSD__) || defined(__DragonFly__) +extern int io_fd; +#endif + +/* dummyflasher.c */ +int dummy_init(void); +int dummy_shutdown(void); +void *dummy_map(const char *descr, unsigned long phys_addr, size_t len); +void dummy_unmap(void *virt_addr, size_t len); +void dummy_chip_writeb(uint8_t val, chipaddr addr); +void dummy_chip_writew(uint16_t val, chipaddr addr); +void dummy_chip_writel(uint32_t val, chipaddr addr); +void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len); +uint8_t dummy_chip_readb(const chipaddr addr); +uint16_t dummy_chip_readw(const chipaddr addr); +uint32_t dummy_chip_readl(const chipaddr addr); +void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); +int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); + +/* nic3com.c */ +int nic3com_init(void); +int nic3com_shutdown(void); +void nic3com_chip_writeb(uint8_t val, chipaddr addr); +uint8_t nic3com_chip_readb(const chipaddr addr); +extern struct pcidev_status nics_3com[]; + +/* gfxnvidia.c */ +int gfxnvidia_init(void); +int gfxnvidia_shutdown(void); +void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr); +uint8_t gfxnvidia_chip_readb(const chipaddr addr); +extern struct pcidev_status gfx_nvidia[]; + +/* drkaiser.c */ +int drkaiser_init(void); +int drkaiser_shutdown(void); +void drkaiser_chip_writeb(uint8_t val, chipaddr addr); +uint8_t drkaiser_chip_readb(const chipaddr addr); +extern struct pcidev_status drkaiser_pcidev[]; + +/* satasii.c */ +int satasii_init(void); +int satasii_shutdown(void); +void satasii_chip_writeb(uint8_t val, chipaddr addr); +uint8_t satasii_chip_readb(const chipaddr addr); +extern struct pcidev_status satas_sii[]; + +/* ft2232_spi.c */ +#define FTDI_FT2232H 0x6010 +#define FTDI_FT4232H 0x6011 +int ft2232_spi_init(void); +int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf); + +/* bitbang_spi.c */ +extern int bitbang_spi_half_period; +extern const struct bitbang_spi_master_entry bitbang_spi_master_table[]; +int bitbang_spi_init(void); +int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf); + +/* buspirate_spi.c */ +struct buspirate_spispeeds { + const char *name; + const int speed; +}; +int buspirate_spi_init(void); +int buspirate_spi_shutdown(void); +int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); + +/* flashrom.c */ +extern char *programmer_param; +extern int verbose; +extern const char *flashrom_version; +#define printf_debug(x...) { if (verbose) printf(x); } +void map_flash_registers(struct flashchip *flash); +int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len); +int erase_flash(struct flashchip *flash); +int min(int a, int b); +int max(int a, int b); +char *extract_param(char **haystack, char *needle, char *delim); +int check_erased_range(struct flashchip *flash, int start, int len); +int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message); +char *strcat_realloc(char *dest, const char *src); + +#define OK 0 +#define NT 1 /* Not tested */ + +/* layout.c */ +int show_id(uint8_t *bios, int size, int force); +int read_romlayout(char *name); +int find_romentry(char *name); +int handle_romentries(uint8_t *buffer, struct flashchip *flash); + +/* cbtable.c */ +int coreboot_init(void); +extern char *lb_part, *lb_vendor; +extern int partvendor_from_cbtable; + +/* spi.c */ +enum spi_controller { + SPI_CONTROLLER_NONE, + SPI_CONTROLLER_ICH7, + SPI_CONTROLLER_ICH9, + SPI_CONTROLLER_IT87XX, + SPI_CONTROLLER_SB600, + SPI_CONTROLLER_VIA, + SPI_CONTROLLER_WBSIO, +#if FT2232_SPI_SUPPORT == 1 + SPI_CONTROLLER_FT2232, +#endif +#if DUMMY_SUPPORT == 1 + SPI_CONTROLLER_DUMMY, +#endif +#if BUSPIRATE_SPI_SUPPORT == 1 + SPI_CONTROLLER_BUSPIRATE, +#endif + SPI_CONTROLLER_INVALID /* This must always be the last entry. */ +}; +extern const int spi_programmer_count; +struct spi_command { + unsigned int writecnt; + unsigned int readcnt; + const unsigned char *writearr; + unsigned char *readarr; +}; +struct spi_programmer { + int (*command)(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); + int (*multicommand)(struct spi_command *cmds); + + /* Optimized functions for this programmer */ + int (*read)(struct flashchip *flash, uint8_t *buf, int start, int len); + int (*write_256)(struct flashchip *flash, uint8_t *buf); +}; + +extern enum spi_controller spi_controller; +extern const struct spi_programmer spi_programmer[]; +extern void *spibar; +int probe_spi_rdid(struct flashchip *flash); +int probe_spi_rdid4(struct flashchip *flash); +int probe_spi_rems(struct flashchip *flash); +int probe_spi_res(struct flashchip *flash); +int spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int spi_send_multicommand(struct spi_command *cmds); +int spi_write_enable(void); +int spi_write_disable(void); +int spi_chip_erase_60(struct flashchip *flash); +int spi_chip_erase_c7(struct flashchip *flash); +int spi_chip_erase_60_c7(struct flashchip *flash); +int spi_chip_erase_d8(struct flashchip *flash); +int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen); +int spi_chip_write_1(struct flashchip *flash, uint8_t *buf); +int spi_chip_write_256(struct flashchip *flash, uint8_t *buf); +int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); +uint8_t spi_read_status_register(void); +int spi_disable_blockprotect(void); +int spi_byte_program(int addr, uint8_t byte); +int spi_nbyte_program(int addr, uint8_t *bytes, int len); +int spi_nbyte_read(int addr, uint8_t *bytes, int len); +int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize); +int spi_aai_write(struct flashchip *flash, uint8_t *buf); +uint32_t spi_get_valid_read_addr(void); +int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int default_spi_send_multicommand(struct spi_command *cmds); + +/* 82802ab.c */ +int probe_82802ab(struct flashchip *flash); +int erase_82802ab(struct flashchip *flash); +int write_82802ab(struct flashchip *flash, uint8_t *buf); + +/* am29f040b.c */ +int probe_29f040b(struct flashchip *flash); +int erase_29f040b(struct flashchip *flash); +int write_29f040b(struct flashchip *flash, uint8_t *buf); + +/* pm29f002.c */ +int write_pm29f002(struct flashchip *flash, uint8_t *buf); + +/* en29f002a.c */ +int probe_en29f002a(struct flashchip *flash); +int erase_en29f002a(struct flashchip *flash); +int write_en29f002a(struct flashchip *flash, uint8_t *buf); + +/* ichspi.c */ +int ich_init_opcodes(void); +int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int ich_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int ich_spi_write_256(struct flashchip *flash, uint8_t * buf); +int ich_spi_send_multicommand(struct spi_command *cmds); + +/* it87spi.c */ +extern uint16_t it8716f_flashport; +void enter_conf_mode_ite(uint16_t port); +void exit_conf_mode_ite(uint16_t port); +int it87spi_init(void); +int it87xx_probe_spi_flash(const char *name); +int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf); + +/* sb600spi.c */ +int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf); +extern uint8_t *sb600_spibar; + +/* jedec.c */ +uint8_t oddparity(uint8_t val); +void toggle_ready_jedec(chipaddr dst); +void data_polling_jedec(chipaddr dst, uint8_t data); +void start_program_jedec(chipaddr bios); +int write_byte_program_jedec(chipaddr bios, uint8_t *src, + chipaddr dst); +int probe_jedec(struct flashchip *flash); +int erase_chip_jedec(struct flashchip *flash); +int write_jedec(struct flashchip *flash, uint8_t *buf); +int write_jedec_1(struct flashchip *flash, uint8_t *buf); +int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize); +int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize); +int write_sector_jedec(chipaddr bios, uint8_t *src, + chipaddr dst, unsigned int page_size); + +/* m29f002.c */ +int erase_m29f002(struct flashchip *flash); +int write_m29f002t(struct flashchip *flash, uint8_t *buf); +int write_m29f002b(struct flashchip *flash, uint8_t *buf); + +/* m29f400bt.c */ +int probe_m29f400bt(struct flashchip *flash); +int erase_m29f400bt(struct flashchip *flash); +int block_erase_m29f400bt(struct flashchip *flash, int start, int len); +int write_m29f400bt(struct flashchip *flash, uint8_t *buf); +int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf); +void toggle_ready_m29f400bt(chipaddr dst); +void data_polling_m29f400bt(chipaddr dst, uint8_t data); +void protect_m29f400bt(chipaddr bios); +void write_page_m29f400bt(chipaddr bios, uint8_t *src, + chipaddr dst, int page_size); + +/* mx29f002.c */ +int probe_29f002(struct flashchip *flash); +int erase_29f002(struct flashchip *flash); +int write_29f002(struct flashchip *flash, uint8_t *buf); + +/* pm49fl00x.c */ +int probe_49fl00x(struct flashchip *flash); +int erase_49fl00x(struct flashchip *flash); +int write_49fl00x(struct flashchip *flash, uint8_t *buf); + +/* sharplhf00l04.c */ +int probe_lhf00l04(struct flashchip *flash); +int erase_lhf00l04(struct flashchip *flash); +int write_lhf00l04(struct flashchip *flash, uint8_t *buf); +void toggle_ready_lhf00l04(chipaddr dst); +void data_polling_lhf00l04(chipaddr dst, uint8_t data); +void protect_lhf00l04(chipaddr bios); + +/* sst28sf040.c */ +int probe_28sf040(struct flashchip *flash); +int erase_28sf040(struct flashchip *flash); +int write_28sf040(struct flashchip *flash, uint8_t *buf); + +/* sst39sf020.c */ +int probe_39sf020(struct flashchip *flash); +int write_39sf020(struct flashchip *flash, uint8_t *buf); + +/* sst49lf040.c */ +int erase_49lf040(struct flashchip *flash); +int write_49lf040(struct flashchip *flash, uint8_t *buf); + +/* sst49lfxxxc.c */ +int probe_49lfxxxc(struct flashchip *flash); +int erase_49lfxxxc(struct flashchip *flash); +int write_49lfxxxc(struct flashchip *flash, uint8_t *buf); + +/* sst_fwhub.c */ +int probe_sst_fwhub(struct flashchip *flash); +int erase_sst_fwhub(struct flashchip *flash); +int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size); +int write_sst_fwhub(struct flashchip *flash, uint8_t *buf); + +/* w39v040c.c */ +int probe_w39v040c(struct flashchip *flash); +int erase_w39v040c(struct flashchip *flash); +int write_w39v040c(struct flashchip *flash, uint8_t *buf); + +/* w39V080fa.c */ +int probe_winbond_fwhub(struct flashchip *flash); +int erase_winbond_fwhub(struct flashchip *flash); +int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf); + +/* w29ee011.c */ +int probe_w29ee011(struct flashchip *flash); + +/* w49f002u.c */ +int write_49f002(struct flashchip *flash, uint8_t *buf); + +/* wbsio_spi.c */ +int wbsio_check_for_spi(const char *name); +int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf); + +/* stm50flw0x0x.c */ +int probe_stm50flw0x0x(struct flashchip *flash); +int erase_stm50flw0x0x(struct flashchip *flash); +int write_stm50flw0x0x(struct flashchip *flash, uint8_t *buf); + +/* serprog.c */ +int serprog_init(void); +int serprog_shutdown(void); +void serprog_chip_writeb(uint8_t val, chipaddr addr); +uint8_t serprog_chip_readb(const chipaddr addr); +void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); +void serprog_delay(int delay); + +/* serial.c */ +void sp_flush_incoming(void); +int sp_openserport(char *dev, unsigned int baud); +void __attribute__((noreturn)) sp_die(char *msg); +extern int sp_fd; + +#endif /* !__FLASH_H__ */ diff --git a/libflashrom/flashchips.c b/libflashrom/flashchips.c new file mode 100644 index 0000000..5e74ccf --- /dev/null +++ b/libflashrom/flashchips.c @@ -0,0 +1,3435 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2004 Tyan Corp + * Copyright (C) 2005-2008 coresystems GmbH + * Copyright (C) 2006-2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" +#include "flashchips.h" + +/** + * List of supported flash chips. + * + * Please keep the list sorted by vendor name and chip name, so that + * the output of 'flashrom -L' is alphabetically sorted. + */ +struct flashchip flashchips[] = { + + /* + * .vendor = Vendor name + * .name = Chip name + * .bustype = Supported flash bus types (Parallel, LPC...) + * .manufacture_id = Manufacturer chip ID + * .model_id = Model chip ID + * .total_size = Total size in (binary) kbytes + * .page_size = Page or eraseblock(?) size in bytes + * .tested = Test status + * .probe = Probe function + * .probe_timing = Probe function delay + * .erase = Chip erase function + * .block_erasers[] = Array of erase layouts and erase functions + * { + * .eraseblocks[] = Array of { blocksize, blockcount } + * .block_erase = Block erase function + * } + * .write = Chip write function + * .read = Chip read function + */ + + { + .vendor = "AMD", + .name = "Am29F010A/B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29F010B, /* Same as Am29F010A */ + .total_size = 128, + .page_size = 16 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_29f040b, + .probe_timing = TIMING_ZERO, + .erase = erase_29f040b, + .write = write_pm29f002, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29F002(N)BB", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29F002BB, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, + .erase = erase_chip_jedec, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29F002(N)BT", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29F002BT, + .total_size = 256, + .page_size = 256, + .tested = TEST_OK_PRE, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, + .erase = erase_chip_jedec, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29F016D", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29F016D, + .total_size = 2048, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_29f040b, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29F040B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29F040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_29f040b, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29F080B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29F080B, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29LV040B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29LV040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_29f040b, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "AMD", + .name = "Am29LV081B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMD_ID, + .model_id = AM_29LV080B, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_29f040b, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "ASD", + .name = "AE49F2008", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ASD_ID, + .model_id = ASD_AE49F2008, + .total_size = 256, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_FIXME, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "AT25DF021", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF021, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25DF041A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF041A, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25DF081", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF081, + .total_size = 1024, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25DF161", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF161, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25DF321", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF321, + .total_size = 4096, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25DF321A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF321A, + .total_size = 4096, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25DF641", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25DF641, + .total_size = 8192, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25F512B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25F512B, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25FS010", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25FS010, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT25FS040", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_25FS040, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT26DF041", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_26DF041, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL /* Incompatible Page write */, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT26DF081A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_26DF081A, + .total_size = 1024, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT26DF161", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_26DF161, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT26DF161A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_26DF161A, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + /*The AT26DF321 has the same ID as the AT25DF321. */ + /*{ + .vendor = "Atmel", + .name = "AT26DF321", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_26DF321, + .total_size = 4096, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + },*/ + + { + .vendor = "Atmel", + .name = "AT26F004", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_26F004, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = NULL /* Incompatible Page write */, + .read = spi_chip_read, + }, + + { + .vendor = "Atmel", + .name = "AT29C512", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_29C512, + .total_size = 64, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10000, /* 10mS, Enter=Exec */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + + }, + + { + .vendor = "Atmel", + .name = "AT29C010A", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_29C010A, + .total_size = 128, + .page_size = 128, + .tested = TEST_OK_PRE, + .probe = probe_jedec, + .probe_timing = 10000, /* 10mS, Enter=Exec */ + .erase = erase_chip_jedec, + .write = write_jedec, /* FIXME */ + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "AT29C020", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_29C020, + .total_size = 256, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10000, /* 10ms */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "AT29C040A", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_29C040A, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = 10000, /* 10 ms */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "AT45CS1282", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45CS1282, + .total_size = 16896 /* No power of two sizes */, + .page_size = 1056 /* No power of two sizes */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL /* Incompatible Page write */, + .read = NULL /* Incompatible read */, + }, + + { + .vendor = "Atmel", + .name = "AT45DB011D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB011D, + .total_size = 128 /* Size can only be determined from status register */, + .page_size = 256 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT45DB021D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB021D, + .total_size = 256 /* Size can only be determined from status register */, + .page_size = 256 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT45DB041D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB041D, + .total_size = 512 /* Size can only be determined from status register */, + .page_size = 256 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT45DB081D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB081D, + .total_size = 1024 /* Size can only be determined from status register */, + .page_size = 256 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT45DB161D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB161D, + .total_size = 2048 /* Size can only be determined from status register */, + .page_size = 512 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT45DB321C", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB321C, + .total_size = 4224 /* No power of two sizes */, + .page_size = 528 /* No power of two sizes */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL /* Incompatible read */, + }, + + { + .vendor = "Atmel", + .name = "AT45DB321D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB321D, + .total_size = 4096 /* Size can only be determined from status register */, + .page_size = 512 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT45DB642D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = AT_45DB642D, + .total_size = 8192 /* Size can only be determined from status register */, + .page_size = 1024 /* Size can only be determined from status register */, + .tested = TEST_BAD_READ, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Atmel", + .name = "AT49BV512", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_49BV512, + .total_size = 64, + .page_size = 64, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "AT49F002(N)", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_49F002N, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "AT49F002(N)T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ATMEL_ID, + .model_id = AT_49F002NT, + .total_size = 256, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "AMIC", + .name = "A25L40P", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = AMIC_ID, + .model_id = AMIC_A25L40P, + .total_size = 512, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid4, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "AMIC", + .name = "A29002B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMIC_ID_NOPREFIX, + .model_id = AMIC_A29002B, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "AMIC", + .name = "A29002T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMIC_ID_NOPREFIX, + .model_id = AMIC_A29002T, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_OK_PRE, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "AMIC", + .name = "A29040B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = AMIC_ID_NOPREFIX, + .model_id = AMIC_A29040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PR, + .probe = probe_29f040b, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "AMIC", + .name = "A49LF040A", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = AMIC_ID_NOPREFIX, + .model_id = AMIC_A49LF040A, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_49fl00x, + .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ + .erase = erase_49fl00x, + .write = write_49fl00x, + .read = read_memmapped, + }, + + { + .vendor = "EMST", + .name = "F49B002UA", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = EMST_ID, + .model_id = EMST_F49B002UA, + .total_size = 256, + .page_size = 4096, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Eon", + .name = "EN25B05", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B05, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B10", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B10, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B20", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B20, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B40", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B40, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B80", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B80, + .total_size = 1024, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B16", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B16, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B32", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B32, + .total_size = 4096, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25B64", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25B64, + .total_size = 8192, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25D16", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25D16, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F05", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F05, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F10", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F10, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F20", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F20, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F40", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F40, + .total_size = 512, + .page_size = 256, + .tested = TEST_OK_PROBE, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F80", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F80, + .total_size = 1024, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F16", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F16, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Eon", + .name = "EN25F32", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = EN_25F32, + .total_size = 4096, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "EON", + .name = "EN29F002(A)(N)B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = EON_ID, + .model_id = EN_29F002B, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "EON", + .name = "EN29F002(A)(N)T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = EON_ID, + .model_id = EN_29F002T, + .total_size = 256, + .page_size = 256, + .tested = TEST_OK_PRE, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Fujitsu", + .name = "MBM29F004BC", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = FUJITSU_ID, + .model_id = MBM29F004BC, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "Fujitsu", + .name = "MBM29F004TC", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = FUJITSU_ID, + .model_id = MBM29F004TC, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "Fujitsu", + .name = "MBM29F400BC", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = FUJITSU_ID, + .model_id = MBM29F400BC, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_m29f400bt, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ + .erase = erase_m29f400bt, + .write = write_coreboot_m29f400bt, + .read = read_memmapped, + }, + + { + .vendor = "Fujitsu", + .name = "MBM29F400TC", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = FUJITSU_ID, + .model_id = MBM29F400TC, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_m29f400bt, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ + .erase = erase_m29f400bt, + .write = write_coreboot_m29f400bt, + .read = read_memmapped, + }, + + { + .vendor = "Intel", + .name = "28F001BX-B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = INTEL_ID, + .model_id = P28F001BXB, + .total_size = 128, + .page_size = 128 * 1024, /* 8k + 2x4k + 112k */ + .tested = TEST_BAD_ERASE|TEST_BAD_WRITE, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "Intel", + .name = "28F001BX-T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = INTEL_ID, + .model_id = P28F001BXT, + .total_size = 128, + .page_size = 128 * 1024, /* 112k + 2x4k + 8k */ + .tested = TEST_OK_PR|TEST_BAD_ERASE|TEST_BAD_WRITE, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "Intel", + .name = "82802AB", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = INTEL_ID, + .model_id = I_82802AB, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_82802ab, + .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ + .erase = erase_82802ab, + .write = write_82802ab, + .read = read_memmapped, + }, + + { + .vendor = "Intel", + .name = "82802AC", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = INTEL_ID, + .model_id = I_82802AC, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_82802ab, + .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ + .erase = erase_82802ab, + .write = write_82802ab, + .read = read_memmapped, + }, + + { + .vendor = "Macronix", + .name = "MX25L512", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L512, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 16} }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 1} }, + .block_erase = spi_block_erase_52, + }, { + .eraseblocks = { {64 * 1024, 1} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {64 * 1024, 1} }, + .block_erase = spi_block_erase_60, + }, { + .eraseblocks = { {64 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + }, + }, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L1005", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L1005, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 32} }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 2} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {128 * 1024, 1} }, + .block_erase = spi_block_erase_60, + }, { + .eraseblocks = { {128 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + }, + }, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L2005", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L2005, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 64} }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 4} }, + .block_erase = spi_block_erase_52, + }, { + .eraseblocks = { {64 * 1024, 4} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {256 * 1024, 1} }, + .block_erase = spi_block_erase_60, + }, { + .eraseblocks = { {256 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + }, + }, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L4005", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L4005, + .total_size = 512, + .page_size = 256, + .tested = TEST_OK_PRW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 128} }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 8} }, + .block_erase = spi_block_erase_52, + }, { + .eraseblocks = { {64 * 1024, 8} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {512 * 1024, 1} }, + .block_erase = spi_block_erase_60, + }, { + .eraseblocks = { {512 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + }, + }, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L8005", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L8005, + .total_size = 1024, + .page_size = 256, + .tested = TEST_OK_PRW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 256} }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 16} }, + .block_erase = spi_block_erase_52, + }, { + .eraseblocks = { {64 * 1024, 16} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {1024 * 1024, 1} }, + .block_erase = spi_block_erase_60, + }, { + .eraseblocks = { {1024 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + }, + }, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L1605", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L1605, + .total_size = 2048, + .page_size = 256, + .tested = TEST_OK_PRW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 512} }, + .block_erase = spi_block_erase_20, /* This erase function has 64k blocksize for eLiteFlash */ + }, { + .eraseblocks = { {64 * 1024, 32} }, /* Not supported in MX25L1605 (eLiteFlash) and MX25L1605D */ + .block_erase = spi_block_erase_52, + }, { + .eraseblocks = { {64 * 1024, 32} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {2 * 1024 * 1024, 1} }, + .block_erase = spi_block_erase_60, + }, { + .eraseblocks = { {2 * 1024 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + }, + }, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L1635D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L1635D, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L3205", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L3205, + .total_size = 4096, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L3235D", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L3235D, + .total_size = 4096, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L6405", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L6405, + .total_size = 8192, + .page_size = 256, + .tested = TEST_OK_PROBE, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX25L12805", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = MX_25L12805, + .total_size = 16384, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Macronix", + .name = "MX29F001B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = MX_ID, + .model_id = MX_29F001B, + .total_size = 128, + .page_size = 32 * 1024, + .tested = TEST_OK_PRE, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Macronix", + .name = "MX29F001T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = MX_ID, + .model_id = MX_29F001T, + .total_size = 128, + .page_size = 32 * 1024, + .tested = TEST_OK_PRE, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Macronix", + .name = "MX29F002B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = MX_ID, + .model_id = MX_29F002B, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Macronix", + .name = "MX29F002T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = MX_ID, + .model_id = MX_29F002T, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_OK_PRE, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Macronix", + .name = "MX29LV040", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = MX_ID, + .model_id = MX_29LV040, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PR, + .probe = probe_29f002, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ + .erase = erase_29f002, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Numonyx", + .name = "M25PE10", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25PE10, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_d8, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Numonyx", + .name = "M25PE20", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25PE20, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_d8, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Numonyx", + .name = "M25PE40", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25PE40, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_d8, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Numonyx", + .name = "M25PE80", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25PE80, + .total_size = 1024, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_d8, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Numonyx", + .name = "M25PE16", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25PE16, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_d8, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm25LV010", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = PMC_25LV010, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm25LV016B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = PMC_25LV016B, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm25LV020", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = PMC_25LV020, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm25LV040", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = PMC_25LV040, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm25LV080B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = PMC_25LV080B, + .total_size = 1024, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm25LV512", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = PMC_25LV512, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "PMC", + .name = "Pm29F0002T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = PMC_ID_NOPREFIX, + .model_id = PMC_29F002T, + .total_size = 256, + .page_size = 8192, + .tested = TEST_OK_PREW, + .probe = probe_29f040b, + .probe_timing = TIMING_FIXME, + .erase = erase_29f040b, + .write = write_pm29f002, + .read = read_memmapped, + }, + + { + .vendor = "PMC", + .name = "Pm29F0002B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = PMC_ID_NOPREFIX, + .model_id = PMC_29F002B, + .total_size = 256, + .page_size = 8192, + .tested = TEST_UNTESTED, + .probe = probe_29f040b, + .probe_timing = TIMING_FIXME, + .erase = erase_29f040b, + .write = write_pm29f002, + .read = read_memmapped, + }, + + { + .vendor = "PMC", + .name = "Pm39LV010", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = PMC_ID_NOPREFIX, + .model_id = PMC_39F010, + .total_size = 128, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "PMC", + .name = "Pm49FL002", + .bustype = CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/ + .manufacture_id = PMC_ID_NOPREFIX, + .model_id = PMC_49FL002, + .total_size = 256, + .page_size = 16 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_49fl00x, + .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ + .erase = erase_49fl00x, + .write = write_49fl00x, + .read = read_memmapped, + }, + + { + .vendor = "PMC", + .name = "Pm49FL004", + .bustype = CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/ + .manufacture_id = PMC_ID_NOPREFIX, + .model_id = PMC_49FL004, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_49fl00x, + .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ + .erase = erase_49fl00x, + .write = write_49fl00x, + .read = read_memmapped, + }, + + { + .vendor = "Sanyo", + .name = "LF25FW203A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SANYO_ID, + .model_id = SANYO_LE25FW203A, + .total_size = 2048, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Sharp", + .name = "LHF00L04", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = SHARP_ID, + .model_id = SHARP_LHF00L04, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_lhf00l04, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sharplhf00l04.c) */ + .erase = erase_lhf00l04, + .write = write_lhf00l04, + .read = read_memmapped, + }, + + { + .vendor = "Spansion", + .name = "S25FL016A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SPANSION_ID, + .model_id = SPANSION_S25FL016A, + .total_size = 2048, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST25VF016B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = SST_25VF016B, + .total_size = 2048, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_1, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST25VF032B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = SST_25VF032B, + .total_size = 4096, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_1, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST25VF040B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = SST_25VF040B, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_1, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST25VF040.REMS", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = SST_25VF040_REMS, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_OK_PR, + .probe = probe_spi_rems, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60, + .write = spi_chip_write_1, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST25VF040B.REMS", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = SST_25VF040B_REMS, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_OK_PR, + .probe = probe_spi_rems, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_1, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST25VF080B", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = SST_25VF080B, + .total_size = 1024, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_60_c7, + .write = spi_chip_write_1, + .read = spi_chip_read, + }, + + { + .vendor = "SST", + .name = "SST28SF040A", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_28SF040, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_28sf040, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst28sf040.c) */ + .erase = erase_28sf040, + .write = write_28sf040, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST29EE010", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_29EE010, + .total_size = 128, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST29LE010", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_29LE010, + .total_size = 128, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST29EE020A", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_29EE020A, + .total_size = 256, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST29LE020", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_29LE020, + .total_size = 256, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39SF010A", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39SF010, + .total_size = 128, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39SF020A", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39SF020, + .total_size = 256, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39SF040", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39SF040, + .total_size = 512, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39VF512", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39VF512, + .total_size = 64, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns*/ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39VF010", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39VF010, + .total_size = 128, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39VF020", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39VF020, + .total_size = 256, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39VF040", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39VF040, + .total_size = 512, + .page_size = 4096, + .tested = TEST_OK_PROBE, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST39VF080", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SST_ID, + .model_id = SST_39VF080, + .total_size = 1024, + .page_size = 4096, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF002A/B", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = SST_ID, + .model_id = SST_49LF002A, + .total_size = 256, + .page_size = 16 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_sst_fwhub, + .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ + .erase = erase_sst_fwhub, + .write = write_sst_fwhub, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF003A/B", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = SST_ID, + .model_id = SST_49LF003A, + .total_size = 384, + .page_size = 64 * 1024, + .tested = TEST_OK_PR, + .probe = probe_sst_fwhub, + .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ + .erase = erase_sst_fwhub, + .write = write_sst_fwhub, + .read = read_memmapped, + }, + + { + /* Contrary to the data sheet, TBL# on the SST49LF004B affects the top 128kB (instead of 64kB) + * and is only honored for 64k block erase, but not 4k sector erase. + */ + .vendor = "SST", + .name = "SST49LF004A/B", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = SST_ID, + .model_id = SST_49LF004A, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_sst_fwhub, + .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ + .erase = NULL, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 128} }, + .block_erase = erase_sector_jedec, /* missing unlock */ + }, { + .eraseblocks = { {64 * 1024, 8} }, + .block_erase = erase_sst_fwhub_block, /* same as erase_block_jedec, but with unlock */ + }, { + .eraseblocks = { {512 * 1024, 1} }, + .block_erase = NULL, /* AA 55 80 AA 55 10, only in PP mode */ + }, + }, + .write = write_sst_fwhub, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF004C", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = SST_ID, + .model_id = SST_49LF004C, + .total_size = 512, + .page_size = 4 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_49lfxxxc, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ + .erase = erase_49lfxxxc, + .write = write_49lfxxxc, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF008A", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = SST_ID, + .model_id = SST_49LF008A, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_sst_fwhub, + .probe_timing = 1, /* 150 ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ + .erase = erase_sst_fwhub, + .write = write_sst_fwhub, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF008C", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = SST_ID, + .model_id = SST_49LF008C, + .total_size = 1024, + .page_size = 4 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_49lfxxxc, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ + .erase = erase_49lfxxxc, + .write = write_49lfxxxc, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF016C", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = SST_ID, + .model_id = SST_49LF016C, + .total_size = 2048, + .page_size = 4 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_49lfxxxc, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ + .erase = erase_49lfxxxc, + .write = write_49lfxxxc, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF020", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = SST_ID, + .model_id = SST_49LF020, + .total_size = 256, + .page_size = 16 * 1024, + .tested = TEST_OK_PR, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_49lf040, + .write = write_49lf040, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF020A", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = SST_ID, + .model_id = SST_49LF020A, + .total_size = 256, + .page_size = 4 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_49lf040, + .write = write_49lf040, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF040", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = SST_ID, + .model_id = SST_49LF040, + .total_size = 512, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 1, /* 150 ns */ + .erase = erase_49lf040, + .write = write_49lf040, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF040B", + .bustype = CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = SST_ID, + .model_id = SST_49LF040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_sst_fwhub, + .probe_timing = 1, /* 150ns | routine is wrapper to probe_jedec (sst_fwhub.c) */ + .erase = erase_sst_fwhub, + .write = write_sst_fwhub, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF080A", + .bustype = CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = SST_ID, + .model_id = SST_49LF080A, + .total_size = 1024, + .page_size = 4096, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = TIMING_FIXME, + .erase = erase_49lf040, + .write = write_49lf040, + .read = read_memmapped, + }, + + { + .vendor = "SST", + .name = "SST49LF160C", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = SST_ID, + .model_id = SST_49LF160C, + .total_size = 2048, + .page_size = 4 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_49lfxxxc, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ + .erase = erase_49lfxxxc, + .write = write_49lfxxxc, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M25P05-A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P05A, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + /* The ST M25P05 is a bit of a problem. It has the same ID as the + * ST M25P05-A in RES mode, but supports only 128 byte writes instead + * of 256 byte writes. We rely heavily on the fact that probe_spi_res + * only is successful if RDID does not work. + */ + { + .vendor = "ST", + .name = "M25P05.RES", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P05_RES, + .total_size = 64, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_res, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_1, /* 128 */ + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P10-A", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P10A, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + /* The ST M25P10 has the same problem as the M25P05. */ + { + .vendor = "ST", + .name = "M25P10.RES", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P10_RES, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_res, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_1, /* 128 */ + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P20", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P20, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P40", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P40, + .total_size = 512, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P40-old", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P40_RES, + .total_size = 512, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_res, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P80", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P80, + .total_size = 1024, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P16", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P16, + .total_size = 2048, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P32", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P32, + .total_size = 4096, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P64", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P64, + .total_size = 8192, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M25P128", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M25P128, + .total_size = 16384, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "ST", + .name = "M29F002B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ST_ID, + .model_id = ST_M29F002B, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_m29f002, + .write = write_m29f002b, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M29F002T/NT", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ST_ID, + .model_id = ST_M29F002T, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_m29f002, + .write = write_m29f002t, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M29F040B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ST_ID, + .model_id = ST_M29F040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_29f040b, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ + .erase = erase_29f040b, + .write = write_29f040b, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M29F400BT", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ST_ID, + .model_id = ST_M29F400BT, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_m29f400bt, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ + .erase = erase_m29f400bt, + .write = write_coreboot_m29f400bt, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M29W010B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ST_ID, + .model_id = ST_M29W010B, + .total_size = 128, + .page_size = 16 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M29W040B", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = ST_ID, + .model_id = ST_M29W040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FLW040A", + .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FLW040A, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_stm50flw0x0x, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ + .erase = erase_stm50flw0x0x, + .write = write_stm50flw0x0x, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FLW040B", + .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FLW040B, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_stm50flw0x0x, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ + .erase = erase_stm50flw0x0x, + .write = write_stm50flw0x0x, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FLW080A", + .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FLW080A, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_stm50flw0x0x, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ + .erase = erase_stm50flw0x0x, + .write = write_stm50flw0x0x, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FLW080B", + .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FLW080B, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_stm50flw0x0x, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ + .erase = erase_stm50flw0x0x, + .write = write_stm50flw0x0x, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FW002", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FW002, + .total_size = 256, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_49lfxxxc, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FW016", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FW016, + .total_size = 2048, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_82802ab, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ + .erase = erase_82802ab, + .write = write_82802ab, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FW040", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FW040, + .total_size = 512, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_82802ab, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ + .erase = erase_82802ab, + .write = write_82802ab, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50FW080", + .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50FW080, + .total_size = 1024, + .page_size = 64 * 1024, + .tested = TEST_OK_PREW, + .probe = probe_82802ab, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ + .erase = erase_82802ab, + .write = write_82802ab, + .read = read_memmapped, + }, + + { + .vendor = "ST", + .name = "M50LPW116", + .bustype = CHIP_BUSTYPE_LPC, /* A/A Mux */ + .manufacture_id = ST_ID, + .model_id = ST_M50LPW116, + .total_size = 2048, + .page_size = 64 * 1024, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "SyncMOS", + .name = "S29C31004T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SYNCMOS_ID, + .model_id = S29C31004T, + .total_size = 512, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SyncMOS", + .name = "S29C51001T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SYNCMOS_ID, + .model_id = S29C51001T, + .total_size = 128, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SyncMOS", + .name = "S29C51002T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SYNCMOS_ID, + .model_id = S29C51002T, + .total_size = 256, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "SyncMOS", + .name = "S29C51004T", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = SYNCMOS_ID, + .model_id = S29C51004T, + .total_size = 512, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "TI", + .name = "TMS29F002RB", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = TI_OLD_ID, + .model_id = TI_TMS29F002RB, + .total_size = 256, + .page_size = 16384, /* Non-uniform sectors */ + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "TI", + .name = "TMS29F002RT", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = TI_OLD_ID, + .model_id = TI_TMS29F002RT, + .total_size = 256, + .page_size = 16384, /* Non-uniform sectors */ + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ + .erase = NULL, + .write = NULL, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W25x10", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X10, + .total_size = 128, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W25x20", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X20, + .total_size = 256, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W25x40", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X40, + .total_size = 512, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W25x80", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X80, + .total_size = 1024, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W25x16", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X16, + .total_size = 2048, + .page_size = 256, + .tested = TEST_OK_PR, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W25x32", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X32, + .total_size = 4096, + .page_size = 256, + .tested = TEST_OK_PROBE, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W25x64", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = W_25X64, + .total_size = 8192, + .page_size = 256, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = spi_chip_erase_c7, + .write = spi_chip_write_256, + .read = spi_chip_read, + }, + + { + .vendor = "Winbond", + .name = "W29C011", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = WINBOND_ID, + .model_id = W_29C011, + .total_size = 128, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, /* used datasheet for the W29C011A */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W29C020C", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = WINBOND_ID, + .model_id = W_29C020C, + .total_size = 256, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W29C040P", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = WINBOND_ID, + .model_id = W_29C040P, + .total_size = 512, + .page_size = 256, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W29EE011", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = WINBOND_ID, + .model_id = W_29C011, + .total_size = 128, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_w29ee011, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w29ee011.c) */ + .erase = erase_chip_jedec, + .write = write_jedec, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V040A", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = WINBOND_ID, + .model_id = W_39V040A, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V040B", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = WINBOND_ID, + .model_id = W_39V040B, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_OK_PR | TEST_BAD_ERASE | TEST_BAD_WRITE, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V040C", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = WINBOND_ID, + .model_id = W_39V040C, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_OK_PREW, + .probe = probe_w39v040c, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v040c.c) */ + .erase = erase_w39v040c, + .write = write_w39v040c, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V040FA", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = WINBOND_ID, + .model_id = W_39V040FA, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V080A", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = WINBOND_ID, + .model_id = W_39V080A, + .total_size = 1024, + .page_size = 64*1024, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W49F002U", + .bustype = CHIP_BUSTYPE_PARALLEL, + .manufacture_id = WINBOND_ID, + .model_id = W_49F002U, + .total_size = 256, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W49V002A", + .bustype = CHIP_BUSTYPE_LPC, + .manufacture_id = WINBOND_ID, + .model_id = W_49V002A, + .total_size = 256, + .page_size = 128, + .tested = TEST_OK_PREW, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W49V002FA", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = WINBOND_ID, + .model_id = W_49V002FA, + .total_size = 256, + .page_size = 128, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = 10, + .erase = erase_chip_jedec, + .write = write_49f002, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V080FA", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = WINBOND_ID, + .model_id = W_39V080FA, + .total_size = 1024, + .page_size = 64*1024, + .tested = TEST_OK_PREW, + .probe = probe_winbond_fwhub, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */ + .erase = erase_winbond_fwhub, + .write = write_winbond_fwhub, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V080FA (dual mode)", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = WINBOND_ID, + .model_id = W_39V080FA_DM, + .total_size = 512, + .page_size = 64*1024, + .tested = TEST_UNTESTED, + .probe = probe_winbond_fwhub, + .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */ + .erase = erase_winbond_fwhub, + .write = write_winbond_fwhub, + .read = read_memmapped, + }, + + { + .vendor = "Atmel", + .name = "unknown Atmel SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ATMEL_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "EON", + .name = "unknown EON SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = EON_ID_NOPREFIX, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Macronix", + .name = "unknown Macronix SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = MX_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "PMC", + .name = "unknown PMC SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = PMC_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "SST", + .name = "unknown SST SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SST_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "ST", + .name = "unknown ST SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = ST_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Sanyo", + .name = "unknown Sanyo SPI chip", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = SANYO_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .erase = NULL, + .write = NULL, + .read = NULL, + }, + + { + .vendor = "Generic", + .name = "unknown SPI chip (RDID)", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = GENERIC_MANUF_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rdid, + .erase = NULL, + .write = NULL, + }, + { + .vendor = "Generic", + .name = "unknown SPI chip (REMS)", + .bustype = CHIP_BUSTYPE_SPI, + .manufacture_id = GENERIC_MANUF_ID, + .model_id = GENERIC_DEVICE_ID, + .total_size = 0, + .page_size = 256, + .tested = TEST_BAD_PREW, + .probe = probe_spi_rems, + .erase = NULL, + .write = NULL, + }, + + { NULL } +}; diff --git a/libflashrom/flashchips.h b/libflashrom/flashchips.h new file mode 100644 index 0000000..684b8b9 --- /dev/null +++ b/libflashrom/flashchips.h @@ -0,0 +1,501 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2000 Ronald G. Minnich + * Copyright (C) 2005-2007 coresystems GmbH + * Copyright (C) 2006-2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __FLASHCHIPS_H__ +#define __FLASHCHIPS_H__ 1 + +/* + * Please keep this list sorted alphabetically by manufacturer. The first + * entry of each section should be the manufacturer ID, followed by the + * list of devices from that manufacturer (sorted by device IDs). + * + * All LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no + * continuation code. + * SPI parts have 16-bit device IDs if they support RDID. + */ + +#define GENERIC_MANUF_ID 0xffff /* Check if there is a vendor ID */ +#define GENERIC_DEVICE_ID 0xffff /* Only match the vendor ID */ + +#define ALLIANCE_ID 0x52 /* Alliance Semiconductor */ + +#define AMD_ID 0x01 /* AMD */ +#define AM_29DL400BT 0x0C +#define AM_29DL400BB 0x0F +#define AM_29DL800BT 0x4A +#define AM_29DL800BB 0xCB +#define AM_29F002BB 0x34 /* Same as Am29F002NBB */ +#define AM_29F002BT 0xB0 /* Same as Am29F002NBT */ +#define AM_29F004BB 0x7B +#define AM_29F004BT 0x77 +#define AM_29F016D 0xAD +#define AM_29F010B 0x20 /* Same as Am29F010A */ +#define AM_29F040B 0xA4 +#define AM_29F080B 0xD5 +#define AM_29F200BB 0x57 +#define AM_29F200BT 0x51 +#define AM_29F400BB 0xAB +#define AM_29F400BT 0x23 +#define AM_29F800BB 0x58 +#define AM_29F800BT 0xD6 +#define AM_29LV002BB 0xC2 +#define AM_29LV002BT 0x40 +#define AM_29LV004BB 0xB6 +#define AM_29LV004BT 0xB5 +#define AM_29LV008BB 0x37 +#define AM_29LV008BT 0x3E +#define AM_29LV040B 0x4F +#define AM_29LV080B 0x38 /* Same as Am29LV081B */ +#define AM_29LV200BB 0xBF +#define AM_29LV200BT 0x3B +#define AM_29LV800BB 0x5B /* Same as Am29LV800DB */ +#define AM_29LV400BT 0xB9 +#define AM_29LV400BB 0xBA +#define AM_29LV800BT 0xDA /* Same as Am29LV800DT */ + +#define AMIC_ID 0x7F37 /* AMIC */ +#define AMIC_ID_NOPREFIX 0x37 /* AMIC */ +#define AMIC_A25L40P 0x2013 +#define AMIC_A29002B 0x0d +#define AMIC_A29002T 0x8C /* Same as A290021T */ +#define AMIC_A29040B 0x86 +#define AMIC_A29400T 0xB0 /* Same as 294001T */ +#define AMIC_A29400U 0x31 /* Same as A294001U */ +#define AMIC_A29800T 0x0E +#define AMIC_A29800U 0x8F +#define AMIC_A29L004T 0x34 /* Same as A29L400T */ +#define AMIC_A29L004U 0xB5 /* Same as A29L400U */ +#define AMIC_A29L008T 0x1A /* Same as A29L800T */ +#define AMIC_A29L008U 0x9B /* Same as A29L800U */ +#define AMIC_A29L040 0x92 +#define AMIC_A49LF040A 0x9d + +/* This chip vendor/device ID is probably a misinterpreted LHA header. */ +#define ASD_ID 0x25 /* ASD, not listed in JEP106W */ +#define ASD_AE49F2008 0x52 + +#define ATMEL_ID 0x1F /* Atmel */ +#define AT_25DF021 0x4300 +#define AT_25DF041A 0x4401 +#define AT_25DF081 0x4502 +#define AT_25DF161 0x4602 +#define AT_25DF321 0x4700 /* Same as 26DF321 */ +#define AT_25DF321A 0x4701 +#define AT_25DF641 0x4800 +#define AT_25F512A 0x65 /* Needs special RDID. AT25F512A_RDID 15 1d */ +#define AT_25F512B 0x6500 +#define AT_25FS010 0x6601 +#define AT_25FS040 0x6604 +#define AT_26DF041 0x4400 +#define AT_26DF081 0x4500 /* guessed, no datasheet available */ +#define AT_26DF081A 0x4501 +#define AT_26DF161 0x4600 +#define AT_26DF161A 0x4601 +#define AT_26DF321 0x4700 /* Same as 25DF321 */ +#define AT_26F004 0x0400 +#define AT_29C040A 0xA4 +#define AT_29C010A 0xD5 +#define AT_29C020 0xDA +#define AT_29C512 0x5D +#define AT_45BR3214B /* No ID available */ +#define AT_45CS1282 0x2920 +#define AT_45D011 /* No ID available */ +#define AT_45D021A /* No ID available */ +#define AT_45D041A /* No ID available */ +#define AT_45D081A /* No ID available */ +#define AT_45D161 /* No ID available */ +#define AT_45DB011 /* No ID available */ +#define AT_45DB011B /* No ID available */ +#define AT_45DB011D 0x2200 +#define AT_45DB021A /* No ID available */ +#define AT_45DB021B /* No ID available */ +#define AT_45DB021D 0x2300 +#define AT_45DB041A /* No ID available */ +#define AT_45DB041D 0x2400 +#define AT_45DB081A /* No ID available */ +#define AT_45DB081D 0x2500 +#define AT_45DB161 /* No ID available */ +#define AT_45DB161B /* No ID available */ +#define AT_45DB161D 0x2600 +#define AT_45DB321 /* No ID available */ +#define AT_45DB321B /* No ID available */ +#define AT_45DB321C 0x2700 +#define AT_45DB321D 0x2701 /* Buggy data sheet */ +#define AT_45DB642 /* No ID available */ +#define AT_45DB642D 0x2800 +#define AT_49BV512 0x03 +#define AT_49F002N 0x07 /* for AT49F002(N) */ +#define AT_49F002NT 0x08 /* for AT49F002(N)T */ + +#define CATALYST_ID 0x31 /* Catalyst */ + +#define EMST_ID 0x8C /* EMST / EFST Elite Flash Storage */ +#define EMST_F49B002UA 0x00 + +/* + * EN25 chips are SPI, first byte of device ID is memory type, + * second byte of device ID is log(bitsize)-9. + * Vendor and device ID of EN29 series are both prefixed with 0x7F, which + * is the continuation code for IDs in bank 2. + * Vendor ID of EN25 series is NOT prefixed with 0x7F, this results in + * a collision with Mitsubishi. Mitsubishi once manufactured flash chips. + * Let's hope they are not manufacturing SPI flash chips as well. + */ +#define EON_ID 0x7F1C /* EON Silicon Devices */ +#define EON_ID_NOPREFIX 0x1C /* EON, missing 0x7F prefix */ +#define EN_25B05 0x2010 /* Same as P05, 2^19 kbit or 2^16 kByte */ +#define EN_25B10 0x2011 /* Same as P10 */ +#define EN_25B20 0x2012 /* Same as P20 */ +#define EN_25B40 0x2013 /* Same as P40 */ +#define EN_25B80 0x2014 /* Same as P80 */ +#define EN_25B16 0x2015 /* Same as P16 */ +#define EN_25B32 0x2016 /* Same as P32 */ +#define EN_25B64 0x2017 /* Same as P64 */ +#define EN_25D16 0x3015 +#define EN_25F05 0x3110 +#define EN_25F10 0x3111 +#define EN_25F20 0x3112 +#define EN_25F40 0x3113 +#define EN_25F80 0x3114 +#define EN_25F16 0x3115 +#define EN_25F32 0x3116 +#define EN_29F512 0x7F21 +#define EN_29F010 0x7F20 +#define EN_29F040A 0x7F04 +#define EN_29LV010 0x7F6E +#define EN_29LV040A 0x7F4F /* EN_29LV040(A) */ +#define EN_29F002T 0x7F92 /* Same as EN29F002A */ +#define EN_29F002B 0x7F97 /* Same as EN29F002AN */ + +#define FUJITSU_ID 0x04 /* Fujitsu */ +#define MBM29DL400BC 0x0F +#define MBM29DL400TC 0x0C +#define MBM29DL800BA 0xCB +#define MBM29DL800TA 0x4A +#define MBM29F002BC 0x34 +#define MBM29F002TC 0xB0 +#define MBM29F004BC 0x7B +#define MBM29F004TC 0x77 +#define MBM29F040C 0xA4 +#define MBM29F080A 0xD5 +#define MBM29F200BC 0x57 +#define MBM29F200TC 0x51 +#define MBM29F400BC 0xAB +#define MBM29F400TC 0x23 +#define MBM29F800BA 0x58 +#define MBM29F800TA 0xD6 +#define MBM29LV002BC 0xC2 +#define MBM29LV002TC 0x40 +#define MBM29LV004BC 0xB6 +#define MBM29LV004TC 0xB5 +#define MBM29LV008BA 0x37 +#define MBM29LV008TA 0x3E +#define MBM29LV080A 0x38 +#define MBM29LV200BC 0xBF +#define MBM29LV200TC 0x3B +#define MBM29LV400BC 0xBA +#define MBM29LV400TC 0xB9 +#define MBM29LV800BA 0x5B /* Same as MBM29LV800BE */ +#define MBM29LV800TA 0xDA /* Same as MBM29LV800TE */ + +#define HYUNDAI_ID 0xAD /* Hyundai */ +#define HY_29F400T 0x23 /* Same as HY_29F400AT */ +#define HY_29F800B 0x58 /* Same as HY_29F800AB */ +#define HY_29LV800B 0x5B +#define HY_29F040A 0xA4 +#define HY_29F400B 0xAB /* Same as HY_29F400AB */ +#define HY_29F002 0xB0 +#define HY_29LV400T 0xB9 +#define HY_29LV400B 0xBA +#define HY_29F080 0xD5 +#define HY_29F800T 0xD6 /* Same as HY_29F800AT */ +#define HY_29LV800T 0xDA + +#define IMT_ID 0x7F1F /* Integrated Memory Technologies */ +#define IM_29F004B 0xAE +#define IM_29F004T 0xAF + +#define INTEL_ID 0x89 /* Intel */ +#define I_82802AB 0xAD +#define I_82802AC 0xAC +#define P28F001BXT 0x94 /* 28F001BX-T */ +#define P28F001BXB 0x95 /* 28F001BX-B */ +#define SHARP_LH28F008SA 0xA2 /* Sharp chip, Intel Vendor ID */ +#define SHARP_LH28F008SC 0xA6 /* Sharp chip, Intel Vendor ID */ + +#define ISSI_ID 0xD5 /* ISSI Integrated Silicon Solutions */ + +/* + * MX25 chips are SPI, first byte of device ID is memory type, + * second byte of device ID is log(bitsize)-9. + * Generalplus SPI chips seem to be compatible with Macronix + * and use the same set of IDs. + */ +#define MX_ID 0xC2 /* Macronix (MX) */ +#define MX_25L512 0x2010 /* Same as MX25V512 */ +#define MX_25L1005 0x2011 +#define MX_25L2005 0x2012 +#define MX_25L4005 0x2013 /* MX25L4005{,A} */ +#define MX_25L8005 0x2014 /* Same as MX25V8005 */ +#define MX_25L1605 0x2015 /* MX25L1605{,A,D} */ +#define MX_25L3205 0x2016 /* MX25L3205{,A} */ +#define MX_25L6405 0x2017 /* MX25L3205{,D} */ +#define MX_25L12805 0x2018 /* MX25L12805 */ +#define MX_25L1635D 0x2415 +#define MX_25L3235D 0x5E16 /* MX25L3225D/MX25L3235D/MX25L3237D */ +#define MX_29F001B 0x19 +#define MX_29F001T 0x18 +#define MX_29F002B 0x34 /* Same as MX29F002NB */ +#define MX_29F002T 0xB0 /* Same as MX29F002NT */ +#define MX_29F004B 0x46 +#define MX_29F004T 0x45 +#define MX_29F022T 0x36 /* Same as MX29F022NT */ +#define MX_29F040 0xA4 /* Same as MX29F040C */ +#define MX_29F080 0xD5 +#define MX_29F200B 0x57 /* Same as MX29F200CB */ +#define MX_29F200T 0x51 /* Same as MX29F200CT */ +#define MX_29F400B 0xAB /* Same as MX29F400CB */ +#define MX_29F400T 0x23 /* Same as MX29F400CT */ +#define MX_29F800B 0x58 +#define MX_29F800T 0xD6 +#define MX_29LV002CB 0x5A +#define MX_29LV002CT 0x59 +#define MX_29LV004B 0xB6 /* Same as MX29LV004CB */ +#define MX_29LV004T 0xB5 /* Same as MX29LV004CT */ +#define MX_29LV008B 0x37 /* Same as MX29LV008CB */ +#define MX_29LV008T 0x3E /* Same as MX29LV008CT */ +#define MX_29LV040 0x4F /* Same as MX29LV040C */ +#define MX_29LV081 0x38 +#define MX_29LV128DB 0x7A +#define MX_29LV128DT 0x7E +#define MX_29LV160DB 0x49 /* Same as MX29LV161DB/MX29LV160CB */ +#define MX_29LV160DT 0xC4 /* Same as MX29LV161DT/MX29LV160CT */ +#define MX_29LV320DB 0xA8 /* Same as MX29LV321DB */ +#define MX_29LV320DT 0xA7 /* Same as MX29LV321DT */ +#define MX_29LV400B 0xBA /* Same as MX29LV400CB */ +#define MX_29LV400T 0xB9 /* Same as MX29LV400CT */ +#define MX_29LV640DB 0xCB /* Same as MX29LV640EB */ +#define MX_29LV640DT 0xC9 /* Same as MX29LV640ET */ +#define MX_29LV800B 0x5B /* Same as MX29LV800CB */ +#define MX_29LV800T 0xDA /* Same as MX29LV800CT */ +#define MX_29SL402CB 0xF1 +#define MX_29SL402CT 0x70 +#define MX_29SL800CB 0x6B /* Same as MX29SL802CB */ +#define MX_29SL800CT 0xEA /* Same as MX29SL802CT */ + +/* + * Programmable Micro Corp is listed in JEP106W in bank 2, so it should + * have a 0x7F continuation code prefix. + */ +#define PMC_ID 0x7F9D /* PMC */ +#define PMC_ID_NOPREFIX 0x9D /* PMC, missing 0x7F prefix */ +#define PMC_25LV512 0x7B +#define PMC_25LV010 0x7C +#define PMC_25LV020 0x7D +#define PMC_25LV040 0x7E +#define PMC_25LV080B 0x13 +#define PMC_25LV016B 0x14 +#define PMC_29F002T 0x1D +#define PMC_29F002B 0x2D +#define PMC_39LV512 0x1B +#define PMC_39F010 0x1C /* Same as Pm39LV010 */ +#define PMC_39LV020 0x3D +#define PMC_39LV040 0x3E +#define PMC_39F020 0x4D +#define PMC_39F040 0x4E +#define PMC_49FL002 0x6D +#define PMC_49FL004 0x6E + +/* + * The Sanyo chip found so far uses SPI, first byte is manufacture code, + * second byte is the device code, + * third byte is a dummy byte. + */ +#define SANYO_ID 0x62 +#define SANYO_LE25FW203A 0x1600 + +#define SHARP_ID 0xB0 /* Sharp */ +#define SHARP_LH28F008BJxxPT 0xEC +#define SHARP_LH28F008BJxxPB 0xED +#define SHARP_LH28F800BVxxBTL 0x4B +#define SHARP_LH28F800BVxxBV 0x4D +#define SHARP_LH28F800BVxxTV 0x4C +#define SHARP_LHF00L02 0xC9 /* Same as LHF00L06/LHF00L07 */ +#define SHARP_LHF00L04 0xCF /* Same as LHF00L03/LHF00L05 */ + +/* + * Spansion was previously a joint venture of AMD and Fujitsu. + * S25 chips are SPI. The first device ID byte is memory type and + * the second device ID byte is memory capacity. + */ +#define SPANSION_ID 0x01 /* Spansion, same ID as AMD */ +#define SPANSION_S25FL016A 0x0214 + +/* + * SST25 chips are SPI, first byte of device ID is memory type, second + * byte of device ID is related to log(bitsize) at least for some chips. + */ +#define SST_ID 0xBF /* SST */ +#define SST_25WF512 0x2501 +#define SST_25WF010 0x2502 +#define SST_25WF020 0x2503 +#define SST_25WF040 0x2504 +#define SST_25VF512A_REMS 0x48 /* REMS or RES opcode */ +#define SST_25VF010_REMS 0x49 /* REMS or RES opcode */ +#define SST_25VF020_REMS 0x43 /* REMS or RES opcode */ +#define SST_25VF040_REMS 0x44 /* REMS or RES opcode */ +#define SST_25VF040B 0x258D +#define SST_25VF040B_REMS 0x8D /* REMS or RES opcode */ +#define SST_25VF080_REMS 0x80 /* REMS or RES opcode */ +#define SST_25VF080B 0x258E +#define SST_25VF080B_REMS 0x8E /* REMS or RES opcode */ +#define SST_25VF016B 0x2541 +#define SST_25VF032B 0x254A +#define SST_25VF032B_REMS 0x4A /* REMS or RES opcode */ +#define SST_26VF016 0x2601 +#define SST_26VF032 0x2602 +#define SST_27SF512 0xA4 +#define SST_27SF010 0xA5 +#define SST_27SF020 0xA6 +#define SST_27VF010 0xA9 +#define SST_27VF020 0xAA +#define SST_28SF040 0x04 +#define SST_29EE512 0x5D +#define SST_29EE010 0x07 +#define SST_29LE010 0x08 /* Same as SST29VE010 */ +#define SST_29EE020A 0x10 /* Same as SST29EE020 */ +#define SST_29LE020 0x12 /* Same as SST29VE020 */ +#define SST_29SF020 0x24 +#define SST_29VF020 0x25 +#define SST_29SF040 0x13 +#define SST_29VF040 0x14 +#define SST_39SF010 0xB5 +#define SST_39SF020 0xB6 /* Same as 39SF020A */ +#define SST_39SF040 0xB7 +#define SST_39VF512 0xD4 +#define SST_39VF010 0xD5 +#define SST_39VF020 0xD6 /* Same as 39LF020 */ +#define SST_39VF040 0xD7 /* Same as 39LF040 */ +#define SST_39VF080 0xD8 /* Same as 39LF080/39VF080/39VF088 */ +#define SST_49LF040B 0x50 +#define SST_49LF040 0x51 +#define SST_49LF020 0x61 +#define SST_49LF020A 0x52 +#define SST_49LF030A 0x1C +#define SST_49LF080A 0x5B +#define SST_49LF002A 0x57 +#define SST_49LF003A 0x1B +#define SST_49LF004A 0x60 /* Same as 49LF004B */ +#define SST_49LF008A 0x5A +#define SST_49LF004C 0x54 +#define SST_49LF008C 0x59 +#define SST_49LF016C 0x5C +#define SST_49LF160C 0x4C + +/* + * ST25P chips are SPI, first byte of device ID is memory type, second + * byte of device ID is related to log(bitsize) at least for some chips. + */ +#define ST_ID 0x20 /* ST / SGS/Thomson */ +#define ST_M25P05A 0x2010 +#define ST_M25P05_RES 0x10 /* Same code as M25P10. */ +#define ST_M25P10A 0x2011 +#define ST_M25P10_RES 0x10 /* Same code as M25P05. */ +#define ST_M25P20 0x2012 +#define ST_M25P40 0x2013 +#define ST_M25P40_RES 0x12 +#define ST_M25P80 0x2014 +#define ST_M25P16 0x2015 +#define ST_M25P32 0x2016 +#define ST_M25P64 0x2017 +#define ST_M25P128 0x2018 +#define ST_M25PE10 0x8011 +#define ST_M25PE20 0x8012 +#define ST_M25PE40 0x8013 +#define ST_M25PE80 0x8014 +#define ST_M25PE16 0x8015 +#define ST_M50FLW040A 0x08 +#define ST_M50FLW040B 0x28 +#define ST_M50FLW080A 0x80 +#define ST_M50FLW080B 0x81 +#define ST_M50FW002 0x29 +#define ST_M50FW040 0x2C +#define ST_M50FW080 0x2D +#define ST_M50FW016 0x2E +#define ST_M50LPW116 0x30 +#define ST_M29F002B 0x34 /* Same as M29F002BB */ +#define ST_M29F002T 0xB0 /* Same as M29F002BT/M29F002NT/M29F002BNT */ +#define ST_M29F040B 0xE2 /* Same as M29F040 */ +#define ST_M29F080 0xF1 +#define ST_M29F200BT 0xD3 +#define ST_M29F200BB 0xD4 +#define ST_M29F400BT 0xD5 /* Same as M29F400T */ +#define ST_M29F400BB 0xD6 /* Same as M29F400B */ +#define ST_M29F800DB 0x58 +#define ST_M29F800DT 0xEC +#define ST_M29W010B 0x23 +#define ST_M29W040B 0xE3 + +#define SYNCMOS_ID 0x40 /* SyncMOS and Mosel Vitelic */ +#define S29C51001T 0x01 +#define S29C51002T 0x02 +#define S29C51004T 0x03 +#define S29C31004T 0x63 + +#define TI_ID 0x97 /* Texas Instruments */ +#define TI_OLD_ID 0x01 /* TI chips from last century */ +#define TI_TMS29F002RT 0xB0 +#define TI_TMS29F002RB 0x34 + +/* + * W25X chips are SPI, first byte of device ID is memory type, second + * byte of device ID is related to log(bitsize). + */ +#define WINBOND_ID 0xDA /* Winbond */ +#define WINBOND_NEX_ID 0xEF /* Winbond (ex Nexcom) serial flashes */ +#define W_25X10 0x3011 +#define W_25X20 0x3012 +#define W_25X40 0x3013 +#define W_25X80 0x3014 +#define W_25X16 0x3015 +#define W_25X32 0x3016 +#define W_25X64 0x3017 +#define W_29C011 0xC1 +#define W_29C020C 0x45 /* Same as W29C020 and ASD AE29F2008 */ +#define W_29C040P 0x46 /* Same as W29C040 */ +#define W_29EE011 0xC1 +#define W_39L020 0xB5 +#define W_39L040 0xB6 +#define W_39V040FA 0x34 +#define W_39V040A 0x3D +#define W_39V040B 0x54 +#define W_39V040C 0x50 +#define W_39V080A 0xD0 +#define W_39V080FA 0xD3 +#define W_39V080FA_DM 0x93 +#define W_49F002U 0x0B +#define W_49F020 0x8C +#define W_49V002A 0xB0 +#define W_49V002FA 0x32 + +#endif /* !FLASHCHIPS_H */ diff --git a/libflashrom/ft2232_spi.c b/libflashrom/ft2232_spi.c new file mode 100644 index 0000000..d565a6f --- /dev/null +++ b/libflashrom/ft2232_spi.c @@ -0,0 +1,320 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Paul Fox + * Copyright (C) 2009 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 + */ + +#if FT2232_SPI_SUPPORT == 1 + +#include +#include +#include +#include +#include +#include "flash.h" +#include "spi.h" +#include + +/* + * The 'H' chips can run internally at either 12MHz or 60MHz. + * The non-H chips can only run at 12MHz. + */ +#define CLOCK_5X 1 + +/* + * In either case, the divisor is a simple integer clock divider. + * If CLOCK_5X is set, this divisor divides 30MHz, else it divides 6MHz. + */ +#define DIVIDE_BY 3 /* e.g. '3' will give either 10MHz or 2MHz SPI clock. */ + +#define BITMODE_BITBANG_NORMAL 1 +#define BITMODE_BITBANG_SPI 2 + +static struct ftdi_context ftdic_context; + +int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_write_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_write_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_read_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_read_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int ft2232_spi_init(void) +{ + int f; + struct ftdi_context *ftdic = &ftdic_context; + unsigned char buf[512]; + char *portpos = NULL; + int ft2232_type = FTDI_FT4232H; + enum ftdi_interface ft2232_interface = INTERFACE_B; + + if (ftdi_init(ftdic) < 0) { + fprintf(stderr, "ftdi_init failed\n"); + return EXIT_FAILURE; // TODO + } + + if (programmer_param && !strlen(programmer_param)) { + free(programmer_param); + programmer_param = NULL; + } + if (programmer_param) { + if (strstr(programmer_param, "2232")) + ft2232_type = FTDI_FT2232H; + if (strstr(programmer_param, "4232")) + ft2232_type = FTDI_FT4232H; + portpos = strstr(programmer_param, "port="); + if (portpos) { + portpos += 5; + switch (toupper(*portpos)) { + case 'A': + ft2232_interface = INTERFACE_A; + break; + case 'B': + ft2232_interface = INTERFACE_B; + break; + default: + fprintf(stderr, "Invalid interface specified, " + "using default.\n"); + } + } + free(programmer_param); + } + printf_debug("Using device type %s ", + (ft2232_type == FTDI_FT2232H) ? "2232H" : "4232H"); + printf_debug("interface %s\n", + (ft2232_interface == INTERFACE_A) ? "A" : "B"); + + f = ftdi_usb_open(ftdic, 0x0403, ft2232_type); + + if (f < 0 && f != -5) { + fprintf(stderr, "Unable to open FTDI device: %d (%s)\n", f, + ftdi_get_error_string(ftdic)); + exit(-1); // TODO + } + + if (ftdi_set_interface(ftdic, ft2232_interface) < 0) { + fprintf(stderr, "Unable to select interface: %s\n", + ftdic->error_str); + } + + if (ftdi_usb_reset(ftdic) < 0) { + fprintf(stderr, "Unable to reset FTDI device\n"); + } + + if (ftdi_set_latency_timer(ftdic, 2) < 0) { + fprintf(stderr, "Unable to set latency timer\n"); + } + + if (ftdi_write_data_set_chunksize(ftdic, 512)) { + fprintf(stderr, "Unable to set chunk size\n"); + } + + if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) { + fprintf(stderr, "Unable to set bitmode to SPI\n"); + } + +#if CLOCK_5X + printf_debug("Disable divide-by-5 front stage\n"); + buf[0] = 0x8a; /* Disable divide-by-5. */ + if (send_buf(ftdic, buf, 1)) + return -1; +#define MPSSE_CLK 60.0 + +#else + +#define MPSSE_CLK 12.0 + +#endif + printf_debug("Set clock divisor\n"); + buf[0] = 0x86; /* command "set divisor" */ + /* valueL/valueH are (desired_divisor - 1) */ + buf[1] = (DIVIDE_BY - 1) & 0xff; + buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf("SPI clock is %fMHz\n", + (double)(MPSSE_CLK / (((DIVIDE_BY - 1) + 1) * 2))); + + /* Disconnect TDI/DO to TDO/DI for loopback. */ + printf_debug("No loopback of TDI/DO TDO/DI\n"); + buf[0] = 0x85; + if (send_buf(ftdic, buf, 1)) + return -1; + + printf_debug("Set data bits\n"); + /* Set data bits low-byte command: + * value: 0x08 CS=high, DI=low, DO=low, SK=low + * dir: 0x0b CS=output, DI=input, DO=output, SK=output + */ +#define CS_BIT 0x08 + buf[0] = SET_BITS_LOW; + buf[1] = CS_BIT; + buf[2] = 0x0b; + if (send_buf(ftdic, buf, 3)) + return -1; + + // printf_debug("\nft2232 chosen\n"); + + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_FT2232; + + return 0; +} + +int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + struct ftdi_context *ftdic = &ftdic_context; + static unsigned char *buf = NULL; + /* failed is special. We use bitwise ops, but it is essentially bool. */ + int i = 0, ret = 0, failed = 0; + int bufsize; + static int oldbufsize = 0; + + if (writecnt > 65536 || readcnt > 65536) + return SPI_INVALID_LENGTH; + + /* buf is not used for the response from the chip. */ + bufsize = max(writecnt + 9, 260 + 9); + /* Never shrink. realloc() calls are expensive. */ + if (bufsize > oldbufsize) { + buf = realloc(buf, bufsize); + if (!buf) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + oldbufsize = bufsize; + } + + /* + * Minimize USB transfers by packing as many commands as possible + * together. If we're not expecting to read, we can assert CS#, write, + * and deassert CS# all in one shot. If reading, we do three separate + * operations. + */ + printf_debug("Assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = 0 & ~CS_BIT; /* assertive */ + buf[i++] = 0x0b; + + if (writecnt) { + buf[i++] = 0x11; + buf[i++] = (writecnt - 1) & 0xff; + buf[i++] = ((writecnt - 1) >> 8) & 0xff; + memcpy(buf + i, writearr, writecnt); + i += writecnt; + } + + /* + * Optionally terminate this batch of commands with a + * read command, then do the fetch of the results. + */ + if (readcnt) { + buf[i++] = 0x20; + buf[i++] = (readcnt - 1) & 0xff; + buf[i++] = ((readcnt - 1) >> 8) & 0xff; + ret = send_buf(ftdic, buf, i); + failed = ret; + /* We can't abort here, we still have to deassert CS#. */ + if (ret) + fprintf(stderr, "send_buf failed before read: %i\n", + ret); + i = 0; + if (ret == 0) { + /* + * FIXME: This is unreliable. There's no guarantee that + * we read the response directly after sending the read + * command. We may be scheduled out etc. + */ + ret = get_buf(ftdic, readarr, readcnt); + failed |= ret; + /* We can't abort here either. */ + if (ret) + fprintf(stderr, "get_buf failed: %i\n", ret); + } + } + + printf_debug("De-assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = CS_BIT; + buf[i++] = 0x0b; + ret = send_buf(ftdic, buf, i); + failed |= ret; + if (ret) + fprintf(stderr, "send_buf failed at end: %i\n", ret); + + return failed ? -1 : 0; +} + +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* Maximum read length is 64k bytes. */ + return spi_read_chunked(flash, buf, start, len, 64 * 1024); +} + +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i; + + spi_disable_blockprotect(); + /* Erase first. */ + printf("Erasing flash before programming... "); + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("done.\n"); + printf_debug("total_size is %d\n", total_size); + for (i = 0; i < total_size; i += 256) { + int l, r; + if (i + 256 <= total_size) + l = 256; + else + l = total_size - i; + + if ((r = spi_nbyte_program(i, &buf[i], l))) { + fprintf(stderr, "%s: write fail %d\n", __func__, r); + return 1; + } + + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + /* loop */; + } + + return 0; +} + +#endif diff --git a/libflashrom/gfxnvidia.c b/libflashrom/gfxnvidia.c new file mode 100644 index 0000000..1e9b679 --- /dev/null +++ b/libflashrom/gfxnvidia.c @@ -0,0 +1,104 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "flash.h" + +#define PCI_VENDOR_ID_NVIDIA 0x10de + +uint8_t *nvidia_bar; + +struct pcidev_status gfx_nvidia[] = { + {0x10de, 0x0010, PCI_NT, "NVIDIA", "Mutara V08 [NV2]" }, + {0x10de, 0x0018, PCI_NT, "NVIDIA", "RIVA 128" }, + {0x10de, 0x0020, PCI_NT, "NVIDIA", "RIVA TNT" }, + {0x10de, 0x0028, PCI_NT, "NVIDIA", "RIVA TNT2/TNT2 Pro" }, + {0x10de, 0x0029, PCI_NT, "NVIDIA", "RIVA TNT2 Ultra" }, + {0x10de, 0x002c, PCI_NT, "NVIDIA", "Vanta/Vanta LT" }, + {0x10de, 0x002d, PCI_OK, "NVIDIA", "RIVA TNT2 Model 64/Model 64 Pro" }, + {0x10de, 0x00a0, PCI_NT, "NVIDIA", "Aladdin TNT2" }, + {0x10de, 0x0100, PCI_NT, "NVIDIA", "GeForce 256" }, + {0x10de, 0x0101, PCI_NT, "NVIDIA", "GeForce DDR" }, + {0x10de, 0x0103, PCI_NT, "NVIDIA", "Quadro" }, + {0x10de, 0x0110, PCI_NT, "NVIDIA", "GeForce2 MX" }, + {0x10de, 0x0111, PCI_NT, "NVIDIA", "GeForce2 MX" }, + {0x10de, 0x0112, PCI_NT, "NVIDIA", "GeForce2 GO" }, + {0x10de, 0x0113, PCI_NT, "NVIDIA", "Quadro2 MXR" }, + {0x10de, 0x0150, PCI_NT, "NVIDIA", "GeForce2 GTS/Pro" }, + {0x10de, 0x0151, PCI_NT, "NVIDIA", "GeForce2 GTS" }, + {0x10de, 0x0152, PCI_NT, "NVIDIA", "GeForce2 Ultra" }, + {0x10de, 0x0153, PCI_NT, "NVIDIA", "Quadro2 Pro" }, + {0x10de, 0x0200, PCI_NT, "NVIDIA", "GeForce 3 nFX" }, + {0x10de, 0x0201, PCI_NT, "NVIDIA", "GeForce 3 nFX" }, + {0x10de, 0x0202, PCI_NT, "NVIDIA", "GeForce 3 nFX Ultra" }, + {0x10de, 0x0203, PCI_NT, "NVIDIA", "Quadro 3 DDC" }, + + {}, +}; + +int gfxnvidia_init(void) +{ + uint32_t reg32; + + get_io_perms(); + + io_base_addr = pcidev_init(PCI_VENDOR_ID_NVIDIA, PCI_BASE_ADDRESS_0, + gfx_nvidia, programmer_param); + io_base_addr += 0x300000; + printf("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr); + + /* Allow access to flash interface (will disable screen). */ + reg32 = pci_read_long(pcidev_dev, 0x50); + reg32 &= ~(1 << 0); + pci_write_long(pcidev_dev, 0x50, reg32); + + nvidia_bar = physmap("NVIDIA", io_base_addr, 16 * 1024 * 1024); + + buses_supported = CHIP_BUSTYPE_PARALLEL; + + return 0; +} + +int gfxnvidia_shutdown(void) +{ + uint32_t reg32; + + /* Disallow access to flash interface (and re-enable screen). */ + reg32 = pci_read_long(pcidev_dev, 0x50); + reg32 |= (1 << 0); + pci_write_long(pcidev_dev, 0x50, reg32); + + free(programmer_param); + pci_cleanup(pacc); + release_io_perms(); + return 0; +} + +void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr) +{ + mmio_writeb(val, nvidia_bar + addr); +} + +uint8_t gfxnvidia_chip_readb(const chipaddr addr) +{ + return mmio_readb(nvidia_bar + addr); +} diff --git a/libflashrom/ichspi.c b/libflashrom/ichspi.c new file mode 100644 index 0000000..cd02b96 --- /dev/null +++ b/libflashrom/ichspi.c @@ -0,0 +1,763 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 Stefan Wildemann + * Copyright (C) 2008 Claus Gindhart + * Copyright (C) 2008 Dominik Geyer + * Copyright (C) 2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This module is designed for supporting the devices + * ST M25P40 + * ST M25P80 + * ST M25P16 + * ST M25P32 already tested + * ST M25P64 + * AT 25DF321 already tested + * + */ + +#include +#include "flash.h" +#include "spi.h" + +/* ICH9 controller register definition */ +#define ICH9_REG_FADDR 0x08 /* 32 Bits */ +#define ICH9_REG_FDATA0 0x10 /* 64 Bytes */ + +#define ICH9_REG_SSFS 0x90 /* 08 Bits */ +#define SSFS_SCIP 0x00000001 +#define SSFS_CDS 0x00000004 +#define SSFS_FCERR 0x00000008 +#define SSFS_AEL 0x00000010 + +#define ICH9_REG_SSFC 0x91 /* 24 Bits */ +#define SSFC_SCGO 0x00000200 +#define SSFC_ACS 0x00000400 +#define SSFC_SPOP 0x00000800 +#define SSFC_COP 0x00001000 +#define SSFC_DBC 0x00010000 +#define SSFC_DS 0x00400000 +#define SSFC_SME 0x00800000 +#define SSFC_SCF 0x01000000 +#define SSFC_SCF_20MHZ 0x00000000 +#define SSFC_SCF_33MHZ 0x01000000 + +#define ICH9_REG_PREOP 0x94 /* 16 Bits */ +#define ICH9_REG_OPTYPE 0x96 /* 16 Bits */ +#define ICH9_REG_OPMENU 0x98 /* 64 Bits */ + +// ICH9R SPI commands +#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0 +#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1 +#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2 +#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3 + +// ICH7 registers +#define ICH7_REG_SPIS 0x00 /* 16 Bits */ +#define SPIS_SCIP 0x00000001 +#define SPIS_CDS 0x00000004 +#define SPIS_FCERR 0x00000008 + +/* VIA SPI is compatible with ICH7, but maxdata + to transfer is 16 bytes. + + DATA byte count on ICH7 is 8:13, on VIA 8:11 + + bit 12 is port select CS0 CS1 + bit 13 is FAST READ enable + bit 7 is used with fast read and one shot controls CS de-assert? +*/ + +#define ICH7_REG_SPIC 0x02 /* 16 Bits */ +#define SPIC_SCGO 0x0002 +#define SPIC_ACS 0x0004 +#define SPIC_SPOP 0x0008 +#define SPIC_DS 0x4000 + +#define ICH7_REG_SPIA 0x04 /* 32 Bits */ +#define ICH7_REG_SPID0 0x08 /* 64 Bytes */ +#define ICH7_REG_PREOP 0x54 /* 16 Bits */ +#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */ +#define ICH7_REG_OPMENU 0x58 /* 64 Bits */ + +/* ICH SPI configuration lock-down. May be set during chipset enabling. */ +int ichspi_lock = 0; + +typedef struct _OPCODE { + uint8_t opcode; //This commands spi opcode + uint8_t spi_type; //This commands spi type + uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1 +} OPCODE; + +/* Opcode definition: + * Preop 1: Write Enable + * Preop 2: Write Status register enable + * + * OP 0: Write address + * OP 1: Read Address + * OP 2: ERASE block + * OP 3: Read Status register + * OP 4: Read ID + * OP 5: Write Status register + * OP 6: chip private (read JDEC id) + * OP 7: Chip erase + */ +typedef struct _OPCODES { + uint8_t preop[2]; + OPCODE opcode[8]; +} OPCODES; + +static OPCODES *curopcodes = NULL; + +/* HW access functions */ +static uint32_t REGREAD32(int X) +{ + return mmio_readl(spibar + X); +} + +static uint16_t REGREAD16(int X) +{ + return mmio_readw(spibar + X); +} + +#define REGWRITE32(X,Y) mmio_writel(Y, spibar+X) +#define REGWRITE16(X,Y) mmio_writew(Y, spibar+X) +#define REGWRITE8(X,Y) mmio_writeb(Y, spibar+X) + +/* Common SPI functions */ +static int find_opcode(OPCODES *op, uint8_t opcode); +static int find_preop(OPCODES *op, uint8_t preop); +static int generate_opcodes(OPCODES * op); +static int program_opcodes(OPCODES * op); +static int run_opcode(OPCODE op, uint32_t offset, + uint8_t datalength, uint8_t * data); +static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes, + int offset, int maxdata); + +/* for pairing opcodes with their required preop */ +struct preop_opcode_pair { + uint8_t preop; + uint8_t opcode; +}; + +struct preop_opcode_pair pops[] = { + {JEDEC_WREN, JEDEC_BYTE_PROGRAM}, + {JEDEC_WREN, JEDEC_SE}, /* sector erase */ + {JEDEC_WREN, JEDEC_BE_52}, /* block erase */ + {JEDEC_WREN, JEDEC_BE_D8}, /* block erase */ + {JEDEC_WREN, JEDEC_CE_60}, /* chip erase */ + {JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */ + {JEDEC_EWSR, JEDEC_WRSR}, + {0,} +}; + +OPCODES O_ST_M25P = { + { + JEDEC_WREN, + 0}, + { + {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte + {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data + {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector + {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg + {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature + {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register + {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID + {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase + } +}; + +OPCODES O_EXISTING = {}; + +static int find_opcode(OPCODES *op, uint8_t opcode) +{ + int a; + + for (a = 0; a < 8; a++) { + if (op->opcode[a].opcode == opcode) + return a; + } + + return -1; +} + +static int find_preop(OPCODES *op, uint8_t preop) +{ + int a; + + for (a = 0; a < 2; a++) { + if (op->preop[a] == preop) + return a; + } + + return -1; +} + +static int generate_opcodes(OPCODES * op) +{ + int a, b, i; + uint16_t preop, optype; + uint32_t opmenu[2]; + + if (op == NULL) { + printf_debug("\n%s: null OPCODES pointer!\n", __func__); + return -1; + } + + switch (spi_controller) { + case SPI_CONTROLLER_ICH7: + case SPI_CONTROLLER_VIA: + preop = REGREAD16(ICH7_REG_PREOP); + optype = REGREAD16(ICH7_REG_OPTYPE); + opmenu[0] = REGREAD32(ICH7_REG_OPMENU); + opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4); + break; + case SPI_CONTROLLER_ICH9: + preop = REGREAD16(ICH9_REG_PREOP); + optype = REGREAD16(ICH9_REG_OPTYPE); + opmenu[0] = REGREAD32(ICH9_REG_OPMENU); + opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4); + break; + default: + printf_debug("%s: unsupported chipset\n", __func__); + return -1; + } + + op->preop[0] = (uint8_t) preop; + op->preop[1] = (uint8_t) (preop >> 8); + + for (a = 0; a < 8; a++) { + op->opcode[a].spi_type = (uint8_t) (optype & 0x3); + optype >>= 2; + } + + for (a = 0; a < 4; a++) { + op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff); + opmenu[0] >>= 8; + } + + for (a = 4; a < 8; a++) { + op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff); + opmenu[1] >>= 8; + } + + /* atomic (link opcode with required pre-op) */ + for (a = 4; a < 8; a++) + op->opcode[a].atomic = 0; + + for (i = 0; pops[i].opcode; i++) { + a = find_opcode(op, pops[i].opcode); + b = find_preop(op, pops[i].preop); + if ((a != -1) && (b != -1)) + op->opcode[a].atomic = (uint8_t) ++b; + } + + return 0; +} + +int program_opcodes(OPCODES * op) +{ + uint8_t a; + uint16_t preop, optype; + uint32_t opmenu[2]; + + /* Program Prefix Opcodes */ + /* 0:7 Prefix Opcode 1 */ + preop = (op->preop[0]); + /* 8:16 Prefix Opcode 2 */ + preop |= ((uint16_t) op->preop[1]) << 8; + + /* Program Opcode Types 0 - 7 */ + optype = 0; + for (a = 0; a < 8; a++) { + optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2); + } + + /* Program Allowable Opcodes 0 - 3 */ + opmenu[0] = 0; + for (a = 0; a < 4; a++) { + opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8); + } + + /*Program Allowable Opcodes 4 - 7 */ + opmenu[1] = 0; + for (a = 4; a < 8; a++) { + opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8); + } + + printf_debug("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]); + switch (spi_controller) { + case SPI_CONTROLLER_ICH7: + case SPI_CONTROLLER_VIA: + REGWRITE16(ICH7_REG_PREOP, preop); + REGWRITE16(ICH7_REG_OPTYPE, optype); + REGWRITE32(ICH7_REG_OPMENU, opmenu[0]); + REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]); + break; + case SPI_CONTROLLER_ICH9: + REGWRITE16(ICH9_REG_PREOP, preop); + REGWRITE16(ICH9_REG_OPTYPE, optype); + REGWRITE32(ICH9_REG_OPMENU, opmenu[0]); + REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]); + break; + default: + printf_debug("%s: unsupported chipset\n", __func__); + return -1; + } + + return 0; +} + +/* This function generates OPCODES from or programs OPCODES to ICH according to + * the chipset's SPI configuration lock. + * + * It should be called before ICH sends any spi command. + */ +int ich_init_opcodes(void) +{ + int rc = 0; + OPCODES *curopcodes_done; + + if (curopcodes) + return 0; + + if (ichspi_lock) { + printf_debug("Generating OPCODES... "); + curopcodes_done = &O_EXISTING; + rc = generate_opcodes(curopcodes_done); + } else { + printf_debug("Programming OPCODES... "); + curopcodes_done = &O_ST_M25P; + rc = program_opcodes(curopcodes_done); + } + + if (rc) { + curopcodes = NULL; + printf_debug("failed\n"); + return 1; + } else { + curopcodes = curopcodes_done; + printf_debug("done\n"); + return 0; + } +} + +static int ich7_run_opcode(OPCODE op, uint32_t offset, + uint8_t datalength, uint8_t * data, int maxdata) +{ + int write_cmd = 0; + int timeout; + uint32_t temp32 = 0; + uint16_t temp16; + uint32_t a; + uint64_t opmenu; + int opcode_index; + + /* Is it a write command? */ + if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) + || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) { + write_cmd = 1; + } + + /* Programm Offset in Flash into FADDR */ + REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */ + + /* Program data into FDATA0 to N */ + if (write_cmd && (datalength != 0)) { + temp32 = 0; + for (a = 0; a < datalength; a++) { + if ((a % 4) == 0) { + temp32 = 0; + } + + temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8); + + if ((a % 4) == 3) { + REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)), + temp32); + } + } + if (((a - 1) % 4) != 3) { + REGWRITE32(ICH7_REG_SPID0 + + ((a - 1) - ((a - 1) % 4)), temp32); + } + + } + + /* Assemble SPIS */ + temp16 = 0; + /* clear error status registers */ + temp16 |= (SPIS_CDS + SPIS_FCERR); + REGWRITE16(ICH7_REG_SPIS, temp16); + + /* Assemble SPIC */ + temp16 = 0; + + if (datalength != 0) { + temp16 |= SPIC_DS; + temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8; + } + + /* Select opcode */ + opmenu = REGREAD32(ICH7_REG_OPMENU); + opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32; + + for (opcode_index = 0; opcode_index < 8; opcode_index++) { + if ((opmenu & 0xff) == op.opcode) { + break; + } + opmenu >>= 8; + } + if (opcode_index == 8) { + printf_debug("Opcode %x not found.\n", op.opcode); + return 1; + } + temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4; + + /* Handle Atomic */ + if (op.atomic != 0) { + /* Select atomic command */ + temp16 |= SPIC_ACS; + /* Select prefix opcode */ + if ((op.atomic - 1) == 1) { + /*Select prefix opcode 2 */ + temp16 |= SPIC_SPOP; + } + } + + /* Start */ + temp16 |= SPIC_SCGO; + + /* write it */ + REGWRITE16(ICH7_REG_SPIC, temp16); + + /* wait for cycle complete */ + timeout = 100 * 1000 * 60; // 60s is a looong timeout. + while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) { + programmer_delay(10); + } + if (!timeout) { + printf_debug("timeout\n"); + } + + if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) { + printf_debug("Transaction error!\n"); + return 1; + } + + if ((!write_cmd) && (datalength != 0)) { + for (a = 0; a < datalength; a++) { + if ((a % 4) == 0) { + temp32 = REGREAD32(ICH7_REG_SPID0 + (a)); + } + + data[a] = + (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) + >> ((a % 4) * 8); + } + } + + return 0; +} + +static int ich9_run_opcode(OPCODE op, uint32_t offset, + uint8_t datalength, uint8_t * data) +{ + int write_cmd = 0; + int timeout; + uint32_t temp32; + uint32_t a; + uint64_t opmenu; + int opcode_index; + + /* Is it a write command? */ + if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) + || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) { + write_cmd = 1; + } + + /* Programm Offset in Flash into FADDR */ + REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */ + + /* Program data into FDATA0 to N */ + if (write_cmd && (datalength != 0)) { + temp32 = 0; + for (a = 0; a < datalength; a++) { + if ((a % 4) == 0) { + temp32 = 0; + } + + temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8); + + if ((a % 4) == 3) { + REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)), + temp32); + } + } + if (((a - 1) % 4) != 3) { + REGWRITE32(ICH9_REG_FDATA0 + + ((a - 1) - ((a - 1) % 4)), temp32); + } + } + + /* Assemble SSFS + SSFC */ + temp32 = 0; + + /* clear error status registers */ + temp32 |= (SSFS_CDS + SSFS_FCERR); + /* USE 20 MhZ */ + temp32 |= SSFC_SCF_20MHZ; + + if (datalength != 0) { + uint32_t datatemp; + temp32 |= SSFC_DS; + datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8); + temp32 |= datatemp; + } + + /* Select opcode */ + opmenu = REGREAD32(ICH9_REG_OPMENU); + opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32; + + for (opcode_index = 0; opcode_index < 8; opcode_index++) { + if ((opmenu & 0xff) == op.opcode) { + break; + } + opmenu >>= 8; + } + if (opcode_index == 8) { + printf_debug("Opcode %x not found.\n", op.opcode); + return 1; + } + temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4); + + /* Handle Atomic */ + if (op.atomic != 0) { + /* Select atomic command */ + temp32 |= SSFC_ACS; + /* Selct prefix opcode */ + if ((op.atomic - 1) == 1) { + /*Select prefix opcode 2 */ + temp32 |= SSFC_SPOP; + } + } + + /* Start */ + temp32 |= SSFC_SCGO; + + /* write it */ + REGWRITE32(ICH9_REG_SSFS, temp32); + + /*wait for cycle complete */ + timeout = 100 * 1000 * 60; // 60s is a looong timeout. + while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) { + programmer_delay(10); + } + if (!timeout) { + printf_debug("timeout\n"); + } + + if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) { + printf_debug("Transaction error!\n"); + return 1; + } + + if ((!write_cmd) && (datalength != 0)) { + for (a = 0; a < datalength; a++) { + if ((a % 4) == 0) { + temp32 = REGREAD32(ICH9_REG_FDATA0 + (a)); + } + + data[a] = + (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) + >> ((a % 4) * 8); + } + } + + return 0; +} + +static int run_opcode(OPCODE op, uint32_t offset, + uint8_t datalength, uint8_t * data) +{ + switch (spi_controller) { + case SPI_CONTROLLER_VIA: + if (datalength > 16) + return SPI_INVALID_LENGTH; + return ich7_run_opcode(op, offset, datalength, data, 16); + case SPI_CONTROLLER_ICH7: + if (datalength > 64) + return SPI_INVALID_LENGTH; + return ich7_run_opcode(op, offset, datalength, data, 64); + case SPI_CONTROLLER_ICH9: + if (datalength > 64) + return SPI_INVALID_LENGTH; + return ich9_run_opcode(op, offset, datalength, data); + default: + printf_debug("%s: unsupported chipset\n", __func__); + } + + /* If we ever get here, something really weird happened */ + return -1; +} + +static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes, + int offset, int maxdata) +{ + int page_size = flash->page_size; + uint32_t remaining = page_size; + int towrite; + + printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n", + offset, page_size, bytes); + + for (; remaining > 0; remaining -= towrite) { + towrite = min(remaining, maxdata); + if (spi_nbyte_program(offset + (page_size - remaining), + &bytes[page_size - remaining], towrite)) { + printf_debug("Error writing"); + return 1; + } + } + + return 0; +} + +int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len) +{ + int maxdata = 64; + + if (spi_controller == SPI_CONTROLLER_VIA) + maxdata = 16; + + return spi_read_chunked(flash, buf, start, len, maxdata); +} + +int ich_spi_write_256(struct flashchip *flash, uint8_t * buf) +{ + int i, j, rc = 0; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + int erase_size = 64 * 1024; + int maxdata = 64; + + spi_disable_blockprotect(); + /* Erase first */ + printf("Erasing flash before programming... "); + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("done.\n"); + + printf("Programming page: \n"); + for (i = 0; i < total_size / erase_size; i++) { + if (spi_controller == SPI_CONTROLLER_VIA) + maxdata = 16; + + for (j = 0; j < erase_size / page_size; j++) { + ich_spi_write_page(flash, + (void *)(buf + (i * erase_size) + (j * page_size)), + (i * erase_size) + (j * page_size), maxdata); + } + } + + printf("\n"); + + return rc; +} + +int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int a; + int result; + int opcode_index = -1; + const unsigned char cmd = *writearr; + OPCODE *opcode; + uint32_t addr = 0; + uint8_t *data; + int count; + + /* find cmd in opcodes-table */ + for (a = 0; a < 8; a++) { + if ((curopcodes->opcode[a]).opcode == cmd) { + opcode_index = a; + break; + } + } + + /* unknown / not programmed command */ + if (opcode_index == -1) { + printf_debug("Invalid OPCODE 0x%02x\n", cmd); + return SPI_INVALID_OPCODE; + } + + opcode = &(curopcodes->opcode[opcode_index]); + + /* if opcode-type requires an address */ + if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS || + opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) { + addr = (writearr[1] << 16) | + (writearr[2] << 8) | (writearr[3] << 0); + } + + /* translate read/write array/count */ + if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) { + data = (uint8_t *) (writearr + 1); + count = writecnt - 1; + } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) { + data = (uint8_t *) (writearr + 4); + count = writecnt - 4; + } else { + data = (uint8_t *) readarr; + count = readcnt; + } + + result = run_opcode(*opcode, addr, count, data); + if (result) { + printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode); + } + + return result; +} + +int ich_spi_send_multicommand(struct spi_command *cmds) +{ + int ret = 0; + int oppos, preoppos; + for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) { + /* Is the next command valid or a terminator? */ + if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) { + preoppos = find_preop(curopcodes, cmds->writearr[0]); + oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]); + /* Is the opcode of the current command listed in the + * ICH struct OPCODES as associated preopcode for the + * opcode of the next command? + */ + if ((oppos != -1) && (preoppos != -1) && + ((curopcodes->opcode[oppos].atomic - 1) == preoppos)) + continue; + } + + ret = ich_spi_send_command(cmds->writecnt, cmds->readcnt, + cmds->writearr, cmds->readarr); + } + return ret; +} diff --git a/libflashrom/internal.c b/libflashrom/internal.c new file mode 100644 index 0000000..fc662c5 --- /dev/null +++ b/libflashrom/internal.c @@ -0,0 +1,320 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "flash.h" + +#if defined(__FreeBSD__) || defined(__DragonFly__) +int io_fd; +#endif + +struct pci_dev *pci_dev_find_filter(struct pci_filter filter) +{ + struct pci_dev *temp; + + for (temp = pacc->devices; temp; temp = temp->next) + if (pci_filter_match(&filter, temp)) + return temp; + + return NULL; +} + +struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class) +{ + struct pci_dev *temp; + struct pci_filter filter; + uint16_t tmp2; + + pci_filter_init(NULL, &filter); + filter.vendor = vendor; + + for (temp = pacc->devices; temp; temp = temp->next) + if (pci_filter_match(&filter, temp)) { + /* Read PCI class */ + tmp2 = pci_read_word(temp, 0x0a); + if (tmp2 == class) + return temp; + } + + return NULL; +} + +struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device) +{ + struct pci_dev *temp; + struct pci_filter filter; + + pci_filter_init(NULL, &filter); + filter.vendor = vendor; + filter.device = device; + + for (temp = pacc->devices; temp; temp = temp->next) + if (pci_filter_match(&filter, temp)) + return temp; + + return NULL; +} + +struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device, + uint16_t card_vendor, uint16_t card_device) +{ + struct pci_dev *temp; + struct pci_filter filter; + + pci_filter_init(NULL, &filter); + filter.vendor = vendor; + filter.device = device; + + for (temp = pacc->devices; temp; temp = temp->next) + if (pci_filter_match(&filter, temp)) { + if ((card_vendor == + pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID)) + && (card_device == + pci_read_word(temp, PCI_SUBSYSTEM_ID))) + return temp; + } + + return NULL; +} + +void get_io_perms(void) +{ +#if defined (__sun) && (defined(__i386) || defined(__amd64)) + if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) { +#elif defined(__FreeBSD__) || defined (__DragonFly__) + if ((io_fd = open("/dev/io", O_RDWR)) < 0) { +#else + if (iopl(3) != 0) { +#endif + fprintf(stderr, "ERROR: Could not get I/O privileges (%s).\n" + "You need to be root.\n", strerror(errno)); + exit(1); + } +} + +void release_io_perms(void) +{ +#if defined(__FreeBSD__) || defined(__DragonFly__) + close(io_fd); +#endif +} + +int internal_init(void) +{ + int ret = 0; + + get_io_perms(); + + /* Initialize PCI access for flash enables */ + pacc = pci_alloc(); /* Get the pci_access structure */ + /* Set all options you want -- here we stick with the defaults */ + pci_init(pacc); /* Initialize the PCI library */ + pci_scan_bus(pacc); /* We want to get the list of devices */ + + /* We look at the lbtable first to see if we need a + * mainboard specific flash enable sequence. + */ + coreboot_init(); + + /* try to enable it. Failure IS an option, since not all motherboards + * really need this to be done, etc., etc. + */ + ret = chipset_flash_enable(); + if (ret == -2) { + printf("WARNING: No chipset found. Flash detection " + "will most likely fail.\n"); + } + + board_flash_enable(lb_vendor, lb_part); + + /* Even if chipset init returns an error code, we don't want to abort. + * The error code might have been a warning only. + * Besides that, we don't check the board enable return code either. + */ + return 0; +} + +int internal_shutdown(void) +{ + release_io_perms(); + + return 0; +} + +void internal_chip_writeb(uint8_t val, chipaddr addr) +{ + mmio_writeb(val, (void *) addr); +} + +void internal_chip_writew(uint16_t val, chipaddr addr) +{ + mmio_writew(val, (void *) addr); +} + +void internal_chip_writel(uint32_t val, chipaddr addr) +{ + mmio_writel(val, (void *) addr); +} + +uint8_t internal_chip_readb(const chipaddr addr) +{ + return mmio_readb((void *) addr); +} + +uint16_t internal_chip_readw(const chipaddr addr) +{ + return mmio_readw((void *) addr); +} + +uint32_t internal_chip_readl(const chipaddr addr) +{ + return mmio_readl((void *) addr); +} + +void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len) +{ + memcpy(buf, (void *)addr, len); + return; +} + +void mmio_writeb(uint8_t val, void *addr) +{ + *(volatile uint8_t *) addr = val; +} + +void mmio_writew(uint16_t val, void *addr) +{ + *(volatile uint16_t *) addr = val; +} + +void mmio_writel(uint32_t val, void *addr) +{ + *(volatile uint32_t *) addr = val; +} + +uint8_t mmio_readb(void *addr) +{ + return *(volatile uint8_t *) addr; +} + +uint16_t mmio_readw(void *addr) +{ + return *(volatile uint16_t *) addr; +} + +uint32_t mmio_readl(void *addr) +{ + return *(volatile uint32_t *) addr; +} + +void internal_delay(int usecs) +{ + /* If the delay is >1 s, use usleep because timing does not need to + * be so precise. + */ + if (usecs > 1000000) { + usleep(usecs); + } else { + myusec_delay(usecs); + } +} + +/* No-op shutdown() for programmers which don't need special handling */ +int noop_shutdown(void) +{ + return 0; +} + +/* Fallback map() for programmers which don't need special handling */ +void *fallback_map(const char *descr, unsigned long phys_addr, size_t len) +{ + /* FIXME: Should return phys_addr. */ + return 0; +} + +/* No-op/fallback unmap() for programmers which don't need special handling */ +void fallback_unmap(void *virt_addr, size_t len) +{ +} + +/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ +uint8_t noop_chip_readb(const chipaddr addr) +{ + return 0xff; +} + +/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ +void noop_chip_writeb(uint8_t val, chipaddr addr) +{ +} + +/* Little-endian fallback for drivers not supporting 16 bit accesses */ +void fallback_chip_writew(uint16_t val, chipaddr addr) +{ + chip_writeb(val & 0xff, addr); + chip_writeb((val >> 8) & 0xff, addr + 1); +} + +/* Little-endian fallback for drivers not supporting 16 bit accesses */ +uint16_t fallback_chip_readw(const chipaddr addr) +{ + uint16_t val; + val = chip_readb(addr); + val |= chip_readb(addr + 1) << 8; + return val; +} + +/* Little-endian fallback for drivers not supporting 32 bit accesses */ +void fallback_chip_writel(uint32_t val, chipaddr addr) +{ + chip_writew(val & 0xffff, addr); + chip_writew((val >> 16) & 0xffff, addr + 2); +} + +/* Little-endian fallback for drivers not supporting 32 bit accesses */ +uint32_t fallback_chip_readl(const chipaddr addr) +{ + uint32_t val; + val = chip_readw(addr); + val |= chip_readw(addr + 2) << 16; + return val; +} + +void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) + chip_writeb(buf[i], addr + i); + return; +} + +void fallback_chip_readn(uint8_t *buf, chipaddr addr, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) + buf[i] = chip_readb(addr + i); + return; +} diff --git a/libflashrom/it87spi.c b/libflashrom/it87spi.c new file mode 100644 index 0000000..a5dc06e --- /dev/null +++ b/libflashrom/it87spi.c @@ -0,0 +1,293 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger + * Copyright (C) 2008 Ronald Hoogenboom + * Copyright (C) 2008 coresystems GmbH + * + * 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 + */ + +/* + * Contains the ITE IT87* SPI specific routines + */ + +#include +#include +#include "flash.h" +#include "spi.h" + +#define ITE_SUPERIO_PORT1 0x2e +#define ITE_SUPERIO_PORT2 0x4e + +uint16_t it8716f_flashport = 0; +/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ +int fast_spi = 1; + +/* Helper functions for most recent ITE IT87xx Super I/O chips */ +#define CHIP_ID_BYTE1_REG 0x20 +#define CHIP_ID_BYTE2_REG 0x21 +void enter_conf_mode_ite(uint16_t port) +{ + OUTB(0x87, port); + OUTB(0x01, port); + OUTB(0x55, port); + if (port == ITE_SUPERIO_PORT1) + OUTB(0x55, port); + else + OUTB(0xaa, port); +} + +void exit_conf_mode_ite(uint16_t port) +{ + sio_write(port, 0x02, 0x02); +} + +static uint16_t find_ite_spi_flash_port(uint16_t port) +{ + uint8_t tmp = 0; + char *portpos = NULL; + uint16_t id, flashport = 0; + + enter_conf_mode_ite(port); + + id = sio_read(port, CHIP_ID_BYTE1_REG) << 8; + id |= sio_read(port, CHIP_ID_BYTE2_REG); + + /* TODO: Handle more IT87xx if they support flash translation */ + if (0x8716 == id || 0x8718 == id) { + /* NOLDN, reg 0x24, mask out lowest bit (suspend) */ + tmp = sio_read(port, 0x24) & 0xFE; + printf("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis"); + printf("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis"); + printf("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis"); + printf("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis"); + printf("LPC write to serial flash %sabled\n", + (tmp & 1 << 4) ? "en" : "dis"); + /* The LPC->SPI force write enable below only makes sense for + * non-programmer mode. + */ + /* If any serial flash segment is enabled, enable writing. */ + if ((tmp & 0xe) && (!(tmp & 1 << 4))) { + printf("Enabling LPC write to serial flash\n"); + tmp |= 1 << 4; + sio_write(port, 0x24, tmp); + } + printf("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); + /* LDN 0x7, reg 0x64/0x65 */ + sio_write(port, 0x07, 0x7); + flashport = sio_read(port, 0x64) << 8; + flashport |= sio_read(port, 0x65); + printf("Serial flash port 0x%04x\n", flashport); + if (programmer_param && !strlen(programmer_param)) { + free(programmer_param); + programmer_param = NULL; + } + if (programmer_param && (portpos = strstr(programmer_param, "port="))) { + portpos += 5; + flashport = strtol(portpos, (char **)NULL, 0); + printf("Forcing serial flash port 0x%04x\n", flashport); + sio_write(port, 0x64, (flashport >> 8)); + sio_write(port, 0x65, (flashport & 0xff)); + } + } + exit_conf_mode_ite(port); + return flashport; +} + +int it87spi_common_init(void) +{ + it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT1); + + if (!it8716f_flashport) + it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT2); + + if (it8716f_flashport) + spi_controller = SPI_CONTROLLER_IT87XX; + + return (!it8716f_flashport); +} + + +int it87spi_init(void) +{ + int ret; + + get_io_perms(); + ret = it87spi_common_init(); + if (!ret) { + buses_supported = CHIP_BUSTYPE_SPI; + } else { + buses_supported = CHIP_BUSTYPE_NONE; + } + return ret; +} + +int it87xx_probe_spi_flash(const char *name) +{ + int ret; + + ret = it87spi_common_init(); + if (!ret) + buses_supported |= CHIP_BUSTYPE_SPI; + return ret; +} + +/* + * The IT8716F only supports commands with length 1,2,4,5 bytes including + * command byte and can not read more than 3 bytes from the device. + * + * This function expects writearr[0] to be the first byte sent to the device, + * whereas the IT8716F splits commands internally into address and non-address + * commands with the address in inverse wire order. That's why the register + * ordering in case 4 and 5 may seem strange. + */ +int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + uint8_t busy, writeenc; + int i; + + do { + busy = INB(it8716f_flashport) & 0x80; + } while (busy); + if (readcnt > 3) { + printf("%s called with unsupported readcnt %i.\n", + __func__, readcnt); + return SPI_INVALID_LENGTH; + } + switch (writecnt) { + case 1: + OUTB(writearr[0], it8716f_flashport + 1); + writeenc = 0x0; + break; + case 2: + OUTB(writearr[0], it8716f_flashport + 1); + OUTB(writearr[1], it8716f_flashport + 7); + writeenc = 0x1; + break; + case 4: + OUTB(writearr[0], it8716f_flashport + 1); + OUTB(writearr[1], it8716f_flashport + 4); + OUTB(writearr[2], it8716f_flashport + 3); + OUTB(writearr[3], it8716f_flashport + 2); + writeenc = 0x2; + break; + case 5: + OUTB(writearr[0], it8716f_flashport + 1); + OUTB(writearr[1], it8716f_flashport + 4); + OUTB(writearr[2], it8716f_flashport + 3); + OUTB(writearr[3], it8716f_flashport + 2); + OUTB(writearr[4], it8716f_flashport + 7); + writeenc = 0x3; + break; + default: + printf("%s called with unsupported writecnt %i.\n", + __func__, writecnt); + return SPI_INVALID_LENGTH; + } + /* + * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes. + * Note: + * We can't use writecnt directly, but have to use a strange encoding. + */ + OUTB(((0x4 + (fast_spi ? 1 : 0)) << 4) + | ((readcnt & 0x3) << 2) | (writeenc), it8716f_flashport); + + if (readcnt > 0) { + do { + busy = INB(it8716f_flashport) & 0x80; + } while (busy); + + for (i = 0; i < readcnt; i++) + readarr[i] = INB(it8716f_flashport + 5 + i); + } + + return 0; +} + +/* Page size is usually 256 bytes */ +static int it8716f_spi_page_program(struct flashchip *flash, int block, uint8_t *buf) +{ + int i; + int result; + chipaddr bios = flash->virtual_memory; + + result = spi_write_enable(); + if (result) + return result; + /* FIXME: The command below seems to be redundant or wrong. */ + OUTB(0x06, it8716f_flashport + 1); + OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport); + for (i = 0; i < 256; i++) { + chip_writeb(buf[256 * block + i], bios + 256 * block + i); + } + OUTB(0, it8716f_flashport); + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 1-10 ms, so wait in 1 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(1000); + return 0; +} + +/* + * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles + * Need to read this big flash using firmware cycles 3 byte at a time. + */ +int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + int total_size = 1024 * flash->total_size; + fast_spi = 0; + + if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) { + spi_read_chunked(flash, buf, start, len, 3); + } else { + read_memmapped(flash, buf, start, len); + } + + return 0; +} + +int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i; + + /* + * IT8716F only allows maximum of 512 kb SPI chip size for memory + * mapped access. + */ + if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) { + spi_chip_write_1(flash, buf); + } else { + spi_disable_blockprotect(); + /* Erase first */ + printf("Erasing flash before programming... "); + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("done.\n"); + for (i = 0; i < total_size / 256; i++) { + it8716f_spi_page_program(flash, i, buf); + } + } + + return 0; +} diff --git a/libflashrom/jedec.c b/libflashrom/jedec.c new file mode 100644 index 0000000..83a0b83 --- /dev/null +++ b/libflashrom/jedec.c @@ -0,0 +1,382 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2006 Giampiero Giancipoli + * Copyright (C) 2006 coresystems GmbH + * Copyright (C) 2007 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +#define MAX_REFLASH_TRIES 0x10 + +/* Check one byte for odd parity */ +uint8_t oddparity(uint8_t val) +{ + val = (val ^ (val >> 4)) & 0xf; + val = (val ^ (val >> 2)) & 0x3; + return (val ^ (val >> 1)) & 0x1; +} + +void toggle_ready_jedec(chipaddr dst) +{ + unsigned int i = 0; + uint8_t tmp1, tmp2; + + tmp1 = chip_readb(dst) & 0x40; + + while (i++ < 0xFFFFFFF) { + tmp2 = chip_readb(dst) & 0x40; + if (tmp1 == tmp2) { + break; + } + tmp1 = tmp2; + } +} + +void data_polling_jedec(chipaddr dst, uint8_t data) +{ + unsigned int i = 0; + uint8_t tmp; + + data &= 0x80; + + while (i++ < 0xFFFFFFF) { + tmp = chip_readb(dst) & 0x80; + if (tmp == data) { + break; + } + } +} + +void start_program_jedec(chipaddr bios) +{ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0xA0, bios + 0x5555); +} + +int probe_jedec(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + uint32_t largeid1, largeid2; + uint32_t flashcontent1, flashcontent2; + int probe_timing_enter, probe_timing_exit; + + if (flash->probe_timing > 0) + probe_timing_enter = probe_timing_exit = flash->probe_timing; + else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */ + probe_timing_enter = probe_timing_exit = 0; + } else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */ + printf_debug("Chip lacks correct probe timing information, " + "using default 10mS/40uS. "); + probe_timing_enter = 10000; + probe_timing_exit = 40; + } else { + printf("Chip has negative value in probe_timing, failing " + "without chip access\n"); + return 0; + } + + /* Issue JEDEC Product ID Entry command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x90, bios + 0x5555); + programmer_delay(probe_timing_enter); + + /* Read product ID */ + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + largeid1 = id1; + largeid2 = id2; + + /* Check if it is a continuation ID, this should be a while loop. */ + if (id1 == 0x7F) { + largeid1 <<= 8; + id1 = chip_readb(bios + 0x100); + largeid1 |= id1; + } + if (id2 == 0x7F) { + largeid2 <<= 8; + id2 = chip_readb(bios + 0x101); + largeid2 |= id2; + } + + /* Issue JEDEC Product ID Exit command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0xF0, bios + 0x5555); + programmer_delay(probe_timing_exit); + + printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2); + if (!oddparity(id1)) + printf_debug(", id1 parity violation"); + + /* Read the product ID location again. We should now see normal flash contents. */ + flashcontent1 = chip_readb(bios); + flashcontent2 = chip_readb(bios + 0x01); + + /* Check if it is a continuation ID, this should be a while loop. */ + if (flashcontent1 == 0x7F) { + flashcontent1 <<= 8; + flashcontent1 |= chip_readb(bios + 0x100); + } + if (flashcontent2 == 0x7F) { + flashcontent2 <<= 8; + flashcontent2 |= chip_readb(bios + 0x101); + } + + if (largeid1 == flashcontent1) + printf_debug(", id1 is normal flash content"); + if (largeid2 == flashcontent2) + printf_debug(", id2 is normal flash content"); + + printf_debug("\n"); + if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id) + return 1; + + return 0; +} + +int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize) +{ + chipaddr bios = flash->virtual_memory; + + /* Issue the Sector Erase command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x80, bios + 0x5555); + programmer_delay(10); + + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x30, bios + page); + programmer_delay(10); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios); + + if (check_erased_range(flash, page, pagesize)) { + fprintf(stderr,"ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int erase_block_jedec(struct flashchip *flash, unsigned int block, unsigned int blocksize) +{ + chipaddr bios = flash->virtual_memory; + + /* Issue the Sector Erase command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x80, bios + 0x5555); + programmer_delay(10); + + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x50, bios + block); + programmer_delay(10); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios); + + if (check_erased_range(flash, block, blocksize)) { + fprintf(stderr,"ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int erase_chip_jedec(struct flashchip *flash) +{ + int total_size = flash->total_size * 1024; + chipaddr bios = flash->virtual_memory; + + /* Issue the JEDEC Chip Erase command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x80, bios + 0x5555); + programmer_delay(10); + + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x10, bios + 0x5555); + programmer_delay(10); + + toggle_ready_jedec(bios); + + if (check_erased_range(flash, 0, total_size)) { + fprintf(stderr,"ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int write_page_write_jedec(struct flashchip *flash, uint8_t *src, + int start, int page_size) +{ + int i, tried = 0, failed; + uint8_t *s = src; + chipaddr bios = flash->virtual_memory; + chipaddr dst = bios + start; + chipaddr d = dst; + +retry: + /* Issue JEDEC Data Unprotect comand */ + start_program_jedec(bios); + + /* transfer data from source to destination */ + for (i = 0; i < page_size; i++) { + /* If the data is 0xFF, don't program it */ + if (*src != 0xFF) + chip_writeb(*src, dst); + dst++; + src++; + } + + toggle_ready_jedec(dst - 1); + + dst = d; + src = s; + failed = verify_range(flash, src, start, page_size, NULL); + + if (failed && tried++ < MAX_REFLASH_TRIES) { + fprintf(stderr, "retrying.\n"); + goto retry; + } + if (failed) { + fprintf(stderr, " page 0x%lx failed!\n", + (d - bios) / page_size); + } + return failed; +} + +int write_byte_program_jedec(chipaddr bios, uint8_t *src, + chipaddr dst) +{ + int tried = 0, failed = 0; + + /* If the data is 0xFF, don't program it and don't complain. */ + if (*src == 0xFF) { + return 0; + } + +retry: + /* Issue JEDEC Byte Program command */ + start_program_jedec(bios); + + /* transfer data from source to destination */ + chip_writeb(*src, dst); + toggle_ready_jedec(bios); + + if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) { + goto retry; + } + + if (tried >= MAX_REFLASH_TRIES) + failed = 1; + + return failed; +} + +int write_sector_jedec(chipaddr bios, uint8_t *src, + chipaddr dst, unsigned int page_size) +{ + int i, failed = 0; + chipaddr olddst; + + olddst = dst; + for (i = 0; i < page_size; i++) { + if (write_byte_program_jedec(bios, src, dst)) + failed = 1; + dst++, src++; + } + if (failed) + fprintf(stderr, " writing sector at 0x%lx failed!\n", olddst); + + return failed; +} + +int write_jedec(struct flashchip *flash, uint8_t *buf) +{ + int i, failed = 0; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + + if (erase_chip_jedec(flash)) { + fprintf(stderr,"ERASE FAILED!\n"); + return -1; + } + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + printf("%04d at address: 0x%08x", i, i * page_size); + if (write_page_write_jedec(flash, buf + i * page_size, + i * page_size, page_size)) + failed = 1; + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + return failed; +} + +int write_jedec_1(struct flashchip *flash, uint8_t * buf) +{ + int i; + chipaddr bios = flash->virtual_memory; + chipaddr dst = bios; + + programmer_delay(10); + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + printf("Programming page: "); + for (i = 0; i < flash->total_size; i++) { + if ((i & 0x3) == 0) + printf("address: 0x%08lx", (unsigned long)i * 1024); + + write_sector_jedec(bios, buf + i * 1024, dst + i * 1024, 1024); + + if ((i & 0x3) == 0) + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + + printf("\n"); + return 0; +} diff --git a/libflashrom/m29f002.c b/libflashrom/m29f002.c new file mode 100644 index 0000000..01a7a50 --- /dev/null +++ b/libflashrom/m29f002.c @@ -0,0 +1,128 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Peter Stuge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +int erase_m29f002(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + chip_writeb(0xaa, bios + 0x555); + chip_writeb(0x55, bios + 0xaaa); + chip_writeb(0x80, bios + 0x555); + chip_writeb(0xaa, bios + 0x555); + chip_writeb(0x55, bios + 0xaaa); + chip_writeb(0x10, bios + 0x555); + programmer_delay(10); + toggle_ready_jedec(bios); + if (check_erased_range(flash, 0, flash->total_size * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +static int rewrite_block(struct flashchip *flash, uint8_t *src, + unsigned long start, int size) +{ + chipaddr bios = flash->virtual_memory; + chipaddr dst = bios + start; + + /* erase */ + /* FIXME: use erase_sector_jedec? */ + chip_writeb(0xaa, bios + 0x555); + chip_writeb(0x55, bios + 0xaaa); + chip_writeb(0x80, bios + 0x555); + chip_writeb(0xaa, bios + 0x555); + chip_writeb(0x55, bios + 0xaaa); + chip_writeb(0x30, dst); + programmer_delay(10); + toggle_ready_jedec(bios); + if (check_erased_range(flash, start, size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* program */ + /* FIXME: use write_sector_jedec? */ + while (size--) { + chip_writeb(0xaa, bios + 0x555); + chip_writeb(0x55, bios + 0xaaa); + chip_writeb(0xa0, bios + 0x555); + chip_writeb(*src, dst); + toggle_ready_jedec(dst); + dst++; + src++; + } + return 0; +} + +static int do_block(struct flashchip *flash, uint8_t *src, int i, + unsigned long start, int size) +{ + int ret; + printf("%d at address: 0x%08lx", i, start); + ret = rewrite_block(flash, src + start, start, size); + if (ret) + return ret; + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + return 0; +} + +int write_m29f002t(struct flashchip *flash, uint8_t *buf) +{ + int i, page_size = flash->page_size; + + /* M29F002(N)T has 7 blocks. From bottom to top their sizes are: + * 64k 64k 64k 32k 8k 8k 16k + * flash->page_size is set to 64k in flashchips.c + */ + + printf("Programming block: "); + for (i = 0; i < 3; i++) + do_block(flash, buf, i, i * page_size, page_size); + do_block(flash, buf, i++, 0x30000, 32 * 1024); + do_block(flash, buf, i++, 0x38000, 8 * 1024); + do_block(flash, buf, i++, 0x3a000, 8 * 1024); + do_block(flash, buf, i, 0x3c000, 16 * 1024); + + printf("\n"); + return 0; +} + +int write_m29f002b(struct flashchip *flash, uint8_t *buf) +{ + int i = 0, page_size = flash->page_size; + + /* M29F002B has 7 blocks. From bottom to top their sizes are: + * 16k 8k 8k 32k 64k 64k 64k + * flash->page_size is set to 64k in flashchips.c + */ + + printf("Programming block: "); + do_block(flash, buf, i++, 0x00000, 16 * 1024); + do_block(flash, buf, i++, 0x04000, 8 * 1024); + do_block(flash, buf, i++, 0x06000, 8 * 1024); + do_block(flash, buf, i++, 0x08000, 32 * 1024); + for (; i < 7; i++) + do_block(flash, buf, i, (i - 3) * page_size, page_size); + + printf("\n"); + return 0; +} diff --git a/libflashrom/m29f400bt.c b/libflashrom/m29f400bt.c new file mode 100644 index 0000000..c327f44 --- /dev/null +++ b/libflashrom/m29f400bt.c @@ -0,0 +1,249 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +/* WARNING! + This chip uses the standard JEDEC Addresses in 16-bit mode as word + addresses. In byte mode, 0xAAA has to be used instead of 0x555 and + 0x555 instead of 0x2AA. Do *not* blindly replace with standard JEDEC + functions. */ + +void write_page_m29f400bt(chipaddr bios, uint8_t *src, + chipaddr dst, int page_size) +{ + int i; + + for (i = 0; i < page_size; i++) { + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + chip_writeb(0xA0, bios + 0xAAA); + + /* transfer data from source to destination */ + chip_writeb(*src, dst); + //chip_writeb(0xF0, bios); + //programmer_delay(5); + toggle_ready_jedec(dst); + printf + ("Value in the flash at address 0x%lx = %#x, want %#x\n", + (dst - bios), chip_readb(dst), *src); + dst++; + src++; + } +} + +int probe_m29f400bt(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + chip_writeb(0x90, bios + 0xAAA); + + programmer_delay(10); + + id1 = chip_readb(bios); + /* The data sheet says id2 is at (bios + 0x01) and id2 listed in + * flash.h does not match. It should be possible to use JEDEC probe. + */ + id2 = chip_readb(bios + 0x02); + + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + chip_writeb(0xF0, bios + 0xAAA); + + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} + +int erase_m29f400bt(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + chip_writeb(0x80, bios + 0xAAA); + + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + chip_writeb(0x10, bios + 0xAAA); + + programmer_delay(10); + toggle_ready_jedec(bios); + + if (check_erased_range(flash, 0, flash->total_size * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int block_erase_m29f400bt(struct flashchip *flash, int start, int len) +{ + chipaddr bios = flash->virtual_memory; + chipaddr dst = bios + start; + + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + chip_writeb(0x80, bios + 0xAAA); + + chip_writeb(0xAA, bios + 0xAAA); + chip_writeb(0x55, bios + 0x555); + //chip_writeb(0x10, bios + 0xAAA); + chip_writeb(0x30, dst); + + programmer_delay(10); + toggle_ready_jedec(bios); + + if (check_erased_range(flash, start, len)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int write_m29f400bt(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + //erase_m29f400bt (flash); + printf("Programming page:\n "); + /********************************* + *Pages for M29F400BT: + * 16 0x7c000 0x7ffff TOP + * 8 0x7a000 0x7bfff + * 8 0x78000 0x79fff + * 32 0x70000 0x77fff + * 64 0x60000 0x6ffff + * 64 0x50000 0x5ffff + * 64 0x40000 0x4ffff + *--------------------------------- + * 64 0x30000 0x3ffff + * 64 0x20000 0x2ffff + * 64 0x10000 0x1ffff + * 64 0x00000 0x0ffff BOTTOM + *********************************/ + printf("total_size/page_size = %d\n", total_size / page_size); + for (i = 0; i < (total_size / page_size) - 1; i++) { + printf("%04d at address: 0x%08x\n", i, i * page_size); + if (block_erase_m29f400bt(flash, i * page_size, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + + printf("%04d at address: 0x%08x\n", 7, 0x70000); + if (block_erase_m29f400bt(flash, 0x70000, 32 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x70000, bios + 0x70000, 32 * 1024); + + printf("%04d at address: 0x%08x\n", 8, 0x78000); + if (block_erase_m29f400bt(flash, 0x78000, 8 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x78000, bios + 0x78000, 8 * 1024); + + printf("%04d at address: 0x%08x\n", 9, 0x7a000); + if (block_erase_m29f400bt(flash, 0x7a000, 8 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x7a000, bios + 0x7a000, 8 * 1024); + + printf("%04d at address: 0x%08x\n", 10, 0x7c000); + if (block_erase_m29f400bt(flash, 0x7c000, 16 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x7c000, bios + 0x7c000, 16 * 1024); + + printf("\n"); + + return 0; +} + +int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf) +{ + chipaddr bios = flash->virtual_memory; + + printf("Programming page:\n "); + /********************************* + *Pages for M29F400BT: + * 16 0x7c000 0x7ffff TOP + * 8 0x7a000 0x7bfff + * 8 0x78000 0x79fff + * 32 0x70000 0x77fff + * 64 0x60000 0x6ffff + * 64 0x50000 0x5ffff + * 64 0x40000 0x4ffff + *--------------------------------- + * 64 0x30000 0x3ffff + * 64 0x20000 0x2ffff + * 64 0x10000 0x1ffff + * 64 0x00000 0x0ffff BOTTOM + *********************************/ + printf("%04d at address: 0x%08x\n", 7, 0x00000); + if (block_erase_m29f400bt(flash, 0x00000, 64 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x00000, bios + 0x00000, 64 * 1024); + + printf("%04d at address: 0x%08x\n", 7, 0x10000); + if (block_erase_m29f400bt(flash, 0x10000, 64 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x10000, bios + 0x10000, 64 * 1024); + + printf("%04d at address: 0x%08x\n", 7, 0x20000); + if (block_erase_m29f400bt(flash, 0x20000, 64 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x20000, bios + 0x20000, 64 * 1024); + + printf("%04d at address: 0x%08x\n", 7, 0x30000); + if (block_erase_m29f400bt(flash, 0x30000, 64 * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + write_page_m29f400bt(bios, buf + 0x30000, bios + 0x30000, 64 * 1024); + + printf("\n"); + + return 0; +} diff --git a/libflashrom/mx29f002.c b/libflashrom/mx29f002.c new file mode 100644 index 0000000..7838c3d --- /dev/null +++ b/libflashrom/mx29f002.c @@ -0,0 +1,69 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +int probe_29f002(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0x90, bios + 0x5555); + + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + + chip_writeb(0xF0, bios); + + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} + +/* FIXME: Use erase_chip_jedec? + * erase_29f002 uses shorter addresses, sends F0 (exit ID mode) and + * and has a bigger delay before polling the toggle bit */ +int erase_29f002(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + + chip_writeb(0xF0, bios + 0x555); + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x80, bios + 0x555); + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0x10, bios + 0x555); + + programmer_delay(100); + toggle_ready_jedec(bios); + + if (check_erased_range(flash, 0, flash->total_size * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} diff --git a/libflashrom/nic3com.c b/libflashrom/nic3com.c new file mode 100644 index 0000000..a4878d2 --- /dev/null +++ b/libflashrom/nic3com.c @@ -0,0 +1,114 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "flash.h" + +#define BIOS_ROM_ADDR 0x04 +#define BIOS_ROM_DATA 0x08 +#define INT_STATUS 0x0e +#define INTERNAL_CONFIG 0x00 +#define SELECT_REG_WINDOW 0x800 + +#define PCI_VENDOR_ID_3COM 0x10b7 + +uint32_t internal_conf; +uint16_t id; + +struct pcidev_status nics_3com[] = { + /* 3C90xB */ + {0x10b7, 0x9055, PCI_OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"}, + {0x10b7, 0x9001, PCI_NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" }, + {0x10b7, 0x9004, PCI_OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" }, + {0x10b7, 0x9005, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" }, + {0x10b7, 0x9006, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" }, + {0x10b7, 0x900a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FL" }, + {0x10b7, 0x905a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FX" }, + {0x10b7, 0x9058, PCI_OK, "3COM", "3C905B: Cyclone 10/100/BNC" }, + + /* 3C905C */ + {0x10b7, 0x9200, PCI_OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" }, + + /* 3C980C */ + {0x10b7, 0x9805, PCI_NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" }, + + {}, +}; + +int nic3com_init(void) +{ + get_io_perms(); + + io_base_addr = pcidev_init(PCI_VENDOR_ID_3COM, PCI_BASE_ADDRESS_0, + nics_3com, programmer_param); + id = pcidev_dev->device_id; + + /* 3COM 3C90xB cards need a special fixup. */ + if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005 + || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) { + /* Select register window 3 and save the receiver status. */ + OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS); + internal_conf = INL(io_base_addr + INTERNAL_CONFIG); + + /* Set receiver type to MII for full BIOS ROM access. */ + OUTL((internal_conf & 0xf00fffff) | 0x00600000, io_base_addr); + } + + /* + * The lowest 16 bytes of the I/O mapped register space of (most) 3COM + * cards form a 'register window' into one of multiple (usually 8) + * register banks. For 3C90xB/3C90xC we need register window/bank 0. + */ + OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS); + + buses_supported = CHIP_BUSTYPE_PARALLEL; + + return 0; +} + +int nic3com_shutdown(void) +{ + /* 3COM 3C90xB cards need a special fixup. */ + if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005 + || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) { + /* Select register window 3 and restore the receiver status. */ + OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS); + OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG); + } + + free(programmer_param); + pci_cleanup(pacc); + release_io_perms(); + return 0; +} + +void nic3com_chip_writeb(uint8_t val, chipaddr addr) +{ + OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); + OUTB(val, io_base_addr + BIOS_ROM_DATA); +} + +uint8_t nic3com_chip_readb(const chipaddr addr) +{ + OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); + return INB(io_base_addr + BIOS_ROM_DATA); +} diff --git a/libflashrom/pcidev.c b/libflashrom/pcidev.c new file mode 100644 index 0000000..6c92c0a --- /dev/null +++ b/libflashrom/pcidev.c @@ -0,0 +1,122 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "flash.h" + +uint32_t io_base_addr; +struct pci_access *pacc; +struct pci_filter filter; +struct pci_dev *pcidev_dev = NULL; + +uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, + struct pcidev_status *devs) +{ + int i; + uint32_t addr; + + for (i = 0; devs[i].device_name != NULL; i++) { + if (dev->device_id != devs[i].device_id) + continue; + + /* + * Don't use dev->base_addr[x] (as value for 'bar'), won't + * work on older libpci. + */ + addr = pci_read_long(dev, bar) & ~0x03; + + printf("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n", + devs[i].vendor_name, devs[i].device_name, + dev->vendor_id, dev->device_id, dev->bus, dev->dev, + dev->func); + + if (devs[i].status == PCI_NT) { + printf("===\nThis PCI device is UNTESTED. Please " + "report the 'flashrom -p xxxx' output \n" + "to flashrom@flashrom.org if it works " + "for you. Thank you for your help!\n===\n"); + } + + return addr; + } + + return 0; +} + +uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, + struct pcidev_status *devs, char *pcidev_bdf) +{ + struct pci_dev *dev; + char *msg = NULL; + int found = 0; + uint32_t addr = 0, curaddr = 0; + + pacc = pci_alloc(); /* Get the pci_access structure */ + pci_init(pacc); /* Initialize the PCI library */ + pci_scan_bus(pacc); /* We want to get the list of devices */ + pci_filter_init(pacc, &filter); + + /* Filter by vendor and also bb:dd.f (if supplied by the user). */ + filter.vendor = vendor_id; + if (pcidev_bdf != NULL) { + if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) { + fprintf(stderr, "Error: %s\n", msg); + exit(1); + } + } + + for (dev = pacc->devices; dev; dev = dev->next) { + if (pci_filter_match(&filter, dev)) { + if ((addr = pcidev_validate(dev, bar, devs)) != 0) { + curaddr = addr; + pcidev_dev = dev; + found++; + } + } + } + + /* Only continue if exactly one supported PCI dev has been found. */ + if (found == 0) { + fprintf(stderr, "Error: No supported PCI device found.\n"); + exit(1); + } else if (found > 1) { + fprintf(stderr, "Error: Multiple supported PCI devices found. " + "Use 'flashrom -p xxxx:bb:dd.f' \n" + "to explicitly select the card with the given BDF " + "(PCI bus, device, function).\n"); + exit(1); + } + + return curaddr; +} + +void print_supported_pcidevs(struct pcidev_status *devs) +{ + int i; + + for (i = 0; devs[i].vendor_name != NULL; i++) { + printf("%s %s [%02x:%02x]%s\n", devs[i].vendor_name, + devs[i].device_name, devs[i].vendor_id, + devs[i].device_id, + (devs[i].status == PCI_NT) ? " (untested)" : ""); + } +} diff --git a/libflashrom/pm29f002.c b/libflashrom/pm29f002.c new file mode 100644 index 0000000..bf78d13 --- /dev/null +++ b/libflashrom/pm29f002.c @@ -0,0 +1,58 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +/* if write_sector_jedec is used, + this is write_jedec_1 */ +int write_pm29f002(struct flashchip *flash, uint8_t *buf) +{ + int i, total_size = flash->total_size * 1024; + chipaddr bios = flash->virtual_memory; + chipaddr dst = bios; + + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* FIXME: use write_sector_jedec? */ + printf("Programming page: "); + for (i = 0; i < total_size; i++) { + if ((i & 0xfff) == 0) + printf("address: 0x%08lx", (unsigned long)i); + + /* Pm29F002T/B only support byte-wise programming. */ + chip_writeb(0xAA, bios + 0x555); + chip_writeb(0x55, bios + 0x2AA); + chip_writeb(0xA0, bios + 0x555); + chip_writeb(*buf++, dst++); + + /* Wait for Toggle bit ready. */ + toggle_ready_jedec(dst); + + if ((i & 0xfff) == 0) + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + + printf("\n"); + + return 0; +} diff --git a/libflashrom/pm49fl00x.c b/libflashrom/pm49fl00x.c new file mode 100644 index 0000000..27a1163 --- /dev/null +++ b/libflashrom/pm49fl00x.c @@ -0,0 +1,116 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2004 Tyan Corporation + * Copyright (C) 2007 Nikolay Petukhov + * Copyright (C) 2007 Reinder E.N. de Haan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +void write_lockbits_49fl00x(chipaddr bios, int size, + unsigned char bits, int block_size) +{ + int i, left = size; + + for (i = 0; left >= block_size; i++, left -= block_size) { + /* pm49fl002 */ + if (block_size == 16384 && i % 2) + continue; + + chip_writeb(bits, bios + (i * block_size) + 2); + } +} + +int probe_49fl00x(struct flashchip *flash) +{ + int ret = probe_jedec(flash); + + if (ret == 1) + map_flash_registers(flash); + + return ret; +} + +int erase_49fl00x(struct flashchip *flash) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + + /* unprotected */ + write_lockbits_49fl00x(flash->virtual_registers, + total_size, 0, page_size); + + /* + * erase_chip_jedec() will not work... Datasheet says + * "Chip erase is available in A/A Mux Mode only". + */ + printf("Erasing page: "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page */ + if (erase_block_jedec(flash, i * page_size, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("%04d at address: 0x%08x", i, i * page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + printf("\n"); + + /* protected */ + write_lockbits_49fl00x(flash->virtual_registers, + total_size, 1, page_size); + + return 0; +} + +int write_49fl00x(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + /* unprotected */ + write_lockbits_49fl00x(flash->virtual_registers, total_size, 0, + page_size); + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page before programming */ + if (erase_block_jedec(flash, i * page_size, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* write to the sector */ + printf("%04d at address: 0x%08x", i, i * page_size); + write_sector_jedec(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + printf("\n"); + + /* protected */ + write_lockbits_49fl00x(flash->virtual_registers, total_size, 1, + page_size); + + return 0; +} diff --git a/libflashrom/satasii.c b/libflashrom/satasii.c new file mode 100644 index 0000000..79d4325 --- /dev/null +++ b/libflashrom/satasii.c @@ -0,0 +1,113 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Datasheets can be found on http://www.siliconimage.com. Great thanks! */ + +#include +#include +#include "flash.h" + +#define PCI_VENDOR_ID_SII 0x1095 + +uint8_t *sii_bar; +uint16_t id; + +struct pcidev_status satas_sii[] = { + {0x1095, 0x0680, PCI_OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"}, + {0x1095, 0x3112, PCI_OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"}, + {0x1095, 0x3114, PCI_OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"}, + {0x1095, 0x3124, PCI_NT, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"}, + {0x1095, 0x3132, PCI_OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"}, + {0x1095, 0x3512, PCI_NT, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"}, + + {}, +}; + +int satasii_init(void) +{ + uint32_t addr; + uint16_t reg_offset; + + get_io_perms(); + + pcidev_init(PCI_VENDOR_ID_SII, PCI_BASE_ADDRESS_0, satas_sii, + programmer_param); + id = pcidev_dev->device_id; + + if ((id == 0x3132) || (id == 0x3124)) { + addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_0) & ~0x07; + reg_offset = 0x70; + } else { + addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_5) & ~0x07; + reg_offset = 0x50; + } + + sii_bar = physmap("SATA SIL registers", addr, 0x100) + reg_offset; + + /* Check if ROM cycle are OK. */ + if ((id != 0x0680) && (!(mmio_readl(sii_bar) & (1 << 26)))) + printf("Warning: Flash seems unconnected.\n"); + + buses_supported = CHIP_BUSTYPE_PARALLEL; + + return 0; +} + +int satasii_shutdown(void) +{ + free(programmer_param); + pci_cleanup(pacc); + release_io_perms(); + return 0; +} + +void satasii_chip_writeb(uint8_t val, chipaddr addr) +{ + uint32_t ctrl_reg, data_reg; + + while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ; + + /* Mask out unused/reserved bits, set writes and start transaction. */ + ctrl_reg &= 0xfcf80000; + ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff); + + data_reg = (mmio_readl((sii_bar + 4)) & ~0xff) | val; + mmio_writel(data_reg, (sii_bar + 4)); + mmio_writel(ctrl_reg, sii_bar); + + while (mmio_readl(sii_bar) & (1 << 25)) ; +} + +uint8_t satasii_chip_readb(const chipaddr addr) +{ + uint32_t ctrl_reg; + + while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ; + + /* Mask out unused/reserved bits, set reads and start transaction. */ + ctrl_reg &= 0xfcf80000; + ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff); + + mmio_writel(ctrl_reg, sii_bar); + + while (mmio_readl(sii_bar) & (1 << 25)) ; + + return (mmio_readl(sii_bar + 4)) & 0xff; +} diff --git a/libflashrom/sb600spi.c b/libflashrom/sb600spi.c new file mode 100644 index 0000000..87f1cc1 --- /dev/null +++ b/libflashrom/sb600spi.c @@ -0,0 +1,179 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 Wang Qingpei + * Copyright (C) 2008 Joe Bao + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "flash.h" +#include "spi.h" + +/* This struct is unused, but helps visualize the SB600 SPI BAR layout. + *struct sb600_spi_controller { + * unsigned int spi_cntrl0; / * 00h * / + * unsigned int restrictedcmd1; / * 04h * / + * unsigned int restrictedcmd2; / * 08h * / + * unsigned int spi_cntrl1; / * 0ch * / + * unsigned int spi_cmdvalue0; / * 10h * / + * unsigned int spi_cmdvalue1; / * 14h * / + * unsigned int spi_cmdvalue2; / * 18h * / + * unsigned int spi_fakeid; / * 1Ch * / + *}; + */ + +uint8_t *sb600_spibar = NULL; + +int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* Maximum read length is 8 bytes. */ + return spi_read_chunked(flash, buf, start, len, 8); +} + +/* FIXME: SB600 can write 5 bytes per transaction. */ +int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int result = 0; + + spi_disable_blockprotect(); + /* Erase first */ + printf("Erasing flash before programming... "); + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("done.\n"); + + printf("Programming flash"); + for (i = 0; i < total_size; i++, buf++) { + result = spi_nbyte_program(i, buf, 1); + if (result) { + fprintf(stderr, "Write error!\n"); + return result; + } + + /* wait program complete. */ + if (i % 0x8000 == 0) + printf("."); + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + ; + } + printf(" done.\n"); + return result; +} + +static void reset_internal_fifo_pointer(void) +{ + mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2); + + while (mmio_readb(sb600_spibar + 0xD) & 0x7) + printf("reset\n"); +} + +static void execute_command(void) +{ + mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2); + + while (mmio_readb(sb600_spibar + 2) & 1) + ; +} + +int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int count; + /* First byte is cmd which can not being sent through FIFO. */ + unsigned char cmd = *writearr++; + unsigned int readoffby1; + + writecnt--; + + printf_debug("%s, cmd=%x, writecnt=%x, readcnt=%x\n", + __func__, cmd, writecnt, readcnt); + + if (readcnt > 8) { + printf("%s, SB600 SPI controller can not receive %d bytes, " + "it is limited to 8 bytes\n", __func__, readcnt); + return SPI_INVALID_LENGTH; + } + + if (writecnt > 8) { + printf("%s, SB600 SPI controller can not send %d bytes, " + "it is limited to 8 bytes\n", __func__, writecnt); + return SPI_INVALID_LENGTH; + } + + /* This is a workaround for a bug in SB600 and SB700. If we only send + * an opcode and no additional data/address, the SPI controller will + * read one byte too few from the chip. Basically, the last byte of + * the chip response is discarded and will not end up in the FIFO. + * It is unclear if the CS# line is set high too early as well. + */ + readoffby1 = (writecnt) ? 0 : 1; + mmio_writeb((readcnt + readoffby1) << 4 | (writecnt), sb600_spibar + 1); + mmio_writeb(cmd, sb600_spibar + 0); + + /* Before we use the FIFO, reset it first. */ + reset_internal_fifo_pointer(); + + /* Send the write byte to FIFO. */ + for (count = 0; count < writecnt; count++, writearr++) { + printf_debug(" [%x]", *writearr); + mmio_writeb(*writearr, sb600_spibar + 0xC); + } + printf_debug("\n"); + + /* + * We should send the data by sequence, which means we need to reset + * the FIFO pointer to the first byte we want to send. + */ + reset_internal_fifo_pointer(); + + execute_command(); + + /* + * After the command executed, we should find out the index of the + * received byte. Here we just reset the FIFO pointer and skip the + * writecnt. + * It would be possible to increase the FIFO pointer by one instead + * of reading and discarding one byte from the FIFO. + * The FIFO is implemented on top of an 8 byte ring buffer and the + * buffer is never cleared. For every byte that is shifted out after + * the opcode, the FIFO already stores the response from the chip. + * Usually, the chip will respond with 0x00 or 0xff. + */ + reset_internal_fifo_pointer(); + + /* Skip the bytes we sent. */ + for (count = 0; count < writecnt; count++) { + cmd = mmio_readb(sb600_spibar + 0xC); + printf_debug("[ %2x]", cmd); + } + + printf_debug("The FIFO pointer after skipping is %d.\n", + mmio_readb(sb600_spibar + 0xd) & 0x07); + for (count = 0; count < readcnt; count++, readarr++) { + *readarr = mmio_readb(sb600_spibar + 0xC); + printf_debug("[%02x]", *readarr); + } + printf_debug("\n"); + + return 0; +} diff --git a/libflashrom/serial.c b/libflashrom/serial.c new file mode 100644 index 0000000..e22a8fa --- /dev/null +++ b/libflashrom/serial.c @@ -0,0 +1,142 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Urja Rannikko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "flash.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int sp_fd; + +void __attribute__((noreturn)) sp_die(char *msg) +{ + perror(msg); + exit(1); +} + +struct baudentry { + int flag; + unsigned int baud; +}; + +/* I'd like if the C preprocessor could have directives in macros */ +#define BAUDENTRY(baud) { B##baud, baud }, +static const struct baudentry sp_baudtable[] = { + BAUDENTRY(9600) + BAUDENTRY(19200) + BAUDENTRY(38400) + BAUDENTRY(57600) + BAUDENTRY(115200) +#ifdef B230400 + BAUDENTRY(230400) +#endif +#ifdef B460800 + BAUDENTRY(460800) +#endif +#ifdef B500000 + BAUDENTRY(500000) +#endif +#ifdef B576000 + BAUDENTRY(576000) +#endif +#ifdef B921600 + BAUDENTRY(921600) +#endif +#ifdef B1000000 + BAUDENTRY(1000000) +#endif +#ifdef B1152000 + BAUDENTRY(1152000) +#endif +#ifdef B1500000 + BAUDENTRY(1500000) +#endif +#ifdef B2000000 + BAUDENTRY(2000000) +#endif +#ifdef B2500000 + BAUDENTRY(2500000) +#endif +#ifdef B3000000 + BAUDENTRY(3000000) +#endif +#ifdef B3500000 + BAUDENTRY(3500000) +#endif +#ifdef B4000000 + BAUDENTRY(4000000) +#endif + {0, 0} /* Terminator */ +}; + +int sp_openserport(char *dev, unsigned int baud) +{ + struct termios options; + int fd, i; + fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd < 0) + sp_die("Error: cannot open serial port"); + fcntl(fd, F_SETFL, 0); + tcgetattr(fd, &options); + for (i = 0;; i++) { + if (sp_baudtable[i].baud == 0) { + close(fd); + fprintf(stderr, + "Error: cannot configure for baudrate %d\n", + baud); + exit(1); + } + if (sp_baudtable[i].baud == baud) { + cfsetispeed(&options, sp_baudtable[i].flag); + cfsetospeed(&options, sp_baudtable[i].flag); + break; + } + } + options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); + options.c_cflag |= (CS8 | CLOCAL | CREAD); + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR); + options.c_oflag &= ~OPOST; + tcsetattr(fd, TCSANOW, &options); + return fd; +} + +void sp_flush_incoming(void) +{ + int i; + for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */ + unsigned char flush[16]; + ssize_t rv; + rv = read(sp_fd, flush, sizeof(flush)); + if ((rv == -1) && (errno == EAGAIN)) + break; + if (rv == -1) + sp_die("flush read"); + } + return; +} diff --git a/libflashrom/serprog-protocol.txt b/libflashrom/serprog-protocol.txt new file mode 100644 index 0000000..0d389e6 --- /dev/null +++ b/libflashrom/serprog-protocol.txt @@ -0,0 +1,101 @@ +Serial Flasher Protocol Specification - version 1 (0x01 return value == 1) + +Command And Answer Sequence - all commands give an answer. +PC: COMMAND(8bit) +DEV: ACK/NAK(8bit) / nothing +Command 0x10 (SYNCNOP) has a special return of NAK+ACK for synchronization. + +ACK = 0x06 +NAK = 0x15 + +All multibyte values are little-endian. Addresses and lengths are 24-bit. + +COMMAND Description Parameters Return Value +0x00 NOP none ACK +0x01 Query programmer iface version none ACK + 16bit version (nonzero) +0x02 Query supported commands bitmap none ACK + 32 bytes (256 bits) of supported cmds flags +0x03 Query programmer name none ACK + 16 bytes string (null padding) / NAK +0x04 Query serial buffer size none ACK + 16bit size / NAK +0x05 Query supported bustypes none ACK + 8-bit flags (as per flashrom) / NAK +0x06 Query connected address lines none ACK + 8bit line count / NAK +0x07 Query operation buffer size none ACK + 16bit size / NAK +0x08 Query write-n maximum data len none ACK + 24bit maximum length / NAK +0x09 Read byte 24-bit addr ACK + BYTE / NAK +0x0A Read n bytes 24-bit addr + 24-bit length ACK + length bytes / NAK +0x0B Initialize operation buffer none ACK / NAK +0x0C Write to opbuf: Write byte 24-bit addr + 8-bit byte ACK / NAK (NOTE: takes 5 bytes in opbuf) +0x0D Write to opbuf: Write n 24-bit length + 24-bit addr + ACK / NAK (NOTE: takes 7+n bytes in opbuf) + + length bytes of data +0x0E Write to opbuf: delay 32-bit usecs ACK / NAK (NOTE: takes 5 bytes in opbuf) +0x0F Execute operation buffer none ACK / NAK +0x10 Sync NOP none NAK + ACK (for synchronization) +0x11 Query maximum read-n length none ACK + 24-bit length (0==2^24) / NAK +0x12 Set used bustype 8-bit flags (as with 0x05) ACK / NAK +0x?? unimplemented command - invalid. + + +Additional information of the above commands: + About unimplemented commands / startup sequence: + Only commands allowed to be used without checking anything are 0x00,0x10 and 0x01 (NOP,SYNCNOP,Q_IFACE). + If 0x01 doesn't return 1, dont do anything if you dont support a newer protocol. + Then, check support for any other opcode (except 0x02) by using 0x02 (Q_CMDMAP). + 0x02 (Q_CMDMAP): + The map's bits are mapped as follows: + cmd 0 support: byte 0 bit 0 + cmd 1 support: byte 0 bit 1 + cmd 7 support: byte 0 bit 7 + cmd 8 support: byte 1 bit 0, and so on. + 0x04 (Q_SERBUF): + If the programmer has guaranteedly working flow control, + it should return a big bogus value - eg 0xFFFF. + 0x05 (Q_BUSTYPE): + The bit's are defined as follows: + bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported). + 0x06 (Q_CHIPSIZE): + Only applicable to parallel programmers. + An LPC/FHW/SPI-programmer can report this as not supported in the command bitmap. + 0x08 (Q_WRNMAXLEN): + If a programmer reports a bigger maximum write-n length than the serial buffer size, + it is assumed that the programmer can process the data fast enough to take in the + reported maximum write-n without problems. + 0x0F (O_EXEC): + Execute operation buffer will also clear it, regardless of the return value. + 0x11 (Q_RDNMAXLEN): + If this command is not supported, assume return of 0 (2^24). + 0x12 (S_BUSTYPE): + Set's the used bustype if the programmer can support more than one flash protocol. + Sending a byte with more than 1 bit set will make the programmer decide among them + on it's own. Bit values as with Q_BUSTYPE. + About mandatory commands: + The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10, + but one can't really do anything with these commands. + Support for the following commands is necessary for flashrom to operate properly: + S_CMD_Q_SERBUF, S_CMD_Q_OPBUF, S_CMD_Q_WRNMAXLEN, S_CMD_R_BYTE, + S_CMD_R_NBYTES, S_CMD_O_INIT, S_CMD_O_WRITEB, S_CMD_O_WRITEN, + S_CMD_O_DELAY, S_CMD_O_EXEC. + In addition, support for these commands is recommended: + S_CMD_Q_PGMNAME, S_CMD_Q_BUSTYPE, S_CMD_Q_CHIPSIZE (if parallel). + + +This define listing should help C coders - (it's here to be the single source for copying - will be a .h someday i think) +#define S_ACK 0x06 +#define S_NAK 0x15 +#define S_CMD_NOP 0x00 /* No operation */ +#define S_CMD_Q_IFACE 0x01 /* Query interface version */ +#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */ +#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */ +#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */ +#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */ +#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */ +#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */ +#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum lenght */ +#define S_CMD_R_BYTE 0x09 /* Read a single byte */ +#define S_CMD_R_NBYTES 0x0A /* Read n bytes */ +#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */ +#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */ +#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */ +#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */ +#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */ +#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */ +#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ +#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ diff --git a/libflashrom/serprog.c b/libflashrom/serprog.c new file mode 100644 index 0000000..6544245 --- /dev/null +++ b/libflashrom/serprog.c @@ -0,0 +1,658 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Urja Rannikko + * Copyright (C) 2009 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "flash.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSGHEADER "serprog:" + +#define S_ACK 0x06 +#define S_NAK 0x15 +#define S_CMD_NOP 0x00 /* No operation */ +#define S_CMD_Q_IFACE 0x01 /* Query interface version */ +#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */ +#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */ +#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */ +#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */ +#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */ +#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */ +#define S_CMD_Q_WRNMAXLEN 0x08 /* Query opbuf-write-N maximum lenght */ +#define S_CMD_R_BYTE 0x09 /* Read a single byte */ +#define S_CMD_R_NBYTES 0x0A /* Read n bytes */ +#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */ +#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */ +#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */ +#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */ +#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */ +#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */ +#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ +#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ + +static uint16_t sp_device_serbuf_size = 16; +static uint16_t sp_device_opbuf_size = 300; +/* Bitmap of supported commands */ +static uint8_t sp_cmdmap[32]; + +/* sp_prev_was_write used to detect writes with continouous addresses + and combine them to write-n's */ +static int sp_prev_was_write = 0; +/* sp_write_n_addr used as the starting addr of the currently + combined write-n operation */ +static uint32_t sp_write_n_addr; +/* The maximum length of an write_n operation; 0 = write-n not supported */ +static uint32_t sp_max_write_n = 0; +/* The maximum length of a read_n operation; 0 = 2^24 */ +static uint32_t sp_max_read_n = 0; + +/* A malloc'd buffer for combining the operation's data + and a counter that tells how much data is there. */ +static uint8_t *sp_write_n_buf; +static uint32_t sp_write_n_bytes = 0; + +/* sp_streamed_* used for flow control checking */ +static int sp_streamed_transmit_ops = 0; +static int sp_streamed_transmit_bytes = 0; + +/* sp_opbuf_usage used for counting the amount of + on-device operation buffer used */ +static int sp_opbuf_usage = 0; +/* if true causes sp_docommand to automatically check + whether the command is supported before doing it */ +static int sp_check_avail_automatic = 0; + +static int sp_opensocket(char *ip, unsigned int port) +{ + int flag = 1; + struct hostent *hostPtr = NULL; + union { struct sockaddr_in si; struct sockaddr s; } sp = {}; + int sock; + printf_debug(MSGHEADER "IP %s port %d\n", ip, port); + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) + sp_die("Error: serprog cannot open socket"); + hostPtr = gethostbyname(ip); + if (NULL == hostPtr) { + hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET); + if (NULL == hostPtr) + sp_die("Error: cannot resolve"); + } + sp.si.sin_family = AF_INET; + sp.si.sin_port = htons(port); + (void)memcpy(&sp.si.sin_addr, hostPtr->h_addr, hostPtr->h_length); + if (connect(sock, &sp.s, sizeof(sp.si)) < 0) { + close(sock); + sp_die("Error: serprog cannot connect"); + } + /* We are latency limited, and sometimes do write-write-read * + * (write-n) - so enable TCP_NODELAY. */ + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); + return sock; +} + +static int sp_sync_read_timeout(int loops) +{ + int i; + unsigned char c; + for (i = 0; i < loops; i++) { + ssize_t rv; + rv = read(sp_fd, &c, 1); + if (rv == 1) + return c; + if ((rv == -1) && (errno != EAGAIN)) + sp_die("read"); + usleep(10 * 1000); /* 10ms units */ + } + return -1; +} + +/* Synchronize: a bit tricky algorhytm that tries to (and in my tests has * + * always succeeded in) bring the serial protocol to known waiting-for- * + * command state - uses nonblocking read - rest of the driver uses * + * blocking read - TODO: add an alarm() timer for the rest of the app on * + * serial operations, though not such a big issue as the first thing to * + * do is synchronize (eg. check that device is alive). */ +static void sp_synchronize(void) +{ + int i; + int flags = fcntl(sp_fd, F_GETFL); + unsigned char buf[8]; + flags |= O_NONBLOCK; + fcntl(sp_fd, F_SETFL, flags); + /* First sends 8 NOPs, then flushes the return data - should cause * + * the device serial parser to get to a sane state, unless if it * + * is waiting for a real long write-n. */ + memset(buf, S_CMD_NOP, 8); + if (write(sp_fd, buf, 8) != 8) + sp_die("flush write"); + /* A second should be enough to get all the answers to the buffer */ + usleep(1000 * 1000); + sp_flush_incoming(); + + /* Then try upto 8 times to send syncnop and get the correct special * + * return of NAK+ACK. Timing note: upto 10 characters, 10*50ms = * + * upto 500ms per try, 8*0.5s = 4s; +1s (above) = upto 5s sync * + * attempt, ~1s if immediate success. */ + for (i = 0; i < 8; i++) { + int n; + unsigned char c = S_CMD_SYNCNOP; + if (write(sp_fd, &c, 1) != 1) + sp_die("sync write"); + printf_debug("."); + fflush(stdout); + for (n = 0; n < 10; n++) { + c = sp_sync_read_timeout(5); /* wait upto 50ms */ + if (c != S_NAK) + continue; + c = sp_sync_read_timeout(2); + if (c != S_ACK) + continue; + c = S_CMD_SYNCNOP; + if (write(sp_fd, &c, 1) != 1) + sp_die("sync write"); + c = sp_sync_read_timeout(50); + if (c != S_NAK) + break; /* fail */ + c = sp_sync_read_timeout(10); + if (c != S_ACK) + break; /* fail */ + /* Ok, synchronized; back to blocking reads and return. */ + flags &= ~O_NONBLOCK; + fcntl(sp_fd, F_SETFL, flags); + printf_debug("\n"); + return; + } + } + fprintf(stderr, + "Error: cannot synchronize protocol\n" + "- check communications and reset device?\n"); + exit(1); +} + +static int sp_check_commandavail(uint8_t command) +{ + int byteoffs, bitoffs; + byteoffs = command / 8; + bitoffs = command % 8; + return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0; +} + +static int sp_automatic_cmdcheck(uint8_t cmd) +{ + if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) { + printf_debug ("Warning: Automatic command availability check" + " failed for cmd %d - wont execute cmd\n",cmd); + return 1; + } + return 0; +} + +static int sp_docommand(uint8_t command, uint32_t parmlen, + uint8_t * params, uint32_t retlen, void *retparms) +{ + unsigned char *sendpacket; + unsigned char c; + if (sp_automatic_cmdcheck(command)) + return 1; + sendpacket = malloc(1 + parmlen); + if (!sendpacket) + sp_die("Error: cannot malloc command buffer"); + sendpacket[0] = command; + memcpy(&(sendpacket[1]), params, parmlen); + if (write(sp_fd, sendpacket, 1 + parmlen) != (1 + parmlen)) { + sp_die("Error: cannot write command"); + } + free(sendpacket); + if (read(sp_fd, &c, 1) != 1) + sp_die("Error: cannot read from device"); + if (c == S_NAK) return 1; + if (c != S_ACK) { + fprintf(stderr, + "Error: invalid response 0x%02X from device\n",c); + exit(1); + } + if (retlen) { + int rd_bytes = 0; + do { + int r; + r = read(sp_fd, retparms + rd_bytes, + retlen - rd_bytes); + if (r <= 0) sp_die + ("Error: cannot read return parameters"); + rd_bytes += r; + } while (rd_bytes != retlen); + } + return 0; +} + +static void sp_flush_stream(void) +{ + if (sp_streamed_transmit_ops) + do { + unsigned char c; + if (read(sp_fd, &c, 1) != 1) { + sp_die + ("Error: cannot read from device (flushing stream)"); + } + if (c == S_NAK) { + fprintf(stderr, + "Error: NAK to a stream buffer operation\n"); + exit(1); + } + if (c != S_ACK) { + fprintf(stderr, + "Error: Invalid reply 0x%02X from device\n", + c); + exit(1); + } + } while (--sp_streamed_transmit_ops); + sp_streamed_transmit_ops = 0; + sp_streamed_transmit_bytes = 0; +} + +static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms) +{ + uint8_t *sp; + if (sp_automatic_cmdcheck(cmd)) + return 1; + sp = malloc(1 + parmlen); + if (!sp) sp_die("Error: cannot malloc command buffer"); + sp[0] = cmd; + memcpy(&(sp[1]), parms, parmlen); + if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) + sp_flush_stream(); + if (write(sp_fd, sp, 1 + parmlen) != (1 + parmlen)) + sp_die("Error: cannot write command"); + free(sp); + sp_streamed_transmit_ops += 1; + sp_streamed_transmit_bytes += 1 + parmlen; + return 0; +} + +int serprog_init(void) +{ + uint16_t iface; + int len; + unsigned char pgmname[17]; + unsigned char rbuf[3]; + unsigned char c; + char *num; + char *dev; + printf_debug("%s\n", __func__); + /* the parameter is either of format "/dev/device:baud" or "ip:port" */ + if ((!programmer_param) || (!strlen(programmer_param))) { + nodevice: + fprintf(stderr, + "Error: No device/host given for the serial programmer driver.\n" + "Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n"); + exit(1); + } + num = strstr(programmer_param, ":"); + len = num - programmer_param; + if (!len) goto nodevice; + if (!num) { + fprintf(stderr, + "Error: No port or baudrate specified to serial programmer driver.\n" + "Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n"); + exit(1); + } + len = num - programmer_param; + dev = malloc(len + 1); + if (!dev) sp_die("Error: memory allocation failure"); + memcpy(dev, programmer_param, len); + dev[len] = 0; + num = strdup(num + 1); + if (!num) sp_die("Error: memory allocation failure"); + free(programmer_param); + programmer_param = NULL; + + if (dev[0] == '/') sp_fd = sp_openserport(dev, atoi(num)); + else sp_fd = sp_opensocket(dev, atoi(num)); + + free(dev); dev = NULL; + free(num); num = NULL; + + printf_debug(MSGHEADER "connected - attempting to synchronize\n"); + + sp_check_avail_automatic = 0; + + sp_synchronize(); + + printf_debug(MSGHEADER "Synchronized\n"); + + if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) { + fprintf(stderr, "Error: NAK to Query Interface version\n"); + exit(1); + } + + if (iface != 1) { + fprintf(stderr, "Error: Unknown interface version %d\n", iface); + exit(1); + } + + printf_debug(MSGHEADER "Interface version ok.\n"); + + if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) { + fprintf(stderr, "Error: query command map not supported\n"); + exit(1); + } + + sp_check_avail_automatic = 1; + + /* Check for the minimum operational set of commands */ + if (sp_check_commandavail(S_CMD_R_BYTE) == 0) { + fprintf(stderr, "Error: Single byte read not supported\n"); + exit(1); + } + /* This could be translated to single byte reads (if missing), * + * but now we dont support that. */ + if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) { + fprintf(stderr, "Error: Read n bytes not supported\n"); + exit(1); + } + /* In the future one could switch to read-only mode if these * + * are not available. */ + if (sp_check_commandavail(S_CMD_O_INIT) == 0) { + fprintf(stderr, + "Error: Initialize operation buffer not supported\n"); + exit(1); + } + if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) { + fprintf(stderr, + "Error: Write to opbuf: write byte not supported\n"); + exit(1); + } + if (sp_check_commandavail(S_CMD_O_DELAY) == 0) { + fprintf(stderr, "Error: Write to opbuf: delay not supported\n"); + exit(1); + } + if (sp_check_commandavail(S_CMD_O_EXEC) == 0) { + fprintf(stderr, + "Error: Execute operation buffer not supported\n"); + exit(1); + } + + if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) { + fprintf(stderr, "Warning: NAK to query programmer name\n"); + strcpy((char *)pgmname, "(unknown)"); + } + pgmname[16] = 0; + printf(MSGHEADER "Programmer name \"%s\"\n", pgmname); + + if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) { + fprintf(stderr, "Warning: NAK to query serial buffer size\n"); + } + printf_debug(MSGHEADER "serial buffer size %d\n", + sp_device_serbuf_size); + + if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) { + fprintf(stderr, + "Warning: NAK to query operation buffer size\n"); + } + printf_debug(MSGHEADER "operation buffer size %d\n", + sp_device_opbuf_size); + + if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) { + fprintf(stderr, "Warning: NAK to query supported buses\n"); + c = CHIP_BUSTYPE_NONSPI; /* A reasonable default for now. */ + } + buses_supported = c; + + if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) { + fprintf(stderr, "Error: NAK to initialize operation buffer\n"); + exit(1); + } + + if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) { + printf_debug(MSGHEADER "Write-n not supported"); + sp_max_write_n = 0; + } else { + sp_max_write_n = ((unsigned int)(rbuf[0]) << 0); + sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8); + sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16); + printf_debug(MSGHEADER "Maximum write-n length %d\n", + sp_max_write_n); + sp_write_n_buf = malloc(sp_max_write_n); + if (!sp_write_n_buf) { + fprintf(stderr, + "Error: cannot allocate memory for Write-n buffer\n"); + exit(1); + } + sp_write_n_bytes = 0; + } + + if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN)) + &&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) { + sp_max_read_n = ((unsigned int)(rbuf[0]) << 0); + sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8); + sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16); + printf_debug(MSGHEADER "Maximum read-n length %d\n", + sp_max_read_n ? sp_max_read_n : (1<<24)); + } else { + printf_debug(MSGHEADER "Maximum read-n length not reported\n"); + sp_max_read_n = 0; + } + + sp_prev_was_write = 0; + sp_streamed_transmit_ops = 0; + sp_streamed_transmit_bytes = 0; + sp_opbuf_usage = 0; + return 0; +} + +/* Move an in flashrom buffer existing write-n operation to * + * the on-device operation buffer. */ +static void sp_pass_writen(void) +{ + unsigned char header[7]; + printf_debug(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", + sp_write_n_bytes, sp_write_n_addr); + if (sp_streamed_transmit_bytes >= + (7 + sp_write_n_bytes + sp_device_serbuf_size)) + sp_flush_stream(); + /* In case it's just a single byte send it as a single write. */ + if (sp_write_n_bytes == 1) { + sp_write_n_bytes = 0; + header[0] = (sp_write_n_addr >> 0) & 0xFF; + header[1] = (sp_write_n_addr >> 8) & 0xFF; + header[2] = (sp_write_n_addr >> 16) & 0xFF; + header[3] = sp_write_n_buf[0]; + sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header); + sp_opbuf_usage += 5; + return; + } + header[0] = S_CMD_O_WRITEN; + header[1] = (sp_write_n_bytes >> 0) & 0xFF; + header[2] = (sp_write_n_bytes >> 8) & 0xFF; + header[3] = (sp_write_n_bytes >> 16) & 0xFF; + header[4] = (sp_write_n_addr >> 0) & 0xFF; + header[5] = (sp_write_n_addr >> 8) & 0xFF; + header[6] = (sp_write_n_addr >> 16) & 0xFF; + if (write(sp_fd, header, 7) != 7) + sp_die("Error: cannot write write-n command\n"); + if (write(sp_fd, sp_write_n_buf, sp_write_n_bytes) != + sp_write_n_bytes) + sp_die("Error: cannot write write-n data"); + sp_streamed_transmit_bytes += 7 + sp_write_n_bytes; + sp_streamed_transmit_ops += 1; + sp_opbuf_usage += 7 + sp_write_n_bytes; + sp_write_n_bytes = 0; + sp_prev_was_write = 0; +} + +static void sp_execute_opbuf_noflush(void) +{ + if ((sp_max_write_n) && (sp_write_n_bytes)) + sp_pass_writen(); + sp_stream_buffer_op(S_CMD_O_EXEC, 0, 0); + printf_debug(MSGHEADER "Executed operation buffer of %d bytes\n", + sp_opbuf_usage); + sp_opbuf_usage = 0; + sp_prev_was_write = 0; + return; +} + +static void sp_execute_opbuf(void) +{ + sp_execute_opbuf_noflush(); + sp_flush_stream(); +} + +int serprog_shutdown(void) +{ + printf_debug("%s\n", __func__); + if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) + sp_execute_opbuf(); + close(sp_fd); + if (sp_max_write_n) + free(sp_write_n_buf); + return 0; +} + +static void sp_check_opbuf_usage(int bytes_to_be_added) +{ + if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) { + sp_execute_opbuf(); + /* If this happens in the mid of an page load the page load * + * will propably fail. */ + printf_debug(MSGHEADER + "Warning: executed operation buffer due to size reasons\n"); + } +} + +void serprog_chip_writeb(uint8_t val, chipaddr addr) +{ + printf_debug("%s\n", __func__); + if (sp_max_write_n) { + if ((sp_prev_was_write) + && (addr == (sp_write_n_addr + sp_write_n_bytes))) { + sp_write_n_buf[sp_write_n_bytes++] = val; + } else { + if ((sp_prev_was_write) && (sp_write_n_bytes)) + sp_pass_writen(); + sp_prev_was_write = 1; + sp_write_n_addr = addr; + sp_write_n_bytes = 1; + sp_write_n_buf[0] = val; + } + sp_check_opbuf_usage(7 + sp_write_n_bytes); + if (sp_write_n_bytes >= sp_max_write_n) + sp_pass_writen(); + } else { + /* We will have to do single writeb ops. */ + unsigned char writeb_parm[4]; + sp_check_opbuf_usage(6); + writeb_parm[0] = (addr >> 0) & 0xFF; + writeb_parm[1] = (addr >> 8) & 0xFF; + writeb_parm[2] = (addr >> 16) & 0xFF; + writeb_parm[3] = val; + sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); + sp_opbuf_usage += 5; + } +} + +uint8_t serprog_chip_readb(const chipaddr addr) +{ + unsigned char c; + unsigned char buf[3]; + /* Will stream the read operation - eg. add it to the stream buffer, * + * then flush the buffer, then read the read answer. */ + if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) + sp_execute_opbuf_noflush(); + buf[0] = ((addr >> 0) & 0xFF); + buf[1] = ((addr >> 8) & 0xFF); + buf[2] = ((addr >> 16) & 0xFF); + sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); + sp_flush_stream(); + if (read(sp_fd, &c, 1) != 1) + sp_die("readb byteread"); + printf_debug("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c); + return c; +} + +/* Local version that really does the job, doesnt care of max_read_n. */ +static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) +{ + int rd_bytes = 0; + unsigned char sbuf[6]; + printf_debug("%s: addr=0x%lx len=%lu\n", __func__, addr, (unsigned long)len); + /* Stream the read-n -- as above. */ + if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) + sp_execute_opbuf_noflush(); + sbuf[0] = ((addr >> 0) & 0xFF); + sbuf[1] = ((addr >> 8) & 0xFF); + sbuf[2] = ((addr >> 16) & 0xFF); + sbuf[3] = ((len >> 0) & 0xFF); + sbuf[4] = ((len >> 8) & 0xFF); + sbuf[5] = ((len >> 16) & 0xFF); + sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf); + sp_flush_stream(); + do { + int r = read(sp_fd, buf + rd_bytes, len - rd_bytes); + if (r <= 0) + sp_die("Error: cannot read read-n data"); + rd_bytes += r; + } while (rd_bytes != len); + return; +} + +/* The externally called version that makes sure that max_read_n is obeyed. */ +void serprog_chip_readn(uint8_t * buf, const chipaddr addr, size_t len) +{ + size_t lenm = len; + chipaddr addrm = addr; + while ((sp_max_read_n)&&(lenm > sp_max_read_n)) { + sp_do_read_n(&(buf[addrm-addr]),addrm,sp_max_read_n); + addrm += sp_max_read_n; + lenm -= sp_max_read_n; + } + if (lenm) sp_do_read_n(&(buf[addrm-addr]),addrm,lenm); +} + +void serprog_delay(int delay) +{ + unsigned char buf[4]; + printf_debug("%s\n", __func__); + if ((sp_max_write_n) && (sp_write_n_bytes)) + sp_pass_writen(); + sp_check_opbuf_usage(5); + buf[0] = ((delay >> 0) & 0xFF); + buf[1] = ((delay >> 8) & 0xFF); + buf[2] = ((delay >> 16) & 0xFF); + buf[3] = ((delay >> 24) & 0xFF); + sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf); + sp_opbuf_usage += 5; + sp_prev_was_write = 0; +} diff --git a/libflashrom/sharplhf00l04.c b/libflashrom/sharplhf00l04.c new file mode 100644 index 0000000..1234ae4 --- /dev/null +++ b/libflashrom/sharplhf00l04.c @@ -0,0 +1,184 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "flash.h" + +// I need that Berkeley bit-map printer +void print_lhf00l04_status(uint8_t status) +{ + printf("%s", status & 0x80 ? "Ready:" : "Busy:"); + printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); + printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); + printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); + printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); + printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); + printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); +} + +int probe_lhf00l04(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + +#if 0 + /* Enter ID mode */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0x90, bios + 0x5555); +#endif + + chip_writeb(0xff, bios); + programmer_delay(10); + chip_writeb(0x90, bios); + programmer_delay(10); + + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + + /* Leave ID mode */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0xF0, bios + 0x5555); + + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (id1 != flash->manufacture_id || id2 != flash->model_id) + return 0; + + map_flash_registers(flash); + + return 1; +} + +uint8_t wait_lhf00l04(chipaddr bios) +{ + uint8_t status; + + chip_writeb(0x70, bios); + if ((chip_readb(bios) & 0x80) == 0) { // it's busy + while ((chip_readb(bios) & 0x80) == 0) ; + } + + status = chip_readb(bios); + + // put another command to get out of status register mode. + + chip_writeb(0x90, bios); + programmer_delay(10); + + chip_readb(bios); // vendor ID + chip_readb(bios + 0x01); // device ID + + // this is needed to jam it out of "read id" mode + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0xF0, bios + 0x5555); + + return status; +} + +int erase_lhf00l04_block(struct flashchip *flash, int offset) +{ + chipaddr bios = flash->virtual_memory + offset; + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t status; + + // clear status register + chip_writeb(0x50, bios); + printf("Erase at 0x%lx\n", bios); + status = wait_lhf00l04(flash->virtual_memory); + print_lhf00l04_status(status); + // clear write protect + printf("write protect is at 0x%lx\n", (wrprotect)); + printf("write protect is 0x%x\n", chip_readb(wrprotect)); + chip_writeb(0, wrprotect); + printf("write protect is 0x%x\n", chip_readb(wrprotect)); + + // now start it + chip_writeb(0x20, bios); + chip_writeb(0xd0, bios); + programmer_delay(10); + // now let's see what the register is + status = wait_lhf00l04(flash->virtual_memory); + print_lhf00l04_status(status); + printf("DONE BLOCK 0x%x\n", offset); + + if (check_erased_range(flash, offset, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int erase_lhf00l04(struct flashchip *flash) +{ + int i; + unsigned int total_size = flash->total_size * 1024; + + printf("total_size is %d; flash->page_size is %d\n", + total_size, flash->page_size); + for (i = 0; i < total_size; i += flash->page_size) + if (erase_lhf00l04_block(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("DONE ERASE\n"); + + return 0; +} + +void write_page_lhf00l04(chipaddr bios, uint8_t *src, + chipaddr dst, int page_size) +{ + int i; + + for (i = 0; i < page_size; i++) { + /* transfer data from source to destination */ + chip_writeb(0x40, dst); + chip_writeb(*src++, dst++); + wait_lhf00l04(bios); + } +} + +int write_lhf00l04(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + if (erase_lhf00l04(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + printf("%04d at address: 0x%08x", i, i * page_size); + write_page_lhf00l04(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/spi.c b/libflashrom/spi.c new file mode 100644 index 0000000..14beed7 --- /dev/null +++ b/libflashrom/spi.c @@ -0,0 +1,1071 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger + * Copyright (C) 2008 coresystems GmbH + * + * 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 + */ + +/* + * Contains the generic SPI framework + */ + +#include +#include "flash.h" +#include "flashchips.h" +#include "spi.h" + +enum spi_controller spi_controller = SPI_CONTROLLER_NONE; +void *spibar = NULL; + +void spi_prettyprint_status_register(struct flashchip *flash); + +const struct spi_programmer spi_programmer[] = { + { /* SPI_CONTROLLER_NONE */ + .command = NULL, + .multicommand = NULL, + .read = NULL, + .write_256 = NULL, + }, + + { /* SPI_CONTROLLER_ICH7 */ + .command = ich_spi_send_command, + .multicommand = ich_spi_send_multicommand, + .read = ich_spi_read, + .write_256 = ich_spi_write_256, + }, + + { /* SPI_CONTROLLER_ICH9 */ + .command = ich_spi_send_command, + .multicommand = ich_spi_send_multicommand, + .read = ich_spi_read, + .write_256 = ich_spi_write_256, + }, + + { /* SPI_CONTROLLER_IT87XX */ + .command = it8716f_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = it8716f_spi_chip_read, + .write_256 = it8716f_spi_chip_write_256, + }, + + { /* SPI_CONTROLLER_SB600 */ + .command = sb600_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = sb600_spi_read, + .write_256 = sb600_spi_write_1, + }, + + { /* SPI_CONTROLLER_VIA */ + .command = ich_spi_send_command, + .multicommand = ich_spi_send_multicommand, + .read = ich_spi_read, + .write_256 = ich_spi_write_256, + }, + + { /* SPI_CONTROLLER_WBSIO */ + .command = wbsio_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = wbsio_spi_read, + .write_256 = wbsio_spi_write_1, + }, + +#if FT2232_SPI_SUPPORT == 1 + { /* SPI_CONTROLLER_FT2232 */ + .command = ft2232_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = ft2232_spi_read, + .write_256 = ft2232_spi_write_256, + }, +#endif + +#if DUMMY_SUPPORT == 1 + { /* SPI_CONTROLLER_DUMMY */ + .command = dummy_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = NULL, + .write_256 = NULL, + }, +#endif + +#if BUSPIRATE_SPI_SUPPORT == 1 + { /* SPI_CONTROLLER_BUSPIRATE */ + .command = buspirate_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = buspirate_spi_read, + .write_256 = spi_chip_write_1, + }, +#endif + + {}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */ +}; + +const int spi_programmer_count = ARRAY_SIZE(spi_programmer); + +int spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + if (!spi_programmer[spi_controller].command) { + fprintf(stderr, "%s called, but SPI is unsupported on this " + "hardware. Please report a bug.\n", __func__); + return 1; + } + + return spi_programmer[spi_controller].command(writecnt, readcnt, + writearr, readarr); +} + +int spi_send_multicommand(struct spi_command *cmds) +{ + if (!spi_programmer[spi_controller].multicommand) { + fprintf(stderr, "%s called, but SPI is unsupported on this " + "hardware. Please report a bug.\n", __func__); + return 1; + } + + return spi_programmer[spi_controller].multicommand(cmds); +} + +int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + struct spi_command cmd[] = { + { + .writecnt = writecnt, + .readcnt = readcnt, + .writearr = writearr, + .readarr = readarr, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + return spi_send_multicommand(cmd); +} + +int default_spi_send_multicommand(struct spi_command *cmds) +{ + int result = 0; + for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) { + result = spi_send_command(cmds->writecnt, cmds->readcnt, + cmds->writearr, cmds->readarr); + } + return result; +} + +static int spi_rdid(unsigned char *readarr, int bytes) +{ + const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID }; + int ret; + int i; + + ret = spi_send_command(sizeof(cmd), bytes, cmd, readarr); + if (ret) + return ret; + printf_debug("RDID returned"); + for (i = 0; i < bytes; i++) + printf_debug(" 0x%02x", readarr[i]); + printf_debug(". "); + return 0; +} + +static int spi_rems(unsigned char *readarr) +{ + unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 }; + uint32_t readaddr; + int ret; + + ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); + if (ret == SPI_INVALID_ADDRESS) { + /* Find the lowest even address allowed for reads. */ + readaddr = (spi_get_valid_read_addr() + 1) & ~1; + cmd[1] = (readaddr >> 16) & 0xff, + cmd[2] = (readaddr >> 8) & 0xff, + cmd[3] = (readaddr >> 0) & 0xff, + ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); + } + if (ret) + return ret; + printf_debug("REMS returned %02x %02x. ", readarr[0], readarr[1]); + return 0; +} + +static int spi_res(unsigned char *readarr) +{ + unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 }; + uint32_t readaddr; + int ret; + + ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); + if (ret == SPI_INVALID_ADDRESS) { + /* Find the lowest even address allowed for reads. */ + readaddr = (spi_get_valid_read_addr() + 1) & ~1; + cmd[1] = (readaddr >> 16) & 0xff, + cmd[2] = (readaddr >> 8) & 0xff, + cmd[3] = (readaddr >> 0) & 0xff, + ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); + } + if (ret) + return ret; + printf_debug("RES returned %02x. ", readarr[0]); + return 0; +} + +int spi_write_enable(void) +{ + const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN }; + int result; + + /* Send WREN (Write Enable) */ + result = spi_send_command(sizeof(cmd), 0, cmd, NULL); + + if (result) + fprintf(stderr, "%s failed\n", __func__); + + return result; +} + +int spi_write_disable(void) +{ + const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI }; + + /* Send WRDI (Write Disable) */ + return spi_send_command(sizeof(cmd), 0, cmd, NULL); +} + +static int probe_spi_rdid_generic(struct flashchip *flash, int bytes) +{ + unsigned char readarr[4]; + uint32_t id1; + uint32_t id2; + + if (spi_rdid(readarr, bytes)) + return 0; + + if (!oddparity(readarr[0])) + printf_debug("RDID byte 0 parity violation. "); + + /* Check if this is a continuation vendor ID */ + if (readarr[0] == 0x7f) { + if (!oddparity(readarr[1])) + printf_debug("RDID byte 1 parity violation. "); + id1 = (readarr[0] << 8) | readarr[1]; + id2 = readarr[2]; + if (bytes > 3) { + id2 <<= 8; + id2 |= readarr[3]; + } + } else { + id1 = readarr[0]; + id2 = (readarr[1] << 8) | readarr[2]; + } + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (id1 == flash->manufacture_id && id2 == flash->model_id) { + /* Print the status register to tell the + * user about possible write protection. + */ + spi_prettyprint_status_register(flash); + + return 1; + } + + /* Test if this is a pure vendor match. */ + if (id1 == flash->manufacture_id && + GENERIC_DEVICE_ID == flash->model_id) + return 1; + + /* Test if there is any vendor ID. */ + if (GENERIC_MANUF_ID == flash->manufacture_id && + id1 != 0xff) + return 1; + + return 0; +} + +int probe_spi_rdid(struct flashchip *flash) +{ + return probe_spi_rdid_generic(flash, 3); +} + +/* support 4 bytes flash ID */ +int probe_spi_rdid4(struct flashchip *flash) +{ + /* only some SPI chipsets support 4 bytes commands */ + switch (spi_controller) { + case SPI_CONTROLLER_ICH7: + case SPI_CONTROLLER_ICH9: + case SPI_CONTROLLER_VIA: + case SPI_CONTROLLER_SB600: + case SPI_CONTROLLER_WBSIO: +#if FT2232_SPI_SUPPORT == 1 + case SPI_CONTROLLER_FT2232: +#endif +#if DUMMY_SUPPORT == 1 + case SPI_CONTROLLER_DUMMY: +#endif +#if BUSPIRATE_SPI_SUPPORT == 1 + case SPI_CONTROLLER_BUSPIRATE: +#endif + return probe_spi_rdid_generic(flash, 4); + default: + printf_debug("4b ID not supported on this SPI controller\n"); + } + + return 0; +} + +int probe_spi_rems(struct flashchip *flash) +{ + unsigned char readarr[JEDEC_REMS_INSIZE]; + uint32_t id1, id2; + + if (spi_rems(readarr)) + return 0; + + id1 = readarr[0]; + id2 = readarr[1]; + + printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); + + if (id1 == flash->manufacture_id && id2 == flash->model_id) { + /* Print the status register to tell the + * user about possible write protection. + */ + spi_prettyprint_status_register(flash); + + return 1; + } + + /* Test if this is a pure vendor match. */ + if (id1 == flash->manufacture_id && + GENERIC_DEVICE_ID == flash->model_id) + return 1; + + /* Test if there is any vendor ID. */ + if (GENERIC_MANUF_ID == flash->manufacture_id && + id1 != 0xff) + return 1; + + return 0; +} + +int probe_spi_res(struct flashchip *flash) +{ + unsigned char readarr[3]; + uint32_t id2; + + /* Check if RDID was successful and did not return 0xff 0xff 0xff. + * In that case, RES is pointless. + */ + if (!spi_rdid(readarr, 3) && ((readarr[0] != 0xff) || + (readarr[1] != 0xff) || (readarr[2] != 0xff))) + return 0; + + if (spi_res(readarr)) + return 0; + + id2 = readarr[0]; + printf_debug("%s: id 0x%x\n", __func__, id2); + if (id2 != flash->model_id) + return 0; + + /* Print the status register to tell the + * user about possible write protection. + */ + spi_prettyprint_status_register(flash); + return 1; +} + +uint8_t spi_read_status_register(void) +{ + const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR }; + /* FIXME: No workarounds for driver/hardware bugs in generic code. */ + unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */ + int ret; + + /* Read Status Register */ + ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr); + if (ret) + fprintf(stderr, "RDSR failed!\n"); + + return readarr[0]; +} + +/* Prettyprint the status register. Common definitions. */ +void spi_prettyprint_status_register_common(uint8_t status) +{ + printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is " + "%sset\n", (status & (1 << 5)) ? "" : "not "); + printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is " + "%sset\n", (status & (1 << 4)) ? "" : "not "); + printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is " + "%sset\n", (status & (1 << 3)) ? "" : "not "); + printf_debug("Chip status register: Bit 2 / Block Protect 0 (BP0) is " + "%sset\n", (status & (1 << 2)) ? "" : "not "); + printf_debug("Chip status register: Write Enable Latch (WEL) is " + "%sset\n", (status & (1 << 1)) ? "" : "not "); + printf_debug("Chip status register: Write In Progress (WIP/BUSY) is " + "%sset\n", (status & (1 << 0)) ? "" : "not "); +} + +/* Prettyprint the status register. Works for + * ST M25P series + * MX MX25L series + */ +void spi_prettyprint_status_register_st_m25p(uint8_t status) +{ + printf_debug("Chip status register: Status Register Write Disable " + "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not "); + printf_debug("Chip status register: Bit 6 is " + "%sset\n", (status & (1 << 6)) ? "" : "not "); + spi_prettyprint_status_register_common(status); +} + +void spi_prettyprint_status_register_sst25(uint8_t status) +{ + printf_debug("Chip status register: Block Protect Write Disable " + "(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not "); + printf_debug("Chip status register: Auto Address Increment Programming " + "(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not "); + spi_prettyprint_status_register_common(status); +} + +/* Prettyprint the status register. Works for + * SST 25VF016 + */ +void spi_prettyprint_status_register_sst25vf016(uint8_t status) +{ + const char *bpt[] = { + "none", + "1F0000H-1FFFFFH", + "1E0000H-1FFFFFH", + "1C0000H-1FFFFFH", + "180000H-1FFFFFH", + "100000H-1FFFFFH", + "all", "all" + }; + spi_prettyprint_status_register_sst25(status); + printf_debug("Resulting block protection : %s\n", + bpt[(status & 0x1c) >> 2]); +} + +void spi_prettyprint_status_register_sst25vf040b(uint8_t status) +{ + const char *bpt[] = { + "none", + "0x70000-0x7ffff", + "0x60000-0x7ffff", + "0x40000-0x7ffff", + "all blocks", "all blocks", "all blocks", "all blocks" + }; + spi_prettyprint_status_register_sst25(status); + printf_debug("Resulting block protection : %s\n", + bpt[(status & 0x1c) >> 2]); +} + +void spi_prettyprint_status_register(struct flashchip *flash) +{ + uint8_t status; + + status = spi_read_status_register(); + printf_debug("Chip status register is %02x\n", status); + switch (flash->manufacture_id) { + case ST_ID: + if (((flash->model_id & 0xff00) == 0x2000) || + ((flash->model_id & 0xff00) == 0x2500)) + spi_prettyprint_status_register_st_m25p(status); + break; + case MX_ID: + if ((flash->model_id & 0xff00) == 0x2000) + spi_prettyprint_status_register_st_m25p(status); + break; + case SST_ID: + switch (flash->model_id) { + case 0x2541: + spi_prettyprint_status_register_sst25vf016(status); + break; + case 0x8d: + case 0x258d: + spi_prettyprint_status_register_sst25vf040b(status); + break; + default: + spi_prettyprint_status_register_sst25(status); + break; + } + break; + } +} + +int spi_chip_erase_60(struct flashchip *flash) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_CE_60_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_CE_60 }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_disable_blockprotect(); + if (result) { + fprintf(stderr, "spi_disable_blockprotect failed\n"); + return result; + } + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution\n", + __func__); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 1-85 s, so wait in 1 s steps. + */ + /* FIXME: We assume spi_read_status_register will never fail. */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(1000 * 1000); + if (check_erased_range(flash, 0, flash->total_size * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int spi_chip_erase_c7(struct flashchip *flash) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_CE_C7_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_CE_C7 }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_disable_blockprotect(); + if (result) { + fprintf(stderr, "spi_disable_blockprotect failed\n"); + return result; + } + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution\n", __func__); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 1-85 s, so wait in 1 s steps. + */ + /* FIXME: We assume spi_read_status_register will never fail. */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(1000 * 1000); + if (check_erased_range(flash, 0, flash->total_size * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int spi_chip_erase_60_c7(struct flashchip *flash) +{ + int result; + result = spi_chip_erase_60(flash); + if (result) { + printf_debug("spi_chip_erase_60 failed, trying c7\n"); + result = spi_chip_erase_c7(flash); + } + return result; +} + +int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BE_52_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_BE_52, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 100-4000 ms, so wait in 100 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(100 * 1000); + if (check_erased_range(flash, addr, blocklen)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +/* Block size is usually + * 64k for Macronix + * 32k for SST + * 4-32k non-uniform for EON + */ +int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BE_D8_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_BE_D8, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 100-4000 ms, so wait in 100 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(100 * 1000); + if (check_erased_range(flash, addr, blocklen)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int spi_chip_erase_d8(struct flashchip *flash) +{ + int i, rc = 0; + int total_size = flash->total_size * 1024; + int erase_size = 64 * 1024; + + spi_disable_blockprotect(); + + printf("Erasing chip: \n"); + + for (i = 0; i < total_size / erase_size; i++) { + rc = spi_block_erase_d8(flash, i * erase_size, erase_size); + if (rc) { + fprintf(stderr, "Error erasing block at 0x%x\n", i); + break; + } + } + + printf("\n"); + + return rc; +} + +/* Sector size is usually 4k, though Macronix eliteflash has 64k */ +int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_SE_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_SE, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 15-800 ms, so wait in 10 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(10 * 1000); + if (check_erased_range(flash, addr, blocklen)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen) +{ + if ((addr != 0) || (blocklen != flash->total_size * 1024)) { + fprintf(stderr, "%s called with incorrect arguments\n", + __func__); + return -1; + } + return spi_chip_erase_60(flash); +} + +int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen) +{ + if ((addr != 0) || (blocklen != flash->total_size * 1024)) { + fprintf(stderr, "%s called with incorrect arguments\n", + __func__); + return -1; + } + return spi_chip_erase_c7(flash); +} + +int spi_write_status_enable(void) +{ + const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR }; + int result; + + /* Send EWSR (Enable Write Status Register). */ + result = spi_send_command(sizeof(cmd), JEDEC_EWSR_INSIZE, cmd, NULL); + + if (result) + fprintf(stderr, "%s failed\n", __func__); + + return result; +} + +/* + * This is according the SST25VF016 datasheet, who knows it is more + * generic that this... + */ +int spi_write_status_register(int status) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_EWSR_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_EWSR }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_WRSR_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution\n", + __func__); + } + return result; +} + +int spi_byte_program(int addr, uint8_t byte) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_BYTE_PROGRAM, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff), byte }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution at address 0x%x\n", + __func__, addr); + } + return result; +} + +int spi_nbyte_program(int addr, uint8_t *bytes, int len) +{ + int result; + /* FIXME: Switch to malloc based on len unless that kills speed. */ + unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = { + JEDEC_BYTE_PROGRAM, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr >> 0) & 0xff, + }; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len, + .writearr = cmd, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + if (!len) { + fprintf(stderr, "%s called for zero-length write\n", __func__); + return 1; + } + if (len > 256) { + fprintf(stderr, "%s called for too long a write\n", __func__); + return 1; + } + + memcpy(&cmd[4], bytes, len); + + result = spi_send_multicommand(cmds); + if (result) { + fprintf(stderr, "%s failed during command execution at address 0x%x\n", + __func__, addr); + } + return result; +} + +int spi_disable_blockprotect(void) +{ + uint8_t status; + int result; + + status = spi_read_status_register(); + /* If there is block protection in effect, unprotect it first. */ + if ((status & 0x3c) != 0) { + printf_debug("Some block protection in effect, disabling\n"); + result = spi_write_status_register(status & ~0x3c); + if (result) { + fprintf(stderr, "spi_write_status_register failed\n"); + return result; + } + } + return 0; +} + +int spi_nbyte_read(int address, uint8_t *bytes, int len) +{ + const unsigned char cmd[JEDEC_READ_OUTSIZE] = { + JEDEC_READ, + (address >> 16) & 0xff, + (address >> 8) & 0xff, + (address >> 0) & 0xff, + }; + + /* Send Read */ + return spi_send_command(sizeof(cmd), len, cmd, bytes); +} + +/* + * Read a complete flash chip. + * Each page is read separately in chunks with a maximum size of chunksize. + */ +int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize) +{ + int rc = 0; + int i, j, starthere, lenhere; + int page_size = flash->page_size; + int toread; + + /* Warning: This loop has a very unusual condition and body. + * The loop needs to go through each page with at least one affected + * byte. The lowest page number is (start / page_size) since that + * division rounds down. The highest page number we want is the page + * where the last byte of the range lives. That last byte has the + * address (start + len - 1), thus the highest page number is + * (start + len - 1) / page_size. Since we want to include that last + * page as well, the loop condition uses <=. + */ + for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { + /* Byte position of the first byte in the range in this page. */ + /* starthere is an offset to the base address of the chip. */ + starthere = max(start, i * page_size); + /* Length of bytes in the range in this page. */ + lenhere = min(start + len, (i + 1) * page_size) - starthere; + for (j = 0; j < lenhere; j += chunksize) { + toread = min(chunksize, lenhere - j); + rc = spi_nbyte_read(starthere + j, buf + starthere - start + j, toread); + if (rc) + break; + } + if (rc) + break; + } + + return rc; +} + +int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + if (!spi_programmer[spi_controller].read) { + fprintf(stderr, "%s called, but SPI read is unsupported on this" + " hardware. Please report a bug.\n", __func__); + return 1; + } + + return spi_programmer[spi_controller].read(flash, buf, start, len); +} + +/* + * Program chip using byte programming. (SLOW!) + * This is for chips which can only handle one byte writes + * and for chips where memory mapped programming is impossible + * (e.g. due to size constraints in IT87* for over 512 kB) + */ +int spi_chip_write_1(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i, result = 0; + + spi_disable_blockprotect(); + /* Erase first */ + printf("Erasing flash before programming... "); + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("done.\n"); + for (i = 0; i < total_size; i++) { + result = spi_byte_program(i, buf[i]); + if (result) + return 1; + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(10); + } + + return 0; +} + +/* + * Program chip using page (256 bytes) programming. + * Some SPI masters can't do this, they use single byte programming instead. + */ +int spi_chip_write_256(struct flashchip *flash, uint8_t *buf) +{ + if (!spi_programmer[spi_controller].write_256) { + fprintf(stderr, "%s called, but SPI page write is unsupported " + " on this hardware. Please report a bug.\n", __func__); + return 1; + } + + return spi_programmer[spi_controller].write_256(flash, buf); +} + +uint32_t spi_get_valid_read_addr(void) +{ + /* Need to return BBAR for ICH chipsets. */ + return 0; +} + +int spi_aai_write(struct flashchip *flash, uint8_t *buf) +{ + uint32_t pos = 2, size = flash->total_size * 1024; + unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]}; + int result; + + switch (spi_controller) { + case SPI_CONTROLLER_WBSIO: + fprintf(stderr, "%s: impossible with Winbond SPI masters," + " degrading to byte program\n", __func__); + return spi_chip_write_1(flash, buf); + default: + break; + } + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + result = spi_write_enable(); + if (result) + return result; + spi_send_command(6, 0, w, NULL); + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(5); /* SST25VF040B Tbp is max 10us */ + while (pos < size) { + w[1] = buf[pos++]; + w[2] = buf[pos++]; + spi_send_command(3, 0, w, NULL); + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(5); /* SST25VF040B Tbp is max 10us */ + } + spi_write_disable(); + return 0; +} diff --git a/libflashrom/spi.h b/libflashrom/spi.h new file mode 100644 index 0000000..2fa7dcd --- /dev/null +++ b/libflashrom/spi.h @@ -0,0 +1,114 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2007, 2008 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 + */ + +#ifndef __SPI_H__ +#define __SPI_H__ 1 + +/* + * Contains the generic SPI headers + */ + +/* Read Electronic ID */ +#define JEDEC_RDID 0x9f +#define JEDEC_RDID_OUTSIZE 0x01 +#define JEDEC_RDID_INSIZE 0x03 + +/* AT25F512A has bit 3 as don't care bit in commands */ +#define AT25F512A_RDID 0x15 +#define AT25F512A_RDID_OUTSIZE 0x01 +#define AT25F512A_RDID_INSIZE 0x02 + +/* Read Electronic Manufacturer Signature */ +#define JEDEC_REMS 0x90 +#define JEDEC_REMS_OUTSIZE 0x04 +#define JEDEC_REMS_INSIZE 0x02 + +/* Read Electronic Signature */ +#define JEDEC_RES 0xab +#define JEDEC_RES_OUTSIZE 0x04 +#define JEDEC_RES_INSIZE 0x01 + +/* Write Enable */ +#define JEDEC_WREN 0x06 +#define JEDEC_WREN_OUTSIZE 0x01 +#define JEDEC_WREN_INSIZE 0x00 + +/* Write Disable */ +#define JEDEC_WRDI 0x04 +#define JEDEC_WRDI_OUTSIZE 0x01 +#define JEDEC_WRDI_INSIZE 0x00 + +/* Chip Erase 0x60 is supported by Macronix/SST chips. */ +#define JEDEC_CE_60 0x60 +#define JEDEC_CE_60_OUTSIZE 0x01 +#define JEDEC_CE_60_INSIZE 0x00 + +/* Chip Erase 0xc7 is supported by SST/ST/EON/Macronix chips. */ +#define JEDEC_CE_C7 0xc7 +#define JEDEC_CE_C7_OUTSIZE 0x01 +#define JEDEC_CE_C7_INSIZE 0x00 + +/* Block Erase 0x52 is supported by SST and old Atmel chips. */ +#define JEDEC_BE_52 0x52 +#define JEDEC_BE_52_OUTSIZE 0x04 +#define JEDEC_BE_52_INSIZE 0x00 + +/* Block Erase 0xd8 is supported by EON/Macronix chips. */ +#define JEDEC_BE_D8 0xd8 +#define JEDEC_BE_D8_OUTSIZE 0x04 +#define JEDEC_BE_D8_INSIZE 0x00 + +/* Sector Erase 0x20 is supported by Macronix/SST chips. */ +#define JEDEC_SE 0x20 +#define JEDEC_SE_OUTSIZE 0x04 +#define JEDEC_SE_INSIZE 0x00 + +/* Read Status Register */ +#define JEDEC_RDSR 0x05 +#define JEDEC_RDSR_OUTSIZE 0x01 +#define JEDEC_RDSR_INSIZE 0x01 +#define JEDEC_RDSR_BIT_WIP (0x01 << 0) + +/* Write Status Enable */ +#define JEDEC_EWSR 0x50 +#define JEDEC_EWSR_OUTSIZE 0x01 +#define JEDEC_EWSR_INSIZE 0x00 + +/* Write Status Register */ +#define JEDEC_WRSR 0x01 +#define JEDEC_WRSR_OUTSIZE 0x02 +#define JEDEC_WRSR_INSIZE 0x00 + +/* Read the memory */ +#define JEDEC_READ 0x03 +#define JEDEC_READ_OUTSIZE 0x04 +/* JEDEC_READ_INSIZE : any length */ + +/* Write memory byte */ +#define JEDEC_BYTE_PROGRAM 0x02 +#define JEDEC_BYTE_PROGRAM_OUTSIZE 0x05 +#define JEDEC_BYTE_PROGRAM_INSIZE 0x00 + +/* Error codes */ +#define SPI_GENERIC_ERROR -1 +#define SPI_INVALID_OPCODE -2 +#define SPI_INVALID_ADDRESS -3 +#define SPI_INVALID_LENGTH -4 + +#endif /* !__SPI_H__ */ diff --git a/libflashrom/sst28sf040.c b/libflashrom/sst28sf040.c new file mode 100644 index 0000000..930ad5b --- /dev/null +++ b/libflashrom/sst28sf040.c @@ -0,0 +1,164 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2005 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +#define AUTO_PG_ERASE1 0x20 +#define AUTO_PG_ERASE2 0xD0 +#define AUTO_PGRM 0x10 +#define CHIP_ERASE 0x30 +#define RESET 0xFF +#define READ_ID 0x90 + +static void protect_28sf040(chipaddr bios) +{ + chip_readb(bios + 0x1823); + chip_readb(bios + 0x1820); + chip_readb(bios + 0x1822); + chip_readb(bios + 0x0418); + chip_readb(bios + 0x041B); + chip_readb(bios + 0x0419); + chip_readb(bios + 0x040A); +} + +static void unprotect_28sf040(chipaddr bios) +{ + chip_readb(bios + 0x1823); + chip_readb(bios + 0x1820); + chip_readb(bios + 0x1822); + chip_readb(bios + 0x0418); + chip_readb(bios + 0x041B); + chip_readb(bios + 0x0419); + chip_readb(bios + 0x041A); +} + +static int erase_sector_28sf040(struct flashchip *flash, unsigned long address, int sector_size) +{ + chipaddr bios = flash->virtual_memory; + + chip_writeb(AUTO_PG_ERASE1, bios); + chip_writeb(AUTO_PG_ERASE2, bios + address); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios); + + if (check_erased_range(flash, address, sector_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +static int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst, + unsigned int page_size) +{ + int i; + + for (i = 0; i < page_size; i++) { + /* transfer data from source to destination */ + if (*src == 0xFF) { + dst++, src++; + /* If the data is 0xFF, don't program it */ + continue; + } + /*issue AUTO PROGRAM command */ + chip_writeb(AUTO_PGRM, dst); + chip_writeb(*src++, dst++); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios); + } + + return 0; +} + +int probe_28sf040(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(RESET, bios); + programmer_delay(10); + + chip_writeb(READ_ID, bios); + programmer_delay(10); + id1 = chip_readb(bios); + programmer_delay(10); + id2 = chip_readb(bios + 0x01); + + chip_writeb(RESET, bios); + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} + +int erase_28sf040(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + + unprotect_28sf040(bios); + chip_writeb(CHIP_ERASE, bios); + chip_writeb(CHIP_ERASE, bios); + protect_28sf040(bios); + + programmer_delay(10); + toggle_ready_jedec(bios); + + if (check_erased_range(flash, 0, flash->total_size * 1024)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int write_28sf040(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + unprotect_28sf040(bios); + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page before programming */ + if (erase_sector_28sf040(flash, i * page_size, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* write to the sector */ + printf("%04d at address: 0x%08x", i, i * page_size); + write_sector_28sf040(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + protect_28sf040(bios); + + return 0; +} diff --git a/libflashrom/sst49lf040.c b/libflashrom/sst49lf040.c new file mode 100644 index 0000000..ab1c918 --- /dev/null +++ b/libflashrom/sst49lf040.c @@ -0,0 +1,72 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +int erase_49lf040(struct flashchip *flash) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + + for (i = 0; i < total_size / page_size; i++) { + /* Chip erase only works in parallel programming mode + * for the 49lf040. Use sector-erase instead */ + if (erase_sector_jedec(flash, i * page_size, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + } + + return 0; +} + +int write_49lf040(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page before programming + * Chip erase only works in parallel programming mode + * for the 49lf040. Use sector-erase instead */ + if (erase_sector_jedec(flash, i * page_size, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* write to the sector */ + if (i % 10 == 0) + printf("%04d at address: 0x%08x ", i, i * page_size); + + write_sector_jedec(bios, buf + i * page_size, + bios + i * page_size, page_size); + + if (i % 10 == 0) + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/sst49lfxxxc.c b/libflashrom/sst49lfxxxc.c new file mode 100644 index 0000000..a421acf --- /dev/null +++ b/libflashrom/sst49lfxxxc.c @@ -0,0 +1,197 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2005-2007 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "flash.h" + +#define SECTOR_ERASE 0x30 +#define BLOCK_ERASE 0x20 +#define ERASE 0xD0 +#define AUTO_PGRM 0x10 +#define RESET 0xFF +#define READ_ID 0x90 +#define READ_STATUS 0x70 +#define CLEAR_STATUS 0x50 + +#define STATUS_BPS (1 << 1) +#define STATUS_ESS (1 << 6) +#define STATUS_WSMS (1 << 7) + +static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits) +{ + chipaddr registers = flash->virtual_registers; + int i, left = flash->total_size * 1024; + unsigned long address; + + printf_debug("\nbios=0x%08lx\n", registers); + for (i = 0; left > 65536; i++, left -= 65536) { + printf_debug("lockbits at address=0x%08lx is 0x%01x\n", + registers + (i * 65536) + 2, + chip_readb(registers + (i * 65536) + 2)); + chip_writeb(bits, registers + (i * 65536) + 2); + } + address = i * 65536; + printf_debug("lockbits at address=0x%08lx is 0x%01x\n", + registers + address + 2, + chip_readb(registers + address + 2)); + chip_writeb(bits, registers + address + 2); + address += 32768; + printf_debug("lockbits at address=0x%08lx is 0x%01x\n", + registers + address + 2, + chip_readb(registers + address + 2)); + chip_writeb(bits, registers + address + 2); + address += 8192; + printf_debug("lockbits at address=0x%08lx is 0x%01x\n", + registers + address + 2, + chip_readb(registers + address + 2)); + chip_writeb(bits, registers + address + 2); + address += 8192; + printf_debug("lockbits at address=0x%08lx is 0x%01x\n", + registers + address + 2, + chip_readb(registers + address + 2)); + chip_writeb(bits, registers + address + 2); + + return 0; +} + +static int erase_sector_49lfxxxc(struct flashchip *flash, unsigned long address, int sector_size) +{ + unsigned char status; + chipaddr bios = flash->virtual_memory; + + chip_writeb(SECTOR_ERASE, bios); + chip_writeb(ERASE, bios + address); + + do { + status = chip_readb(bios); + if (status & (STATUS_ESS | STATUS_BPS)) { + printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", bios + address, status); + chip_writeb(CLEAR_STATUS, bios); + return (-1); + } + } while (!(status & STATUS_WSMS)); + chip_writeb(RESET, bios); + + if (check_erased_range(flash, address, sector_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +static int write_sector_49lfxxxc(chipaddr bios, uint8_t *src, chipaddr dst, + unsigned int page_size) +{ + int i; + unsigned char status; + + chip_writeb(CLEAR_STATUS, bios); + for (i = 0; i < page_size; i++) { + /* transfer data from source to destination */ + if (*src == 0xFF) { + dst++, src++; + /* If the data is 0xFF, don't program it */ + continue; + } + /*issue AUTO PROGRAM command */ + chip_writeb(AUTO_PGRM, bios); + chip_writeb(*src++, dst++); + + do { + status = chip_readb(bios); + if (status & (STATUS_ESS | STATUS_BPS)) { + printf("sector write FAILED at address=0x%08lx status=0x%01x\n", dst, status); + chip_writeb(CLEAR_STATUS, bios); + return (-1); + } + } while (!(status & STATUS_WSMS)); + } + + return 0; +} + +int probe_49lfxxxc(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + + chip_writeb(RESET, bios); + + chip_writeb(READ_ID, bios); + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + + chip_writeb(RESET, bios); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (!(id1 == flash->manufacture_id && id2 == flash->model_id)) + return 0; + + map_flash_registers(flash); + + return 1; +} + +int erase_49lfxxxc(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + int i; + unsigned int total_size = flash->total_size * 1024; + + write_lockbits_49lfxxxc(flash, 0); + for (i = 0; i < total_size; i += flash->page_size) + if (erase_sector_49lfxxxc(flash, i, flash->page_size)) + return (-1); + + chip_writeb(RESET, bios); + + return 0; +} + +int write_49lfxxxc(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + write_lockbits_49lfxxxc(flash, 0); + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page before programming */ + if (erase_sector_49lfxxxc(flash, i * page_size, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + /* write to the sector */ + printf("%04d at address: 0x%08x", i, i * page_size); + write_sector_49lfxxxc(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + chip_writeb(RESET, bios); + + return 0; +} diff --git a/libflashrom/sst_fwhub.c b/libflashrom/sst_fwhub.c new file mode 100644 index 0000000..f09aa54 --- /dev/null +++ b/libflashrom/sst_fwhub.c @@ -0,0 +1,168 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * Copyright (C) 2009 Kontron Modular Computers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Adapted from the Intel FW hub stuff for 82802ax parts. */ + +#include +#include +#include "flash.h" + +// I need that Berkeley bit-map printer +void print_sst_fwhub_status(uint8_t status) +{ + printf("%s", status & 0x80 ? "Ready:" : "Busy:"); + printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); + printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); + printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); + printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); + printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); + printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); +} + +int check_sst_fwhub_block_lock(struct flashchip *flash, int offset) +{ + chipaddr registers = flash->virtual_registers; + uint8_t blockstatus; + + blockstatus = chip_readb(registers + offset + 2); + printf_debug("Lock status for 0x%06x (size 0x%06x) is %02x, ", + offset, flash->page_size, blockstatus); + switch (blockstatus & 0x3) { + case 0x0: + printf_debug("full access\n"); + break; + case 0x1: + printf_debug("write locked\n"); + break; + case 0x2: + printf_debug("locked open\n"); + break; + case 0x3: + printf_debug("write locked down\n"); + break; + } + /* Return content of the write_locked bit */ + return blockstatus & 0x1; +} + +int clear_sst_fwhub_block_lock(struct flashchip *flash, int offset) +{ + chipaddr registers = flash->virtual_registers; + uint8_t blockstatus; + + blockstatus = check_sst_fwhub_block_lock(flash, offset); + + if (blockstatus) { + printf_debug("Trying to clear lock for 0x%06x... ", offset) + chip_writeb(0, registers + offset + 2); + + blockstatus = check_sst_fwhub_block_lock(flash, offset); + printf_debug("%s\n", (blockstatus) ? "failed" : "OK"); + } + + return blockstatus; +} + +/* probe_jedec works fine for probing */ +int probe_sst_fwhub(struct flashchip *flash) +{ + int i; + + if (probe_jedec(flash) == 0) + return 0; + + map_flash_registers(flash); + + for (i = 0; i < flash->total_size * 1024; i += flash->page_size) + check_sst_fwhub_block_lock(flash, i); + + return 1; +} + +int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size) +{ + uint8_t blockstatus = clear_sst_fwhub_block_lock(flash, offset); + + if (blockstatus) { + printf("Block lock clearing failed, not erasing block " + "at 0x%06x\n", offset); + return 1; + } + + if (erase_block_jedec(flash, offset, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + toggle_ready_jedec(flash->virtual_memory); + + return 0; +} + +int erase_sst_fwhub(struct flashchip *flash) +{ + int i; + unsigned int total_size = flash->total_size * 1024; + + for (i = 0; i < total_size; i += flash->page_size) { + if (erase_sst_fwhub_block(flash, i, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + } + + return 0; +} + +int write_sst_fwhub(struct flashchip *flash, uint8_t *buf) +{ + int i, rc; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + uint8_t *readbuf = malloc(page_size); + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + printf("%04d at address: 0x%08x", i, i * page_size); + + /* Auto Skip Blocks, which already contain the desired data: + * Faster, because we only write, what has changed + * More secure, because blocks, which are excluded + * (with the exclude or layout feature) + * are not erased and rewritten; data is retained also + * in sudden power off situations + */ + flash->read(flash, readbuf, i * page_size, page_size); + if (memcmp((void *)(buf + i * page_size), + (void *)(readbuf), page_size)) { + rc = erase_sst_fwhub_block(flash, i * page_size, + page_size); + if (rc) + return 1; + write_sector_jedec(bios, buf + i * page_size, + bios + i * page_size, page_size); + } + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/stm50flw0x0x.c b/libflashrom/stm50flw0x0x.c new file mode 100644 index 0000000..0ae6eb8 --- /dev/null +++ b/libflashrom/stm50flw0x0x.c @@ -0,0 +1,245 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 Claus Gindhart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This module is designed for supporting the devices + * ST M50FLW040A (not yet tested) + * ST M50FLW040B (not yet tested) + * ST M50FLW080A + * ST M50FLW080B (not yet tested) + */ + +#include +#include +#include "flash.h" +#include "flashchips.h" + +int probe_stm50flw0x0x(struct flashchip *flash) +{ + int result = probe_jedec(flash); + + if (!result) + return result; + + map_flash_registers(flash); + + return 1; +} + +static void wait_stm50flw0x0x(chipaddr bios) +{ + chip_writeb(0x70, bios); + if ((chip_readb(bios) & 0x80) == 0) { // it's busy + while ((chip_readb(bios) & 0x80) == 0) ; + } + + // put another command to get out of status register mode + + chip_writeb(0x90, bios); + programmer_delay(10); + + chip_readb(bios); // Read device ID (to make sure?) + + // this is needed to jam it out of "read id" mode + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0xF0, bios + 0x5555); +} + +/* + * claus.gindhart@kontron.com + * The ST M50FLW080B and STM50FLW080B chips have to be unlocked, + * before you can erase them or write to them. + */ +int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) +{ + chipaddr wrprotect = flash->virtual_registers + 2; + const uint8_t unlock_sector = 0x00; + int j; + + /* + * These chips have to be unlocked before you can erase them or write + * to them. The size of the locking sectors depends on the type + * of chip. + * + * Sometimes, the BIOS does this for you; so you propably + * don't need to worry about that. + */ + + /* Check, if it's is a top/bottom-block with 4k-sectors. */ + /* TODO: What about the other types? */ + if ((offset == 0) || + (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000)) + || (offset == 0xF0000)) { + + // unlock each 4k-sector + for (j = 0; j < 0x10000; j += 0x1000) { + printf_debug("unlocking at 0x%x\n", offset + j); + chip_writeb(unlock_sector, wrprotect + offset + j); + if (chip_readb(wrprotect + offset + j) != unlock_sector) { + printf("Cannot unlock sector @ 0x%x\n", + offset + j); + return -1; + } + } + } else { + printf_debug("unlocking at 0x%x\n", offset); + chip_writeb(unlock_sector, wrprotect + offset); + if (chip_readb(wrprotect + offset) != unlock_sector) { + printf("Cannot unlock sector @ 0x%x\n", offset); + return -1; + } + } + + return 0; +} + +int erase_block_stm50flw0x0x(struct flashchip *flash, int offset) +{ + chipaddr bios = flash->virtual_memory + offset; + + // clear status register + chip_writeb(0x50, bios); + printf_debug("Erase at 0x%lx\n", bios); + // now start it + chip_writeb(0x20, bios); + chip_writeb(0xd0, bios); + programmer_delay(10); + + wait_stm50flw0x0x(flash->virtual_memory); + + if (check_erased_range(flash, offset, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + printf("DONE BLOCK 0x%x\n", offset); + + return 0; +} + +int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src, + chipaddr dst, int page_size) +{ + int i, rc = 0; + chipaddr d = dst; + uint8_t *s = src; + + /* transfer data from source to destination */ + for (i = 0; i < page_size; i++) { + chip_writeb(0x40, dst); + chip_writeb(*src++, dst++); + wait_stm50flw0x0x(bios); + } + +/* claus.gindhart@kontron.com + * TODO + * I think, that verification is not required, but + * i leave it in anyway + */ + dst = d; + src = s; + for (i = 0; i < page_size; i++) { + if (chip_readb(dst) != *src) { + rc = -1; + break; + } + dst++; + src++; + } + + if (rc) { + fprintf(stderr, " page 0x%lx failed!\n", + (d - bios) / page_size); + } + + return rc; +} + +/* I simply erase block by block + * I Chip This is not the fastest way, but it works + */ +int erase_stm50flw0x0x(struct flashchip *flash) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + + printf("Erasing page:\n"); + for (i = 0; i < total_size / page_size; i++) { + printf + ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%04d at address: 0x%08x ", i, i * page_size); + if (unlock_block_stm50flw0x0x(flash, i * page_size)) { + fprintf(stderr, "UNLOCK FAILED!\n"); + return -1; + } + if (erase_block_stm50flw0x0x(flash, i * page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + } + printf("\n"); + + return 0; +} + +int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf) +{ + int i, rc = 0; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + uint8_t *tmpbuf = malloc(page_size); + + if (!tmpbuf) { + printf("Could not allocate memory!\n"); + exit(1); + } + printf("Programming page: \n"); + for (i = 0; (i < total_size / page_size) && (rc == 0); i++) { + printf + ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%04d at address: 0x%08x ", i, i * page_size); + + /* Auto Skip Blocks, which already contain the desired data + * Faster, because we only write, what has changed + * More secure, because blocks, which are excluded + * (with the exclude or layout feature) + * are not erased and rewritten; data is retained also + * in sudden power off situations + */ + chip_readn(tmpbuf, bios + i * page_size, page_size); + if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) { + printf("SKIPPED\n"); + continue; + } + + rc = unlock_block_stm50flw0x0x(flash, i * page_size); + if (!rc) + rc = erase_block_stm50flw0x0x(flash, i * page_size); + if (!rc) + write_page_stm50flw0x0x(bios, buf + i * page_size, + bios + i * page_size, page_size); + } + printf("\n"); + free(tmpbuf); + + return rc; +} diff --git a/libflashrom/w29ee011.c b/libflashrom/w29ee011.c new file mode 100644 index 0000000..de9a547 --- /dev/null +++ b/libflashrom/w29ee011.c @@ -0,0 +1,70 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2007 Markus Boas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "flash.h" + +int probe_w29ee011(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + uint8_t id1, id2; + extern char *chip_to_probe; + + if (!chip_to_probe || strcmp(chip_to_probe, "W29EE011")) { + printf_debug("Probing disabled for Winbond W29EE011 because " + "the probing sequence puts the AMIC A49LF040A in " + "a funky state. Use 'flashrom -c W29EE011' if you " + "have a board with this chip.\n"); + return 0; + } + + /* Issue JEDEC Product ID Entry command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x80, bios + 0x5555); + programmer_delay(10); + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x60, bios + 0x5555); + programmer_delay(10); + + /* Read product ID */ + id1 = chip_readb(bios); + id2 = chip_readb(bios + 0x01); + + /* Issue JEDEC Product ID Exit command */ + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0xF0, bios + 0x5555); + programmer_delay(10); + + printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + + if (id1 == flash->manufacture_id && id2 == flash->model_id) + return 1; + + return 0; +} diff --git a/libflashrom/w39v040c.c b/libflashrom/w39v040c.c new file mode 100644 index 0000000..722ae29 --- /dev/null +++ b/libflashrom/w39v040c.c @@ -0,0 +1,90 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 Peter Stuge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +int probe_w39v040c(struct flashchip *flash) +{ + chipaddr bios = flash->virtual_memory; + int result = probe_jedec(flash); + uint8_t lock; + + if (!result) + return result; + + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0x90, bios + 0x5555); + programmer_delay(10); + + lock = chip_readb(bios + 0xfff2); + + chip_writeb(0xAA, bios + 0x5555); + programmer_delay(10); + chip_writeb(0x55, bios + 0x2AAA); + programmer_delay(10); + chip_writeb(0xF0, bios + 0x5555); + programmer_delay(40); + + printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n", + __func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un"); + return 1; +} + +int erase_w39v040c(struct flashchip *flash) +{ + int i; + unsigned int total_size = flash->total_size * 1024; + + for (i = 0; i < total_size; i += flash->page_size) { + if (erase_sector_jedec(flash, i, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + } + + return 0; +} + +int write_w39v040c(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + if (erase_flash(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + printf("%04d at address: 0x%08x", i, i * page_size); + write_sector_jedec(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/w39v080fa.c b/libflashrom/w39v080fa.c new file mode 100644 index 0000000..580657f --- /dev/null +++ b/libflashrom/w39v080fa.c @@ -0,0 +1,190 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +int probe_winbond_fwhub(struct flashchip *flash) +{ + int result = probe_jedec(flash); + + if (!result) + return result; + + map_flash_registers(flash); + + return 1; +} + +static int unlock_block_winbond_fwhub(struct flashchip *flash, int offset) +{ + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t locking; + + printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset, + chip_readb(wrprotect)); + + locking = chip_readb(wrprotect); + switch (locking & 0x7) { + case 0: + printf_debug("Full Access.\n"); + return 0; + case 1: + printf_debug("Write Lock (Default State).\n"); + chip_writeb(0, wrprotect); + return 0; + case 2: + printf_debug("Locked Open (Full Access, Lock Down).\n"); + return 0; + case 3: + fprintf(stderr, "Error: Write Lock, Locked Down.\n"); + return -1; + case 4: + printf_debug("Read Lock.\n"); + chip_writeb(0, wrprotect); + return 0; + case 5: + printf_debug("Read/Write Lock.\n"); + chip_writeb(0, wrprotect); + return 0; + case 6: + fprintf(stderr, "Error: Read Lock, Locked Down.\n"); + return -1; + case 7: + fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n"); + return -1; + } + + /* We will never reach this point, but GCC doesn't know */ + return -1; +} + +int unlock_winbond_fwhub(struct flashchip *flash) +{ + int i, total_size = flash->total_size * 1024; + chipaddr bios = flash->virtual_memory; + uint8_t locking; + + /* Are there any hardware restrictions that we can't overcome? + * If flashrom fail here, someone's got to check all those GPIOs. + */ + + /* Product Identification Entry */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0x90, bios + 0x5555); + programmer_delay(10); + + /* Read Hardware Lock Bits */ + locking = chip_readb(bios + 0xffff2); + + /* Product Identification Exit */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0xF0, bios + 0x5555); + programmer_delay(10); + + printf_debug("Lockout bits:\n"); + + if (locking & (1 << 2)) + fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n"); + else + printf_debug("No hardware bootblock locking (good!)\n"); + + if (locking & (1 << 3)) + fprintf(stderr, "Error: hardware block locking (#WP).\n"); + else + printf_debug("No hardware block locking (good!)\n"); + + if (locking & ((1 << 2) | (1 << 3))) + return -1; + + /* Unlock the complete chip */ + for (i = 0; i < total_size; i += flash->page_size) + if (unlock_block_winbond_fwhub(flash, i)) + return -1; + + return 0; +} + +static int erase_sector_winbond_fwhub(struct flashchip *flash, + unsigned int sector) +{ + chipaddr bios = flash->virtual_memory; + /* Remember: too much sleep can waste your day. */ + + printf("0x%08x\b\b\b\b\b\b\b\b\b\b", sector); + + /* Sector Erase */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0x80, bios + 0x5555); + + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0x30, bios + sector); + + /* wait for Toggle bit ready */ + toggle_ready_jedec(bios); + + if (check_erased_range(flash, sector, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + return 0; +} + +int erase_winbond_fwhub(struct flashchip *flash) +{ + int i, total_size = flash->total_size * 1024; + + unlock_winbond_fwhub(flash); + + printf("Erasing: "); + + for (i = 0; i < total_size; i += flash->page_size) { + if (erase_sector_winbond_fwhub(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + } + + printf("\n"); + + return 0; +} + +int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + chipaddr bios = flash->virtual_memory; + + if (erase_winbond_fwhub(flash)) + return -1; + + printf("Programming: "); + for (i = 0; i < total_size; i += flash->page_size) { + printf("0x%08x\b\b\b\b\b\b\b\b\b\b", i); + write_sector_jedec(bios, buf + i, bios + i, flash->page_size); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/w49f002u.c b/libflashrom/w49f002u.c new file mode 100644 index 0000000..d12bc72 --- /dev/null +++ b/libflashrom/w49f002u.c @@ -0,0 +1,47 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "flash.h" + +int write_49f002(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024; + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + + if (erase_chip_jedec(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } + + printf("Programming page: "); + for (i = 0; i < total_size / page_size; i++) { + printf("%04d at address: 0x%08x ", i, i * page_size); + /* Byte-wise writing of 'page_size' bytes. */ + write_sector_jedec(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + printf("\n"); + + return 0; +} diff --git a/libflashrom/wbsio_spi.c b/libflashrom/wbsio_spi.c new file mode 100644 index 0000000..6b9425f --- /dev/null +++ b/libflashrom/wbsio_spi.c @@ -0,0 +1,199 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 Peter Stuge + * + * 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 "flash.h" +#include "spi.h" + +#define WBSIO_PORT1 0x2e +#define WBSIO_PORT2 0x4e + +static uint16_t wbsio_spibase = 0; + +static uint16_t wbsio_get_spibase(uint16_t port) +{ + uint8_t id; + uint16_t flashport = 0; + + w836xx_ext_enter(port); + id = sio_read(port, 0x20); + if (id != 0xa0) { + fprintf(stderr, "\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id); + goto done; + } + + if (0 == (sio_read(port, 0x24) & 2)) { + fprintf(stderr, "\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port); + goto done; + } + + sio_write(port, 0x07, 0x06); + if (0 == (sio_read(port, 0x30) & 1)) { + fprintf(stderr, "\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port); + goto done; + } + + flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63); + +done: + w836xx_ext_leave(port); + return flashport; +} + +int wbsio_check_for_spi(const char *name) +{ + if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1))) + if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2))) + return 1; + + printf_debug("\nwbsio_spibase = 0x%x\n", wbsio_spibase); + + buses_supported |= CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_WBSIO; + + return 0; +} + +/* W83627DHG has 11 command modes: + * 1=1 command only + * 2=1 command+1 data write + * 3=1 command+2 data read + * 4=1 command+3 address + * 5=1 command+3 address+1 data write + * 6=1 command+3 address+4 data write + * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read + * 8=1 command+3 address+1 data read + * 9=1 command+3 address+2 data read + * a=1 command+3 address+3 data read + * b=1 command+3 address+4 data read + * + * mode[7:4] holds the command mode + * mode[3:0] holds SPI address bits [19:16] + * + * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\ + * Would one more byte of RAM in the chip (to get all 24 bits) really make + * such a big difference? + */ +int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int i; + uint8_t mode = 0; + + printf_debug("%s:", __func__); + + if (1 == writecnt && 0 == readcnt) { + mode = 0x10; + } else if (2 == writecnt && 0 == readcnt) { + OUTB(writearr[1], wbsio_spibase + 4); + printf_debug(" data=0x%02x", writearr[1]); + mode = 0x20; + } else if (1 == writecnt && 2 == readcnt) { + mode = 0x30; + } else if (4 == writecnt && 0 == readcnt) { + printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); + for (i = 2; i < writecnt; i++) { + OUTB(writearr[i], wbsio_spibase + i); + printf_debug("%02x", writearr[i]); + } + mode = 0x40 | (writearr[1] & 0x0f); + } else if (5 == writecnt && 0 == readcnt) { + printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); + for (i = 2; i < 4; i++) { + OUTB(writearr[i], wbsio_spibase + i); + printf_debug("%02x", writearr[i]); + } + OUTB(writearr[i], wbsio_spibase + i); + printf_debug(" data=0x%02x", writearr[i]); + mode = 0x50 | (writearr[1] & 0x0f); + } else if (8 == writecnt && 0 == readcnt) { + printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); + for (i = 2; i < 4; i++) { + OUTB(writearr[i], wbsio_spibase + i); + printf_debug("%02x", writearr[i]); + } + printf_debug(" data=0x"); + for (; i < writecnt; i++) { + OUTB(writearr[i], wbsio_spibase + i); + printf_debug("%02x", writearr[i]); + } + mode = 0x60 | (writearr[1] & 0x0f); + } else if (5 == writecnt && 4 == readcnt) { + /* XXX: TODO not supported by flashrom infrastructure! + * This mode, 7, discards the fifth byte in writecnt, + * but since we can not express that in flashrom, fail + * the operation for now. + */ + ; + } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) { + printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); + for (i = 2; i < writecnt; i++) { + OUTB(writearr[i], wbsio_spibase + i); + printf_debug("%02x", writearr[i]); + } + mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f); + } + printf_debug(" cmd=%02x mode=%02x\n", writearr[0], mode); + + if (!mode) { + fprintf(stderr, "%s: unsupported command type wr=%d rd=%d\n", + __func__, writecnt, readcnt); + /* Command type refers to the number of bytes read/written. */ + return SPI_INVALID_LENGTH; + } + + OUTB(writearr[0], wbsio_spibase); + OUTB(mode, wbsio_spibase + 1); + programmer_delay(10); + + if (!readcnt) + return 0; + + printf_debug("%s: returning data =", __func__); + for (i = 0; i < readcnt; i++) { + readarr[i] = INB(wbsio_spibase + 4 + i); + printf_debug(" 0x%02x", readarr[i]); + } + printf_debug("\n"); + return 0; +} + +int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + int size = flash->total_size * 1024; + + if (size > 1024 * 1024) { + fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); + return 1; + } + + return read_memmapped(flash, buf, start, len); +} + +int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf) +{ + int size = flash->total_size * 1024; + + if (size > 1024 * 1024) { + fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); + return 1; + } + + return spi_chip_write_1(flash, buf); +} diff --git a/m29f002.c b/m29f002.c deleted file mode 100644 index 01a7a50..0000000 --- a/m29f002.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Peter Stuge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -int erase_m29f002(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - chip_writeb(0xaa, bios + 0x555); - chip_writeb(0x55, bios + 0xaaa); - chip_writeb(0x80, bios + 0x555); - chip_writeb(0xaa, bios + 0x555); - chip_writeb(0x55, bios + 0xaaa); - chip_writeb(0x10, bios + 0x555); - programmer_delay(10); - toggle_ready_jedec(bios); - if (check_erased_range(flash, 0, flash->total_size * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -static int rewrite_block(struct flashchip *flash, uint8_t *src, - unsigned long start, int size) -{ - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios + start; - - /* erase */ - /* FIXME: use erase_sector_jedec? */ - chip_writeb(0xaa, bios + 0x555); - chip_writeb(0x55, bios + 0xaaa); - chip_writeb(0x80, bios + 0x555); - chip_writeb(0xaa, bios + 0x555); - chip_writeb(0x55, bios + 0xaaa); - chip_writeb(0x30, dst); - programmer_delay(10); - toggle_ready_jedec(bios); - if (check_erased_range(flash, start, size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* program */ - /* FIXME: use write_sector_jedec? */ - while (size--) { - chip_writeb(0xaa, bios + 0x555); - chip_writeb(0x55, bios + 0xaaa); - chip_writeb(0xa0, bios + 0x555); - chip_writeb(*src, dst); - toggle_ready_jedec(dst); - dst++; - src++; - } - return 0; -} - -static int do_block(struct flashchip *flash, uint8_t *src, int i, - unsigned long start, int size) -{ - int ret; - printf("%d at address: 0x%08lx", i, start); - ret = rewrite_block(flash, src + start, start, size); - if (ret) - return ret; - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int write_m29f002t(struct flashchip *flash, uint8_t *buf) -{ - int i, page_size = flash->page_size; - - /* M29F002(N)T has 7 blocks. From bottom to top their sizes are: - * 64k 64k 64k 32k 8k 8k 16k - * flash->page_size is set to 64k in flashchips.c - */ - - printf("Programming block: "); - for (i = 0; i < 3; i++) - do_block(flash, buf, i, i * page_size, page_size); - do_block(flash, buf, i++, 0x30000, 32 * 1024); - do_block(flash, buf, i++, 0x38000, 8 * 1024); - do_block(flash, buf, i++, 0x3a000, 8 * 1024); - do_block(flash, buf, i, 0x3c000, 16 * 1024); - - printf("\n"); - return 0; -} - -int write_m29f002b(struct flashchip *flash, uint8_t *buf) -{ - int i = 0, page_size = flash->page_size; - - /* M29F002B has 7 blocks. From bottom to top their sizes are: - * 16k 8k 8k 32k 64k 64k 64k - * flash->page_size is set to 64k in flashchips.c - */ - - printf("Programming block: "); - do_block(flash, buf, i++, 0x00000, 16 * 1024); - do_block(flash, buf, i++, 0x04000, 8 * 1024); - do_block(flash, buf, i++, 0x06000, 8 * 1024); - do_block(flash, buf, i++, 0x08000, 32 * 1024); - for (; i < 7; i++) - do_block(flash, buf, i, (i - 3) * page_size, page_size); - - printf("\n"); - return 0; -} diff --git a/m29f400bt.c b/m29f400bt.c deleted file mode 100644 index c327f44..0000000 --- a/m29f400bt.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -/* WARNING! - This chip uses the standard JEDEC Addresses in 16-bit mode as word - addresses. In byte mode, 0xAAA has to be used instead of 0x555 and - 0x555 instead of 0x2AA. Do *not* blindly replace with standard JEDEC - functions. */ - -void write_page_m29f400bt(chipaddr bios, uint8_t *src, - chipaddr dst, int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - chip_writeb(0xA0, bios + 0xAAA); - - /* transfer data from source to destination */ - chip_writeb(*src, dst); - //chip_writeb(0xF0, bios); - //programmer_delay(5); - toggle_ready_jedec(dst); - printf - ("Value in the flash at address 0x%lx = %#x, want %#x\n", - (dst - bios), chip_readb(dst), *src); - dst++; - src++; - } -} - -int probe_m29f400bt(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - chip_writeb(0x90, bios + 0xAAA); - - programmer_delay(10); - - id1 = chip_readb(bios); - /* The data sheet says id2 is at (bios + 0x01) and id2 listed in - * flash.h does not match. It should be possible to use JEDEC probe. - */ - id2 = chip_readb(bios + 0x02); - - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - chip_writeb(0xF0, bios + 0xAAA); - - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} - -int erase_m29f400bt(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - chip_writeb(0x80, bios + 0xAAA); - - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - chip_writeb(0x10, bios + 0xAAA); - - programmer_delay(10); - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, flash->total_size * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int block_erase_m29f400bt(struct flashchip *flash, int start, int len) -{ - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios + start; - - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - chip_writeb(0x80, bios + 0xAAA); - - chip_writeb(0xAA, bios + 0xAAA); - chip_writeb(0x55, bios + 0x555); - //chip_writeb(0x10, bios + 0xAAA); - chip_writeb(0x30, dst); - - programmer_delay(10); - toggle_ready_jedec(bios); - - if (check_erased_range(flash, start, len)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int write_m29f400bt(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - //erase_m29f400bt (flash); - printf("Programming page:\n "); - /********************************* - *Pages for M29F400BT: - * 16 0x7c000 0x7ffff TOP - * 8 0x7a000 0x7bfff - * 8 0x78000 0x79fff - * 32 0x70000 0x77fff - * 64 0x60000 0x6ffff - * 64 0x50000 0x5ffff - * 64 0x40000 0x4ffff - *--------------------------------- - * 64 0x30000 0x3ffff - * 64 0x20000 0x2ffff - * 64 0x10000 0x1ffff - * 64 0x00000 0x0ffff BOTTOM - *********************************/ - printf("total_size/page_size = %d\n", total_size / page_size); - for (i = 0; i < (total_size / page_size) - 1; i++) { - printf("%04d at address: 0x%08x\n", i, i * page_size); - if (block_erase_m29f400bt(flash, i * page_size, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - - printf("%04d at address: 0x%08x\n", 7, 0x70000); - if (block_erase_m29f400bt(flash, 0x70000, 32 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x70000, bios + 0x70000, 32 * 1024); - - printf("%04d at address: 0x%08x\n", 8, 0x78000); - if (block_erase_m29f400bt(flash, 0x78000, 8 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x78000, bios + 0x78000, 8 * 1024); - - printf("%04d at address: 0x%08x\n", 9, 0x7a000); - if (block_erase_m29f400bt(flash, 0x7a000, 8 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x7a000, bios + 0x7a000, 8 * 1024); - - printf("%04d at address: 0x%08x\n", 10, 0x7c000); - if (block_erase_m29f400bt(flash, 0x7c000, 16 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x7c000, bios + 0x7c000, 16 * 1024); - - printf("\n"); - - return 0; -} - -int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf) -{ - chipaddr bios = flash->virtual_memory; - - printf("Programming page:\n "); - /********************************* - *Pages for M29F400BT: - * 16 0x7c000 0x7ffff TOP - * 8 0x7a000 0x7bfff - * 8 0x78000 0x79fff - * 32 0x70000 0x77fff - * 64 0x60000 0x6ffff - * 64 0x50000 0x5ffff - * 64 0x40000 0x4ffff - *--------------------------------- - * 64 0x30000 0x3ffff - * 64 0x20000 0x2ffff - * 64 0x10000 0x1ffff - * 64 0x00000 0x0ffff BOTTOM - *********************************/ - printf("%04d at address: 0x%08x\n", 7, 0x00000); - if (block_erase_m29f400bt(flash, 0x00000, 64 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x00000, bios + 0x00000, 64 * 1024); - - printf("%04d at address: 0x%08x\n", 7, 0x10000); - if (block_erase_m29f400bt(flash, 0x10000, 64 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x10000, bios + 0x10000, 64 * 1024); - - printf("%04d at address: 0x%08x\n", 7, 0x20000); - if (block_erase_m29f400bt(flash, 0x20000, 64 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x20000, bios + 0x20000, 64 * 1024); - - printf("%04d at address: 0x%08x\n", 7, 0x30000); - if (block_erase_m29f400bt(flash, 0x30000, 64 * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x30000, bios + 0x30000, 64 * 1024); - - printf("\n"); - - return 0; -} diff --git a/mx29f002.c b/mx29f002.c deleted file mode 100644 index 7838c3d..0000000 --- a/mx29f002.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -int probe_29f002(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0x90, bios + 0x5555); - - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - - chip_writeb(0xF0, bios); - - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} - -/* FIXME: Use erase_chip_jedec? - * erase_29f002 uses shorter addresses, sends F0 (exit ID mode) and - * and has a bigger delay before polling the toggle bit */ -int erase_29f002(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - - chip_writeb(0xF0, bios + 0x555); - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x80, bios + 0x555); - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0x10, bios + 0x555); - - programmer_delay(100); - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, flash->total_size * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} diff --git a/nic3com.c b/nic3com.c deleted file mode 100644 index a4878d2..0000000 --- a/nic3com.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Uwe Hermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" - -#define BIOS_ROM_ADDR 0x04 -#define BIOS_ROM_DATA 0x08 -#define INT_STATUS 0x0e -#define INTERNAL_CONFIG 0x00 -#define SELECT_REG_WINDOW 0x800 - -#define PCI_VENDOR_ID_3COM 0x10b7 - -uint32_t internal_conf; -uint16_t id; - -struct pcidev_status nics_3com[] = { - /* 3C90xB */ - {0x10b7, 0x9055, PCI_OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"}, - {0x10b7, 0x9001, PCI_NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" }, - {0x10b7, 0x9004, PCI_OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" }, - {0x10b7, 0x9005, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" }, - {0x10b7, 0x9006, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" }, - {0x10b7, 0x900a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FL" }, - {0x10b7, 0x905a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FX" }, - {0x10b7, 0x9058, PCI_OK, "3COM", "3C905B: Cyclone 10/100/BNC" }, - - /* 3C905C */ - {0x10b7, 0x9200, PCI_OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" }, - - /* 3C980C */ - {0x10b7, 0x9805, PCI_NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" }, - - {}, -}; - -int nic3com_init(void) -{ - get_io_perms(); - - io_base_addr = pcidev_init(PCI_VENDOR_ID_3COM, PCI_BASE_ADDRESS_0, - nics_3com, programmer_param); - id = pcidev_dev->device_id; - - /* 3COM 3C90xB cards need a special fixup. */ - if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005 - || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) { - /* Select register window 3 and save the receiver status. */ - OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS); - internal_conf = INL(io_base_addr + INTERNAL_CONFIG); - - /* Set receiver type to MII for full BIOS ROM access. */ - OUTL((internal_conf & 0xf00fffff) | 0x00600000, io_base_addr); - } - - /* - * The lowest 16 bytes of the I/O mapped register space of (most) 3COM - * cards form a 'register window' into one of multiple (usually 8) - * register banks. For 3C90xB/3C90xC we need register window/bank 0. - */ - OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS); - - buses_supported = CHIP_BUSTYPE_PARALLEL; - - return 0; -} - -int nic3com_shutdown(void) -{ - /* 3COM 3C90xB cards need a special fixup. */ - if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005 - || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) { - /* Select register window 3 and restore the receiver status. */ - OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS); - OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG); - } - - free(programmer_param); - pci_cleanup(pacc); - release_io_perms(); - return 0; -} - -void nic3com_chip_writeb(uint8_t val, chipaddr addr) -{ - OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); - OUTB(val, io_base_addr + BIOS_ROM_DATA); -} - -uint8_t nic3com_chip_readb(const chipaddr addr) -{ - OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); - return INB(io_base_addr + BIOS_ROM_DATA); -} diff --git a/pcidev.c b/pcidev.c deleted file mode 100644 index 6c92c0a..0000000 --- a/pcidev.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Uwe Hermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" - -uint32_t io_base_addr; -struct pci_access *pacc; -struct pci_filter filter; -struct pci_dev *pcidev_dev = NULL; - -uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, - struct pcidev_status *devs) -{ - int i; - uint32_t addr; - - for (i = 0; devs[i].device_name != NULL; i++) { - if (dev->device_id != devs[i].device_id) - continue; - - /* - * Don't use dev->base_addr[x] (as value for 'bar'), won't - * work on older libpci. - */ - addr = pci_read_long(dev, bar) & ~0x03; - - printf("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n", - devs[i].vendor_name, devs[i].device_name, - dev->vendor_id, dev->device_id, dev->bus, dev->dev, - dev->func); - - if (devs[i].status == PCI_NT) { - printf("===\nThis PCI device is UNTESTED. Please " - "report the 'flashrom -p xxxx' output \n" - "to flashrom@flashrom.org if it works " - "for you. Thank you for your help!\n===\n"); - } - - return addr; - } - - return 0; -} - -uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, - struct pcidev_status *devs, char *pcidev_bdf) -{ - struct pci_dev *dev; - char *msg = NULL; - int found = 0; - uint32_t addr = 0, curaddr = 0; - - pacc = pci_alloc(); /* Get the pci_access structure */ - pci_init(pacc); /* Initialize the PCI library */ - pci_scan_bus(pacc); /* We want to get the list of devices */ - pci_filter_init(pacc, &filter); - - /* Filter by vendor and also bb:dd.f (if supplied by the user). */ - filter.vendor = vendor_id; - if (pcidev_bdf != NULL) { - if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) { - fprintf(stderr, "Error: %s\n", msg); - exit(1); - } - } - - for (dev = pacc->devices; dev; dev = dev->next) { - if (pci_filter_match(&filter, dev)) { - if ((addr = pcidev_validate(dev, bar, devs)) != 0) { - curaddr = addr; - pcidev_dev = dev; - found++; - } - } - } - - /* Only continue if exactly one supported PCI dev has been found. */ - if (found == 0) { - fprintf(stderr, "Error: No supported PCI device found.\n"); - exit(1); - } else if (found > 1) { - fprintf(stderr, "Error: Multiple supported PCI devices found. " - "Use 'flashrom -p xxxx:bb:dd.f' \n" - "to explicitly select the card with the given BDF " - "(PCI bus, device, function).\n"); - exit(1); - } - - return curaddr; -} - -void print_supported_pcidevs(struct pcidev_status *devs) -{ - int i; - - for (i = 0; devs[i].vendor_name != NULL; i++) { - printf("%s %s [%02x:%02x]%s\n", devs[i].vendor_name, - devs[i].device_name, devs[i].vendor_id, - devs[i].device_id, - (devs[i].status == PCI_NT) ? " (untested)" : ""); - } -} diff --git a/physmap.c b/physmap.c deleted file mode 100644 index 3a003fe..0000000 --- a/physmap.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Peter Stuge - * Copyright (C) 2009 coresystems GmbH - * - * 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 "flash.h" - -#ifdef __DARWIN__ -#include - -#define MEM_DEV "DirectIO" - -void *sys_physmap(unsigned long phys_addr, size_t len) -{ - return map_physical(phys_addr, len); -} - -void physunmap(void *virt_addr, size_t len) -{ - unmap_physical(virt_addr, len); -} - -#else -#include - -#if defined (__sun) && (defined(__i386) || defined(__amd64)) -# define MEM_DEV "/dev/xsvc" -#else -# define MEM_DEV "/dev/mem" -#endif - -static int fd_mem = -1; - -void *sys_physmap(unsigned long phys_addr, size_t len) -{ - void *virt_addr; - - if (-1 == fd_mem) { - /* Open the memory device UNCACHED. Important for MMIO. */ - if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) { - perror("Critical error: open(" MEM_DEV ")"); - exit(2); - } - } - - virt_addr = mmap(0, len, PROT_WRITE | PROT_READ, MAP_SHARED, - fd_mem, (off_t)phys_addr); - return MAP_FAILED == virt_addr ? NULL : virt_addr; -} - -void physunmap(void *virt_addr, size_t len) -{ - if (len == 0) { - printf_debug("Not unmapping zero size at %p\n", virt_addr); - return; - } - - munmap(virt_addr, len); -} -#endif - -void *physmap(const char *descr, unsigned long phys_addr, size_t len) -{ - void *virt_addr; - - if (len == 0) { - printf_debug("Not mapping %s, zero size at 0x%08lx.\n", - descr, phys_addr); - return NULL; - } - - if ((getpagesize() - 1) & len) { - fprintf(stderr, "Mapping %s at 0x%08lx, unaligned size 0x%lx.\n", - descr, phys_addr, (unsigned long)len); - } - - if ((getpagesize() - 1) & phys_addr) { - fprintf(stderr, "Mapping %s, 0x%lx bytes at unaligned 0x%08lx.\n", - descr, (unsigned long)len, phys_addr); - } - - virt_addr = sys_physmap(phys_addr, len); - - if (NULL == virt_addr) { - if (NULL == descr) - descr = "memory"; - fprintf(stderr, "Error accessing %s, 0x%lx bytes at 0x%08lx\n", descr, (unsigned long)len, phys_addr); - perror(MEM_DEV " mmap failed"); - if (EINVAL == errno) { - fprintf(stderr, "In Linux this error can be caused by the CONFIG_NONPROMISC_DEVMEM (<2.6.27),\n"); - fprintf(stderr, "CONFIG_STRICT_DEVMEM (>=2.6.27) and CONFIG_X86_PAT kernel options.\n"); - fprintf(stderr, "Please check if either is enabled in your kernel before reporting a failure.\n"); - fprintf(stderr, "You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n"); - fprintf(stderr, "disabling the other option unfortunately requires a kernel recompile. Sorry!\n"); - } - exit(3); - } - - return virt_addr; -} - -#ifdef __linux__ -/* - * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr, - * which are ring0 privileged instructions so only the kernel can do the - * read/write. This function, therefore, requires that the msr kernel module - * be loaded to access these instructions from user space using device - * /dev/cpu/0/msr. - */ - -static int fd_msr = -1; - -msr_t rdmsr(int addr) -{ - uint32_t buf[2]; - msr_t msr = { 0xffffffff, 0xffffffff }; - - if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) { - perror("Could not lseek() to MSR"); - close(fd_msr); - exit(1); - } - - if (read(fd_msr, buf, 8) == 8) { - msr.lo = buf[0]; - msr.hi = buf[1]; - - return msr; - } - - if (errno != EIO) { - // A severe error. - perror("Could not read() MSR"); - close(fd_msr); - exit(1); - } - - return msr; -} - -int wrmsr(int addr, msr_t msr) -{ - if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) { - perror("Could not lseek() to MSR"); - close(fd_msr); - exit(1); - } - - if (write(fd_msr, &msr, 8) != 8 && errno != EIO) { - perror("Could not write() MSR"); - close(fd_msr); - exit(1); - } - - /* some MSRs must not be written */ - if (errno == EIO) - return -1; - - return 0; -} - -int setup_cpu_msr(int cpu) -{ - char msrfilename[64]; - memset(msrfilename, 0, 64); - sprintf(msrfilename, "/dev/cpu/%d/msr", cpu); - - if (fd_msr != -1) { - printf("MSR was already initialized\n"); - return -1; - } - - fd_msr = open(msrfilename, O_RDWR); - - if (fd_msr < 0) { - perror("Error while opening /dev/cpu/0/msr"); - printf("Did you run 'modprobe msr'?\n"); - return -1; - } - - return 0; -} - -void cleanup_cpu_msr(void) -{ - if (fd_msr == -1) { - printf("No MSR initialized.\n"); - return; - } - - close(fd_msr); - - /* Clear MSR file descriptor */ - fd_msr = -1; -} -#else -#if defined(__FreeBSD__) || defined(__DragonFly__) -#include - -typedef struct { - int msr; - uint64_t data; -} cpu_msr_args_t; -#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t) -#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t) - -static int fd_msr = -1; - -msr_t rdmsr(int addr) -{ - cpu_msr_args_t args; - - msr_t msr = { 0xffffffff, 0xffffffff }; - - args.msr = addr; - - if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) { - perror("CPU_RDMSR"); - close(fd_msr); - exit(1); - } - - msr.lo = args.data & 0xffffffff; - msr.hi = args.data >> 32; - - return msr; -} - -int wrmsr(int addr, msr_t msr) -{ - cpu_msr_args_t args; - - args.msr = addr; - args.data = (((uint64_t)msr.hi) << 32) | msr.lo; - - if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) { - perror("CPU_WRMSR"); - close(fd_msr); - exit(1); - } - - return 0; -} - -int setup_cpu_msr(int cpu) -{ - char msrfilename[64]; - memset(msrfilename, 0, 64); - sprintf(msrfilename, "/dev/cpu%d", cpu); - - if (fd_msr != -1) { - printf("MSR was already initialized\n"); - return -1; - } - - fd_msr = open(msrfilename, O_RDWR); - - if (fd_msr < 0) { - perror("Error while opening /dev/cpu0"); - printf("Did you install ports/sysutils/devcpu?\n"); - return -1; - } - - return 0; -} - -void cleanup_cpu_msr(void) -{ - if (fd_msr == -1) { - printf("No MSR initialized.\n"); - return; - } - - close(fd_msr); - - /* Clear MSR file descriptor */ - fd_msr = -1; -} - -#else - -#ifdef __DARWIN__ -int setup_cpu_msr(int cpu) -{ - // Always succeed for now - return 0; -} - -void cleanup_cpu_msr(void) -{ - // Nothing, yet. -} -#else -msr_t rdmsr(int addr) -{ - msr_t ret = { 0xffffffff, 0xffffffff }; - - return ret; -} - -int wrmsr(int addr, msr_t msr) -{ - return -1; -} - -int setup_cpu_msr(int cpu) -{ - printf("No MSR support for your OS yet.\n"); - return -1; -} - -void cleanup_cpu_msr(void) -{ - // Nothing, yet. -} -#endif -#endif -#endif - diff --git a/pm29f002.c b/pm29f002.c deleted file mode 100644 index bf78d13..0000000 --- a/pm29f002.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Uwe Hermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -/* if write_sector_jedec is used, - this is write_jedec_1 */ -int write_pm29f002(struct flashchip *flash, uint8_t *buf) -{ - int i, total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios; - - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* FIXME: use write_sector_jedec? */ - printf("Programming page: "); - for (i = 0; i < total_size; i++) { - if ((i & 0xfff) == 0) - printf("address: 0x%08lx", (unsigned long)i); - - /* Pm29F002T/B only support byte-wise programming. */ - chip_writeb(0xAA, bios + 0x555); - chip_writeb(0x55, bios + 0x2AA); - chip_writeb(0xA0, bios + 0x555); - chip_writeb(*buf++, dst++); - - /* Wait for Toggle bit ready. */ - toggle_ready_jedec(dst); - - if ((i & 0xfff) == 0) - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - - printf("\n"); - - return 0; -} diff --git a/pm49fl00x.c b/pm49fl00x.c deleted file mode 100644 index 27a1163..0000000 --- a/pm49fl00x.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2004 Tyan Corporation - * Copyright (C) 2007 Nikolay Petukhov - * Copyright (C) 2007 Reinder E.N. de Haan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -void write_lockbits_49fl00x(chipaddr bios, int size, - unsigned char bits, int block_size) -{ - int i, left = size; - - for (i = 0; left >= block_size; i++, left -= block_size) { - /* pm49fl002 */ - if (block_size == 16384 && i % 2) - continue; - - chip_writeb(bits, bios + (i * block_size) + 2); - } -} - -int probe_49fl00x(struct flashchip *flash) -{ - int ret = probe_jedec(flash); - - if (ret == 1) - map_flash_registers(flash); - - return ret; -} - -int erase_49fl00x(struct flashchip *flash) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - - /* unprotected */ - write_lockbits_49fl00x(flash->virtual_registers, - total_size, 0, page_size); - - /* - * erase_chip_jedec() will not work... Datasheet says - * "Chip erase is available in A/A Mux Mode only". - */ - printf("Erasing page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page */ - if (erase_block_jedec(flash, i * page_size, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("%04d at address: 0x%08x", i, i * page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - fflush(stdout); - } - printf("\n"); - - /* protected */ - write_lockbits_49fl00x(flash->virtual_registers, - total_size, 1, page_size); - - return 0; -} - -int write_49fl00x(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - /* unprotected */ - write_lockbits_49fl00x(flash->virtual_registers, total_size, 0, - page_size); - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming */ - if (erase_block_jedec(flash, i * page_size, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ - printf("%04d at address: 0x%08x", i, i * page_size); - write_sector_jedec(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - fflush(stdout); - } - printf("\n"); - - /* protected */ - write_lockbits_49fl00x(flash->virtual_registers, total_size, 1, - page_size); - - return 0; -} diff --git a/print.c b/print.c deleted file mode 100644 index a2a6c63..0000000 --- a/print.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Uwe Hermann - * Copyright (C) 2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include "flash.h" -#include "flashchips.h" - -/* - * Return a string corresponding to the bustype parameter. - * Memory is obtained with malloc() and can be freed with free(). - */ -char *flashbuses_to_text(enum chipbustype bustype) -{ - char *ret = calloc(1, 1); - if (bustype == CHIP_BUSTYPE_UNKNOWN) { - ret = strcat_realloc(ret, "Unknown,"); - /* - * FIXME: Once all chipsets and flash chips have been updated, NONSPI - * will cease to exist and should be eliminated here as well. - */ - } else if (bustype == CHIP_BUSTYPE_NONSPI) { - ret = strcat_realloc(ret, "Non-SPI,"); - } else { - if (bustype & CHIP_BUSTYPE_PARALLEL) - ret = strcat_realloc(ret, "Parallel,"); - if (bustype & CHIP_BUSTYPE_LPC) - ret = strcat_realloc(ret, "LPC,"); - if (bustype & CHIP_BUSTYPE_FWH) - ret = strcat_realloc(ret, "FWH,"); - if (bustype & CHIP_BUSTYPE_SPI) - ret = strcat_realloc(ret, "SPI,"); - if (bustype == CHIP_BUSTYPE_NONE) - ret = strcat_realloc(ret, "None,"); - } - /* Kill last comma. */ - ret[strlen(ret) - 1] = '\0'; - ret = realloc(ret, strlen(ret) + 1); - return ret; -} - -#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0) - -static int digits(int n) -{ - int i; - - if (!n) - return 1; - - for (i = 0; n; ++i) - n /= 10; - - return i; -} - -void print_supported_chips(void) -{ - int okcol = 0, pos = 0, i, chipcount = 0; - struct flashchip *f; - - for (f = flashchips; f->name != NULL; f++) { - if (GENERIC_DEVICE_ID == f->model_id) - continue; - okcol = max(okcol, strlen(f->vendor) + 1 + strlen(f->name)); - } - okcol = (okcol + 7) & ~7; - - for (f = flashchips; f->name != NULL; f++) - chipcount++; - - printf("\nSupported flash chips (total: %d):\n\n", chipcount); - POS_PRINT("Vendor: Device:"); - while (pos < okcol) { - printf("\t"); - pos += 8 - (pos % 8); - } - - printf("Tested OK:\tKnown BAD: Size/KB: Type:\n\n"); - printf("(P = PROBE, R = READ, E = ERASE, W = WRITE)\n\n"); - - for (f = flashchips; f->name != NULL; f++) { - /* Don't print "unknown XXXX SPI chip" entries. */ - if (!strncmp(f->name, "unknown", 7)) - continue; - - printf("%s", f->vendor); - for (i = 0; i < 10 - strlen(f->vendor); i++) - printf(" "); - printf("%s", f->name); - - pos = 10 + strlen(f->name); - while (pos < okcol) { - printf("\t"); - pos += 8 - (pos % 8); - } - if ((f->tested & TEST_OK_MASK)) { - if ((f->tested & TEST_OK_PROBE)) - POS_PRINT("P "); - if ((f->tested & TEST_OK_READ)) - POS_PRINT("R "); - if ((f->tested & TEST_OK_ERASE)) - POS_PRINT("E "); - if ((f->tested & TEST_OK_WRITE)) - POS_PRINT("W "); - } - while (pos < okcol + 9) { - printf("\t"); - pos += 8 - (pos % 8); - } - if ((f->tested & TEST_BAD_MASK)) { - if ((f->tested & TEST_BAD_PROBE)) - printf("P "); - if ((f->tested & TEST_BAD_READ)) - printf("R "); - if ((f->tested & TEST_BAD_ERASE)) - printf("E "); - if ((f->tested & TEST_BAD_WRITE)) - printf("W "); - } - - printf("\t %d", f->total_size); - for (i = 0; i < 10 - digits(f->total_size); i++) - printf(" "); - printf("%s\n", flashbuses_to_text(f->bustype)); - } -} - -void print_supported_chipsets(void) -{ - int i, j, chipsetcount = 0; - const struct penable *c = chipset_enables; - - for (i = 0; c[i].vendor_name != NULL; i++) - chipsetcount++; - - printf("\nSupported chipsets (total: %d):\n\nVendor: " - "Chipset: PCI IDs:\n\n", chipsetcount); - - for (i = 0; c[i].vendor_name != NULL; i++) { - printf("%s", c[i].vendor_name); - for (j = 0; j < 25 - strlen(c[i].vendor_name); j++) - printf(" "); - printf("%s", c[i].device_name); - for (j = 0; j < 25 - strlen(c[i].device_name); j++) - printf(" "); - printf("%04x:%04x%s\n", c[i].vendor_id, c[i].device_id, - (c[i].status == OK) ? "" : " (untested)"); - } -} - -void print_supported_boards_helper(const struct board_info *b, const char *msg) -{ - int i, j, boardcount = 0; - - for (i = 0; b[i].vendor != NULL; i++) - boardcount++; - - printf("\n%s (total: %d):\n\n", msg, boardcount); - - for (i = 0; b[i].vendor != NULL; i++) { - printf("%s", b[i].vendor); - for (j = 0; j < 25 - strlen(b[i].vendor); j++) - printf(" "); - printf("%s", b[i].name); - for (j = 0; j < 28 - strlen(b[i].name); j++) - printf(" "); - printf("\n"); - } -} - -void print_supported_boards(void) -{ - int i, j, boardcount = 0; - struct board_pciid_enable *b = board_pciid_enables; - - for (i = 0; b[i].vendor_name != NULL; i++) - boardcount++; - - printf("\nSupported boards which need write-enable code (total: %d):" - "\n\nVendor: Board: " - "Required option:\n\n", boardcount); - - for (i = 0; b[i].vendor_name != NULL; i++) { - printf("%s", b[i].vendor_name); - for (j = 0; j < 25 - strlen(b[i].vendor_name); j++) - printf(" "); - printf("%s", b[i].board_name); - for (j = 0; j < 30 - strlen(b[i].board_name); j++) - printf(" "); - if (b[i].lb_vendor != NULL) - printf("-m %s:%s\n", b[i].lb_vendor, b[i].lb_part); - else - printf("(none, board is autodetected)\n"); - } - - print_supported_boards_helper(boards_ok, - "Supported boards which don't need write-enable code"); - print_supported_boards_helper(boards_bad, - "Boards which have been verified to NOT work yet"); - print_supported_boards_helper(laptops_ok, - "Laptops which have been verified to work"); - print_supported_boards_helper(laptops_bad, - "Laptops which have been verified to NOT work yet"); -} - -void print_supported(void) -{ - print_supported_chips(); - print_supported_chipsets(); - print_supported_boards(); - printf("\nSupported PCI devices flashrom can use " - "as programmer:\n\n"); -#if NIC3COM_SUPPORT == 1 - print_supported_pcidevs(nics_3com); -#endif -#if GFXNVIDIA_SUPPORT == 1 - print_supported_pcidevs(gfx_nvidia); -#endif -#if DRKAISER_SUPPORT == 1 - print_supported_pcidevs(drkaiser_pcidev); -#endif -#if SATASII_SUPPORT == 1 - print_supported_pcidevs(satas_sii); -#endif -} - - -/* Please keep this list alphabetically ordered by vendor/board. */ -const struct board_info boards_ok[] = { - /* Verified working boards that don't need write-enables. */ - { "Abit", "AX8", }, - { "Abit", "Fatal1ty F-I90HD", }, - { "Advantech", "PCM-5820", }, - { "ASI", "MB-5BLMP", }, - { "ASRock", "A770CrossFire", }, - { "ASRock", "K8S8X", }, - { "ASUS", "A7N8X Deluxe", }, - { "ASUS", "A7N8X-E Deluxe", }, - { "ASUS", "A7V400-MX", }, - { "ASUS", "A7V8X-MX", }, - { "ASUS", "A8N-E", }, - { "ASUS", "A8NE-FM/S", }, - { "ASUS", "A8N-SLI", }, - { "ASUS", "A8N-SLI Premium", }, - { "ASUS", "A8V Deluxe", }, - { "ASUS", "A8V-E Deluxe", }, - { "ASUS", "A8V-E SE", }, - { "ASUS", "K8V", }, - { "ASUS", "K8V SE Deluxe", }, - { "ASUS", "K8V-X SE", }, - { "ASUS", "M2A-MX", }, - { "ASUS", "M2A-VM", }, - { "ASUS", "M2N-E", }, - { "ASUS", "M2V", }, - { "ASUS", "M3A78-EM", }, - { "ASUS", "P2B", }, - { "ASUS", "P2B-D", }, - { "ASUS", "P2B-DS", }, - { "ASUS", "P2B-F", }, - { "ASUS", "P2L97-S", }, - { "ASUS", "P5B-Deluxe", }, - { "ASUS", "P5KC", }, - { "ASUS", "P5L-MX", }, - { "ASUS", "P6T Deluxe V2", }, - { "A-Trend", "ATC-6220", }, - { "BCOM", "WinNET100", }, - { "DFI", "Blood-Iron P35 T2RL", }, - { "Elitegroup", "K7S5A", }, - { "Elitegroup", "P6VAP-A+", }, - { "GIGABYTE", "GA-6BXC", }, - { "GIGABYTE", "GA-6BXDU", }, - { "GIGABYTE", "GA-6ZMA", }, - { "GIGABYTE", "GA-7ZM", }, - { "GIGABYTE", "GA-EP35-DS3L", }, - { "GIGABYTE", "GA-EX58-UD4P", }, - { "GIGABYTE", "GA-MA78GPM-DS2H", }, - { "GIGABYTE", "GA-MA790GP-DS4H", }, - { "GIGABYTE", "GA-MA770T-UD3P", }, - { "Intel", "EP80759", }, - { "Jetway", "J7F4K1G5D-PB", }, - { "MSI", "MS-6153", }, - { "MSI", "MS-6156", }, - { "MSI", "MS-6570 (K7N2)", }, - { "MSI", "MS-7065", }, - { "MSI", "MS-7168 (Orion)", }, - { "MSI", "MS-7236 (945PL Neo3)", }, - { "MSI", "MS-7255 (P4M890M)", }, - { "MSI", "MS-7345 (P35 Neo2-FIR)", }, - { "MSI", "MS-7368 (K9AG Neo2-Digital)", }, - { "NEC", "PowerMate 2000", }, - { "PC Engines", "Alix.1c", }, - { "PC Engines", "Alix.2c2", }, - { "PC Engines", "Alix.2c3", }, - { "PC Engines", "Alix.3c3", }, - { "PC Engines", "Alix.3d3", }, - { "RCA", "RM4100", }, - { "Sun", "Blade x6250", }, - { "Supermicro", "H8QC8", }, - { "Thomson", "IP1000", }, - { "TriGem", "Lomita", }, - { "T-Online", "S-100", }, - { "Tyan", "iS5375-1U", }, - { "Tyan", "S1846", }, - { "Tyan", "S2466", }, - { "Tyan", "S2881", }, - { "Tyan", "S2882", }, - { "Tyan", "S2882-D", }, - { "Tyan", "S2891", }, - { "Tyan", "S2892", }, - { "Tyan", "S2895", }, - { "Tyan", "S3095", }, - { "Tyan", "S5180", }, - { "Tyan", "S5191", }, - { "Tyan", "S5197", }, - { "Tyan", "S5211", }, - { "Tyan", "S5211-1U", }, - { "Tyan", "S5220", }, - { "Tyan", "S5375", }, - { "Tyan", "S5376G2NR/S5376WAG2NR", }, - { "Tyan", "S5377", }, - { "Tyan", "S5397", }, - { "VIA", "EPIA-EX15000G", }, - { "VIA", "EPIA-LN", }, - { "VIA", "EPIA-M700", }, - { "VIA", "EPIA-NX15000G", }, - { "VIA", "NAB74X0", }, - { "VIA", "pc2500e", }, - { "VIA", "VB700X", }, - - {}, -}; - -/* Please keep this list alphabetically ordered by vendor/board. */ -const struct board_info boards_bad[] = { - /* Verified non-working boards (for now). */ - { "Abit", "IS-10", }, - { "ASRock", "K7VT4A+", }, - { "ASUS", "MEW-AM", }, - { "ASUS", "MEW-VM", }, - { "ASUS", "P3B-F", }, - { "ASUS", "P5B", }, - { "ASUS", "P5BV-M", }, - { "Biostar", "M6TBA", }, - { "Boser", "HS-6637", }, - { "DFI", "855GME-MGF", }, - { "FIC", "VA-502", }, - { "MSI", "MS-6178", }, - { "MSI", "MS-7260 (K9N Neo)", }, - { "Soyo", "SY-5VD", }, - { "Sun", "Fire x4150", }, - { "Sun", "Fire x4200", }, - { "Sun", "Fire x4540", }, - { "Sun", "Fire x4600", }, - - {}, -}; - -/* Please keep this list alphabetically ordered by vendor/board. */ -const struct board_info laptops_ok[] = { - /* Verified working laptops. */ - { "Lenovo", "3000 V100 TF05Cxx", }, - - {}, -}; - -/* Please keep this list alphabetically ordered by vendor/board. */ -const struct board_info laptops_bad[] = { - /* Verified non-working laptops (for now). */ - { "Acer", "Aspire One", }, - { "ASUS", "Eee PC 701 4G", }, - { "Dell", "Latitude CPi A366XT", }, - { "HP/Compaq", "nx9010", }, - { "IBM/Lenovo", "Thinkpad T40p", }, - { "IBM/Lenovo", "240", }, - - {}, -}; - diff --git a/print_wiki.c b/print_wiki.c deleted file mode 100644 index ce41ad4..0000000 --- a/print_wiki.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Uwe Hermann - * Copyright (C) 2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" -#include "flashchips.h" - -struct board_info_url { - const char *vendor; - const char *name; - const char *url; -}; - -struct board_info_notes { - const char *vendor; - const char *name; - const char *note; -}; - -const char *wiki_header = "= Supported devices =\n\n\ -
\n\ -Please do '''not''' edit these tables in the wiki directly, they are \ -generated by pasting '''flashrom -z''' output.
\ -'''Last update:''' %s(generated by flashrom %s)\n
\n"; - -const char *chipset_th = "{| border=\"0\" style=\"font-size: smaller\"\n\ -|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -! align=\"left\" | Southbridge\n! align=\"left\" | PCI IDs\n\ -! align=\"left\" | Status\n\n"; - -const char *board_th = "{| border=\"0\" style=\"font-size: smaller\" \ -valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -! align=\"left\" | Mainboard\n! align=\"left\" | Status\n\n"; - -const char *board_th2 = "{| border=\"0\" style=\"font-size: smaller\" \ -valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -! align=\"left\" | Mainboard\n! align=\"left\" | Required option\n\ -! align=\"left\" | Status\n\n"; - -const char *board_intro = "\ -\n== Supported mainboards ==\n\n\ -In general, it is very likely that flashrom works out of the box even if your \ -mainboard is not listed below.\n\nThis is a list of mainboards where we have \ -verified that they either do or do not need any special initialization to \ -make flashrom work (given flashrom supports the respective chipset and flash \ -chip), or that they do not yet work at all. If they do not work, support may \ -or may not be added later.\n\n\ -Mainboards which don't appear in the list may or may not work (we don't \ -know, someone has to give it a try). Please report any further verified \ -mainboards on the [[Mailinglist|mailing list]].\n"; - -const char *chip_th = "{| border=\"0\" style=\"font-size: smaller\" \ -valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -! align=\"left\" | Device\n! align=\"left\" | Size / KB\n\ -! align=\"left\" | Type\n! align=\"left\" colspan=\"4\" | Status\n\n\ -|- bgcolor=\"#6699ff\"\n| colspan=\"4\" |  \n\ -| Probe\n| Read\n| Write\n| Erase\n\n"; - -const char *programmer_section = "\ -\n== Supported programmers ==\n\nThis is a list \ -of supported PCI devices flashrom can use as programmer:\n\n{| border=\"0\" \ -valign=\"top\"\n| valign=\"top\"|\n\n{| border=\"0\" style=\"font-size: \ -smaller\" valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -! align=\"left\" | Device\n! align=\"left\" | PCI IDs\n\ -! align=\"left\" | Status\n\n"; - -const char *laptop_intro = "\n== Supported laptops/notebooks ==\n\n\ -In general, flashing laptops is more difficult because laptops\n\n\ -* often use the flash chip for stuff besides the BIOS,\n\ -* often have special protection stuff which has to be handled by flashrom,\n\ -* often use flash translation circuits which need drivers in flashrom.\n\n\ -
\n\ -'''IMPORTANT:''' At this point we recommend to '''not''' use flashrom on \ -untested laptops unless you have a means to recover from a flashing that goes \ -wrong (a working backup flash chip and/or good soldering skills).\n
\n"; - -/* Please keep these lists alphabetically ordered by vendor/board. */ -const struct board_info_url boards_url[] = { - /* Verified working boards that don't need write-enables. */ - { "Abit", "AX8", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?DEFTITLE=Y&fMTYPE=Socket%20939&pMODEL_NAME=AX8" }, - { "Abit", "Fatal1ty F-I90HD", "http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?pMODEL_NAME=Fatal1ty+F-I90HD&fMTYPE=LGA775" }, - { "Advantech", "PCM-5820", "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm" }, - { "ASI", "MB-5BLMP", "http://www.hojerteknik.com/winnet.htm" }, - { "ASRock", "A770CrossFire", "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire&s=AM2\%2b" }, - { "ASRock", "K8S8X", "http://www.asrock.com/mb/overview.asp?Model=K8S8X" }, - { "ASUS", "A7N8X Deluxe", "http://www.asus.com/Product.aspx?P_ID=wAsRYm41KTp78MFC" }, - { "ASUS", "A7N8X-E Deluxe", "http://www.asus.com/products.aspx?l1=3&l2=13&l3=56&l4=0&model=217&modelmenu=1" }, - { "ASUS", "A7V400-MX", "http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=63&l4=0&model=228&modelmenu=1" }, - { "ASUS", "A7V8X-MX", "http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=64&l4=0&model=229&modelmenu=1" }, - { "ASUS", "A8N-E", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=171&l4=0&model=455&modelmenu=2" }, - { "ASUS", "A8NE-FM/S", "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM" }, - { "ASUS", "A8N-SLI", "http://asus.com/product.aspx?P_ID=J9FKa8z2xVId3pDK" }, - { "ASUS", "A8N-SLI Premium", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=148&l4=0&model=539&modelmenu=1" }, - { "ASUS", "A8V Deluxe", "http://www.asus.com/product.aspx?P_ID=tvpdgPNCPaABZRVU" }, - { "ASUS", "A8V-E Deluxe", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=376&modelmenu=1" }, - { "ASUS", "A8V-E SE", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=576&modelmenu=1" }, - { "ASUS", "K8V", "http://www.asus.com/product.aspx?P_ID=fG2KZOWF7v6MRFRm" }, - { "ASUS", "K8V SE Deluxe", "http://www.asus.com/product.aspx?P_ID=65HeDI8XM1u6Uy6o" }, - { "ASUS", "K8V-X SE", "http://asus.com/product.aspx?P_ID=lzDXlbBVHkdckHVr" }, - { "ASUS", "M2A-MX", "http://www.asus.com/products.aspx?l1=3&l2=101&l3=583&l4=0&model=1909&modelmenu=1" }, - { "ASUS", "M2A-VM", "http://www.asus.com.tw/products.aspx?l1=3&l2=101&l3=496&l4=0&model=1568&modelmenu=1" }, - { "ASUS", "M2N-E", "http://www.asus.com/products.aspx?l1=3&l2=101&l3=308&l4=0&model=1181&modelmenu=1" }, - { "ASUS", "M2V", "http://asus.com/Product.aspx?P_ID=OqYlEDFfF6ZqZGvp" }, - { "ASUS", "M3A78-EM", "http://www.asus.com/product.aspx?P_ID=KjpYqzmAd9vsTM2D" }, - { "ASUS", "P2B", "http://www.motherboard.cz/mb/asus/P2B.htm" }, - { "ASUS", "P2B-D", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" }, - { "ASUS", "P2B-DS", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/" }, - { "ASUS", "P2B-F", "http://www.motherboard.cz/mb/asus/P2B-F.htm" }, - { "ASUS", "P2L97-S", "http://www.motherboard.cz/mb/asus/P2L97-S.htm" }, - { "ASUS", "P5B-Deluxe", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-Deluxe/" }, - { "ASUS", "P5KC", "http://www.asus.com/product.aspx?P_ID=fFZ8oUIGmLpwNMjj" }, - { "ASUS", "P5L-MX", "http://www.asus.com/product.aspx?P_ID=X70d3NCzH2DE9vWH" }, - { "ASUS", "P6T Deluxe V2", "http://www.asus.com/product.aspx?P_ID=iRlP8RG9han6saZx" }, - { "A-Trend", "ATC-6220", "http://www.motherboard.cz/mb/atrend/atc6220.htm" }, - { "BCOM", "WinNET100", "http://www.coreboot.org/BCOM_WINNET100" }, - { "DFI", "Blood-Iron P35 T2RL", "http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1" }, - { "Elitegroup", "K7S5A", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=279&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" }, - { "Elitegroup", "P6VAP-A+", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=117&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" }, - { "GIGABYTE", "GA-6BXC", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ClassValue=Motherboard&ProductID=1445&ProductName=GA-6BXC" }, - { "GIGABYTE", "GA-6BXDU", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1429" }, - { "GIGABYTE", "GA-6ZMA", "http://www.gigabyte.de/Support/Motherboard/BIOS_Model.aspx?ProductID=3289" }, - { "GIGABYTE", "GA-EX58-UD4P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2986" }, - { "GIGABYTE", "GA-EP35-DS3L", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2778" }, - { "GIGABYTE", "GA-MA790GP-DS4H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2887" }, - { "GIGABYTE", "GA-MA78GPM-DS2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2859" }, - { "GIGABYTE", "GA-MA770T-UD3P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=3096" }, - { "Intel", "EP80759", NULL }, - { "Jetway", "J7F4K1G5D-PB", "http://www.jetway.com.tw/jetway/system/productshow2.asp?id=389&proname=J7F4K1G5D-P" }, - { "MSI", "MS-6153", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=336" }, - { "MSI", "MS-6156", "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm" }, - { "MSI", "MS-6570 (K7N2)", "http://www.msi-computer.de/index.php?func=proddesc&prod_no=519&maincat_no=1" }, - { "MSI", "MS-7065", "http://browse.geekbench.ca/geekbench2/view/53114" }, - { "MSI", "MS-7168 (Orion)", "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart" }, - { "MSI", "MS-7236 (945PL Neo3)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1173" }, - { "MSI", "MS-7255 (P4M890M)", "http://www.tcsbahamas.com/P4M89.htm" }, - { "MSI", "MS-7345 (P35 Neo2-FIR)","http://www.msi.com/index.php?func=prodcpusupport&maincat_no=1&cat2_no=170&cat3_no=&prod_no=1261" }, - { "MSI", "MS-7368 (K9AG Neo2-Digital)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1241" }, - { "NEC", "PowerMate 2000", "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/" }, - { "PC Engines", "Alix.1c", "http://pcengines.ch/alix1c.htm" }, - { "PC Engines", "Alix.2c2", "http://pcengines.ch/alix2c2.htm" }, - { "PC Engines", "Alix.2c3", "http://pcengines.ch/alix2c3.htm" }, - { "PC Engines", "Alix.3c3", "http://pcengines.ch/alix3c3.htm" }, - { "PC Engines", "Alix.3d3", "http://pcengines.ch/alix3d3.htm" }, - { "RCA", "RM4100", "http://www.settoplinux.org/index.php?title=RCA_RM4100" }, - { "Sun", "Blade x6250", "http://www.sun.com/servers/blades/x6250/" }, - { "Supermicro", "H8QC8", "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm" }, - { "Thomson", "IP1000", "http://www.settoplinux.org/index.php?title=Thomson_IP1000" }, - { "TriGem", "Lomita", "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml" }, - { "T-Online", "S-100", "http://wiki.freifunk-hannover.de/T-Online_S_100" }, - { "Tyan", "iS5375-1U", "http://www.tyan.com/product_board_detail.aspx?pid=610" }, - { "Tyan", "S1846", "http://www.tyan.com/archive/products/html/tsunamiatx.html" }, - { "Tyan", "S2466", "http://www.tyan.com/product_board_detail.aspx?pid=461" }, - { "Tyan", "S2881", "http://www.tyan.com/product_board_detail.aspx?pid=115" }, - { "Tyan", "S2882", "http://www.tyan.com/product_board_detail.aspx?pid=121" }, - { "Tyan", "S2882-D", "http://www.tyan.com/product_board_detail.aspx?pid=127" }, - { "Tyan", "S2891", "http://www.tyan.com/product_board_detail.aspx?pid=144" }, - { "Tyan", "S2892", "http://www.tyan.com/product_board_detail.aspx?pid=145" }, - { "Tyan", "S2895", "http://www.tyan.com/archive/products/html/thunderk8we.html" }, - { "Tyan", "S3095", "http://www.tyan.com/product_board_detail.aspx?pid=181" }, - { "Tyan", "S5180", "http://www.tyan.com/product_board_detail.aspx?pid=456" }, - { "Tyan", "S5191", "http://www.tyan.com/product_board_detail.aspx?pid=343" }, - { "Tyan", "S5197", "http://www.tyan.com/product_board_detail.aspx?pid=349" }, - { "Tyan", "S5211", "http://www.tyan.com/product_board_detail.aspx?pid=591" }, - { "Tyan", "S5211-1U", "http://www.tyan.com/product_board_detail.aspx?pid=593" }, - { "Tyan", "S5220", "http://www.tyan.com/product_board_detail.aspx?pid=597" }, - { "Tyan", "S5375", "http://www.tyan.com/product_board_detail.aspx?pid=566" }, - { "Tyan", "S5376G2NR/S5376WAG2NR","http://www.tyan.com/product_board_detail.aspx?pid=605" }, - { "Tyan", "S5377", "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017" }, - { "Tyan", "S5397", "http://www.tyan.com/product_board_detail.aspx?pid=560" }, - { "VIA", "EPIA-EX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450" }, - { "VIA", "EPIA-LN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473" }, - { "VIA", "EPIA-M700", "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700" }, - { "VIA", "EPIA-NX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470" }, - { "VIA", "NAB74X0", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590" }, - { "VIA", "pc2500e", "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp" }, - { "VIA", "VB700X", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490" }, - - /* Verified working boards that DO need write-enables. */ - { "Abit", "IP35", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=LGA775&pMODEL_NAME=IP35" }, - { "Acorp", "6A815EPD", "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp" }, - { "agami", "Aruma", "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series" }, - { "Albatron", "PM266A Pro", "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56" }, /* FIXME */ - { "AOpen", "vKM400Am-S", "http://usa.aopen.com/products_detail.aspx?Auno=824" }, - { "Artec Group", "DBE61", "http://wiki.thincan.org/DBE61" }, - { "Artec Group", "DBE62", "http://wiki.thincan.org/DBE62" }, - { "ASUS", "A7V600-X", "http://www.asus.com/product.aspx?P_ID=L2XYS0rmtCjeOr4k" }, - { "ASUS", "A7V8X", "http://www.asus.com/product.aspx?P_ID=qfpaGrAy2kLVo0f2" }, - { "ASUS", "A7V8X-MX SE", "http://www.asus.com/product.aspx?P_ID=1guVBT1qV5oqhHyZ" }, - { "ASUS", "P4B266", "http://www.ciao.co.uk/ASUS_Intel_845D_Chipset_P4B266__5409807#productdetail" }, - { "ASUS", "P4P800-E Deluxe", "http://www.asus.com/product.aspx?P_ID=INIJUvLlif7LHp3g" }, - { "ASUS", "P5ND2-SLI Deluxe", "http://www.asus.com/product.aspx?P_ID=WY7XroDuUImVbgp5" }, - { "ASUS", "P5A", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/" }, - { "Biostar", "P4M80-M4", "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4" }, - { "Dell", "PowerEdge 1850", "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm" }, - { "Elitegroup", "K7VTA3", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" }, - { "EPoX", "EP-8K5A2", "http://www.epox.com/product.asp?ID=EP-8K5A2" }, - { "EPoX", "EP-8RDA3+", "http://www.epox.com/product.asp?ID=EP-8RDA3plus" }, - { "EPoX", "EP-BX3", "http://www.epox.com/product.asp?ID=EP-BX3" }, - { "GIGABYTE", "GA-2761GXDK", "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/" }, - { "GIGABYTE", "GA-7VT600", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1666" }, - { "GIGABYTE", "GA-7ZM", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1366" }, - { "GIGABYTE", "GA-K8N-SLI", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1928" }, - { "GIGABYTE", "GA-M57SLI-S4", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2287&ModelName=GA-M57SLI-S4" }, - { "GIGABYTE", "GA-M61P-S3", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2434" }, - { "GIGABYTE", "GA-MA78G-DS3H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2800" }, /* TODO: Rev 1.x or 2.x? */ - { "GIGABYTE", "GA-MA78GM-S2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2758" }, /* TODO: Rev. 1.0, 1.1, or 2.x? */ - { "GIGABYTE", "GA-MA790FX-DQ6", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2690" }, - { "HP", "DL145 G3", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351" }, - { "IBM", "x3455", "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html" }, - { "Intel", "D201GLY", "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm" }, - { "IWILL", "DK8-HTX", "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98" }, - { "Kontron", "986LCD-M", "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html" }, - { "Mitac", "6513WU", "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm" }, - { "MSI", "MS-6590 (KT4 Ultra)", "http://www.msicomputer.com/product/p_spec.asp?model=KT4_Ultra&class=mb" }, - { "MSI", "MS-6702E (K8T Neo2-F)","http://www.msicomputer.com/product/p_spec.asp?model=K8T_Neo2-F&class=mb" }, - { "MSI", "MS-6712 (KT4V)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=505" }, - { "MSI", "MS-7046", "http://www.heimir.de/ms7046/" }, - { "MSI", "MS-7135 (K8N Neo3)", "http://www.msi-computer.de/index.php?func=proddesc&prod_no=170&maincat_no=1" }, - { "Shuttle", "AK38N", "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/" }, - { "Soyo", "SY-7VCA", "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html" }, - { "Tyan", "S2498 (Tomcat K7M)", "http://www.tyan.com/archive/products/html/tomcatk7m.html" }, - { "VIA", "EPIA-CN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400" }, - { "VIA", "EPIA M/MII/...", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202" }, /* EPIA-MII link for now */ - { "VIA", "EPIA-N/NL", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221" }, /* EPIA-N link for now */ - { "VIA", "EPIA SP", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261" }, - { "VIA", "PC3500G", "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp" }, - - /* Verified non-working boards (for now). */ - { "Abit", "IS-10", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?pMODEL_NAME=IS-10&fMTYPE=Socket+478" }, - { "ASRock", "K7VT4A+", "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%%2b&s=" }, - { "ASUS", "MEW-AM", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/" }, - { "ASUS", "MEW-VM", "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm" }, - { "ASUS", "P3B-F", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/" }, - { "ASUS", "P5B", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/" }, - { "ASUS", "P5BV-M", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/" }, - { "Biostar", "M6TBA", "ftp://ftp.biostar-usa.com/manuals/M6TBA/" }, - { "Boser", "HS-6637", "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf" }, - { "DFI", "855GME-MGF", "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433" }, - { "FIC", "VA-502", "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/" }, - { "MSI", "MS-6178", "http://www.msi-technology.de/index.php?func=proddesc&prod_no=343&maincat_no=1" }, - { "MSI", "MS-7260 (K9N Neo)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=255" }, - { "Soyo", "SY-5VD", "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English" }, - { "Sun", "Fire x4540", "http://www.sun.com/servers/x64/x4540/" }, - { "Sun", "Fire x4150", "http://www.sun.com/servers/x64/x4150/" }, - { "Sun", "Fire x4200", "http://www.sun.com/servers/entry/x4200/" }, - { "Sun", "Fire x4600", "http://www.sun.com/servers/x64/x4600/" }, - - /* Verified working laptops. */ - { "Lenovo", "3000 V100 TF05Cxx", "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop" }, - - /* Verified non-working laptops (for now). */ - { "Acer", "Aspire One", NULL }, - { "ASUS", "Eee PC 701 4G", "http://www.asus.com/product.aspx?P_ID=h6SPd3tEzLEsrEiS" }, - { "Dell", "Latitude CPi A366XT", "http://www.coreboot.org/Dell_Latitude_CPi_A366XT" }, - { "HP/Compaq", "nx9010", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514" }, - { "IBM/Lenovo", "Thinkpad T40p", "http://www.thinkwiki.org/wiki/Category:T40p" }, - { "IBM/Lenovo", "240", "http://www.stanford.edu/~bresnan//tp240.html" }, - - { NULL, NULL, 0 }, -}; - -/* Please keep these lists alphabetically ordered by vendor/board. */ -const struct board_info_notes boards_notes[] = { - /* Verified working boards that don't need write-enables. */ - { "ASI", "MB-5BLMP", "Used in the IGEL WinNET III thin client." }, - { "ASRock", "K8S8X", "The Super I/O isn't found on this board. See http://www.flashrom.org/pipermail/flashrom/2009-November/000937.html." }, - { "ASUS", "A8V-E SE", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html." }, - { "ASUS", "M2A-VM", "See http://www.coreboot.org/pipermail/coreboot/2007-September/025281.html." }, - { "BCOM", "WinNET100", "Used in the IGEL-316 thin client." }, - { "GIGABYTE", "GA-7ZM", "Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option." }, - { "ASUS", "M2N-E", "If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See http://www.flashrom.org/pipermail/flashrom/2009-November/000879.html" }, - - /* Verified working boards that DO need write-enables. */ - { "Acer", "Aspire One", "See http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html." }, - - /* Verified non-working boards (for now). */ - { "MSI", "MS-6178", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot." }, - { "MSI", "MS-7260 (K9N Neo)", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot." }, - - /* Verified working laptops. */ - /* None which need comments, yet... */ - - /* Verified non-working laptops (for now). */ - { "Acer", "Aspire One", "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html" }, - { "ASUS", "Eee PC 701 4G", "It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)." }, - { "Dell", "Latitude CPi A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop." }, - { "HP/Compaq", "nx9010", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)." }, - { "IBM/Lenovo", "Thinkpad T40p", "Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later." }, - - { NULL, NULL, 0 }, -}; - -static int url(const char *vendor, const char *board) -{ - int i; - const struct board_info_url *b = boards_url; - - for (i = 0; b[i].vendor != NULL; i++) { - if (!strcmp(vendor, b[i].vendor) && !strcmp(board, b[i].name)) - return i; - } - - return -1; -} - -static int note(const char *vendor, const char *board) -{ - int i; - const struct board_info_notes *n = boards_notes; - - for (i = 0; n[i].vendor != NULL; i++) { - if (!strcmp(vendor, n[i].vendor) && !strcmp(board, n[i].name)) - return i; - } - - return -1; -} - -void print_supported_chipsets_wiki(void) -{ - int i, j, enablescount = 0, color = 1; - const struct penable *e; - - for (e = chipset_enables; e->vendor_name != NULL; e++) - enablescount++; - - printf("\n== Supported chipsets ==\n\nTotal amount of supported " - "chipsets: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n| " - "valign=\"top\"|\n\n%s", enablescount, chipset_th); - - e = chipset_enables; - for (i = 0, j = 0; e[i].vendor_name != NULL; i++, j++) { - /* Alternate colors if the vendor changes. */ - if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name)) - color = !color; - - printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s " - "|| %04x:%04x || %s\n", (color) ? "eeeeee" : "dddddd", - e[i].vendor_name, e[i].device_name, - e[i].vendor_id, e[i].device_id, - (e[i].status == OK) ? "{{OK}}" : "?"); - - /* Split table in three columns. */ - if (j >= (enablescount / 3 + 1)) { - printf("\n|}\n\n| valign=\"top\"|\n\n%s", chipset_th); - j = 0; - } - } - - printf("\n|}\n\n|}\n"); -} - -static void wiki_helper(const char *heading, const char *status, - int cols, const struct board_info boards[]) -{ - int i, j, k, c, boardcount = 0, color = 1, num_notes = 0; - const struct board_info *b; - const struct board_info_url *u = boards_url; - char *notes = calloc(1, 1); - char tmp[900 + 1]; - - for (b = boards; b->vendor != NULL; b++) - boardcount++; - - printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" - "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", - heading, boardcount, board_th); - - for (i = 0, j = 0, b = boards; b[i].vendor != NULL; i++, j++) { - /* Alternate colors if the vendor changes. */ - if (i > 0 && strcmp(b[i].vendor, b[i - 1].vendor)) - color = !color; - - k = url(b[i].vendor, b[i].name); - c = note(b[i].vendor, b[i].name); - - printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s ||" - " {{%s}}", (color) ? "eeeeee" : "dddddd", b[i].vendor, - (k != -1 && u[k].url) ? "[" : "", - (k != -1 && u[k].url) ? u[k].url : "", - b[i].name, (k != -1 && u[k].url) ? "]" : "", status); - - if (c != -1) { - printf("%d\n", num_notes + 1); - snprintf((char *)&tmp, 900, "%d %s
\n", - 1 + num_notes++, boards_notes[c].note); - notes = strcat_realloc(notes, (char *)&tmp); - } else { - printf("\n"); - } - - /* Split table in 'cols' columns. */ - if (j >= (boardcount / cols + 1)) { - printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th); - j = 0; - } - } - - printf("\n|}\n\n|}\n"); - - if (num_notes > 0) - printf("\n\n%s\n", notes); - free(notes); -} - -static void wiki_helper2(const char *heading, int cols) -{ - int i, j, k, boardcount = 0, color = 1; - struct board_pciid_enable *b; - const struct board_info_url *u = boards_url; - - for (b = board_pciid_enables; b->vendor_name != NULL; b++) - boardcount++; - - printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" - "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", - heading, boardcount, board_th2); - - b = board_pciid_enables; - for (i = 0, j = 0; b[i].vendor_name != NULL; i++, j++) { - /* Alternate colors if the vendor changes. */ - if (i > 0 && strcmp(b[i].vendor_name, b[i - 1].vendor_name)) - color = !color; - - k = url(b[i].vendor_name, b[i].board_name); - - printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s " - "|| %s%s%s%s || {{OK}}\n", (color) ? "eeeeee" : "dddddd", - b[i].vendor_name, (k != -1 && u[k].url) ? "[" : "", - (k != -1 && u[k].url) ? u[k].url : "", b[i].board_name, - (k != -1 && u[k].url) ? "]" : "", - (b[i].lb_vendor) ? "-m " : "—", - (b[i].lb_vendor) ? b[i].lb_vendor : "", - (b[i].lb_vendor) ? ":" : "", - (b[i].lb_vendor) ? b[i].lb_part : ""); - - /* Split table in three columns. */ - if (j >= (boardcount / cols + 1)) { - printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th2); - j = 0; - } - } - - printf("\n|}\n\n|}\n"); -} - -void print_supported_boards_wiki(void) -{ - printf("%s", board_intro); - wiki_helper("Known good (worked out of the box)", "OK", 3, boards_ok); - wiki_helper2("Known good (with write-enable code in flashrom)", 3); - wiki_helper("Not supported (yet)", "No", 3, boards_bad); - - printf("%s", laptop_intro); - wiki_helper("Known good (worked out of the box)", "OK", 1, laptops_ok); - wiki_helper("Not supported (yet)", "No", 1, laptops_bad); -} - -void print_supported_chips_wiki(void) -{ - int i = 0, c = 1, chipcount = 0; - struct flashchip *f, *old = NULL; - uint32_t t; - - for (f = flashchips; f->name != NULL; f++) - chipcount++; - - printf("\n== Supported chips ==\n\nTotal amount of supported " - "chips: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n" - "| valign=\"top\"|\n\n%s", chipcount, chip_th); - - for (f = flashchips; f->name != NULL; f++, i++) { - /* Don't print "unknown XXXX SPI chip" entries. */ - if (!strncmp(f->name, "unknown", 7)) - continue; - - /* Alternate colors if the vendor changes. */ - if (old != NULL && strcmp(old->vendor, f->vendor)) - c = !c; - - t = f->tested; - printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || %d " - "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}\n", - (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name, - f->total_size, flashbuses_to_text(f->bustype), - (t & TEST_OK_PROBE) ? "OK" : - (t & TEST_BAD_PROBE) ? "No" : ((c) ? "?2" : "?"), - (t & TEST_OK_READ) ? "OK" : - (t & TEST_BAD_READ) ? "No" : ((c) ? "?2" : "?"), - (t & TEST_OK_ERASE) ? "OK" : - (t & TEST_BAD_ERASE) ? "No" : ((c) ? "?2" : "?"), - (t & TEST_OK_WRITE) ? "OK" : - (t & TEST_BAD_WRITE) ? "No" : ((c) ? "?2" : "?")); - - /* Split table into three columns. */ - if (i >= (chipcount / 3 + 1)) { - printf("\n|}\n\n| valign=\"top\"|\n\n%s", chip_th); - i = 0; - } - - old = f; - } - - printf("\n|}\n\n|}\n"); -} - -void print_supported_pcidevs_wiki(struct pcidev_status *devs) -{ - int i = 0; - static int c = 0; - - /* Alternate colors if the vendor changes. */ - c = !c; - - for (i = 0; devs[i].vendor_name != NULL; i++) { - printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || " - "%04x:%04x || {{%s}}\n", (c) ? "eeeeee" : "dddddd", - devs[i].vendor_name, devs[i].device_name, - devs[i].vendor_id, devs[i].device_id, - (devs[i].status == PCI_NT) ? (c) ? "?2" : "?" : "OK"); - } -} - -void print_supported_wiki(void) -{ - time_t t = time(NULL); - - printf(wiki_header, ctime(&t), flashrom_version); - print_supported_chips_wiki(); - print_supported_chipsets_wiki(); - print_supported_boards_wiki(); - printf("%s", programmer_section); -#if NIC3COM_SUPPORT == 1 - print_supported_pcidevs_wiki(nics_3com); -#endif -#if GFXNVIDIA_SUPPORT == 1 - print_supported_pcidevs_wiki(gfx_nvidia); -#endif -#if DRKAISER_SUPPORT == 1 - print_supported_pcidevs_wiki(drkaiser_pcidev); -#endif -#if SATASII_SUPPORT == 1 - print_supported_pcidevs_wiki(satas_sii); -#endif - printf("\n|}\n"); -} - diff --git a/satasii.c b/satasii.c deleted file mode 100644 index 79d4325..0000000 --- a/satasii.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Rudolf Marek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Datasheets can be found on http://www.siliconimage.com. Great thanks! */ - -#include -#include -#include "flash.h" - -#define PCI_VENDOR_ID_SII 0x1095 - -uint8_t *sii_bar; -uint16_t id; - -struct pcidev_status satas_sii[] = { - {0x1095, 0x0680, PCI_OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"}, - {0x1095, 0x3112, PCI_OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"}, - {0x1095, 0x3114, PCI_OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"}, - {0x1095, 0x3124, PCI_NT, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"}, - {0x1095, 0x3132, PCI_OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"}, - {0x1095, 0x3512, PCI_NT, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"}, - - {}, -}; - -int satasii_init(void) -{ - uint32_t addr; - uint16_t reg_offset; - - get_io_perms(); - - pcidev_init(PCI_VENDOR_ID_SII, PCI_BASE_ADDRESS_0, satas_sii, - programmer_param); - id = pcidev_dev->device_id; - - if ((id == 0x3132) || (id == 0x3124)) { - addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_0) & ~0x07; - reg_offset = 0x70; - } else { - addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_5) & ~0x07; - reg_offset = 0x50; - } - - sii_bar = physmap("SATA SIL registers", addr, 0x100) + reg_offset; - - /* Check if ROM cycle are OK. */ - if ((id != 0x0680) && (!(mmio_readl(sii_bar) & (1 << 26)))) - printf("Warning: Flash seems unconnected.\n"); - - buses_supported = CHIP_BUSTYPE_PARALLEL; - - return 0; -} - -int satasii_shutdown(void) -{ - free(programmer_param); - pci_cleanup(pacc); - release_io_perms(); - return 0; -} - -void satasii_chip_writeb(uint8_t val, chipaddr addr) -{ - uint32_t ctrl_reg, data_reg; - - while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ; - - /* Mask out unused/reserved bits, set writes and start transaction. */ - ctrl_reg &= 0xfcf80000; - ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff); - - data_reg = (mmio_readl((sii_bar + 4)) & ~0xff) | val; - mmio_writel(data_reg, (sii_bar + 4)); - mmio_writel(ctrl_reg, sii_bar); - - while (mmio_readl(sii_bar) & (1 << 25)) ; -} - -uint8_t satasii_chip_readb(const chipaddr addr) -{ - uint32_t ctrl_reg; - - while ((ctrl_reg = mmio_readl(sii_bar)) & (1 << 25)) ; - - /* Mask out unused/reserved bits, set reads and start transaction. */ - ctrl_reg &= 0xfcf80000; - ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff); - - mmio_writel(ctrl_reg, sii_bar); - - while (mmio_readl(sii_bar) & (1 << 25)) ; - - return (mmio_readl(sii_bar + 4)) & 0xff; -} diff --git a/sb600spi.c b/sb600spi.c deleted file mode 100644 index 87f1cc1..0000000 --- a/sb600spi.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Wang Qingpei - * Copyright (C) 2008 Joe Bao - * Copyright (C) 2008 Advanced Micro Devices, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "flash.h" -#include "spi.h" - -/* This struct is unused, but helps visualize the SB600 SPI BAR layout. - *struct sb600_spi_controller { - * unsigned int spi_cntrl0; / * 00h * / - * unsigned int restrictedcmd1; / * 04h * / - * unsigned int restrictedcmd2; / * 08h * / - * unsigned int spi_cntrl1; / * 0ch * / - * unsigned int spi_cmdvalue0; / * 10h * / - * unsigned int spi_cmdvalue1; / * 14h * / - * unsigned int spi_cmdvalue2; / * 18h * / - * unsigned int spi_fakeid; / * 1Ch * / - *}; - */ - -uint8_t *sb600_spibar = NULL; - -int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - /* Maximum read length is 8 bytes. */ - return spi_read_chunked(flash, buf, start, len, 8); -} - -/* FIXME: SB600 can write 5 bytes per transaction. */ -int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int result = 0; - - spi_disable_blockprotect(); - /* Erase first */ - printf("Erasing flash before programming... "); - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("done.\n"); - - printf("Programming flash"); - for (i = 0; i < total_size; i++, buf++) { - result = spi_nbyte_program(i, buf, 1); - if (result) { - fprintf(stderr, "Write error!\n"); - return result; - } - - /* wait program complete. */ - if (i % 0x8000 == 0) - printf("."); - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - ; - } - printf(" done.\n"); - return result; -} - -static void reset_internal_fifo_pointer(void) -{ - mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2); - - while (mmio_readb(sb600_spibar + 0xD) & 0x7) - printf("reset\n"); -} - -static void execute_command(void) -{ - mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2); - - while (mmio_readb(sb600_spibar + 2) & 1) - ; -} - -int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - int count; - /* First byte is cmd which can not being sent through FIFO. */ - unsigned char cmd = *writearr++; - unsigned int readoffby1; - - writecnt--; - - printf_debug("%s, cmd=%x, writecnt=%x, readcnt=%x\n", - __func__, cmd, writecnt, readcnt); - - if (readcnt > 8) { - printf("%s, SB600 SPI controller can not receive %d bytes, " - "it is limited to 8 bytes\n", __func__, readcnt); - return SPI_INVALID_LENGTH; - } - - if (writecnt > 8) { - printf("%s, SB600 SPI controller can not send %d bytes, " - "it is limited to 8 bytes\n", __func__, writecnt); - return SPI_INVALID_LENGTH; - } - - /* This is a workaround for a bug in SB600 and SB700. If we only send - * an opcode and no additional data/address, the SPI controller will - * read one byte too few from the chip. Basically, the last byte of - * the chip response is discarded and will not end up in the FIFO. - * It is unclear if the CS# line is set high too early as well. - */ - readoffby1 = (writecnt) ? 0 : 1; - mmio_writeb((readcnt + readoffby1) << 4 | (writecnt), sb600_spibar + 1); - mmio_writeb(cmd, sb600_spibar + 0); - - /* Before we use the FIFO, reset it first. */ - reset_internal_fifo_pointer(); - - /* Send the write byte to FIFO. */ - for (count = 0; count < writecnt; count++, writearr++) { - printf_debug(" [%x]", *writearr); - mmio_writeb(*writearr, sb600_spibar + 0xC); - } - printf_debug("\n"); - - /* - * We should send the data by sequence, which means we need to reset - * the FIFO pointer to the first byte we want to send. - */ - reset_internal_fifo_pointer(); - - execute_command(); - - /* - * After the command executed, we should find out the index of the - * received byte. Here we just reset the FIFO pointer and skip the - * writecnt. - * It would be possible to increase the FIFO pointer by one instead - * of reading and discarding one byte from the FIFO. - * The FIFO is implemented on top of an 8 byte ring buffer and the - * buffer is never cleared. For every byte that is shifted out after - * the opcode, the FIFO already stores the response from the chip. - * Usually, the chip will respond with 0x00 or 0xff. - */ - reset_internal_fifo_pointer(); - - /* Skip the bytes we sent. */ - for (count = 0; count < writecnt; count++) { - cmd = mmio_readb(sb600_spibar + 0xC); - printf_debug("[ %2x]", cmd); - } - - printf_debug("The FIFO pointer after skipping is %d.\n", - mmio_readb(sb600_spibar + 0xd) & 0x07); - for (count = 0; count < readcnt; count++, readarr++) { - *readarr = mmio_readb(sb600_spibar + 0xC); - printf_debug("[%02x]", *readarr); - } - printf_debug("\n"); - - return 0; -} diff --git a/serial.c b/serial.c deleted file mode 100644 index e22a8fa..0000000 --- a/serial.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Urja Rannikko - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" -#include -#include -#include -#include -#include -#include -#include -#include - -int sp_fd; - -void __attribute__((noreturn)) sp_die(char *msg) -{ - perror(msg); - exit(1); -} - -struct baudentry { - int flag; - unsigned int baud; -}; - -/* I'd like if the C preprocessor could have directives in macros */ -#define BAUDENTRY(baud) { B##baud, baud }, -static const struct baudentry sp_baudtable[] = { - BAUDENTRY(9600) - BAUDENTRY(19200) - BAUDENTRY(38400) - BAUDENTRY(57600) - BAUDENTRY(115200) -#ifdef B230400 - BAUDENTRY(230400) -#endif -#ifdef B460800 - BAUDENTRY(460800) -#endif -#ifdef B500000 - BAUDENTRY(500000) -#endif -#ifdef B576000 - BAUDENTRY(576000) -#endif -#ifdef B921600 - BAUDENTRY(921600) -#endif -#ifdef B1000000 - BAUDENTRY(1000000) -#endif -#ifdef B1152000 - BAUDENTRY(1152000) -#endif -#ifdef B1500000 - BAUDENTRY(1500000) -#endif -#ifdef B2000000 - BAUDENTRY(2000000) -#endif -#ifdef B2500000 - BAUDENTRY(2500000) -#endif -#ifdef B3000000 - BAUDENTRY(3000000) -#endif -#ifdef B3500000 - BAUDENTRY(3500000) -#endif -#ifdef B4000000 - BAUDENTRY(4000000) -#endif - {0, 0} /* Terminator */ -}; - -int sp_openserport(char *dev, unsigned int baud) -{ - struct termios options; - int fd, i; - fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); - if (fd < 0) - sp_die("Error: cannot open serial port"); - fcntl(fd, F_SETFL, 0); - tcgetattr(fd, &options); - for (i = 0;; i++) { - if (sp_baudtable[i].baud == 0) { - close(fd); - fprintf(stderr, - "Error: cannot configure for baudrate %d\n", - baud); - exit(1); - } - if (sp_baudtable[i].baud == baud) { - cfsetispeed(&options, sp_baudtable[i].flag); - cfsetospeed(&options, sp_baudtable[i].flag); - break; - } - } - options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); - options.c_cflag |= (CS8 | CLOCAL | CREAD); - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR); - options.c_oflag &= ~OPOST; - tcsetattr(fd, TCSANOW, &options); - return fd; -} - -void sp_flush_incoming(void) -{ - int i; - for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */ - unsigned char flush[16]; - ssize_t rv; - rv = read(sp_fd, flush, sizeof(flush)); - if ((rv == -1) && (errno == EAGAIN)) - break; - if (rv == -1) - sp_die("flush read"); - } - return; -} diff --git a/serprog-protocol.txt b/serprog-protocol.txt deleted file mode 100644 index 0d389e6..0000000 --- a/serprog-protocol.txt +++ /dev/null @@ -1,101 +0,0 @@ -Serial Flasher Protocol Specification - version 1 (0x01 return value == 1) - -Command And Answer Sequence - all commands give an answer. -PC: COMMAND(8bit) -DEV: ACK/NAK(8bit) / nothing -Command 0x10 (SYNCNOP) has a special return of NAK+ACK for synchronization. - -ACK = 0x06 -NAK = 0x15 - -All multibyte values are little-endian. Addresses and lengths are 24-bit. - -COMMAND Description Parameters Return Value -0x00 NOP none ACK -0x01 Query programmer iface version none ACK + 16bit version (nonzero) -0x02 Query supported commands bitmap none ACK + 32 bytes (256 bits) of supported cmds flags -0x03 Query programmer name none ACK + 16 bytes string (null padding) / NAK -0x04 Query serial buffer size none ACK + 16bit size / NAK -0x05 Query supported bustypes none ACK + 8-bit flags (as per flashrom) / NAK -0x06 Query connected address lines none ACK + 8bit line count / NAK -0x07 Query operation buffer size none ACK + 16bit size / NAK -0x08 Query write-n maximum data len none ACK + 24bit maximum length / NAK -0x09 Read byte 24-bit addr ACK + BYTE / NAK -0x0A Read n bytes 24-bit addr + 24-bit length ACK + length bytes / NAK -0x0B Initialize operation buffer none ACK / NAK -0x0C Write to opbuf: Write byte 24-bit addr + 8-bit byte ACK / NAK (NOTE: takes 5 bytes in opbuf) -0x0D Write to opbuf: Write n 24-bit length + 24-bit addr + ACK / NAK (NOTE: takes 7+n bytes in opbuf) - + length bytes of data -0x0E Write to opbuf: delay 32-bit usecs ACK / NAK (NOTE: takes 5 bytes in opbuf) -0x0F Execute operation buffer none ACK / NAK -0x10 Sync NOP none NAK + ACK (for synchronization) -0x11 Query maximum read-n length none ACK + 24-bit length (0==2^24) / NAK -0x12 Set used bustype 8-bit flags (as with 0x05) ACK / NAK -0x?? unimplemented command - invalid. - - -Additional information of the above commands: - About unimplemented commands / startup sequence: - Only commands allowed to be used without checking anything are 0x00,0x10 and 0x01 (NOP,SYNCNOP,Q_IFACE). - If 0x01 doesn't return 1, dont do anything if you dont support a newer protocol. - Then, check support for any other opcode (except 0x02) by using 0x02 (Q_CMDMAP). - 0x02 (Q_CMDMAP): - The map's bits are mapped as follows: - cmd 0 support: byte 0 bit 0 - cmd 1 support: byte 0 bit 1 - cmd 7 support: byte 0 bit 7 - cmd 8 support: byte 1 bit 0, and so on. - 0x04 (Q_SERBUF): - If the programmer has guaranteedly working flow control, - it should return a big bogus value - eg 0xFFFF. - 0x05 (Q_BUSTYPE): - The bit's are defined as follows: - bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported). - 0x06 (Q_CHIPSIZE): - Only applicable to parallel programmers. - An LPC/FHW/SPI-programmer can report this as not supported in the command bitmap. - 0x08 (Q_WRNMAXLEN): - If a programmer reports a bigger maximum write-n length than the serial buffer size, - it is assumed that the programmer can process the data fast enough to take in the - reported maximum write-n without problems. - 0x0F (O_EXEC): - Execute operation buffer will also clear it, regardless of the return value. - 0x11 (Q_RDNMAXLEN): - If this command is not supported, assume return of 0 (2^24). - 0x12 (S_BUSTYPE): - Set's the used bustype if the programmer can support more than one flash protocol. - Sending a byte with more than 1 bit set will make the programmer decide among them - on it's own. Bit values as with Q_BUSTYPE. - About mandatory commands: - The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10, - but one can't really do anything with these commands. - Support for the following commands is necessary for flashrom to operate properly: - S_CMD_Q_SERBUF, S_CMD_Q_OPBUF, S_CMD_Q_WRNMAXLEN, S_CMD_R_BYTE, - S_CMD_R_NBYTES, S_CMD_O_INIT, S_CMD_O_WRITEB, S_CMD_O_WRITEN, - S_CMD_O_DELAY, S_CMD_O_EXEC. - In addition, support for these commands is recommended: - S_CMD_Q_PGMNAME, S_CMD_Q_BUSTYPE, S_CMD_Q_CHIPSIZE (if parallel). - - -This define listing should help C coders - (it's here to be the single source for copying - will be a .h someday i think) -#define S_ACK 0x06 -#define S_NAK 0x15 -#define S_CMD_NOP 0x00 /* No operation */ -#define S_CMD_Q_IFACE 0x01 /* Query interface version */ -#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */ -#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */ -#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */ -#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */ -#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */ -#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */ -#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum lenght */ -#define S_CMD_R_BYTE 0x09 /* Read a single byte */ -#define S_CMD_R_NBYTES 0x0A /* Read n bytes */ -#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */ -#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */ -#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */ -#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */ -#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */ -#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */ -#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ -#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ diff --git a/serprog.c b/serprog.c deleted file mode 100644 index 6544245..0000000 --- a/serprog.c +++ /dev/null @@ -1,658 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2009 Urja Rannikko - * Copyright (C) 2009 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "flash.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MSGHEADER "serprog:" - -#define S_ACK 0x06 -#define S_NAK 0x15 -#define S_CMD_NOP 0x00 /* No operation */ -#define S_CMD_Q_IFACE 0x01 /* Query interface version */ -#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */ -#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */ -#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */ -#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */ -#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */ -#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */ -#define S_CMD_Q_WRNMAXLEN 0x08 /* Query opbuf-write-N maximum lenght */ -#define S_CMD_R_BYTE 0x09 /* Read a single byte */ -#define S_CMD_R_NBYTES 0x0A /* Read n bytes */ -#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */ -#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */ -#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */ -#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */ -#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */ -#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */ -#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ -#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ - -static uint16_t sp_device_serbuf_size = 16; -static uint16_t sp_device_opbuf_size = 300; -/* Bitmap of supported commands */ -static uint8_t sp_cmdmap[32]; - -/* sp_prev_was_write used to detect writes with continouous addresses - and combine them to write-n's */ -static int sp_prev_was_write = 0; -/* sp_write_n_addr used as the starting addr of the currently - combined write-n operation */ -static uint32_t sp_write_n_addr; -/* The maximum length of an write_n operation; 0 = write-n not supported */ -static uint32_t sp_max_write_n = 0; -/* The maximum length of a read_n operation; 0 = 2^24 */ -static uint32_t sp_max_read_n = 0; - -/* A malloc'd buffer for combining the operation's data - and a counter that tells how much data is there. */ -static uint8_t *sp_write_n_buf; -static uint32_t sp_write_n_bytes = 0; - -/* sp_streamed_* used for flow control checking */ -static int sp_streamed_transmit_ops = 0; -static int sp_streamed_transmit_bytes = 0; - -/* sp_opbuf_usage used for counting the amount of - on-device operation buffer used */ -static int sp_opbuf_usage = 0; -/* if true causes sp_docommand to automatically check - whether the command is supported before doing it */ -static int sp_check_avail_automatic = 0; - -static int sp_opensocket(char *ip, unsigned int port) -{ - int flag = 1; - struct hostent *hostPtr = NULL; - union { struct sockaddr_in si; struct sockaddr s; } sp = {}; - int sock; - printf_debug(MSGHEADER "IP %s port %d\n", ip, port); - sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) - sp_die("Error: serprog cannot open socket"); - hostPtr = gethostbyname(ip); - if (NULL == hostPtr) { - hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET); - if (NULL == hostPtr) - sp_die("Error: cannot resolve"); - } - sp.si.sin_family = AF_INET; - sp.si.sin_port = htons(port); - (void)memcpy(&sp.si.sin_addr, hostPtr->h_addr, hostPtr->h_length); - if (connect(sock, &sp.s, sizeof(sp.si)) < 0) { - close(sock); - sp_die("Error: serprog cannot connect"); - } - /* We are latency limited, and sometimes do write-write-read * - * (write-n) - so enable TCP_NODELAY. */ - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); - return sock; -} - -static int sp_sync_read_timeout(int loops) -{ - int i; - unsigned char c; - for (i = 0; i < loops; i++) { - ssize_t rv; - rv = read(sp_fd, &c, 1); - if (rv == 1) - return c; - if ((rv == -1) && (errno != EAGAIN)) - sp_die("read"); - usleep(10 * 1000); /* 10ms units */ - } - return -1; -} - -/* Synchronize: a bit tricky algorhytm that tries to (and in my tests has * - * always succeeded in) bring the serial protocol to known waiting-for- * - * command state - uses nonblocking read - rest of the driver uses * - * blocking read - TODO: add an alarm() timer for the rest of the app on * - * serial operations, though not such a big issue as the first thing to * - * do is synchronize (eg. check that device is alive). */ -static void sp_synchronize(void) -{ - int i; - int flags = fcntl(sp_fd, F_GETFL); - unsigned char buf[8]; - flags |= O_NONBLOCK; - fcntl(sp_fd, F_SETFL, flags); - /* First sends 8 NOPs, then flushes the return data - should cause * - * the device serial parser to get to a sane state, unless if it * - * is waiting for a real long write-n. */ - memset(buf, S_CMD_NOP, 8); - if (write(sp_fd, buf, 8) != 8) - sp_die("flush write"); - /* A second should be enough to get all the answers to the buffer */ - usleep(1000 * 1000); - sp_flush_incoming(); - - /* Then try upto 8 times to send syncnop and get the correct special * - * return of NAK+ACK. Timing note: upto 10 characters, 10*50ms = * - * upto 500ms per try, 8*0.5s = 4s; +1s (above) = upto 5s sync * - * attempt, ~1s if immediate success. */ - for (i = 0; i < 8; i++) { - int n; - unsigned char c = S_CMD_SYNCNOP; - if (write(sp_fd, &c, 1) != 1) - sp_die("sync write"); - printf_debug("."); - fflush(stdout); - for (n = 0; n < 10; n++) { - c = sp_sync_read_timeout(5); /* wait upto 50ms */ - if (c != S_NAK) - continue; - c = sp_sync_read_timeout(2); - if (c != S_ACK) - continue; - c = S_CMD_SYNCNOP; - if (write(sp_fd, &c, 1) != 1) - sp_die("sync write"); - c = sp_sync_read_timeout(50); - if (c != S_NAK) - break; /* fail */ - c = sp_sync_read_timeout(10); - if (c != S_ACK) - break; /* fail */ - /* Ok, synchronized; back to blocking reads and return. */ - flags &= ~O_NONBLOCK; - fcntl(sp_fd, F_SETFL, flags); - printf_debug("\n"); - return; - } - } - fprintf(stderr, - "Error: cannot synchronize protocol\n" - "- check communications and reset device?\n"); - exit(1); -} - -static int sp_check_commandavail(uint8_t command) -{ - int byteoffs, bitoffs; - byteoffs = command / 8; - bitoffs = command % 8; - return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0; -} - -static int sp_automatic_cmdcheck(uint8_t cmd) -{ - if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) { - printf_debug ("Warning: Automatic command availability check" - " failed for cmd %d - wont execute cmd\n",cmd); - return 1; - } - return 0; -} - -static int sp_docommand(uint8_t command, uint32_t parmlen, - uint8_t * params, uint32_t retlen, void *retparms) -{ - unsigned char *sendpacket; - unsigned char c; - if (sp_automatic_cmdcheck(command)) - return 1; - sendpacket = malloc(1 + parmlen); - if (!sendpacket) - sp_die("Error: cannot malloc command buffer"); - sendpacket[0] = command; - memcpy(&(sendpacket[1]), params, parmlen); - if (write(sp_fd, sendpacket, 1 + parmlen) != (1 + parmlen)) { - sp_die("Error: cannot write command"); - } - free(sendpacket); - if (read(sp_fd, &c, 1) != 1) - sp_die("Error: cannot read from device"); - if (c == S_NAK) return 1; - if (c != S_ACK) { - fprintf(stderr, - "Error: invalid response 0x%02X from device\n",c); - exit(1); - } - if (retlen) { - int rd_bytes = 0; - do { - int r; - r = read(sp_fd, retparms + rd_bytes, - retlen - rd_bytes); - if (r <= 0) sp_die - ("Error: cannot read return parameters"); - rd_bytes += r; - } while (rd_bytes != retlen); - } - return 0; -} - -static void sp_flush_stream(void) -{ - if (sp_streamed_transmit_ops) - do { - unsigned char c; - if (read(sp_fd, &c, 1) != 1) { - sp_die - ("Error: cannot read from device (flushing stream)"); - } - if (c == S_NAK) { - fprintf(stderr, - "Error: NAK to a stream buffer operation\n"); - exit(1); - } - if (c != S_ACK) { - fprintf(stderr, - "Error: Invalid reply 0x%02X from device\n", - c); - exit(1); - } - } while (--sp_streamed_transmit_ops); - sp_streamed_transmit_ops = 0; - sp_streamed_transmit_bytes = 0; -} - -static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms) -{ - uint8_t *sp; - if (sp_automatic_cmdcheck(cmd)) - return 1; - sp = malloc(1 + parmlen); - if (!sp) sp_die("Error: cannot malloc command buffer"); - sp[0] = cmd; - memcpy(&(sp[1]), parms, parmlen); - if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) - sp_flush_stream(); - if (write(sp_fd, sp, 1 + parmlen) != (1 + parmlen)) - sp_die("Error: cannot write command"); - free(sp); - sp_streamed_transmit_ops += 1; - sp_streamed_transmit_bytes += 1 + parmlen; - return 0; -} - -int serprog_init(void) -{ - uint16_t iface; - int len; - unsigned char pgmname[17]; - unsigned char rbuf[3]; - unsigned char c; - char *num; - char *dev; - printf_debug("%s\n", __func__); - /* the parameter is either of format "/dev/device:baud" or "ip:port" */ - if ((!programmer_param) || (!strlen(programmer_param))) { - nodevice: - fprintf(stderr, - "Error: No device/host given for the serial programmer driver.\n" - "Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n"); - exit(1); - } - num = strstr(programmer_param, ":"); - len = num - programmer_param; - if (!len) goto nodevice; - if (!num) { - fprintf(stderr, - "Error: No port or baudrate specified to serial programmer driver.\n" - "Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n"); - exit(1); - } - len = num - programmer_param; - dev = malloc(len + 1); - if (!dev) sp_die("Error: memory allocation failure"); - memcpy(dev, programmer_param, len); - dev[len] = 0; - num = strdup(num + 1); - if (!num) sp_die("Error: memory allocation failure"); - free(programmer_param); - programmer_param = NULL; - - if (dev[0] == '/') sp_fd = sp_openserport(dev, atoi(num)); - else sp_fd = sp_opensocket(dev, atoi(num)); - - free(dev); dev = NULL; - free(num); num = NULL; - - printf_debug(MSGHEADER "connected - attempting to synchronize\n"); - - sp_check_avail_automatic = 0; - - sp_synchronize(); - - printf_debug(MSGHEADER "Synchronized\n"); - - if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) { - fprintf(stderr, "Error: NAK to Query Interface version\n"); - exit(1); - } - - if (iface != 1) { - fprintf(stderr, "Error: Unknown interface version %d\n", iface); - exit(1); - } - - printf_debug(MSGHEADER "Interface version ok.\n"); - - if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) { - fprintf(stderr, "Error: query command map not supported\n"); - exit(1); - } - - sp_check_avail_automatic = 1; - - /* Check for the minimum operational set of commands */ - if (sp_check_commandavail(S_CMD_R_BYTE) == 0) { - fprintf(stderr, "Error: Single byte read not supported\n"); - exit(1); - } - /* This could be translated to single byte reads (if missing), * - * but now we dont support that. */ - if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) { - fprintf(stderr, "Error: Read n bytes not supported\n"); - exit(1); - } - /* In the future one could switch to read-only mode if these * - * are not available. */ - if (sp_check_commandavail(S_CMD_O_INIT) == 0) { - fprintf(stderr, - "Error: Initialize operation buffer not supported\n"); - exit(1); - } - if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) { - fprintf(stderr, - "Error: Write to opbuf: write byte not supported\n"); - exit(1); - } - if (sp_check_commandavail(S_CMD_O_DELAY) == 0) { - fprintf(stderr, "Error: Write to opbuf: delay not supported\n"); - exit(1); - } - if (sp_check_commandavail(S_CMD_O_EXEC) == 0) { - fprintf(stderr, - "Error: Execute operation buffer not supported\n"); - exit(1); - } - - if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) { - fprintf(stderr, "Warning: NAK to query programmer name\n"); - strcpy((char *)pgmname, "(unknown)"); - } - pgmname[16] = 0; - printf(MSGHEADER "Programmer name \"%s\"\n", pgmname); - - if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) { - fprintf(stderr, "Warning: NAK to query serial buffer size\n"); - } - printf_debug(MSGHEADER "serial buffer size %d\n", - sp_device_serbuf_size); - - if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) { - fprintf(stderr, - "Warning: NAK to query operation buffer size\n"); - } - printf_debug(MSGHEADER "operation buffer size %d\n", - sp_device_opbuf_size); - - if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) { - fprintf(stderr, "Warning: NAK to query supported buses\n"); - c = CHIP_BUSTYPE_NONSPI; /* A reasonable default for now. */ - } - buses_supported = c; - - if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) { - fprintf(stderr, "Error: NAK to initialize operation buffer\n"); - exit(1); - } - - if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) { - printf_debug(MSGHEADER "Write-n not supported"); - sp_max_write_n = 0; - } else { - sp_max_write_n = ((unsigned int)(rbuf[0]) << 0); - sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8); - sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16); - printf_debug(MSGHEADER "Maximum write-n length %d\n", - sp_max_write_n); - sp_write_n_buf = malloc(sp_max_write_n); - if (!sp_write_n_buf) { - fprintf(stderr, - "Error: cannot allocate memory for Write-n buffer\n"); - exit(1); - } - sp_write_n_bytes = 0; - } - - if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN)) - &&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) { - sp_max_read_n = ((unsigned int)(rbuf[0]) << 0); - sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8); - sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16); - printf_debug(MSGHEADER "Maximum read-n length %d\n", - sp_max_read_n ? sp_max_read_n : (1<<24)); - } else { - printf_debug(MSGHEADER "Maximum read-n length not reported\n"); - sp_max_read_n = 0; - } - - sp_prev_was_write = 0; - sp_streamed_transmit_ops = 0; - sp_streamed_transmit_bytes = 0; - sp_opbuf_usage = 0; - return 0; -} - -/* Move an in flashrom buffer existing write-n operation to * - * the on-device operation buffer. */ -static void sp_pass_writen(void) -{ - unsigned char header[7]; - printf_debug(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", - sp_write_n_bytes, sp_write_n_addr); - if (sp_streamed_transmit_bytes >= - (7 + sp_write_n_bytes + sp_device_serbuf_size)) - sp_flush_stream(); - /* In case it's just a single byte send it as a single write. */ - if (sp_write_n_bytes == 1) { - sp_write_n_bytes = 0; - header[0] = (sp_write_n_addr >> 0) & 0xFF; - header[1] = (sp_write_n_addr >> 8) & 0xFF; - header[2] = (sp_write_n_addr >> 16) & 0xFF; - header[3] = sp_write_n_buf[0]; - sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header); - sp_opbuf_usage += 5; - return; - } - header[0] = S_CMD_O_WRITEN; - header[1] = (sp_write_n_bytes >> 0) & 0xFF; - header[2] = (sp_write_n_bytes >> 8) & 0xFF; - header[3] = (sp_write_n_bytes >> 16) & 0xFF; - header[4] = (sp_write_n_addr >> 0) & 0xFF; - header[5] = (sp_write_n_addr >> 8) & 0xFF; - header[6] = (sp_write_n_addr >> 16) & 0xFF; - if (write(sp_fd, header, 7) != 7) - sp_die("Error: cannot write write-n command\n"); - if (write(sp_fd, sp_write_n_buf, sp_write_n_bytes) != - sp_write_n_bytes) - sp_die("Error: cannot write write-n data"); - sp_streamed_transmit_bytes += 7 + sp_write_n_bytes; - sp_streamed_transmit_ops += 1; - sp_opbuf_usage += 7 + sp_write_n_bytes; - sp_write_n_bytes = 0; - sp_prev_was_write = 0; -} - -static void sp_execute_opbuf_noflush(void) -{ - if ((sp_max_write_n) && (sp_write_n_bytes)) - sp_pass_writen(); - sp_stream_buffer_op(S_CMD_O_EXEC, 0, 0); - printf_debug(MSGHEADER "Executed operation buffer of %d bytes\n", - sp_opbuf_usage); - sp_opbuf_usage = 0; - sp_prev_was_write = 0; - return; -} - -static void sp_execute_opbuf(void) -{ - sp_execute_opbuf_noflush(); - sp_flush_stream(); -} - -int serprog_shutdown(void) -{ - printf_debug("%s\n", __func__); - if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) - sp_execute_opbuf(); - close(sp_fd); - if (sp_max_write_n) - free(sp_write_n_buf); - return 0; -} - -static void sp_check_opbuf_usage(int bytes_to_be_added) -{ - if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) { - sp_execute_opbuf(); - /* If this happens in the mid of an page load the page load * - * will propably fail. */ - printf_debug(MSGHEADER - "Warning: executed operation buffer due to size reasons\n"); - } -} - -void serprog_chip_writeb(uint8_t val, chipaddr addr) -{ - printf_debug("%s\n", __func__); - if (sp_max_write_n) { - if ((sp_prev_was_write) - && (addr == (sp_write_n_addr + sp_write_n_bytes))) { - sp_write_n_buf[sp_write_n_bytes++] = val; - } else { - if ((sp_prev_was_write) && (sp_write_n_bytes)) - sp_pass_writen(); - sp_prev_was_write = 1; - sp_write_n_addr = addr; - sp_write_n_bytes = 1; - sp_write_n_buf[0] = val; - } - sp_check_opbuf_usage(7 + sp_write_n_bytes); - if (sp_write_n_bytes >= sp_max_write_n) - sp_pass_writen(); - } else { - /* We will have to do single writeb ops. */ - unsigned char writeb_parm[4]; - sp_check_opbuf_usage(6); - writeb_parm[0] = (addr >> 0) & 0xFF; - writeb_parm[1] = (addr >> 8) & 0xFF; - writeb_parm[2] = (addr >> 16) & 0xFF; - writeb_parm[3] = val; - sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); - sp_opbuf_usage += 5; - } -} - -uint8_t serprog_chip_readb(const chipaddr addr) -{ - unsigned char c; - unsigned char buf[3]; - /* Will stream the read operation - eg. add it to the stream buffer, * - * then flush the buffer, then read the read answer. */ - if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) - sp_execute_opbuf_noflush(); - buf[0] = ((addr >> 0) & 0xFF); - buf[1] = ((addr >> 8) & 0xFF); - buf[2] = ((addr >> 16) & 0xFF); - sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); - sp_flush_stream(); - if (read(sp_fd, &c, 1) != 1) - sp_die("readb byteread"); - printf_debug("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c); - return c; -} - -/* Local version that really does the job, doesnt care of max_read_n. */ -static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) -{ - int rd_bytes = 0; - unsigned char sbuf[6]; - printf_debug("%s: addr=0x%lx len=%lu\n", __func__, addr, (unsigned long)len); - /* Stream the read-n -- as above. */ - if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) - sp_execute_opbuf_noflush(); - sbuf[0] = ((addr >> 0) & 0xFF); - sbuf[1] = ((addr >> 8) & 0xFF); - sbuf[2] = ((addr >> 16) & 0xFF); - sbuf[3] = ((len >> 0) & 0xFF); - sbuf[4] = ((len >> 8) & 0xFF); - sbuf[5] = ((len >> 16) & 0xFF); - sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf); - sp_flush_stream(); - do { - int r = read(sp_fd, buf + rd_bytes, len - rd_bytes); - if (r <= 0) - sp_die("Error: cannot read read-n data"); - rd_bytes += r; - } while (rd_bytes != len); - return; -} - -/* The externally called version that makes sure that max_read_n is obeyed. */ -void serprog_chip_readn(uint8_t * buf, const chipaddr addr, size_t len) -{ - size_t lenm = len; - chipaddr addrm = addr; - while ((sp_max_read_n)&&(lenm > sp_max_read_n)) { - sp_do_read_n(&(buf[addrm-addr]),addrm,sp_max_read_n); - addrm += sp_max_read_n; - lenm -= sp_max_read_n; - } - if (lenm) sp_do_read_n(&(buf[addrm-addr]),addrm,lenm); -} - -void serprog_delay(int delay) -{ - unsigned char buf[4]; - printf_debug("%s\n", __func__); - if ((sp_max_write_n) && (sp_write_n_bytes)) - sp_pass_writen(); - sp_check_opbuf_usage(5); - buf[0] = ((delay >> 0) & 0xFF); - buf[1] = ((delay >> 8) & 0xFF); - buf[2] = ((delay >> 16) & 0xFF); - buf[3] = ((delay >> 24) & 0xFF); - sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf); - sp_opbuf_usage += 5; - sp_prev_was_write = 0; -} diff --git a/sharplhf00l04.c b/sharplhf00l04.c deleted file mode 100644 index 1234ae4..0000000 --- a/sharplhf00l04.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "flash.h" - -// I need that Berkeley bit-map printer -void print_lhf00l04_status(uint8_t status) -{ - printf("%s", status & 0x80 ? "Ready:" : "Busy:"); - printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); - printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); - printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); - printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); - printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); - printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); -} - -int probe_lhf00l04(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - -#if 0 - /* Enter ID mode */ - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0x90, bios + 0x5555); -#endif - - chip_writeb(0xff, bios); - programmer_delay(10); - chip_writeb(0x90, bios); - programmer_delay(10); - - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - - /* Leave ID mode */ - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0xF0, bios + 0x5555); - - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 != flash->manufacture_id || id2 != flash->model_id) - return 0; - - map_flash_registers(flash); - - return 1; -} - -uint8_t wait_lhf00l04(chipaddr bios) -{ - uint8_t status; - - chip_writeb(0x70, bios); - if ((chip_readb(bios) & 0x80) == 0) { // it's busy - while ((chip_readb(bios) & 0x80) == 0) ; - } - - status = chip_readb(bios); - - // put another command to get out of status register mode. - - chip_writeb(0x90, bios); - programmer_delay(10); - - chip_readb(bios); // vendor ID - chip_readb(bios + 0x01); // device ID - - // this is needed to jam it out of "read id" mode - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0xF0, bios + 0x5555); - - return status; -} - -int erase_lhf00l04_block(struct flashchip *flash, int offset) -{ - chipaddr bios = flash->virtual_memory + offset; - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t status; - - // clear status register - chip_writeb(0x50, bios); - printf("Erase at 0x%lx\n", bios); - status = wait_lhf00l04(flash->virtual_memory); - print_lhf00l04_status(status); - // clear write protect - printf("write protect is at 0x%lx\n", (wrprotect)); - printf("write protect is 0x%x\n", chip_readb(wrprotect)); - chip_writeb(0, wrprotect); - printf("write protect is 0x%x\n", chip_readb(wrprotect)); - - // now start it - chip_writeb(0x20, bios); - chip_writeb(0xd0, bios); - programmer_delay(10); - // now let's see what the register is - status = wait_lhf00l04(flash->virtual_memory); - print_lhf00l04_status(status); - printf("DONE BLOCK 0x%x\n", offset); - - if (check_erased_range(flash, offset, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int erase_lhf00l04(struct flashchip *flash) -{ - int i; - unsigned int total_size = flash->total_size * 1024; - - printf("total_size is %d; flash->page_size is %d\n", - total_size, flash->page_size); - for (i = 0; i < total_size; i += flash->page_size) - if (erase_lhf00l04_block(flash, i)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("DONE ERASE\n"); - - return 0; -} - -void write_page_lhf00l04(chipaddr bios, uint8_t *src, - chipaddr dst, int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - /* transfer data from source to destination */ - chip_writeb(0x40, dst); - chip_writeb(*src++, dst++); - wait_lhf00l04(bios); - } -} - -int write_lhf00l04(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - if (erase_lhf00l04(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - printf("%04d at address: 0x%08x", i, i * page_size); - write_page_lhf00l04(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - return 0; -} diff --git a/spi.c b/spi.c deleted file mode 100644 index 14beed7..0000000 --- a/spi.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger - * Copyright (C) 2008 coresystems GmbH - * - * 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 - */ - -/* - * Contains the generic SPI framework - */ - -#include -#include "flash.h" -#include "flashchips.h" -#include "spi.h" - -enum spi_controller spi_controller = SPI_CONTROLLER_NONE; -void *spibar = NULL; - -void spi_prettyprint_status_register(struct flashchip *flash); - -const struct spi_programmer spi_programmer[] = { - { /* SPI_CONTROLLER_NONE */ - .command = NULL, - .multicommand = NULL, - .read = NULL, - .write_256 = NULL, - }, - - { /* SPI_CONTROLLER_ICH7 */ - .command = ich_spi_send_command, - .multicommand = ich_spi_send_multicommand, - .read = ich_spi_read, - .write_256 = ich_spi_write_256, - }, - - { /* SPI_CONTROLLER_ICH9 */ - .command = ich_spi_send_command, - .multicommand = ich_spi_send_multicommand, - .read = ich_spi_read, - .write_256 = ich_spi_write_256, - }, - - { /* SPI_CONTROLLER_IT87XX */ - .command = it8716f_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = it8716f_spi_chip_read, - .write_256 = it8716f_spi_chip_write_256, - }, - - { /* SPI_CONTROLLER_SB600 */ - .command = sb600_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = sb600_spi_read, - .write_256 = sb600_spi_write_1, - }, - - { /* SPI_CONTROLLER_VIA */ - .command = ich_spi_send_command, - .multicommand = ich_spi_send_multicommand, - .read = ich_spi_read, - .write_256 = ich_spi_write_256, - }, - - { /* SPI_CONTROLLER_WBSIO */ - .command = wbsio_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = wbsio_spi_read, - .write_256 = wbsio_spi_write_1, - }, - -#if FT2232_SPI_SUPPORT == 1 - { /* SPI_CONTROLLER_FT2232 */ - .command = ft2232_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = ft2232_spi_read, - .write_256 = ft2232_spi_write_256, - }, -#endif - -#if DUMMY_SUPPORT == 1 - { /* SPI_CONTROLLER_DUMMY */ - .command = dummy_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = NULL, - .write_256 = NULL, - }, -#endif - -#if BUSPIRATE_SPI_SUPPORT == 1 - { /* SPI_CONTROLLER_BUSPIRATE */ - .command = buspirate_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = buspirate_spi_read, - .write_256 = spi_chip_write_1, - }, -#endif - - {}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */ -}; - -const int spi_programmer_count = ARRAY_SIZE(spi_programmer); - -int spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - if (!spi_programmer[spi_controller].command) { - fprintf(stderr, "%s called, but SPI is unsupported on this " - "hardware. Please report a bug.\n", __func__); - return 1; - } - - return spi_programmer[spi_controller].command(writecnt, readcnt, - writearr, readarr); -} - -int spi_send_multicommand(struct spi_command *cmds) -{ - if (!spi_programmer[spi_controller].multicommand) { - fprintf(stderr, "%s called, but SPI is unsupported on this " - "hardware. Please report a bug.\n", __func__); - return 1; - } - - return spi_programmer[spi_controller].multicommand(cmds); -} - -int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - struct spi_command cmd[] = { - { - .writecnt = writecnt, - .readcnt = readcnt, - .writearr = writearr, - .readarr = readarr, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - return spi_send_multicommand(cmd); -} - -int default_spi_send_multicommand(struct spi_command *cmds) -{ - int result = 0; - for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) { - result = spi_send_command(cmds->writecnt, cmds->readcnt, - cmds->writearr, cmds->readarr); - } - return result; -} - -static int spi_rdid(unsigned char *readarr, int bytes) -{ - const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID }; - int ret; - int i; - - ret = spi_send_command(sizeof(cmd), bytes, cmd, readarr); - if (ret) - return ret; - printf_debug("RDID returned"); - for (i = 0; i < bytes; i++) - printf_debug(" 0x%02x", readarr[i]); - printf_debug(". "); - return 0; -} - -static int spi_rems(unsigned char *readarr) -{ - unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 }; - uint32_t readaddr; - int ret; - - ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); - if (ret == SPI_INVALID_ADDRESS) { - /* Find the lowest even address allowed for reads. */ - readaddr = (spi_get_valid_read_addr() + 1) & ~1; - cmd[1] = (readaddr >> 16) & 0xff, - cmd[2] = (readaddr >> 8) & 0xff, - cmd[3] = (readaddr >> 0) & 0xff, - ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); - } - if (ret) - return ret; - printf_debug("REMS returned %02x %02x. ", readarr[0], readarr[1]); - return 0; -} - -static int spi_res(unsigned char *readarr) -{ - unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 }; - uint32_t readaddr; - int ret; - - ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); - if (ret == SPI_INVALID_ADDRESS) { - /* Find the lowest even address allowed for reads. */ - readaddr = (spi_get_valid_read_addr() + 1) & ~1; - cmd[1] = (readaddr >> 16) & 0xff, - cmd[2] = (readaddr >> 8) & 0xff, - cmd[3] = (readaddr >> 0) & 0xff, - ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); - } - if (ret) - return ret; - printf_debug("RES returned %02x. ", readarr[0]); - return 0; -} - -int spi_write_enable(void) -{ - const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN }; - int result; - - /* Send WREN (Write Enable) */ - result = spi_send_command(sizeof(cmd), 0, cmd, NULL); - - if (result) - fprintf(stderr, "%s failed\n", __func__); - - return result; -} - -int spi_write_disable(void) -{ - const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI }; - - /* Send WRDI (Write Disable) */ - return spi_send_command(sizeof(cmd), 0, cmd, NULL); -} - -static int probe_spi_rdid_generic(struct flashchip *flash, int bytes) -{ - unsigned char readarr[4]; - uint32_t id1; - uint32_t id2; - - if (spi_rdid(readarr, bytes)) - return 0; - - if (!oddparity(readarr[0])) - printf_debug("RDID byte 0 parity violation. "); - - /* Check if this is a continuation vendor ID */ - if (readarr[0] == 0x7f) { - if (!oddparity(readarr[1])) - printf_debug("RDID byte 1 parity violation. "); - id1 = (readarr[0] << 8) | readarr[1]; - id2 = readarr[2]; - if (bytes > 3) { - id2 <<= 8; - id2 |= readarr[3]; - } - } else { - id1 = readarr[0]; - id2 = (readarr[1] << 8) | readarr[2]; - } - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) { - /* Print the status register to tell the - * user about possible write protection. - */ - spi_prettyprint_status_register(flash); - - return 1; - } - - /* Test if this is a pure vendor match. */ - if (id1 == flash->manufacture_id && - GENERIC_DEVICE_ID == flash->model_id) - return 1; - - /* Test if there is any vendor ID. */ - if (GENERIC_MANUF_ID == flash->manufacture_id && - id1 != 0xff) - return 1; - - return 0; -} - -int probe_spi_rdid(struct flashchip *flash) -{ - return probe_spi_rdid_generic(flash, 3); -} - -/* support 4 bytes flash ID */ -int probe_spi_rdid4(struct flashchip *flash) -{ - /* only some SPI chipsets support 4 bytes commands */ - switch (spi_controller) { - case SPI_CONTROLLER_ICH7: - case SPI_CONTROLLER_ICH9: - case SPI_CONTROLLER_VIA: - case SPI_CONTROLLER_SB600: - case SPI_CONTROLLER_WBSIO: -#if FT2232_SPI_SUPPORT == 1 - case SPI_CONTROLLER_FT2232: -#endif -#if DUMMY_SUPPORT == 1 - case SPI_CONTROLLER_DUMMY: -#endif -#if BUSPIRATE_SPI_SUPPORT == 1 - case SPI_CONTROLLER_BUSPIRATE: -#endif - return probe_spi_rdid_generic(flash, 4); - default: - printf_debug("4b ID not supported on this SPI controller\n"); - } - - return 0; -} - -int probe_spi_rems(struct flashchip *flash) -{ - unsigned char readarr[JEDEC_REMS_INSIZE]; - uint32_t id1, id2; - - if (spi_rems(readarr)) - return 0; - - id1 = readarr[0]; - id2 = readarr[1]; - - printf_debug("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) { - /* Print the status register to tell the - * user about possible write protection. - */ - spi_prettyprint_status_register(flash); - - return 1; - } - - /* Test if this is a pure vendor match. */ - if (id1 == flash->manufacture_id && - GENERIC_DEVICE_ID == flash->model_id) - return 1; - - /* Test if there is any vendor ID. */ - if (GENERIC_MANUF_ID == flash->manufacture_id && - id1 != 0xff) - return 1; - - return 0; -} - -int probe_spi_res(struct flashchip *flash) -{ - unsigned char readarr[3]; - uint32_t id2; - - /* Check if RDID was successful and did not return 0xff 0xff 0xff. - * In that case, RES is pointless. - */ - if (!spi_rdid(readarr, 3) && ((readarr[0] != 0xff) || - (readarr[1] != 0xff) || (readarr[2] != 0xff))) - return 0; - - if (spi_res(readarr)) - return 0; - - id2 = readarr[0]; - printf_debug("%s: id 0x%x\n", __func__, id2); - if (id2 != flash->model_id) - return 0; - - /* Print the status register to tell the - * user about possible write protection. - */ - spi_prettyprint_status_register(flash); - return 1; -} - -uint8_t spi_read_status_register(void) -{ - const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR }; - /* FIXME: No workarounds for driver/hardware bugs in generic code. */ - unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */ - int ret; - - /* Read Status Register */ - ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr); - if (ret) - fprintf(stderr, "RDSR failed!\n"); - - return readarr[0]; -} - -/* Prettyprint the status register. Common definitions. */ -void spi_prettyprint_status_register_common(uint8_t status) -{ - printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is " - "%sset\n", (status & (1 << 5)) ? "" : "not "); - printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is " - "%sset\n", (status & (1 << 4)) ? "" : "not "); - printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is " - "%sset\n", (status & (1 << 3)) ? "" : "not "); - printf_debug("Chip status register: Bit 2 / Block Protect 0 (BP0) is " - "%sset\n", (status & (1 << 2)) ? "" : "not "); - printf_debug("Chip status register: Write Enable Latch (WEL) is " - "%sset\n", (status & (1 << 1)) ? "" : "not "); - printf_debug("Chip status register: Write In Progress (WIP/BUSY) is " - "%sset\n", (status & (1 << 0)) ? "" : "not "); -} - -/* Prettyprint the status register. Works for - * ST M25P series - * MX MX25L series - */ -void spi_prettyprint_status_register_st_m25p(uint8_t status) -{ - printf_debug("Chip status register: Status Register Write Disable " - "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not "); - printf_debug("Chip status register: Bit 6 is " - "%sset\n", (status & (1 << 6)) ? "" : "not "); - spi_prettyprint_status_register_common(status); -} - -void spi_prettyprint_status_register_sst25(uint8_t status) -{ - printf_debug("Chip status register: Block Protect Write Disable " - "(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not "); - printf_debug("Chip status register: Auto Address Increment Programming " - "(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not "); - spi_prettyprint_status_register_common(status); -} - -/* Prettyprint the status register. Works for - * SST 25VF016 - */ -void spi_prettyprint_status_register_sst25vf016(uint8_t status) -{ - const char *bpt[] = { - "none", - "1F0000H-1FFFFFH", - "1E0000H-1FFFFFH", - "1C0000H-1FFFFFH", - "180000H-1FFFFFH", - "100000H-1FFFFFH", - "all", "all" - }; - spi_prettyprint_status_register_sst25(status); - printf_debug("Resulting block protection : %s\n", - bpt[(status & 0x1c) >> 2]); -} - -void spi_prettyprint_status_register_sst25vf040b(uint8_t status) -{ - const char *bpt[] = { - "none", - "0x70000-0x7ffff", - "0x60000-0x7ffff", - "0x40000-0x7ffff", - "all blocks", "all blocks", "all blocks", "all blocks" - }; - spi_prettyprint_status_register_sst25(status); - printf_debug("Resulting block protection : %s\n", - bpt[(status & 0x1c) >> 2]); -} - -void spi_prettyprint_status_register(struct flashchip *flash) -{ - uint8_t status; - - status = spi_read_status_register(); - printf_debug("Chip status register is %02x\n", status); - switch (flash->manufacture_id) { - case ST_ID: - if (((flash->model_id & 0xff00) == 0x2000) || - ((flash->model_id & 0xff00) == 0x2500)) - spi_prettyprint_status_register_st_m25p(status); - break; - case MX_ID: - if ((flash->model_id & 0xff00) == 0x2000) - spi_prettyprint_status_register_st_m25p(status); - break; - case SST_ID: - switch (flash->model_id) { - case 0x2541: - spi_prettyprint_status_register_sst25vf016(status); - break; - case 0x8d: - case 0x258d: - spi_prettyprint_status_register_sst25vf040b(status); - break; - default: - spi_prettyprint_status_register_sst25(status); - break; - } - break; - } -} - -int spi_chip_erase_60(struct flashchip *flash) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_CE_60_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_CE_60 }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_disable_blockprotect(); - if (result) { - fprintf(stderr, "spi_disable_blockprotect failed\n"); - return result; - } - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution\n", - __func__); - return result; - } - /* Wait until the Write-In-Progress bit is cleared. - * This usually takes 1-85 s, so wait in 1 s steps. - */ - /* FIXME: We assume spi_read_status_register will never fail. */ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(1000 * 1000); - if (check_erased_range(flash, 0, flash->total_size * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int spi_chip_erase_c7(struct flashchip *flash) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_CE_C7_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_CE_C7 }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_disable_blockprotect(); - if (result) { - fprintf(stderr, "spi_disable_blockprotect failed\n"); - return result; - } - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution\n", __func__); - return result; - } - /* Wait until the Write-In-Progress bit is cleared. - * This usually takes 1-85 s, so wait in 1 s steps. - */ - /* FIXME: We assume spi_read_status_register will never fail. */ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(1000 * 1000); - if (check_erased_range(flash, 0, flash->total_size * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int spi_chip_erase_60_c7(struct flashchip *flash) -{ - int result; - result = spi_chip_erase_60(flash); - if (result) { - printf_debug("spi_chip_erase_60 failed, trying c7\n"); - result = spi_chip_erase_c7(flash); - } - return result; -} - -int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_BE_52_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_BE_52, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution at address 0x%x\n", - __func__, addr); - return result; - } - /* Wait until the Write-In-Progress bit is cleared. - * This usually takes 100-4000 ms, so wait in 100 ms steps. - */ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(100 * 1000); - if (check_erased_range(flash, addr, blocklen)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -/* Block size is usually - * 64k for Macronix - * 32k for SST - * 4-32k non-uniform for EON - */ -int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_BE_D8_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_BE_D8, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution at address 0x%x\n", - __func__, addr); - return result; - } - /* Wait until the Write-In-Progress bit is cleared. - * This usually takes 100-4000 ms, so wait in 100 ms steps. - */ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(100 * 1000); - if (check_erased_range(flash, addr, blocklen)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int spi_chip_erase_d8(struct flashchip *flash) -{ - int i, rc = 0; - int total_size = flash->total_size * 1024; - int erase_size = 64 * 1024; - - spi_disable_blockprotect(); - - printf("Erasing chip: \n"); - - for (i = 0; i < total_size / erase_size; i++) { - rc = spi_block_erase_d8(flash, i * erase_size, erase_size); - if (rc) { - fprintf(stderr, "Error erasing block at 0x%x\n", i); - break; - } - } - - printf("\n"); - - return rc; -} - -/* Sector size is usually 4k, though Macronix eliteflash has 64k */ -int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_SE_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_SE, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution at address 0x%x\n", - __func__, addr); - return result; - } - /* Wait until the Write-In-Progress bit is cleared. - * This usually takes 15-800 ms, so wait in 10 ms steps. - */ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(10 * 1000); - if (check_erased_range(flash, addr, blocklen)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -{ - if ((addr != 0) || (blocklen != flash->total_size * 1024)) { - fprintf(stderr, "%s called with incorrect arguments\n", - __func__); - return -1; - } - return spi_chip_erase_60(flash); -} - -int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -{ - if ((addr != 0) || (blocklen != flash->total_size * 1024)) { - fprintf(stderr, "%s called with incorrect arguments\n", - __func__); - return -1; - } - return spi_chip_erase_c7(flash); -} - -int spi_write_status_enable(void) -{ - const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR }; - int result; - - /* Send EWSR (Enable Write Status Register). */ - result = spi_send_command(sizeof(cmd), JEDEC_EWSR_INSIZE, cmd, NULL); - - if (result) - fprintf(stderr, "%s failed\n", __func__); - - return result; -} - -/* - * This is according the SST25VF016 datasheet, who knows it is more - * generic that this... - */ -int spi_write_status_register(int status) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_EWSR_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_EWSR }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_WRSR_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution\n", - __func__); - } - return result; -} - -int spi_byte_program(int addr, uint8_t byte) -{ - int result; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_BYTE_PROGRAM, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff), byte }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution at address 0x%x\n", - __func__, addr); - } - return result; -} - -int spi_nbyte_program(int addr, uint8_t *bytes, int len) -{ - int result; - /* FIXME: Switch to malloc based on len unless that kills speed. */ - unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = { - JEDEC_BYTE_PROGRAM, - (addr >> 16) & 0xff, - (addr >> 8) & 0xff, - (addr >> 0) & 0xff, - }; - struct spi_command cmds[] = { - { - .writecnt = JEDEC_WREN_OUTSIZE, - .writearr = (const unsigned char[]){ JEDEC_WREN }, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len, - .writearr = cmd, - .readcnt = 0, - .readarr = NULL, - }, { - .writecnt = 0, - .writearr = NULL, - .readcnt = 0, - .readarr = NULL, - }}; - - if (!len) { - fprintf(stderr, "%s called for zero-length write\n", __func__); - return 1; - } - if (len > 256) { - fprintf(stderr, "%s called for too long a write\n", __func__); - return 1; - } - - memcpy(&cmd[4], bytes, len); - - result = spi_send_multicommand(cmds); - if (result) { - fprintf(stderr, "%s failed during command execution at address 0x%x\n", - __func__, addr); - } - return result; -} - -int spi_disable_blockprotect(void) -{ - uint8_t status; - int result; - - status = spi_read_status_register(); - /* If there is block protection in effect, unprotect it first. */ - if ((status & 0x3c) != 0) { - printf_debug("Some block protection in effect, disabling\n"); - result = spi_write_status_register(status & ~0x3c); - if (result) { - fprintf(stderr, "spi_write_status_register failed\n"); - return result; - } - } - return 0; -} - -int spi_nbyte_read(int address, uint8_t *bytes, int len) -{ - const unsigned char cmd[JEDEC_READ_OUTSIZE] = { - JEDEC_READ, - (address >> 16) & 0xff, - (address >> 8) & 0xff, - (address >> 0) & 0xff, - }; - - /* Send Read */ - return spi_send_command(sizeof(cmd), len, cmd, bytes); -} - -/* - * Read a complete flash chip. - * Each page is read separately in chunks with a maximum size of chunksize. - */ -int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize) -{ - int rc = 0; - int i, j, starthere, lenhere; - int page_size = flash->page_size; - int toread; - - /* Warning: This loop has a very unusual condition and body. - * The loop needs to go through each page with at least one affected - * byte. The lowest page number is (start / page_size) since that - * division rounds down. The highest page number we want is the page - * where the last byte of the range lives. That last byte has the - * address (start + len - 1), thus the highest page number is - * (start + len - 1) / page_size. Since we want to include that last - * page as well, the loop condition uses <=. - */ - for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { - /* Byte position of the first byte in the range in this page. */ - /* starthere is an offset to the base address of the chip. */ - starthere = max(start, i * page_size); - /* Length of bytes in the range in this page. */ - lenhere = min(start + len, (i + 1) * page_size) - starthere; - for (j = 0; j < lenhere; j += chunksize) { - toread = min(chunksize, lenhere - j); - rc = spi_nbyte_read(starthere + j, buf + starthere - start + j, toread); - if (rc) - break; - } - if (rc) - break; - } - - return rc; -} - -int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - if (!spi_programmer[spi_controller].read) { - fprintf(stderr, "%s called, but SPI read is unsupported on this" - " hardware. Please report a bug.\n", __func__); - return 1; - } - - return spi_programmer[spi_controller].read(flash, buf, start, len); -} - -/* - * Program chip using byte programming. (SLOW!) - * This is for chips which can only handle one byte writes - * and for chips where memory mapped programming is impossible - * (e.g. due to size constraints in IT87* for over 512 kB) - */ -int spi_chip_write_1(struct flashchip *flash, uint8_t *buf) -{ - int total_size = 1024 * flash->total_size; - int i, result = 0; - - spi_disable_blockprotect(); - /* Erase first */ - printf("Erasing flash before programming... "); - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("done.\n"); - for (i = 0; i < total_size; i++) { - result = spi_byte_program(i, buf[i]); - if (result) - return 1; - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(10); - } - - return 0; -} - -/* - * Program chip using page (256 bytes) programming. - * Some SPI masters can't do this, they use single byte programming instead. - */ -int spi_chip_write_256(struct flashchip *flash, uint8_t *buf) -{ - if (!spi_programmer[spi_controller].write_256) { - fprintf(stderr, "%s called, but SPI page write is unsupported " - " on this hardware. Please report a bug.\n", __func__); - return 1; - } - - return spi_programmer[spi_controller].write_256(flash, buf); -} - -uint32_t spi_get_valid_read_addr(void) -{ - /* Need to return BBAR for ICH chipsets. */ - return 0; -} - -int spi_aai_write(struct flashchip *flash, uint8_t *buf) -{ - uint32_t pos = 2, size = flash->total_size * 1024; - unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]}; - int result; - - switch (spi_controller) { - case SPI_CONTROLLER_WBSIO: - fprintf(stderr, "%s: impossible with Winbond SPI masters," - " degrading to byte program\n", __func__); - return spi_chip_write_1(flash, buf); - default: - break; - } - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - result = spi_write_enable(); - if (result) - return result; - spi_send_command(6, 0, w, NULL); - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(5); /* SST25VF040B Tbp is max 10us */ - while (pos < size) { - w[1] = buf[pos++]; - w[2] = buf[pos++]; - spi_send_command(3, 0, w, NULL); - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - programmer_delay(5); /* SST25VF040B Tbp is max 10us */ - } - spi_write_disable(); - return 0; -} diff --git a/spi.h b/spi.h deleted file mode 100644 index 2fa7dcd..0000000 --- a/spi.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2007, 2008 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 - */ - -#ifndef __SPI_H__ -#define __SPI_H__ 1 - -/* - * Contains the generic SPI headers - */ - -/* Read Electronic ID */ -#define JEDEC_RDID 0x9f -#define JEDEC_RDID_OUTSIZE 0x01 -#define JEDEC_RDID_INSIZE 0x03 - -/* AT25F512A has bit 3 as don't care bit in commands */ -#define AT25F512A_RDID 0x15 -#define AT25F512A_RDID_OUTSIZE 0x01 -#define AT25F512A_RDID_INSIZE 0x02 - -/* Read Electronic Manufacturer Signature */ -#define JEDEC_REMS 0x90 -#define JEDEC_REMS_OUTSIZE 0x04 -#define JEDEC_REMS_INSIZE 0x02 - -/* Read Electronic Signature */ -#define JEDEC_RES 0xab -#define JEDEC_RES_OUTSIZE 0x04 -#define JEDEC_RES_INSIZE 0x01 - -/* Write Enable */ -#define JEDEC_WREN 0x06 -#define JEDEC_WREN_OUTSIZE 0x01 -#define JEDEC_WREN_INSIZE 0x00 - -/* Write Disable */ -#define JEDEC_WRDI 0x04 -#define JEDEC_WRDI_OUTSIZE 0x01 -#define JEDEC_WRDI_INSIZE 0x00 - -/* Chip Erase 0x60 is supported by Macronix/SST chips. */ -#define JEDEC_CE_60 0x60 -#define JEDEC_CE_60_OUTSIZE 0x01 -#define JEDEC_CE_60_INSIZE 0x00 - -/* Chip Erase 0xc7 is supported by SST/ST/EON/Macronix chips. */ -#define JEDEC_CE_C7 0xc7 -#define JEDEC_CE_C7_OUTSIZE 0x01 -#define JEDEC_CE_C7_INSIZE 0x00 - -/* Block Erase 0x52 is supported by SST and old Atmel chips. */ -#define JEDEC_BE_52 0x52 -#define JEDEC_BE_52_OUTSIZE 0x04 -#define JEDEC_BE_52_INSIZE 0x00 - -/* Block Erase 0xd8 is supported by EON/Macronix chips. */ -#define JEDEC_BE_D8 0xd8 -#define JEDEC_BE_D8_OUTSIZE 0x04 -#define JEDEC_BE_D8_INSIZE 0x00 - -/* Sector Erase 0x20 is supported by Macronix/SST chips. */ -#define JEDEC_SE 0x20 -#define JEDEC_SE_OUTSIZE 0x04 -#define JEDEC_SE_INSIZE 0x00 - -/* Read Status Register */ -#define JEDEC_RDSR 0x05 -#define JEDEC_RDSR_OUTSIZE 0x01 -#define JEDEC_RDSR_INSIZE 0x01 -#define JEDEC_RDSR_BIT_WIP (0x01 << 0) - -/* Write Status Enable */ -#define JEDEC_EWSR 0x50 -#define JEDEC_EWSR_OUTSIZE 0x01 -#define JEDEC_EWSR_INSIZE 0x00 - -/* Write Status Register */ -#define JEDEC_WRSR 0x01 -#define JEDEC_WRSR_OUTSIZE 0x02 -#define JEDEC_WRSR_INSIZE 0x00 - -/* Read the memory */ -#define JEDEC_READ 0x03 -#define JEDEC_READ_OUTSIZE 0x04 -/* JEDEC_READ_INSIZE : any length */ - -/* Write memory byte */ -#define JEDEC_BYTE_PROGRAM 0x02 -#define JEDEC_BYTE_PROGRAM_OUTSIZE 0x05 -#define JEDEC_BYTE_PROGRAM_INSIZE 0x00 - -/* Error codes */ -#define SPI_GENERIC_ERROR -1 -#define SPI_INVALID_OPCODE -2 -#define SPI_INVALID_ADDRESS -3 -#define SPI_INVALID_LENGTH -4 - -#endif /* !__SPI_H__ */ diff --git a/sst28sf040.c b/sst28sf040.c deleted file mode 100644 index 930ad5b..0000000 --- a/sst28sf040.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2005 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -#define AUTO_PG_ERASE1 0x20 -#define AUTO_PG_ERASE2 0xD0 -#define AUTO_PGRM 0x10 -#define CHIP_ERASE 0x30 -#define RESET 0xFF -#define READ_ID 0x90 - -static void protect_28sf040(chipaddr bios) -{ - chip_readb(bios + 0x1823); - chip_readb(bios + 0x1820); - chip_readb(bios + 0x1822); - chip_readb(bios + 0x0418); - chip_readb(bios + 0x041B); - chip_readb(bios + 0x0419); - chip_readb(bios + 0x040A); -} - -static void unprotect_28sf040(chipaddr bios) -{ - chip_readb(bios + 0x1823); - chip_readb(bios + 0x1820); - chip_readb(bios + 0x1822); - chip_readb(bios + 0x0418); - chip_readb(bios + 0x041B); - chip_readb(bios + 0x0419); - chip_readb(bios + 0x041A); -} - -static int erase_sector_28sf040(struct flashchip *flash, unsigned long address, int sector_size) -{ - chipaddr bios = flash->virtual_memory; - - chip_writeb(AUTO_PG_ERASE1, bios); - chip_writeb(AUTO_PG_ERASE2, bios + address); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios); - - if (check_erased_range(flash, address, sector_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -static int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst, - unsigned int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - /* transfer data from source to destination */ - if (*src == 0xFF) { - dst++, src++; - /* If the data is 0xFF, don't program it */ - continue; - } - /*issue AUTO PROGRAM command */ - chip_writeb(AUTO_PGRM, dst); - chip_writeb(*src++, dst++); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios); - } - - return 0; -} - -int probe_28sf040(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(RESET, bios); - programmer_delay(10); - - chip_writeb(READ_ID, bios); - programmer_delay(10); - id1 = chip_readb(bios); - programmer_delay(10); - id2 = chip_readb(bios + 0x01); - - chip_writeb(RESET, bios); - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} - -int erase_28sf040(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - - unprotect_28sf040(bios); - chip_writeb(CHIP_ERASE, bios); - chip_writeb(CHIP_ERASE, bios); - protect_28sf040(bios); - - programmer_delay(10); - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, flash->total_size * 1024)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int write_28sf040(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - unprotect_28sf040(bios); - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming */ - if (erase_sector_28sf040(flash, i * page_size, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ - printf("%04d at address: 0x%08x", i, i * page_size); - write_sector_28sf040(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - protect_28sf040(bios); - - return 0; -} diff --git a/sst49lf040.c b/sst49lf040.c deleted file mode 100644 index ab1c918..0000000 --- a/sst49lf040.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -int erase_49lf040(struct flashchip *flash) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - - for (i = 0; i < total_size / page_size; i++) { - /* Chip erase only works in parallel programming mode - * for the 49lf040. Use sector-erase instead */ - if (erase_sector_jedec(flash, i * page_size, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - } - - return 0; -} - -int write_49lf040(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming - * Chip erase only works in parallel programming mode - * for the 49lf040. Use sector-erase instead */ - if (erase_sector_jedec(flash, i * page_size, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ - if (i % 10 == 0) - printf("%04d at address: 0x%08x ", i, i * page_size); - - write_sector_jedec(bios, buf + i * page_size, - bios + i * page_size, page_size); - - if (i % 10 == 0) - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - fflush(stdout); - } - printf("\n"); - - return 0; -} diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c deleted file mode 100644 index a421acf..0000000 --- a/sst49lfxxxc.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2005-2007 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "flash.h" - -#define SECTOR_ERASE 0x30 -#define BLOCK_ERASE 0x20 -#define ERASE 0xD0 -#define AUTO_PGRM 0x10 -#define RESET 0xFF -#define READ_ID 0x90 -#define READ_STATUS 0x70 -#define CLEAR_STATUS 0x50 - -#define STATUS_BPS (1 << 1) -#define STATUS_ESS (1 << 6) -#define STATUS_WSMS (1 << 7) - -static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits) -{ - chipaddr registers = flash->virtual_registers; - int i, left = flash->total_size * 1024; - unsigned long address; - - printf_debug("\nbios=0x%08lx\n", registers); - for (i = 0; left > 65536; i++, left -= 65536) { - printf_debug("lockbits at address=0x%08lx is 0x%01x\n", - registers + (i * 65536) + 2, - chip_readb(registers + (i * 65536) + 2)); - chip_writeb(bits, registers + (i * 65536) + 2); - } - address = i * 65536; - printf_debug("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - address += 32768; - printf_debug("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - address += 8192; - printf_debug("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - address += 8192; - printf_debug("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - - return 0; -} - -static int erase_sector_49lfxxxc(struct flashchip *flash, unsigned long address, int sector_size) -{ - unsigned char status; - chipaddr bios = flash->virtual_memory; - - chip_writeb(SECTOR_ERASE, bios); - chip_writeb(ERASE, bios + address); - - do { - status = chip_readb(bios); - if (status & (STATUS_ESS | STATUS_BPS)) { - printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", bios + address, status); - chip_writeb(CLEAR_STATUS, bios); - return (-1); - } - } while (!(status & STATUS_WSMS)); - chip_writeb(RESET, bios); - - if (check_erased_range(flash, address, sector_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -static int write_sector_49lfxxxc(chipaddr bios, uint8_t *src, chipaddr dst, - unsigned int page_size) -{ - int i; - unsigned char status; - - chip_writeb(CLEAR_STATUS, bios); - for (i = 0; i < page_size; i++) { - /* transfer data from source to destination */ - if (*src == 0xFF) { - dst++, src++; - /* If the data is 0xFF, don't program it */ - continue; - } - /*issue AUTO PROGRAM command */ - chip_writeb(AUTO_PGRM, bios); - chip_writeb(*src++, dst++); - - do { - status = chip_readb(bios); - if (status & (STATUS_ESS | STATUS_BPS)) { - printf("sector write FAILED at address=0x%08lx status=0x%01x\n", dst, status); - chip_writeb(CLEAR_STATUS, bios); - return (-1); - } - } while (!(status & STATUS_WSMS)); - } - - return 0; -} - -int probe_49lfxxxc(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - - chip_writeb(RESET, bios); - - chip_writeb(READ_ID, bios); - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - - chip_writeb(RESET, bios); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (!(id1 == flash->manufacture_id && id2 == flash->model_id)) - return 0; - - map_flash_registers(flash); - - return 1; -} - -int erase_49lfxxxc(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - int i; - unsigned int total_size = flash->total_size * 1024; - - write_lockbits_49lfxxxc(flash, 0); - for (i = 0; i < total_size; i += flash->page_size) - if (erase_sector_49lfxxxc(flash, i, flash->page_size)) - return (-1); - - chip_writeb(RESET, bios); - - return 0; -} - -int write_49lfxxxc(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - write_lockbits_49lfxxxc(flash, 0); - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming */ - if (erase_sector_49lfxxxc(flash, i * page_size, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ - printf("%04d at address: 0x%08x", i, i * page_size); - write_sector_49lfxxxc(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - chip_writeb(RESET, bios); - - return 0; -} diff --git a/sst_fwhub.c b/sst_fwhub.c deleted file mode 100644 index f09aa54..0000000 --- a/sst_fwhub.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2009 Kontron Modular Computers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Adapted from the Intel FW hub stuff for 82802ax parts. */ - -#include -#include -#include "flash.h" - -// I need that Berkeley bit-map printer -void print_sst_fwhub_status(uint8_t status) -{ - printf("%s", status & 0x80 ? "Ready:" : "Busy:"); - printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); - printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); - printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); - printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); - printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); - printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); -} - -int check_sst_fwhub_block_lock(struct flashchip *flash, int offset) -{ - chipaddr registers = flash->virtual_registers; - uint8_t blockstatus; - - blockstatus = chip_readb(registers + offset + 2); - printf_debug("Lock status for 0x%06x (size 0x%06x) is %02x, ", - offset, flash->page_size, blockstatus); - switch (blockstatus & 0x3) { - case 0x0: - printf_debug("full access\n"); - break; - case 0x1: - printf_debug("write locked\n"); - break; - case 0x2: - printf_debug("locked open\n"); - break; - case 0x3: - printf_debug("write locked down\n"); - break; - } - /* Return content of the write_locked bit */ - return blockstatus & 0x1; -} - -int clear_sst_fwhub_block_lock(struct flashchip *flash, int offset) -{ - chipaddr registers = flash->virtual_registers; - uint8_t blockstatus; - - blockstatus = check_sst_fwhub_block_lock(flash, offset); - - if (blockstatus) { - printf_debug("Trying to clear lock for 0x%06x... ", offset) - chip_writeb(0, registers + offset + 2); - - blockstatus = check_sst_fwhub_block_lock(flash, offset); - printf_debug("%s\n", (blockstatus) ? "failed" : "OK"); - } - - return blockstatus; -} - -/* probe_jedec works fine for probing */ -int probe_sst_fwhub(struct flashchip *flash) -{ - int i; - - if (probe_jedec(flash) == 0) - return 0; - - map_flash_registers(flash); - - for (i = 0; i < flash->total_size * 1024; i += flash->page_size) - check_sst_fwhub_block_lock(flash, i); - - return 1; -} - -int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size) -{ - uint8_t blockstatus = clear_sst_fwhub_block_lock(flash, offset); - - if (blockstatus) { - printf("Block lock clearing failed, not erasing block " - "at 0x%06x\n", offset); - return 1; - } - - if (erase_block_jedec(flash, offset, page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - toggle_ready_jedec(flash->virtual_memory); - - return 0; -} - -int erase_sst_fwhub(struct flashchip *flash) -{ - int i; - unsigned int total_size = flash->total_size * 1024; - - for (i = 0; i < total_size; i += flash->page_size) { - if (erase_sst_fwhub_block(flash, i, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - } - - return 0; -} - -int write_sst_fwhub(struct flashchip *flash, uint8_t *buf) -{ - int i, rc; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - uint8_t *readbuf = malloc(page_size); - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - printf("%04d at address: 0x%08x", i, i * page_size); - - /* Auto Skip Blocks, which already contain the desired data: - * Faster, because we only write, what has changed - * More secure, because blocks, which are excluded - * (with the exclude or layout feature) - * are not erased and rewritten; data is retained also - * in sudden power off situations - */ - flash->read(flash, readbuf, i * page_size, page_size); - if (memcmp((void *)(buf + i * page_size), - (void *)(readbuf), page_size)) { - rc = erase_sst_fwhub_block(flash, i * page_size, - page_size); - if (rc) - return 1; - write_sector_jedec(bios, buf + i * page_size, - bios + i * page_size, page_size); - } - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - return 0; -} diff --git a/stm50flw0x0x.c b/stm50flw0x0x.c deleted file mode 100644 index 0ae6eb8..0000000 --- a/stm50flw0x0x.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Claus Gindhart - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * This module is designed for supporting the devices - * ST M50FLW040A (not yet tested) - * ST M50FLW040B (not yet tested) - * ST M50FLW080A - * ST M50FLW080B (not yet tested) - */ - -#include -#include -#include "flash.h" -#include "flashchips.h" - -int probe_stm50flw0x0x(struct flashchip *flash) -{ - int result = probe_jedec(flash); - - if (!result) - return result; - - map_flash_registers(flash); - - return 1; -} - -static void wait_stm50flw0x0x(chipaddr bios) -{ - chip_writeb(0x70, bios); - if ((chip_readb(bios) & 0x80) == 0) { // it's busy - while ((chip_readb(bios) & 0x80) == 0) ; - } - - // put another command to get out of status register mode - - chip_writeb(0x90, bios); - programmer_delay(10); - - chip_readb(bios); // Read device ID (to make sure?) - - // this is needed to jam it out of "read id" mode - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0xF0, bios + 0x5555); -} - -/* - * claus.gindhart@kontron.com - * The ST M50FLW080B and STM50FLW080B chips have to be unlocked, - * before you can erase them or write to them. - */ -int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) -{ - chipaddr wrprotect = flash->virtual_registers + 2; - const uint8_t unlock_sector = 0x00; - int j; - - /* - * These chips have to be unlocked before you can erase them or write - * to them. The size of the locking sectors depends on the type - * of chip. - * - * Sometimes, the BIOS does this for you; so you propably - * don't need to worry about that. - */ - - /* Check, if it's is a top/bottom-block with 4k-sectors. */ - /* TODO: What about the other types? */ - if ((offset == 0) || - (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000)) - || (offset == 0xF0000)) { - - // unlock each 4k-sector - for (j = 0; j < 0x10000; j += 0x1000) { - printf_debug("unlocking at 0x%x\n", offset + j); - chip_writeb(unlock_sector, wrprotect + offset + j); - if (chip_readb(wrprotect + offset + j) != unlock_sector) { - printf("Cannot unlock sector @ 0x%x\n", - offset + j); - return -1; - } - } - } else { - printf_debug("unlocking at 0x%x\n", offset); - chip_writeb(unlock_sector, wrprotect + offset); - if (chip_readb(wrprotect + offset) != unlock_sector) { - printf("Cannot unlock sector @ 0x%x\n", offset); - return -1; - } - } - - return 0; -} - -int erase_block_stm50flw0x0x(struct flashchip *flash, int offset) -{ - chipaddr bios = flash->virtual_memory + offset; - - // clear status register - chip_writeb(0x50, bios); - printf_debug("Erase at 0x%lx\n", bios); - // now start it - chip_writeb(0x20, bios); - chip_writeb(0xd0, bios); - programmer_delay(10); - - wait_stm50flw0x0x(flash->virtual_memory); - - if (check_erased_range(flash, offset, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - printf("DONE BLOCK 0x%x\n", offset); - - return 0; -} - -int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src, - chipaddr dst, int page_size) -{ - int i, rc = 0; - chipaddr d = dst; - uint8_t *s = src; - - /* transfer data from source to destination */ - for (i = 0; i < page_size; i++) { - chip_writeb(0x40, dst); - chip_writeb(*src++, dst++); - wait_stm50flw0x0x(bios); - } - -/* claus.gindhart@kontron.com - * TODO - * I think, that verification is not required, but - * i leave it in anyway - */ - dst = d; - src = s; - for (i = 0; i < page_size; i++) { - if (chip_readb(dst) != *src) { - rc = -1; - break; - } - dst++; - src++; - } - - if (rc) { - fprintf(stderr, " page 0x%lx failed!\n", - (d - bios) / page_size); - } - - return rc; -} - -/* I simply erase block by block - * I Chip This is not the fastest way, but it works - */ -int erase_stm50flw0x0x(struct flashchip *flash) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - - printf("Erasing page:\n"); - for (i = 0; i < total_size / page_size; i++) { - printf - ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - printf("%04d at address: 0x%08x ", i, i * page_size); - if (unlock_block_stm50flw0x0x(flash, i * page_size)) { - fprintf(stderr, "UNLOCK FAILED!\n"); - return -1; - } - if (erase_block_stm50flw0x0x(flash, i * page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - } - printf("\n"); - - return 0; -} - -int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf) -{ - int i, rc = 0; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - uint8_t *tmpbuf = malloc(page_size); - - if (!tmpbuf) { - printf("Could not allocate memory!\n"); - exit(1); - } - printf("Programming page: \n"); - for (i = 0; (i < total_size / page_size) && (rc == 0); i++) { - printf - ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - printf("%04d at address: 0x%08x ", i, i * page_size); - - /* Auto Skip Blocks, which already contain the desired data - * Faster, because we only write, what has changed - * More secure, because blocks, which are excluded - * (with the exclude or layout feature) - * are not erased and rewritten; data is retained also - * in sudden power off situations - */ - chip_readn(tmpbuf, bios + i * page_size, page_size); - if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) { - printf("SKIPPED\n"); - continue; - } - - rc = unlock_block_stm50flw0x0x(flash, i * page_size); - if (!rc) - rc = erase_block_stm50flw0x0x(flash, i * page_size); - if (!rc) - write_page_stm50flw0x0x(bios, buf + i * page_size, - bios + i * page_size, page_size); - } - printf("\n"); - free(tmpbuf); - - return rc; -} diff --git a/udelay.c b/udelay.c deleted file mode 100644 index 9a0ab36..0000000 --- a/udelay.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "flash.h" - -// count to a billion. Time it. If it's < 1 sec, count to 10B, etc. -unsigned long micro = 1; - -void myusec_delay(int usecs) -{ - volatile unsigned long i; - for (i = 0; i < usecs * micro; i++) ; -} - -void myusec_calibrate_delay(void) -{ - int count = 1000; - unsigned long timeusec; - struct timeval start, end; - int ok = 0; - - printf("Calibrating delay loop... "); - - while (!ok) { - gettimeofday(&start, 0); - myusec_delay(count); - gettimeofday(&end, 0); - timeusec = 1000000 * (end.tv_sec - start.tv_sec) + - (end.tv_usec - start.tv_usec); - count *= 2; - if (timeusec < 1000000 / 4) - continue; - ok = 1; - } - - // compute one microsecond. That will be count / time - micro = count / timeusec; - - gettimeofday(&start, 0); - myusec_delay(100); - gettimeofday(&end, 0); - timeusec = 1000000 * (end.tv_sec - start.tv_sec) + - (end.tv_usec - start.tv_usec); - printf_debug("%ldM loops per second, 100 myus = %ld us. ", - (unsigned long)micro, timeusec); - printf("OK.\n"); -} diff --git a/w29ee011.c b/w29ee011.c deleted file mode 100644 index de9a547..0000000 --- a/w29ee011.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2007 Markus Boas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "flash.h" - -int probe_w29ee011(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; - extern char *chip_to_probe; - - if (!chip_to_probe || strcmp(chip_to_probe, "W29EE011")) { - printf_debug("Probing disabled for Winbond W29EE011 because " - "the probing sequence puts the AMIC A49LF040A in " - "a funky state. Use 'flashrom -c W29EE011' if you " - "have a board with this chip.\n"); - return 0; - } - - /* Issue JEDEC Product ID Entry command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x80, bios + 0x5555); - programmer_delay(10); - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x60, bios + 0x5555); - programmer_delay(10); - - /* Read product ID */ - id1 = chip_readb(bios); - id2 = chip_readb(bios + 0x01); - - /* Issue JEDEC Product ID Exit command */ - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(10); - - printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; - - return 0; -} diff --git a/w39v040c.c b/w39v040c.c deleted file mode 100644 index 722ae29..0000000 --- a/w39v040c.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Peter Stuge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -int probe_w39v040c(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - int result = probe_jedec(flash); - uint8_t lock; - - if (!result) - return result; - - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0x90, bios + 0x5555); - programmer_delay(10); - - lock = chip_readb(bios + 0xfff2); - - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); - chip_writeb(0x55, bios + 0x2AAA); - programmer_delay(10); - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(40); - - printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n", - __func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un"); - return 1; -} - -int erase_w39v040c(struct flashchip *flash) -{ - int i; - unsigned int total_size = flash->total_size * 1024; - - for (i = 0; i < total_size; i += flash->page_size) { - if (erase_sector_jedec(flash, i, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - } - - return 0; -} - -int write_w39v040c(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - if (erase_flash(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - printf("%04d at address: 0x%08x", i, i * page_size); - write_sector_jedec(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - printf("\n"); - - return 0; -} diff --git a/w39v080fa.c b/w39v080fa.c deleted file mode 100644 index 580657f..0000000 --- a/w39v080fa.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2008 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -int probe_winbond_fwhub(struct flashchip *flash) -{ - int result = probe_jedec(flash); - - if (!result) - return result; - - map_flash_registers(flash); - - return 1; -} - -static int unlock_block_winbond_fwhub(struct flashchip *flash, int offset) -{ - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; - - printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset, - chip_readb(wrprotect)); - - locking = chip_readb(wrprotect); - switch (locking & 0x7) { - case 0: - printf_debug("Full Access.\n"); - return 0; - case 1: - printf_debug("Write Lock (Default State).\n"); - chip_writeb(0, wrprotect); - return 0; - case 2: - printf_debug("Locked Open (Full Access, Lock Down).\n"); - return 0; - case 3: - fprintf(stderr, "Error: Write Lock, Locked Down.\n"); - return -1; - case 4: - printf_debug("Read Lock.\n"); - chip_writeb(0, wrprotect); - return 0; - case 5: - printf_debug("Read/Write Lock.\n"); - chip_writeb(0, wrprotect); - return 0; - case 6: - fprintf(stderr, "Error: Read Lock, Locked Down.\n"); - return -1; - case 7: - fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n"); - return -1; - } - - /* We will never reach this point, but GCC doesn't know */ - return -1; -} - -int unlock_winbond_fwhub(struct flashchip *flash) -{ - int i, total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory; - uint8_t locking; - - /* Are there any hardware restrictions that we can't overcome? - * If flashrom fail here, someone's got to check all those GPIOs. - */ - - /* Product Identification Entry */ - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0x90, bios + 0x5555); - programmer_delay(10); - - /* Read Hardware Lock Bits */ - locking = chip_readb(bios + 0xffff2); - - /* Product Identification Exit */ - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(10); - - printf_debug("Lockout bits:\n"); - - if (locking & (1 << 2)) - fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n"); - else - printf_debug("No hardware bootblock locking (good!)\n"); - - if (locking & (1 << 3)) - fprintf(stderr, "Error: hardware block locking (#WP).\n"); - else - printf_debug("No hardware block locking (good!)\n"); - - if (locking & ((1 << 2) | (1 << 3))) - return -1; - - /* Unlock the complete chip */ - for (i = 0; i < total_size; i += flash->page_size) - if (unlock_block_winbond_fwhub(flash, i)) - return -1; - - return 0; -} - -static int erase_sector_winbond_fwhub(struct flashchip *flash, - unsigned int sector) -{ - chipaddr bios = flash->virtual_memory; - /* Remember: too much sleep can waste your day. */ - - printf("0x%08x\b\b\b\b\b\b\b\b\b\b", sector); - - /* Sector Erase */ - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0x80, bios + 0x5555); - - chip_writeb(0xAA, bios + 0x5555); - chip_writeb(0x55, bios + 0x2AAA); - chip_writeb(0x30, bios + sector); - - /* wait for Toggle bit ready */ - toggle_ready_jedec(bios); - - if (check_erased_range(flash, sector, flash->page_size)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - return 0; -} - -int erase_winbond_fwhub(struct flashchip *flash) -{ - int i, total_size = flash->total_size * 1024; - - unlock_winbond_fwhub(flash); - - printf("Erasing: "); - - for (i = 0; i < total_size; i += flash->page_size) { - if (erase_sector_winbond_fwhub(flash, i)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - } - - printf("\n"); - - return 0; -} - -int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory; - - if (erase_winbond_fwhub(flash)) - return -1; - - printf("Programming: "); - for (i = 0; i < total_size; i += flash->page_size) { - printf("0x%08x\b\b\b\b\b\b\b\b\b\b", i); - write_sector_jedec(bios, buf + i, bios + i, flash->page_size); - } - printf("\n"); - - return 0; -} diff --git a/w49f002u.c b/w49f002u.c deleted file mode 100644 index d12bc72..0000000 --- a/w49f002u.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -int write_49f002(struct flashchip *flash, uint8_t *buf) -{ - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - - if (erase_chip_jedec(flash)) { - fprintf(stderr, "ERASE FAILED!\n"); - return -1; - } - - printf("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - printf("%04d at address: 0x%08x ", i, i * page_size); - /* Byte-wise writing of 'page_size' bytes. */ - write_sector_jedec(bios, buf + i * page_size, - bios + i * page_size, page_size); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - fflush(stdout); - } - printf("\n"); - - return 0; -} diff --git a/wbsio_spi.c b/wbsio_spi.c deleted file mode 100644 index 6b9425f..0000000 --- a/wbsio_spi.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Peter Stuge - * - * 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 "flash.h" -#include "spi.h" - -#define WBSIO_PORT1 0x2e -#define WBSIO_PORT2 0x4e - -static uint16_t wbsio_spibase = 0; - -static uint16_t wbsio_get_spibase(uint16_t port) -{ - uint8_t id; - uint16_t flashport = 0; - - w836xx_ext_enter(port); - id = sio_read(port, 0x20); - if (id != 0xa0) { - fprintf(stderr, "\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id); - goto done; - } - - if (0 == (sio_read(port, 0x24) & 2)) { - fprintf(stderr, "\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port); - goto done; - } - - sio_write(port, 0x07, 0x06); - if (0 == (sio_read(port, 0x30) & 1)) { - fprintf(stderr, "\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port); - goto done; - } - - flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63); - -done: - w836xx_ext_leave(port); - return flashport; -} - -int wbsio_check_for_spi(const char *name) -{ - if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1))) - if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2))) - return 1; - - printf_debug("\nwbsio_spibase = 0x%x\n", wbsio_spibase); - - buses_supported |= CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_WBSIO; - - return 0; -} - -/* W83627DHG has 11 command modes: - * 1=1 command only - * 2=1 command+1 data write - * 3=1 command+2 data read - * 4=1 command+3 address - * 5=1 command+3 address+1 data write - * 6=1 command+3 address+4 data write - * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read - * 8=1 command+3 address+1 data read - * 9=1 command+3 address+2 data read - * a=1 command+3 address+3 data read - * b=1 command+3 address+4 data read - * - * mode[7:4] holds the command mode - * mode[3:0] holds SPI address bits [19:16] - * - * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\ - * Would one more byte of RAM in the chip (to get all 24 bits) really make - * such a big difference? - */ -int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) -{ - int i; - uint8_t mode = 0; - - printf_debug("%s:", __func__); - - if (1 == writecnt && 0 == readcnt) { - mode = 0x10; - } else if (2 == writecnt && 0 == readcnt) { - OUTB(writearr[1], wbsio_spibase + 4); - printf_debug(" data=0x%02x", writearr[1]); - mode = 0x20; - } else if (1 == writecnt && 2 == readcnt) { - mode = 0x30; - } else if (4 == writecnt && 0 == readcnt) { - printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < writecnt; i++) { - OUTB(writearr[i], wbsio_spibase + i); - printf_debug("%02x", writearr[i]); - } - mode = 0x40 | (writearr[1] & 0x0f); - } else if (5 == writecnt && 0 == readcnt) { - printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < 4; i++) { - OUTB(writearr[i], wbsio_spibase + i); - printf_debug("%02x", writearr[i]); - } - OUTB(writearr[i], wbsio_spibase + i); - printf_debug(" data=0x%02x", writearr[i]); - mode = 0x50 | (writearr[1] & 0x0f); - } else if (8 == writecnt && 0 == readcnt) { - printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < 4; i++) { - OUTB(writearr[i], wbsio_spibase + i); - printf_debug("%02x", writearr[i]); - } - printf_debug(" data=0x"); - for (; i < writecnt; i++) { - OUTB(writearr[i], wbsio_spibase + i); - printf_debug("%02x", writearr[i]); - } - mode = 0x60 | (writearr[1] & 0x0f); - } else if (5 == writecnt && 4 == readcnt) { - /* XXX: TODO not supported by flashrom infrastructure! - * This mode, 7, discards the fifth byte in writecnt, - * but since we can not express that in flashrom, fail - * the operation for now. - */ - ; - } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) { - printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < writecnt; i++) { - OUTB(writearr[i], wbsio_spibase + i); - printf_debug("%02x", writearr[i]); - } - mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f); - } - printf_debug(" cmd=%02x mode=%02x\n", writearr[0], mode); - - if (!mode) { - fprintf(stderr, "%s: unsupported command type wr=%d rd=%d\n", - __func__, writecnt, readcnt); - /* Command type refers to the number of bytes read/written. */ - return SPI_INVALID_LENGTH; - } - - OUTB(writearr[0], wbsio_spibase); - OUTB(mode, wbsio_spibase + 1); - programmer_delay(10); - - if (!readcnt) - return 0; - - printf_debug("%s: returning data =", __func__); - for (i = 0; i < readcnt; i++) { - readarr[i] = INB(wbsio_spibase + 4 + i); - printf_debug(" 0x%02x", readarr[i]); - } - printf_debug("\n"); - return 0; -} - -int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -{ - int size = flash->total_size * 1024; - - if (size > 1024 * 1024) { - fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); - return 1; - } - - return read_memmapped(flash, buf, start, len); -} - -int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf) -{ - int size = flash->total_size * 1024; - - if (size > 1024 * 1024) { - fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); - return 1; - } - - return spi_chip_write_1(flash, buf); -}