Commit 9dedbdb2 authored by Boris Baykov's avatar Boris Baykov Committed by Timothy Pearson
parent f5dd7ce1
......@@ -514,7 +514,7 @@ endif
CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
sst28sf040.o 82802ab.o \
sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \
opaque.o sfdp.o en29lv640b.o at45db.o
spi4ba.o opaque.o sfdp.o en29lv640b.o at45db.o
###############################################################################
# Library code.
......
......@@ -195,4 +195,26 @@ int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int
int probe_en29lv640b(struct flashctx *flash);
int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
/* spi4ba.c */
int spi_enter_4ba_b7(struct flashctx *flash);
int spi_enter_4ba_b7_we(struct flashctx *flash);
int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
#endif /* !__CHIPDRIVERS_H__ */
......@@ -90,7 +90,8 @@ int print(enum msglevel level, const char *fmt, ...)
fflush(output_type);
}
#ifndef STANDALONE
if ((level <= verbose_logfile) && logfile) {
/* skip of msgs starting from '\b' added to skip progress percents */
if ((level <= verbose_logfile) && logfile && (!fmt || fmt[0] != '\b')) {
va_start(ap, fmt);
ret = vfprintf(logfile, fmt, ap);
va_end(ap);
......
......@@ -123,6 +123,14 @@ enum write_granularity {
#define FEATURE_WRSR_EITHER (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
#define FEATURE_OTP (1 << 8)
#define FEATURE_QPI (1 << 9)
/* Feature bits used for 4-bytes addressing mode */
#define FEATURE_4BA_SUPPORT (1 << 10)
#define FEATURE_4BA_ONLY (1 << 11)
#define FEATURE_4BA_EXTENDED_ADDR_REG (1 << 12)
#define FEATURE_4BA_DIRECT_READ (1 << 13)
#define FEATURE_4BA_DIRECT_WRITE (1 << 14)
#define FEATURE_4BA_ALL_ERASERS_DIRECT (1 << 15)
#define FEATURE_4BA_ALL_DIRECT (FEATURE_4BA_DIRECT_READ | FEATURE_4BA_DIRECT_WRITE | FEATURE_4BA_ALL_ERASERS_DIRECT)
enum test_state {
OK = 0,
......@@ -167,6 +175,14 @@ struct flashchip {
unsigned int page_size;
int feature_bits;
/* set of function pointers to use in 4-bytes addressing mode */
struct four_bytes_addr_funcs_set {
int (*enter_4ba) (struct flashctx *flash);
int (*read_nbyte) (struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int (*program_byte) (struct flashctx *flash, unsigned int addr, const uint8_t databyte);
int (*program_nbyte) (struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
} four_bytes_addr_funcs;
/* Indicate how well flashrom supports different operations of this flash chip. */
struct tested {
enum test_state probe;
......@@ -344,6 +360,11 @@ __attribute__((format(printf, 2, 3)));
#define msg_pspew(...) print(MSG_SPEW, __VA_ARGS__) /* programmer debug spew */
#define msg_cspew(...) print(MSG_SPEW, __VA_ARGS__) /* chip debug spew */
/* Read progress will be shown for reads more than 256KB */
#define MIN_LENGTH_TO_SHOW_READ_PROGRESS 256 * 1024
/* Read progress will be shown for erases and writes more than 64KB */
#define MIN_LENGTH_TO_SHOW_ERASE_AND_WRITE_PROGRESS 64 * 1024
/* layout.c */
int register_include_arg(char *name);
int process_include_args(void);
......
......@@ -14586,6 +14586,54 @@ const struct flashchip flashchips[] = {
.voltage = {2700, 3600},
},
{
.vendor = "Winbond",
.name = "W25Q256.V",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
.model_id = WINBOND_NEX_W25Q256_V,
.total_size = 32768,
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
/* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_SUPPORT | FEATURE_4BA_DIRECT_READ,
.four_bytes_addr_funcs =
{
.enter_4ba = spi_enter_4ba_b7_we, /* enter 4-bytes addressing mode by CMD B7 + WREN */
.read_nbyte = spi_nbyte_read_4ba_direct, /* read directly from any mode, no need to enter 4ba */
.program_byte = spi_byte_program_4ba, /* write from 4-bytes addressing mode */
.program_nbyte = spi_nbyte_program_4ba /* write from 4-bytes addressing mode */
},
.tested = TEST_OK_PREW,
.probe = probe_spi_rdid,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
.block_erase = spi_block_erase_20_4ba, /* erases 4k from 4-bytes addressing mode */
}, {
.eraseblocks = { {32 * 1024, 1024} },
.block_erase = spi_block_erase_52_4ba, /* erases 32k from 4-bytes addressing mode */
}, {
.eraseblocks = { {64 * 1024, 512} },
.block_erase = spi_block_erase_d8_4ba, /* erases 64k from 4-bytes addressing mode */
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
.block_erase = spi_block_erase_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
.block_erase = spi_block_erase_c7,
}
},
.printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
.unlock = spi_disable_blockprotect,
.write = spi_chip_write_256,
.read = spi_chip_read,
.voltage = {2700, 3600},
},
{
.vendor = "Winbond",
.name = "W25Q20.W",
......
......@@ -1527,6 +1527,17 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction,
unsigned int start = 0;
unsigned int len;
struct block_eraser eraser = flash->chip->block_erasers[erasefunction];
int show_progress = 0;
unsigned int percent_last, percent_current;
unsigned long size = flash->chip->total_size * 1024;
/* progress visualizaion init */
if(size >= MIN_LENGTH_TO_SHOW_ERASE_AND_WRITE_PROGRESS) {
msg_cinfo(" "); /* only this space will go to logfile but all strings with \b wont. */
msg_cinfo("\b 0%%");
percent_last = percent_current = 0;
show_progress = 1; /* enable progress visualizaion */
}
for (i = 0; i < NUM_ERASEREGIONS; i++) {
/* count==0 for all automatically initialized array
......@@ -1544,8 +1555,20 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction,
return 1;
}
start += len;
if(show_progress) {
percent_current = (unsigned int) ((unsigned long long)start * 100 / size);
if(percent_current != percent_last) {
msg_cinfo("\b\b\b%2d%%", percent_current);
percent_last = percent_current;
}
}
}
}
if(show_progress)
msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */
msg_cdbg("\n");
return 0;
}
......@@ -2001,6 +2024,44 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
if (flash->chip->unlock)
flash->chip->unlock(flash);
/* Switching to 4-Bytes Addressing mode if flash chip supports it */
if(flash->chip->feature_bits & FEATURE_4BA_SUPPORT) {
/* Do not switch if chip is already in 4-bytes addressing mode */
if (flash->chip->feature_bits & FEATURE_4BA_ONLY) {
msg_cdbg("Flash chip is already in 4-bytes addressing mode.\n");
}
/* Do not switch to 4-Bytes Addressing mode if using Extended Address Register */
else if(flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) {
msg_cdbg("Using 4-bytes addressing with extended address register.\n");
}
/* Go to 4-Bytes Addressing mode if selected
operation requires 4-Bytes Addressing mode
(no need if functions are direct-4BA) */
else if(((read_it || verify_it)
&& (!(flash->chip->feature_bits & FEATURE_4BA_DIRECT_READ)))
|| ((erase_it || write_it)
&& ((flash->chip->feature_bits & FEATURE_4BA_ALL_DIRECT) != FEATURE_4BA_ALL_DIRECT))) {
if (!flash->chip->four_bytes_addr_funcs.enter_4ba) {
msg_cerr("No function for Enter 4-bytes addressing mode for this flash chip.\n"
"Please report to flashrom@flashrom.org\n");
return 1;
}
if(flash->chip->four_bytes_addr_funcs.enter_4ba(flash)) {
msg_cerr("Switching to 4-bytes addressing mode failed!\n");
return 1;
}
msg_cdbg("Switched to 4-bytes addressing mode.\n");
}
/* Do not switch to 4-Bytes Addressing mode if all instructions are direct-4BA
or if the flash chip is 4-Bytes Addressing Only and always in 4BA-mode */
else {
msg_cdbg2("No need to switch to 4-bytes addressing mode.\n");
}
}
if (read_it) {
return read_flash_to_file(flash, filename);
}
......
......@@ -945,7 +945,10 @@ static int serprog_spi_read(struct flashctx *flash, uint8_t *buf,
for (i = 0; i < len; i += cur_len) {
int ret;
cur_len = min(max_read, (len - i));
ret = spi_nbyte_read(flash, start + i, buf + i, cur_len);
ret = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
? spi_nbyte_read(flash, start + i, buf + i, cur_len)
: flash->chip->four_bytes_addr_funcs.read_nbyte(flash,
start + i, buf + i, cur_len);
if (ret)
return ret;
}
......
......@@ -110,7 +110,10 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
* means 0xffffff, the highest unsigned 24bit number.
*/
addrbase = spi_get_valid_read_addr(flash);
if (addrbase + flash->chip->total_size * 1024 > (1 << 24)) {
/* Show flash chip size warning if flash chip doesn't support
4-Bytes Addressing mode and last address excedes 24 bits */
if (!(flash->chip->feature_bits & FEATURE_4BA_SUPPORT) &&
addrbase + flash->chip->total_size * 1024 > (1 << 24)) {
msg_perr("Flash chip size exceeds the allowed access window. ");
msg_perr("Read will probably fail.\n");
/* Try to get the best alignment subject to constraints. */
......
......@@ -28,6 +28,7 @@
#include "chipdrivers.h"
#include "programmer.h"
#include "spi.h"
#include "spi4ba.h"
static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
{
......@@ -948,6 +949,16 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
int rc = 0;
unsigned int i, j, starthere, lenhere, toread;
unsigned int page_size = flash->chip->page_size;
int show_progress = 0;
unsigned int percent_last, percent_current;
/* progress visualizaion init */
if(len >= MIN_LENGTH_TO_SHOW_READ_PROGRESS) {
msg_cinfo(" "); /* only this space will go to logfile but all strings with \b wont. */
msg_cinfo("\b 0%%");
percent_last = percent_current = 0;
show_progress = 1; /* enable progress visualizaion */
}
/* Warning: This loop has a very unusual condition and body.
* The loop needs to go through each page with at least one affected
......@@ -966,14 +977,29 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
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(flash, starthere + j, buf + starthere - start + j, toread);
rc = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
? spi_nbyte_read(flash, starthere + j, buf + starthere - start + j, toread)
: flash->chip->four_bytes_addr_funcs.read_nbyte(flash, starthere + j,
buf + starthere - start + j, toread);
if (rc)
break;
}
if (rc)
break;
if(show_progress) {
percent_current = (unsigned int) ((unsigned long long)(starthere +
lenhere - start) * 100 / len);
if(percent_current != percent_last) {
msg_cinfo("\b\b\b%2d%%", percent_current);
percent_last = percent_current;
}
}
}
if(show_progress && !rc)
msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */
return rc;
}
......@@ -1011,7 +1037,10 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
lenhere = min(start + len, (i + 1) * page_size) - starthere;
for (j = 0; j < lenhere; j += chunksize) {
towrite = min(chunksize, lenhere - j);
rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
rc = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
? spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite)
: flash->chip->four_bytes_addr_funcs.program_nbyte(flash, starthere + j,
buf + starthere - start + j, towrite);
if (rc)
break;
while (spi_read_status_register(flash) & SPI_SR_WIP)
......@@ -1037,7 +1066,9 @@ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int st
int result = 0;
for (i = start; i < start + len; i++) {
result = spi_byte_program(flash, i, buf[i - start]);
result = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
? spi_byte_program(flash, i, buf[i - start])
: flash->chip->four_bytes_addr_funcs.program_byte(flash, i, buf[i - start]);
if (result)
return 1;
while (spi_read_status_register(flash) & SPI_SR_WIP)
......
This diff is collapsed.
/*
* This file is part of the flashrom project.
*
* Copyright (C) 2014 Boris Baykov
*
* 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
*/
/*
* JEDEC flash chips instructions for 4-bytes addressing
* SPI chip driver functions for 4-bytes addressing
*/
#ifndef __SPI_4BA_H__
#define __SPI_4BA_H__ 1
/* Enter 4-byte Address Mode */
#define JEDEC_ENTER_4_BYTE_ADDR_MODE 0xB7
#define JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE 0x01
#define JEDEC_ENTER_4_BYTE_ADDR_MODE_INSIZE 0x00
/* Exit 4-byte Address Mode */
#define JEDEC_EXIT_4_BYTE_ADDR_MODE 0xE9
#define JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE 0x01
#define JEDEC_EXIT_4_BYTE_ADDR_MODE_INSIZE 0x00
/* Write Extended Address Register */
#define JEDEC_WRITE_EXT_ADDR_REG 0xC5
#define JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE 0x02
#define JEDEC_WRITE_EXT_ADDR_REG_INSIZE 0x00
/* Read Extended Address Register */
#define JEDEC_READ_EXT_ADDR_REG 0xC8
#define JEDEC_READ_EXT_ADDR_REG_OUTSIZE 0x01
#define JEDEC_READ_EXT_ADDR_REG_INSIZE 0x01
/* Read the memory with 4-byte address
From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
#define JEDEC_READ_4BA 0x13
#define JEDEC_READ_4BA_OUTSIZE 0x05
/* JEDEC_READ_4BA_INSIZE : any length */
/* Write memory byte with 4-byte address
From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
#define JEDEC_BYTE_PROGRAM_4BA 0x12
#define JEDEC_BYTE_PROGRAM_4BA_OUTSIZE 0x06
#define JEDEC_BYTE_PROGRAM_4BA_INSIZE 0x00
/* Sector Erase 0x21 (with 4-byte address), usually 4k size.
From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
#define JEDEC_SE_4BA 0x21
#define JEDEC_SE_4BA_OUTSIZE 0x05
#define JEDEC_SE_4BA_INSIZE 0x00
/* Block Erase 0x5C (with 4-byte address), usually 32k size.
From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
#define JEDEC_BE_5C_4BA 0x5C
#define JEDEC_BE_5C_4BA_OUTSIZE 0x05
#define JEDEC_BE_5C_4BA_INSIZE 0x00
/* Block Erase 0xDC (with 4-byte address), usually 64k size.
From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
#define JEDEC_BE_DC_4BA 0xdc
#define JEDEC_BE_DC_4BA_OUTSIZE 0x05
#define JEDEC_BE_DC_4BA_INSIZE 0x00
/* enter 4-bytes addressing mode */
int spi_enter_4ba_b7(struct flashctx *flash);
int spi_enter_4ba_b7_we(struct flashctx *flash);
/* read/write flash bytes in 4-bytes addressing mode */
int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
/* erase flash bytes in 4-bytes addressing mode */
int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
/* read/write flash bytes from 3-bytes addressing mode using extended address register */
int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
/* erase flash bytes from 3-bytes addressing mode using extended address register */
int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
/* read/write flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
/* erase flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
#endif /* __SPI_4BA_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment