@@ -26,26 +26,27 @@
#ifndef __LIBPAYLOAD__
#include <fcntl.h>
#include <sys/stat.h>
#endif
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
#if HAVE_UTSNAME == 1
#include <sys/utsname.h>
#endif
+#include "chipdrivers.h"
#include "flash.h"
#include "flashchips.h"
#include "programmer.h"
#include "hwaccess.h"
const char flashrom_version[] = FLASHROM_VERSION;
const char *chip_to_probe = NULL;
static enum programmer programmer = PROGRAMMER_INVALID;
static const char *programmer_param = NULL;
/*
* Programmers supporting multiple buses can have differing size limits on
@@ -1250,29 +1251,37 @@ notfound:
msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) ", force ? "Assuming" : "Found",
flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp);
free(tmp);
#if CONFIG_INTERNAL == 1
if (programmer_table[programmer].map_flash_region == physmap)
msg_cinfo("mapped at physical address 0x%0*" PRIxPTR ".\n",
PRIxPTR_WIDTH, flash->physical_memory);
else
#endif
msg_cinfo("on %s.\n", programmer_table[programmer].name);
/* Flash registers may more likely not be mapped if the chip was forced.
* Lock info may be stored in registers, so avoid lock info printing. */
- if (!force)
- if (flash->chip->printlock)
+ if (!force) {
+ if (flash->chip->status_register) {
+ for (enum status_register_num SRn = SR1; SRn <= top_status_register(flash); SRn++)
+ flash->chip->status_register->print(flash, SRn);
+ flash->chip->status_register->print_wp_mode(flash);
+ if (flash->chip->wp)
+ print_range_generic(flash);
+ } else if (flash->chip->printlock) {
flash->chip->printlock(flash);
+ }
+ }
/* Get out of the way for later runs. */
unmap_flash(flash);
/* Return position of matching chip. */
return chip - flashchips;
}
int read_buf_from_file(unsigned char *buf, unsigned long size,
const char *filename)
{
#ifdef __LIBPAYLOAD__
msg_gerr("Error: No file I/O support in libpayload\n");
@@ -1988,27 +1997,29 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) {
msg_cerr("Aborting.\n");
return 1;
}
if (normalize_romentries(flash)) {
msg_cerr("Requested regions can not be handled. Aborting.\n");
return 1;
}
/* Given the existence of read locks, we want to unlock for read,
* erase and write.
*/
- if (flash->chip->unlock)
+ if (flash->chip->wp)
+ flash->chip->wp->disable(flash);
+ else if (flash->chip->unlock)
flash->chip->unlock(flash);
if (read_it) {
return read_flash_to_file(flash, filename);
}
oldcontents = malloc(size);
if (!oldcontents) {
msg_gerr("Out of memory!\n");
exit(1);
}
/* Assume worst case: All bits are 0. */
memset(oldcontents, 0x00, size);
@@ -341,29 +341,35 @@ int spi_chip_erase_60(struct flashctx *flash)
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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(flash) & SPI_SR_WIP)
- programmer_delay(1000 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(1000 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(1000 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
int spi_chip_erase_62(struct flashctx *flash)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
.readcnt = 0,
.readarr = NULL,
@@ -378,29 +384,35 @@ int spi_chip_erase_62(struct flashctx *flash)
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution\n",
__func__);
return result;
}
/* Wait until the Write-In-Progress bit is cleared.
* This usually takes 2-5 s, so wait in 100 ms steps.
*/
- /* FIXME: We assume spi_read_status_register will never fail. */
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(100 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
int spi_chip_erase_c7(struct flashctx *flash)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
.readcnt = 0,
.readarr = NULL,
@@ -414,29 +426,35 @@ int spi_chip_erase_c7(struct flashctx *flash)
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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(flash) & SPI_SR_WIP)
- programmer_delay(1000 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(1000 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(1000 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
int spi_block_erase_52(struct flashctx *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,
@@ -457,28 +475,35 @@ int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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(flash) & SPI_SR_WIP)
- programmer_delay(100 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
/* Block size is usually
* 32M (one die) for Micron
*/
int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
@@ -500,28 +525,35 @@ int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int b
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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 240-480 s, so wait in 500 ms steps.
*/
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(500 * 1000 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(500 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(500 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
/* Block size is usually
* 64k for Macronix
* 32k for SST
* 4-32k non-uniform for EON
*/
int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
{
int result;
@@ -547,28 +579,35 @@ int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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(flash) & SPI_SR_WIP)
- programmer_delay(100 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
/* Block size is usually
* 4k for PMC
*/
int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
{
int result;
struct spi_command cmds[] = {
{
@@ -592,28 +631,35 @@ int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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(flash) & SPI_SR_WIP)
- programmer_delay(100 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(100 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
/* Page erase (usually 256B blocks) */
int spi_block_erase_db(struct flashctx *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,
@@ -633,28 +679,35 @@ int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int b
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
} };
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
return result;
}
/* Wait until the Write-In-Progress bit is cleared.
* This takes up to 20 ms usually (on worn out devices up to the 0.5s range), so wait in 1 ms steps. */
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(1 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(1 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(1 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
/* Sector size is usually 4k, though Macronix eliteflash has 64k */
int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
@@ -676,28 +729,35 @@ int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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(flash) & SPI_SR_WIP)
- programmer_delay(10 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(10 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(10 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
int spi_block_erase_50(struct flashctx *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,
@@ -716,28 +776,35 @@ int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int b
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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 10 ms, so wait in 1 ms steps.
*/
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(1 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(1 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(1 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
int spi_block_erase_81(struct flashctx *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,
@@ -756,28 +823,35 @@ int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int b
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%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 8 ms, so wait in 1 ms steps.
*/
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(1 * 1000);
+ /* FIXME: We assume reading status register(s) will never fail. */
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(1 * 1000);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(1 * 1000);
+ }
/* FIXME: Check the status register for errors. */
return 0;
}
int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
{
if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
msg_cerr("%s called with incorrect arguments\n",
__func__);
return -1;
}
return spi_chip_erase_60(flash);
@@ -1004,54 +1078,66 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
* 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) {
towrite = min(chunksize, lenhere - j);
rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
if (rc)
break;
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(10);
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(10);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(10);
+ }
}
if (rc)
break;
}
return rc;
}
/*
* 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)
*/
/* real chunksize is 1, logical chunksize is 1 */
int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
{
unsigned int i;
int result = 0;
for (i = start; i < start + len; i++) {
result = spi_byte_program(flash, i, buf[i - start]);
if (result)
return 1;
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(10);
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(10);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(10);
+ }
}
return 0;
}
int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
{
uint32_t pos = start;
int result;
unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
JEDEC_AAI_WORD_PROGRAM,
};
struct spi_command cmds[] = {
@@ -1120,43 +1206,55 @@ int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned i
if (len % 2) {
msg_cerr("%s: total write length not even! Please report a "
"bug at flashrom@flashrom.org\n", __func__);
/* Do not return an error for now. */
//return SPI_GENERIC_ERROR;
}
result = spi_send_multicommand(flash, cmds);
if (result != 0) {
msg_cerr("%s failed during start command execution: %d\n", __func__, result);
goto bailout;
}
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(10);
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(10);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(10);
+ }
/* We already wrote 2 bytes in the multicommand step. */
pos += 2;
/* Are there at least two more bytes to write? */
while (pos < start + len - 1) {
cmd[1] = buf[pos++ - start];
cmd[2] = buf[pos++ - start];
result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
if (result != 0) {
msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result);
goto bailout;
}
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(10);
+ // TODO(hatim): Switch to newer infrastructure completely after integration
+ if (flash->chip->status_register) {
+ while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP)
+ programmer_delay(10);
+ } else {
+ while (spi_read_status_register(flash) & SPI_SR_WIP)
+ programmer_delay(10);
+ }
}
/* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */
result = spi_write_disable(flash);
if (result != 0) {
msg_cerr("%s failed to disable AAI mode.\n", __func__);
return SPI_GENERIC_ERROR;
}
/* Write remaining byte (if any). */
if (pos < start + len) {
if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
return SPI_GENERIC_ERROR;
- New infrastructure is used to read status register (for chips that have support for struct status_register) throughout spi25.c. - New infrastructure is used to prettyprint status register and write protection mode of status register (for chips that have support for struct status_register) in flashrom.c. - New disable from access protection infrastructure is used (for chips that have support for struct wp) in flashrom.c Signed-off-by: Hatim Kanchwala <hatim@hatimak.me> --- flashrom.c | 17 +++++-- spi25.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 145 insertions(+), 36 deletions(-)