123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2000 Silicon Integrated System Corporation
- * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
- * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
- * Copyright (C) 2007 Carl-Daniel Hailfinger
- * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
- *
- * 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
- #define MASK_FULL 0xffff
- #define MASK_2AA 0x7ff
- #define MASK_AAA 0xfff
- /* 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;
- }
- static void toggle_ready_jedec_common(const struct flashctx *flash, chipaddr dst, int delay)
- {
- unsigned int i = 0;
- uint8_t tmp1, tmp2;
- tmp1 = chip_readb(flash, dst) & 0x40;
- while (i++ < 0xFFFFFFF) {
- if (delay)
- programmer_delay(delay);
- tmp2 = chip_readb(flash, dst) & 0x40;
- if (tmp1 == tmp2) {
- break;
- }
- tmp1 = tmp2;
- }
- if (i > 0x100000)
- msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
- }
- void toggle_ready_jedec(const struct flashctx *flash, chipaddr dst)
- {
- toggle_ready_jedec_common(flash, dst, 0);
- }
- /* Some chips require a minimum delay between toggle bit reads.
- * The Winbond W39V040C wants 50 ms between reads on sector erase toggle,
- * but experiments show that 2 ms are already enough. Pick a safety factor
- * of 4 and use an 8 ms delay.
- * Given that erase is slow on all chips, it is recommended to use
- * toggle_ready_jedec_slow in erase functions.
- */
- static void toggle_ready_jedec_slow(const struct flashctx *flash, chipaddr dst)
- {
- toggle_ready_jedec_common(flash, dst, 8 * 1000);
- }
- void data_polling_jedec(const struct flashctx *flash, chipaddr dst, uint8_t data)
- {
- unsigned int i = 0;
- uint8_t tmp;
- data &= 0x80;
- while (i++ < 0xFFFFFFF) {
- tmp = chip_readb(flash, dst) & 0x80;
- if (tmp == data) {
- break;
- }
- }
- if (i > 0x100000)
- msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
- }
- static unsigned int getaddrmask(struct flashctx *flash)
- {
- switch (flash->feature_bits & FEATURE_ADDR_MASK) {
- case FEATURE_ADDR_FULL:
- return MASK_FULL;
- break;
- case FEATURE_ADDR_2AA:
- return MASK_2AA;
- break;
- case FEATURE_ADDR_AAA:
- return MASK_AAA;
- break;
- default:
- msg_cerr("%s called with unknown mask\n", __func__);
- return 0;
- break;
- }
- }
- static void start_program_jedec_common(struct flashctx *flash, unsigned int mask)
- {
- chipaddr bios = flash->virtual_memory;
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- chip_writeb(flash, 0xA0, bios + (0x5555 & mask));
- }
- static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
- {
- 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 */
- msg_cdbg("Chip lacks correct probe timing information, "
- "using default 10mS/40uS. ");
- probe_timing_enter = 10000;
- probe_timing_exit = 40;
- } else {
- msg_cerr("Chip has negative value in probe_timing, failing "
- "without chip access\n");
- return 0;
- }
- /* Earlier probes might have been too fast for the chip to enter ID
- * mode completely. Allow the chip to finish this before seeing a
- * reset command.
- */
- if (probe_timing_enter)
- programmer_delay(probe_timing_enter);
- /* Reset chip to a clean slate */
- if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
- {
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- if (probe_timing_exit)
- programmer_delay(10);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- if (probe_timing_exit)
- programmer_delay(10);
- }
- chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
- if (probe_timing_exit)
- programmer_delay(probe_timing_exit);
- /* Issue JEDEC Product ID Entry command */
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- if (probe_timing_enter)
- programmer_delay(10);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- if (probe_timing_enter)
- programmer_delay(10);
- chip_writeb(flash, 0x90, bios + (0x5555 & mask));
- if (probe_timing_enter)
- programmer_delay(probe_timing_enter);
- /* Read product ID */
- id1 = chip_readb(flash, bios);
- id2 = chip_readb(flash, 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(flash, bios + 0x100);
- largeid1 |= id1;
- }
- if (id2 == 0x7F) {
- largeid2 <<= 8;
- id2 = chip_readb(flash, bios + 0x101);
- largeid2 |= id2;
- }
- /* Issue JEDEC Product ID Exit command */
- if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
- {
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- if (probe_timing_exit)
- programmer_delay(10);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- if (probe_timing_exit)
- programmer_delay(10);
- }
- chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
- if (probe_timing_exit)
- programmer_delay(probe_timing_exit);
- msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
- if (!oddparity(id1))
- msg_cdbg(", id1 parity violation");
- /* Read the product ID location again. We should now see normal flash contents. */
- flashcontent1 = chip_readb(flash, bios);
- flashcontent2 = chip_readb(flash, bios + 0x01);
- /* Check if it is a continuation ID, this should be a while loop. */
- if (flashcontent1 == 0x7F) {
- flashcontent1 <<= 8;
- flashcontent1 |= chip_readb(flash, bios + 0x100);
- }
- if (flashcontent2 == 0x7F) {
- flashcontent2 <<= 8;
- flashcontent2 |= chip_readb(flash, bios + 0x101);
- }
- if (largeid1 == flashcontent1)
- msg_cdbg(", id1 is normal flash content");
- if (largeid2 == flashcontent2)
- msg_cdbg(", id2 is normal flash content");
- msg_cdbg("\n");
- if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id)
- return 0;
- if (flash->feature_bits & FEATURE_REGISTERMAP)
- map_flash_registers(flash);
- return 1;
- }
- static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
- unsigned int pagesize, unsigned int mask)
- {
- chipaddr bios = flash->virtual_memory;
- int delay_us = 0;
- if(flash->probe_timing != TIMING_ZERO)
- delay_us = 10;
- /* Issue the Sector Erase command */
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x80, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x30, bios + page);
- programmer_delay(delay_us);
- /* wait for Toggle bit ready */
- toggle_ready_jedec_slow(flash, bios);
- /* FIXME: Check the status register for errors. */
- return 0;
- }
- static int erase_block_jedec_common(struct flashctx *flash, unsigned int block,
- unsigned int blocksize, unsigned int mask)
- {
- chipaddr bios = flash->virtual_memory;
- int delay_us = 0;
- if(flash->probe_timing != TIMING_ZERO)
- delay_us = 10;
- /* Issue the Sector Erase command */
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x80, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x50, bios + block);
- programmer_delay(delay_us);
- /* wait for Toggle bit ready */
- toggle_ready_jedec_slow(flash, bios);
- /* FIXME: Check the status register for errors. */
- return 0;
- }
- static int erase_chip_jedec_common(struct flashctx *flash, unsigned int mask)
- {
- chipaddr bios = flash->virtual_memory;
- int delay_us = 0;
- if(flash->probe_timing != TIMING_ZERO)
- delay_us = 10;
- /* Issue the JEDEC Chip Erase command */
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x80, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x10, bios + (0x5555 & mask));
- programmer_delay(delay_us);
- toggle_ready_jedec_slow(flash, bios);
- /* FIXME: Check the status register for errors. */
- return 0;
- }
- static int write_byte_program_jedec_common(struct flashctx *flash, uint8_t *src,
- chipaddr dst, unsigned int mask)
- {
- int tried = 0, failed = 0;
- chipaddr bios = flash->virtual_memory;
- /* 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_common(flash, mask);
- /* transfer data from source to destination */
- chip_writeb(flash, *src, dst);
- toggle_ready_jedec(flash, bios);
- if (chip_readb(flash, dst) != *src && tried++ < MAX_REFLASH_TRIES) {
- goto retry;
- }
- if (tried >= MAX_REFLASH_TRIES)
- failed = 1;
- return failed;
- }
- /* chunksize is 1 */
- int write_jedec_1(struct flashctx *flash, uint8_t *src, unsigned int start, unsigned int len)
- {
- int i, failed = 0;
- chipaddr dst = flash->virtual_memory + start;
- chipaddr olddst;
- unsigned int mask;
- mask = getaddrmask(flash);
- olddst = dst;
- for (i = 0; i < len; i++) {
- if (write_byte_program_jedec_common(flash, src, dst, mask))
- failed = 1;
- dst++, src++;
- }
- if (failed)
- msg_cerr(" writing sector at 0x%lx failed!\n", olddst);
- return failed;
- }
- int write_page_write_jedec_common(struct flashctx *flash, uint8_t *src, unsigned int start, unsigned int page_size)
- {
- int i, tried = 0, failed;
- uint8_t *s = src;
- chipaddr bios = flash->virtual_memory;
- chipaddr dst = bios + start;
- chipaddr d = dst;
- unsigned int mask;
- mask = getaddrmask(flash);
- retry:
- /* Issue JEDEC Start Program command */
- start_program_jedec_common(flash, mask);
- /* 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(flash, *src, dst);
- dst++;
- src++;
- }
- toggle_ready_jedec(flash, dst - 1);
- dst = d;
- src = s;
- failed = verify_range(flash, src, start, page_size, NULL);
- if (failed && tried++ < MAX_REFLASH_TRIES) {
- msg_cerr("retrying.\n");
- goto retry;
- }
- if (failed) {
- msg_cerr(" page 0x%lx failed!\n",
- (d - bios) / page_size);
- }
- return failed;
- }
- /* chunksize is page_size */
- /*
- * Write a part of the flash chip.
- * FIXME: Use the chunk code from Michael Karcher instead.
- * This function is a slightly modified copy of spi_write_chunked.
- * Each page is written separately in chunks with a maximum size of chunksize.
- */
- int write_jedec(struct flashctx *flash, uint8_t *buf, unsigned int start, int unsigned len)
- {
- unsigned int i, starthere, lenhere;
- /* FIXME: page_size is the wrong variable. We need max_writechunk_size
- * in struct flashctx to do this properly. All chips using
- * write_jedec have page_size set to max_writechunk_size, so
- * we're OK for now.
- */
- unsigned int page_size = flash->page_size;
- /* 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;
- if (write_page_write_jedec_common(flash, buf + starthere - start, starthere, lenhere))
- return 1;
- }
- return 0;
- }
- /* erase chip with block_erase() prototype */
- int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr,
- unsigned int blocksize)
- {
- unsigned int mask;
- mask = getaddrmask(flash);
- if ((addr != 0) || (blocksize != flash->total_size * 1024)) {
- msg_cerr("%s called with incorrect arguments\n",
- __func__);
- return -1;
- }
- return erase_chip_jedec_common(flash, mask);
- }
- int probe_jedec(struct flashctx *flash)
- {
- unsigned int mask;
- mask = getaddrmask(flash);
- return probe_jedec_common(flash, mask);
- }
- int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int size)
- {
- unsigned int mask;
- mask = getaddrmask(flash);
- return erase_sector_jedec_common(flash, page, size, mask);
- }
- int erase_block_jedec(struct flashctx *flash, unsigned int page, unsigned int size)
- {
- unsigned int mask;
- mask = getaddrmask(flash);
- return erase_block_jedec_common(flash, page, size, mask);
- }
- int erase_chip_jedec(struct flashctx *flash)
- {
- unsigned int mask;
- mask = getaddrmask(flash);
- return erase_chip_jedec_common(flash, mask);
- }
|