diff --git a/Makefile b/Makefile index 0f20b8a66..370318cca 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ override CONFIG_FT2232_SPI = no endif endif -CHIP_OBJS = jedec.o stm50flw0x0x.o w39v040c.o w39v080fa.o w29ee011.o \ +CHIP_OBJS = jedec.o stm50flw0x0x.o w39.o w29ee011.o \ sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \ sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o sharplhf00l04.o diff --git a/chipdrivers.h b/chipdrivers.h index cf1956914..a65cb9986 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -109,11 +109,17 @@ int unlock_49lfxxxc(struct flashchip *flash); int printlock_sst_fwhub(struct flashchip *flash); int unlock_sst_fwhub(struct flashchip *flash); -/* w39v040c.c */ +/* w39.c */ +int printlock_w39v040a(struct flashchip *flash); +int printlock_w39v040b(struct flashchip *flash); int printlock_w39v040c(struct flashchip *flash); - -/* w39V080fa.c */ -int unlock_winbond_fwhub(struct flashchip *flash); +int printlock_w39v040fa(struct flashchip *flash); +int printlock_w39v040fb(struct flashchip *flash); +int printlock_w39v040fc(struct flashchip *flash); +int printlock_w39v080a(struct flashchip *flash); +int printlock_w39v080fa(struct flashchip *flash); +int printlock_w39v080fa_dual(struct flashchip *flash); +int unlock_w39v080fa(struct flashchip *flash); /* w29ee011.c */ int probe_w29ee011(struct flashchip *flash); diff --git a/flashchips.c b/flashchips.c index e30c29cce..e7a222333 100644 --- a/flashchips.c +++ b/flashchips.c @@ -7593,13 +7593,14 @@ struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, + .printlock = printlock_w39v040a, .write = write_jedec_1, .read = read_memmapped, }, { .vendor = "Winbond", - .name = "W39V040(F)B", + .name = "W39V040B", .bustype = CHIP_BUSTYPE_LPC, .manufacture_id = WINBOND_ID, .model_id = WINBOND_W39V040B, @@ -7619,13 +7620,14 @@ struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, + .printlock = printlock_w39v040b, .write = write_jedec_1, .read = read_memmapped, }, { .vendor = "Winbond", - .name = "W39V040(F)C", + .name = "W39V040C", .bustype = CHIP_BUSTYPE_LPC, .manufacture_id = WINBOND_ID, .model_id = WINBOND_W39V040C, @@ -7634,7 +7636,7 @@ struct flashchip flashchips[] = { .feature_bits = FEATURE_EITHER_RESET, .tested = TEST_UNTESTED, .probe = probe_jedec, - .probe_timing = TIMING_FIXME, + .probe_timing = 10, .block_erasers = { { @@ -7675,12 +7677,66 @@ struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, - .printlock = printlock_sst_fwhub, + .printlock = printlock_w39v040fa, .unlock = unlock_sst_fwhub, .write = write_jedec_1, .read = read_memmapped, }, + { + .vendor = "Winbond", + .name = "W39V040FB", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = WINBOND_ID, + .model_id = WINBOND_W39V040B, + .total_size = 512, + .page_size = 64 * 1024, + .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, + .tested = TEST_OK_PRE, + .probe = probe_jedec, + .probe_timing = 10, + .block_erasers = + { + { + .eraseblocks = { {64 * 1024, 8} }, + .block_erase = erase_sector_jedec, + }, { + .eraseblocks = { {512 * 1024, 1} }, + .block_erase = erase_chip_block_jedec, + } + }, + .printlock = printlock_w39v040fb, + .write = write_jedec_1, + .read = read_memmapped, + }, + + { + .vendor = "Winbond", + .name = "W39V040FC", + .bustype = CHIP_BUSTYPE_FWH, + .manufacture_id = WINBOND_ID, + .model_id = WINBOND_W39V040C, + .total_size = 512, + .page_size = 64 * 1024, + .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, + .tested = TEST_UNTESTED, + .probe = probe_jedec, + .probe_timing = 10, + .block_erasers = + { + { + .eraseblocks = { {64 * 1024, 8} }, + .block_erase = erase_sector_jedec, + }, { + .eraseblocks = { {512 * 1024, 1} }, + .block_erase = erase_chip_block_jedec, + } + }, + .printlock = printlock_w39v040fc, + .write = write_jedec_1, + .read = read_memmapped, + }, + { .vendor = "Winbond", .name = "W39V080A", @@ -7703,6 +7759,7 @@ struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, + .printlock = printlock_w39v080a, .write = write_jedec_1, .read = read_memmapped, }, @@ -7834,7 +7891,7 @@ struct flashchip flashchips[] = { .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, .tested = TEST_OK_PRE, .probe = probe_jedec, - .probe_timing = TIMING_FIXME, + .probe_timing = 10, .block_erasers = { { @@ -7845,7 +7902,8 @@ struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, - .unlock = unlock_winbond_fwhub, + .printlock = printlock_w39v080fa, + .unlock = unlock_w39v080fa, .write = write_jedec_1, .read = read_memmapped, }, @@ -7861,7 +7919,7 @@ struct flashchip flashchips[] = { .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, .tested = TEST_UNTESTED, .probe = probe_jedec, - .probe_timing = TIMING_FIXME, + .probe_timing = 10, .block_erasers = { { @@ -7872,7 +7930,7 @@ struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, - .unlock = unlock_winbond_fwhub, + .printlock = printlock_w39v080fa_dual, .write = write_jedec_1, .read = read_memmapped, }, diff --git a/w39.c b/w39.c new file mode 100644 index 000000000..65cf32f4b --- /dev/null +++ b/w39.c @@ -0,0 +1,255 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2010 Carl-Daniel Hailfinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 "chipdrivers.h" + +static int printlock_w39_fwh_block(struct flashchip *flash, int offset) +{ + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t locking; + + locking = chip_readb(wrprotect); + msg_cdbg("Lock status of block at 0x%08x is ", offset); + switch (locking & 0x7) { + case 0: + msg_cdbg("Full Access.\n"); + break; + case 1: + msg_cdbg("Write Lock (Default State).\n"); + break; + case 2: + msg_cdbg("Locked Open (Full Access, Lock Down).\n"); + break; + case 3: + msg_cerr("Error: Write Lock, Locked Down.\n"); + break; + case 4: + msg_cdbg("Read Lock.\n"); + break; + case 5: + msg_cdbg("Read/Write Lock.\n"); + break; + case 6: + msg_cerr("Error: Read Lock, Locked Down.\n"); + break; + case 7: + msg_cerr("Error: Read/Write Lock, Locked Down.\n"); + break; + } + + /* Read or write lock present? */ + return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0; +} + +static int unlock_w39_fwh_block(struct flashchip *flash, int offset) +{ + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t locking; + + locking = chip_readb(wrprotect); + /* Read or write lock present? */ + if (locking & ((1 << 2) | (1 << 0))) { + /* Lockdown active? */ + if (locking & (1 << 1)) { + msg_cerr("Can't unlock block at 0x%x!\n", offset); + return -1; + } else { + msg_cdbg("Unlocking block at 0x%x\n", offset); + chip_writeb(0, wrprotect); + } + } + + return 0; +} + +static uint8_t w39_idmode_readb(struct flashchip *flash, int offset) +{ + chipaddr bios = flash->virtual_memory; + uint8_t val; + + /* Product Identification Entry */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0x90, bios + 0x5555); + programmer_delay(10); + + /* Read something, maybe hardware lock bits */ + val = chip_readb(bios + offset); + + /* Product Identification Exit */ + chip_writeb(0xAA, bios + 0x5555); + chip_writeb(0x55, bios + 0x2AAA); + chip_writeb(0xF0, bios + 0x5555); + programmer_delay(10); + + return val; +} + +static int printlock_w39_tblwp(uint8_t lock) +{ + msg_cdbg("Hardware bootblock locking (#TBL) is %sactive.\n", + (lock & (1 << 2)) ? "" : "not "); + msg_cdbg("Hardware remaining chip locking (#WP) is %sactive..\n", + (lock & (1 << 3)) ? "" : "not "); + if (lock & ((1 << 2) | (1 << 3))) + return -1; + + return 0; +} + +static int printlock_w39_bootblock_64k16k(uint8_t lock) +{ + msg_cdbg("Software 64 kB bootblock locking is %sactive.\n", + (lock & (1 << 0)) ? "" : "not "); + msg_cdbg("Software 16 kB bootblock locking is %sactive.\n", + (lock & (1 << 1)) ? "" : "not "); + if (lock & ((1 << 1) | (1 << 0))) + return -1; + + return 0; +} + +static int printlock_w39_common(struct flashchip *flash, int offset) +{ + uint8_t lock; + + lock = w39_idmode_readb(flash, offset); + msg_cdbg("Lockout bits:\n"); + return printlock_w39_tblwp(lock); +} + +static int printlock_w39_fwh(struct flashchip *flash) +{ + int i, total_size = flash->total_size * 1024; + int ret = 0; + + /* Print lock status of the complete chip */ + for (i = 0; i < total_size; i += flash->page_size) + ret |= printlock_w39_fwh_block(flash, i); + + return ret; +} + +static int unlock_w39_fwh(struct flashchip *flash) +{ + int i, total_size = flash->total_size * 1024; + + /* Unlock the complete chip */ + for (i = 0; i < total_size; i += flash->page_size) + if (unlock_w39_fwh_block(flash, i)) + return -1; + + return 0; +} + +int printlock_w39v040a(struct flashchip *flash) +{ + uint8_t lock; + int ret = 0; + + /* The W39V040A datasheet contradicts itself on the lock register + * location: 0x00002 and 0x7fff2 are both mentioned. Pick the one + * which is similar to the other chips of the same family. + */ + lock = w39_idmode_readb(flash, 0x7fff2); + msg_cdbg("Lockout bits:\n"); + + ret = printlock_w39_tblwp(lock); + ret |= printlock_w39_bootblock_64k16k(lock); + + return ret; +} + +int printlock_w39v040b(struct flashchip *flash) +{ + return printlock_w39_common(flash, 0x7fff2); +} + +int printlock_w39v040c(struct flashchip *flash) +{ + /* Typo in the datasheet? The other chips use 0x7fff2. */ + return printlock_w39_common(flash, 0xfff2); +} + +int printlock_w39v040fa(struct flashchip *flash) +{ + int ret = 0; + + ret = printlock_w39v040a(flash); + ret |= printlock_w39_fwh(flash); + + return ret; +} + +int printlock_w39v040fb(struct flashchip *flash) +{ + int ret = 0; + + ret = printlock_w39v040b(flash); + ret |= printlock_w39_fwh(flash); + + return ret; +} + +int printlock_w39v040fc(struct flashchip *flash) +{ + int ret = 0; + + /* W39V040C and W39V040FC use different WP/TBL offsets. */ + ret = printlock_w39_common(flash, 0x7fff2); + ret |= printlock_w39_fwh(flash); + + return ret; +} + +int printlock_w39v080a(struct flashchip *flash) +{ + return printlock_w39_common(flash, 0xffff2); +} + +int printlock_w39v080fa(struct flashchip *flash) +{ + int ret = 0; + + ret = printlock_w39v080a(flash); + ret |= printlock_w39_fwh(flash); + + return ret; +} + +int printlock_w39v080fa_dual(struct flashchip *flash) +{ + msg_cinfo("Block locking for W39V080FA in dual mode is " + "undocumented.\n"); + /* Better safe than sorry. */ + return -1; +} + +int unlock_w39v080fa(struct flashchip *flash) +{ + if (unlock_w39_fwh(flash)) + return -1; + if (printlock_w39_common(flash, 0xffff2)) + return -1; + + return 0; +} diff --git a/w39v040c.c b/w39v040c.c deleted file mode 100644 index dc4de1c3c..000000000 --- a/w39v040c.c +++ /dev/null @@ -1,48 +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" -#include "chipdrivers.h" - -int printlock_w39v040c(struct flashchip *flash) -{ - chipaddr bios = flash->virtual_memory; - uint8_t lock; - - 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); - - msg_cdbg("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n", - __func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un"); - return 0; -} diff --git a/w39v080fa.c b/w39v080fa.c deleted file mode 100644 index 62c55f4a0..000000000 --- a/w39v080fa.c +++ /dev/null @@ -1,113 +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" -#include "chipdrivers.h" - -static int unlock_block_winbond_fwhub(struct flashchip *flash, int offset) -{ - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; - - msg_cdbg("Trying to unlock block @0x%08x = 0x%02x\n", offset, - chip_readb(wrprotect)); - - locking = chip_readb(wrprotect); - switch (locking & 0x7) { - case 0: - msg_cdbg("Full Access.\n"); - return 0; - case 1: - msg_cdbg("Write Lock (Default State).\n"); - chip_writeb(0, wrprotect); - return 0; - case 2: - msg_cdbg("Locked Open (Full Access, Lock Down).\n"); - return 0; - case 3: - msg_cerr("Error: Write Lock, Locked Down.\n"); - return -1; - case 4: - msg_cdbg("Read Lock.\n"); - chip_writeb(0, wrprotect); - return 0; - case 5: - msg_cdbg("Read/Write Lock.\n"); - chip_writeb(0, wrprotect); - return 0; - case 6: - msg_cerr("Error: Read Lock, Locked Down.\n"); - return -1; - case 7: - msg_cerr("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); - - msg_cdbg("Lockout bits:\n"); - - if (locking & (1 << 2)) - msg_cerr("Error: hardware bootblock locking (#TBL).\n"); - else - msg_cdbg("No hardware bootblock locking (good!)\n"); - - if (locking & (1 << 3)) - msg_cerr("Error: hardware block locking (#WP).\n"); - else - msg_cdbg("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; -}