Anastasia Klimchuk has uploaded this change for review.
tree: Removing forward-declarations for spi masters
Reordering functions to avoid forward-declarations. It looks like
for most of the spi masters this has already been done before, I
found 7 that still have forward-declarations and covered them all
in one patch.
BUG=b:140394053
TEST=builds
Change-Id: I23ff6b79d794876f73b327f18784ca7c04c32c84
Signed-off-by: Anastasia Klimchuk <aklm@chromium.org>
---
M buspirate_spi.c
M dummyflasher.c
M ft2232_spi.c
M ichspi.c
M linux_spi.c
M ni845x_spi.c
M serprog.c
7 files changed, 1,165 insertions(+), 1,224 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/11/50711/1
diff --git a/buspirate_spi.c b/buspirate_spi.c
index fdfc0e4..eee8daa 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -128,11 +128,6 @@
return ret;
}
-static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
-static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
-
static struct spi_master spi_master_buspirate = {
.features = SPI_MASTER_4BA,
.max_data_read = MAX_DATA_UNSPECIFIED,
@@ -205,6 +200,99 @@
return ret;
}
+static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ unsigned int i = 0;
+ int ret = 0;
+
+ if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
+ return SPI_INVALID_LENGTH;
+
+ /* 3 bytes extra for CS#, len, CS#. */
+ if (buspirate_commbuf_grow(writecnt + readcnt + 3))
+ return ERROR_OOM;
+
+ /* Assert CS# */
+ bp_commbuf[i++] = 0x02;
+
+ bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
+ memcpy(bp_commbuf + i, writearr, writecnt);
+ i += writecnt;
+ memset(bp_commbuf + i, 0, readcnt);
+
+ i += readcnt;
+ /* De-assert CS# */
+ bp_commbuf[i++] = 0x03;
+
+ ret = buspirate_sendrecv(bp_commbuf, i, i);
+
+ if (ret) {
+ msg_perr("Bus Pirate communication error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[0] != 0x01) {
+ msg_perr("Protocol error while lowering CS#!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[1] != 0x01) {
+ msg_perr("Protocol error while reading/writing SPI!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[i - 1] != 0x01) {
+ msg_perr("Protocol error while raising CS#!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ /* Skip CS#, length, writearr. */
+ memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
+
+ return ret;
+}
+
+static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ int i = 0, ret = 0;
+
+ if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
+ return SPI_INVALID_LENGTH;
+
+ /* 5 bytes extra for command, writelen, readlen.
+ * 1 byte extra for Ack/Nack.
+ */
+ if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1)))
+ return ERROR_OOM;
+
+ /* Combined SPI write/read. */
+ bp_commbuf[i++] = 0x04;
+ bp_commbuf[i++] = (writecnt >> 8) & 0xff;
+ bp_commbuf[i++] = writecnt & 0xff;
+ bp_commbuf[i++] = (readcnt >> 8) & 0xff;
+ bp_commbuf[i++] = readcnt & 0xff;
+ memcpy(bp_commbuf + i, writearr, writecnt);
+
+ ret = buspirate_sendrecv(bp_commbuf, i + writecnt, 1 + readcnt);
+
+ if (ret) {
+ msg_perr("Bus Pirate communication error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[0] != 0x01) {
+ msg_perr("Protocol error while sending SPI write/read!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ /* Skip Ack. */
+ memcpy(readarr, bp_commbuf + 1, readcnt);
+
+ return ret;
+}
+
#define BP_FWVERSION(a,b) ((a) << 8 | (b))
#define BP_HWVERSION(a,b) BP_FWVERSION(a,b)
@@ -571,96 +659,3 @@
return 0;
}
-
-static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr)
-{
- unsigned int i = 0;
- int ret = 0;
-
- if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
- return SPI_INVALID_LENGTH;
-
- /* 3 bytes extra for CS#, len, CS#. */
- if (buspirate_commbuf_grow(writecnt + readcnt + 3))
- return ERROR_OOM;
-
- /* Assert CS# */
- bp_commbuf[i++] = 0x02;
-
- bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
- memcpy(bp_commbuf + i, writearr, writecnt);
- i += writecnt;
- memset(bp_commbuf + i, 0, readcnt);
-
- i += readcnt;
- /* De-assert CS# */
- bp_commbuf[i++] = 0x03;
-
- ret = buspirate_sendrecv(bp_commbuf, i, i);
-
- if (ret) {
- msg_perr("Bus Pirate communication error!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[0] != 0x01) {
- msg_perr("Protocol error while lowering CS#!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[1] != 0x01) {
- msg_perr("Protocol error while reading/writing SPI!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[i - 1] != 0x01) {
- msg_perr("Protocol error while raising CS#!\n");
- return SPI_GENERIC_ERROR;
- }
-
- /* Skip CS#, length, writearr. */
- memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
-
- return ret;
-}
-
-static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr)
-{
- int i = 0, ret = 0;
-
- if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
- return SPI_INVALID_LENGTH;
-
- /* 5 bytes extra for command, writelen, readlen.
- * 1 byte extra for Ack/Nack.
- */
- if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1)))
- return ERROR_OOM;
-
- /* Combined SPI write/read. */
- bp_commbuf[i++] = 0x04;
- bp_commbuf[i++] = (writecnt >> 8) & 0xff;
- bp_commbuf[i++] = writecnt & 0xff;
- bp_commbuf[i++] = (readcnt >> 8) & 0xff;
- bp_commbuf[i++] = readcnt & 0xff;
- memcpy(bp_commbuf + i, writearr, writecnt);
-
- ret = buspirate_sendrecv(bp_commbuf, i + writecnt, 1 + readcnt);
-
- if (ret) {
- msg_perr("Bus Pirate communication error!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[0] != 0x01) {
- msg_perr("Protocol error while sending SPI write/read!\n");
- return SPI_GENERIC_ERROR;
- }
-
- /* Skip Ack. */
- memcpy(readarr, bp_commbuf + 1, readcnt);
-
- return ret;
-}
diff --git a/dummyflasher.c b/dummyflasher.c
index 92c30ee..5190282 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -102,19 +102,514 @@
#endif
static unsigned int spi_write_256_chunksize = 256;
+static enum chipbustype dummy_buses_supported = BUS_NONE;
-static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
-static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf,
- unsigned int start, unsigned int len);
-static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
-static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
-static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len);
-static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr);
-static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr);
-static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr);
-static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
+void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
+{
+ msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
+ __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
+ return (void *)phys_addr;
+}
+
+void dummy_unmap(void *virt_addr, size_t len)
+{
+ msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
+}
+
+static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+{
+ return spi_write_chunked(flash, buf, start, len,
+ spi_write_256_chunksize);
+}
+
+static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%02x\n", __func__, addr, val);
+}
+
+static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%04x\n", __func__, addr, val);
+}
+
+static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08x\n", __func__, addr, val);
+}
+
+static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
+{
+ size_t i;
+ msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, writing data (hex):", __func__, addr, len);
+ for (i = 0; i < len; i++) {
+ if ((i % 16) == 0)
+ msg_pspew("\n");
+ msg_pspew("%02x ", buf[i]);
+ }
+}
+
+static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xff\n", __func__, addr);
+ return 0xff;
+}
+
+static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffff\n", __func__, addr);
+ return 0xffff;
+}
+
+static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffffffff\n", __func__, addr);
+ return 0xffffffff;
+}
+
+static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len)
+{
+ msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, returning array of 0xff\n", __func__, addr, len);
+ memset(buf, 0xff, len);
+ return;
+}
+
+static struct emu_data* get_data_from_context(const struct flashctx *flash)
+{
+ if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
+ return (struct emu_data *)flash->mst->par.data;
+ else if (dummy_buses_supported & BUS_SPI)
+ return (struct emu_data *)flash->mst->spi.data;
+
+ return NULL; /* buses was set to BUS_NONE. */
+}
+
+#if EMULATE_SPI_CHIP
+static int emulate_spi_chip_response(unsigned int writecnt,
+ unsigned int readcnt,
+ const unsigned char *writearr,
+ unsigned char *readarr,
+ struct emu_data *data)
+{
+ unsigned int offs, i, toread;
+ static int unsigned aai_offs;
+ const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
+ const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
+ const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
+ const unsigned char w25q128fv_rems_response[2] = {0xef, 0x17};
+
+ if (writecnt == 0) {
+ msg_perr("No command sent to the chip!\n");
+ return 1;
+ }
+ /* spi_blacklist has precedence over spi_ignorelist. */
+ for (i = 0; i < data->spi_blacklist_size; i++) {
+ if (writearr[0] == data->spi_blacklist[i]) {
+ msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
+ data->spi_blacklist[i]);
+ return SPI_INVALID_OPCODE;
+ }
+ }
+ for (i = 0; i < data->spi_ignorelist_size; i++) {
+ if (writearr[0] == data->spi_ignorelist[i]) {
+ msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
+ data->spi_ignorelist[i]);
+ /* Return success because the command does not fail,
+ * it is simply ignored.
+ */
+ return 0;
+ }
+ }
+
+ if (data->emu_max_aai_size && (data->emu_status & SPI_SR_AAI)) {
+ if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
+ writearr[0] != JEDEC_WRDI &&
+ writearr[0] != JEDEC_RDSR) {
+ msg_perr("Forbidden opcode (0x%02x) attempted during "
+ "AAI sequence!\n", writearr[0]);
+ return 0;
+ }
+ }
+
+ switch (writearr[0]) {
+ case JEDEC_RES:
+ if (writecnt < JEDEC_RES_OUTSIZE)
+ break;
+ /* offs calculation is only needed for SST chips which treat RES like REMS. */
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ offs += writecnt - JEDEC_REMS_OUTSIZE;
+ switch (data->emu_chip) {
+ case EMULATE_ST_M25P10_RES:
+ if (readcnt > 0)
+ memset(readarr, 0x10, readcnt);
+ break;
+ case EMULATE_SST_SST25VF040_REMS:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
+ break;
+ case EMULATE_SST_SST25VF032B:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
+ break;
+ case EMULATE_MACRONIX_MX25L6436:
+ if (readcnt > 0)
+ memset(readarr, 0x16, readcnt);
+ break;
+ case EMULATE_WINBOND_W25Q128FV:
+ if (readcnt > 0)
+ memset(readarr, 0x17, readcnt);
+ break;
+ default: /* ignore */
+ break;
+ }
+ break;
+ case JEDEC_REMS:
+ /* REMS response has wraparound and uses an address parameter. */
+ if (writecnt < JEDEC_REMS_OUTSIZE)
+ break;
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ offs += writecnt - JEDEC_REMS_OUTSIZE;
+ switch (data->emu_chip) {
+ case EMULATE_SST_SST25VF040_REMS:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
+ break;
+ case EMULATE_SST_SST25VF032B:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
+ break;
+ case EMULATE_MACRONIX_MX25L6436:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = mx25l6436_rems_response[(offs + i) % 2];
+ break;
+ case EMULATE_WINBOND_W25Q128FV:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = w25q128fv_rems_response[(offs + i) % 2];
+ break;
+ default: /* ignore */
+ break;
+ }
+ break;
+ case JEDEC_RDID:
+ switch (data->emu_chip) {
+ case EMULATE_SST_SST25VF032B:
+ if (readcnt > 0)
+ readarr[0] = 0xbf;
+ if (readcnt > 1)
+ readarr[1] = 0x25;
+ if (readcnt > 2)
+ readarr[2] = 0x4a;
+ break;
+ case EMULATE_MACRONIX_MX25L6436:
+ if (readcnt > 0)
+ readarr[0] = 0xc2;
+ if (readcnt > 1)
+ readarr[1] = 0x20;
+ if (readcnt > 2)
+ readarr[2] = 0x17;
+ break;
+ case EMULATE_WINBOND_W25Q128FV:
+ if (readcnt > 0)
+ readarr[0] = 0xef;
+ if (readcnt > 1)
+ readarr[1] = 0x40;
+ if (readcnt > 2)
+ readarr[2] = 0x18;
+ break;
+ case EMULATE_VARIABLE_SIZE:
+ if (readcnt > 0)
+ readarr[0] = (PROGMANUF_ID >> 8) & 0xff;
+ if (readcnt > 1)
+ readarr[1] = PROGMANUF_ID & 0xff;
+ if (readcnt > 2)
+ readarr[2] = (PROGDEV_ID >> 8) & 0xff;
+ if (readcnt > 3)
+ readarr[3] = PROGDEV_ID & 0xff;
+ break;
+ default: /* ignore */
+ break;
+ }
+ break;
+ case JEDEC_RDSR:
+ memset(readarr, data->emu_status, readcnt);
+ break;
+ /* FIXME: this should be chip-specific. */
+ case JEDEC_EWSR:
+ case JEDEC_WREN:
+ data->emu_status |= SPI_SR_WEL;
+ break;
+ case JEDEC_WRSR:
+ if (!(data->emu_status & SPI_SR_WEL)) {
+ msg_perr("WRSR attempted, but WEL is 0!\n");
+ break;
+ }
+ /* FIXME: add some reasonable simulation of the busy flag */
+ data->emu_status = writearr[1] & ~SPI_SR_WIP;
+ msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status);
+ break;
+ case JEDEC_READ:
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ /* Truncate to emu_chip_size. */
+ offs %= data->emu_chip_size;
+ if (readcnt > 0)
+ memcpy(readarr, flashchip_contents + offs, readcnt);
+ break;
+ case JEDEC_READ_4BA:
+ offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
+ /* Truncate to emu_chip_size. */
+ offs %= data->emu_chip_size;
+ if (readcnt > 0)
+ memcpy(readarr, flashchip_contents + offs, readcnt);
+ break;
+ case JEDEC_BYTE_PROGRAM:
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ /* Truncate to emu_chip_size. */
+ offs %= data->emu_chip_size;
+ if (writecnt < 5) {
+ msg_perr("BYTE PROGRAM size too short!\n");
+ return 1;
+ }
+ if (writecnt - 4 > data->emu_max_byteprogram_size) {
+ msg_perr("Max BYTE PROGRAM size exceeded!\n");
+ return 1;
+ }
+ memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_BYTE_PROGRAM_4BA:
+ offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
+ /* Truncate to emu_chip_size. */
+ offs %= data->emu_chip_size;
+ if (writecnt < 6) {
+ msg_perr("BYTE PROGRAM size too short!\n");
+ return 1;
+ }
+ if (writecnt - 5 > data->emu_max_byteprogram_size) {
+ msg_perr("Max BYTE PROGRAM size exceeded!\n");
+ return 1;
+ }
+ memcpy(flashchip_contents + offs, writearr + 5, writecnt - 5);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_AAI_WORD_PROGRAM:
+ if (!data->emu_max_aai_size)
+ break;
+ if (!(data->emu_status & SPI_SR_AAI)) {
+ if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
+ msg_perr("Initial AAI WORD PROGRAM size too "
+ "short!\n");
+ return 1;
+ }
+ if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
+ msg_perr("Initial AAI WORD PROGRAM size too "
+ "long!\n");
+ return 1;
+ }
+ data->emu_status |= SPI_SR_AAI;
+ aai_offs = writearr[1] << 16 | writearr[2] << 8 |
+ writearr[3];
+ /* Truncate to emu_chip_size. */
+ aai_offs %= data->emu_chip_size;
+ memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
+ aai_offs += 2;
+ } else {
+ if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
+ msg_perr("Continuation AAI WORD PROGRAM size "
+ "too short!\n");
+ return 1;
+ }
+ if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
+ msg_perr("Continuation AAI WORD PROGRAM size "
+ "too long!\n");
+ return 1;
+ }
+ memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
+ aai_offs += 2;
+ }
+ data->emu_modified = 1;
+ break;
+ case JEDEC_WRDI:
+ if (data->emu_max_aai_size)
+ data->emu_status &= ~SPI_SR_AAI;
+ break;
+ case JEDEC_SE:
+ if (!data->emu_jedec_se_size)
+ break;
+ if (writecnt != JEDEC_SE_OUTSIZE) {
+ msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
+ return 1;
+ }
+ if (readcnt != JEDEC_SE_INSIZE) {
+ msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
+ return 1;
+ }
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ if (offs & (data->emu_jedec_se_size - 1))
+ msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
+ offs &= ~(data->emu_jedec_se_size - 1);
+ memset(flashchip_contents + offs, 0xff, data->emu_jedec_se_size);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_BE_52:
+ if (!data->emu_jedec_be_52_size)
+ break;
+ if (writecnt != JEDEC_BE_52_OUTSIZE) {
+ msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
+ return 1;
+ }
+ if (readcnt != JEDEC_BE_52_INSIZE) {
+ msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
+ return 1;
+ }
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ if (offs & (data->emu_jedec_be_52_size - 1))
+ msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
+ offs &= ~(data->emu_jedec_be_52_size - 1);
+ memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_BE_D8:
+ if (!data->emu_jedec_be_d8_size)
+ break;
+ if (writecnt != JEDEC_BE_D8_OUTSIZE) {
+ msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
+ return 1;
+ }
+ if (readcnt != JEDEC_BE_D8_INSIZE) {
+ msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
+ return 1;
+ }
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ if (offs & (data->emu_jedec_be_d8_size - 1))
+ msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
+ offs &= ~(data->emu_jedec_be_d8_size - 1);
+ memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_CE_60:
+ if (!data->emu_jedec_ce_60_size)
+ break;
+ if (writecnt != JEDEC_CE_60_OUTSIZE) {
+ msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
+ return 1;
+ }
+ if (readcnt != JEDEC_CE_60_INSIZE) {
+ msg_perr("CHIP ERASE 0x60 insize invalid!\n");
+ return 1;
+ }
+ /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
+ /* emu_jedec_ce_60_size is emu_chip_size. */
+ memset(flashchip_contents, 0xff, data->emu_jedec_ce_60_size);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_CE_C7:
+ if (!data->emu_jedec_ce_c7_size)
+ break;
+ if (writecnt != JEDEC_CE_C7_OUTSIZE) {
+ msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
+ return 1;
+ }
+ if (readcnt != JEDEC_CE_C7_INSIZE) {
+ msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
+ return 1;
+ }
+ /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
+ /* emu_jedec_ce_c7_size is emu_chip_size. */
+ memset(flashchip_contents, 0xff, data->emu_jedec_ce_c7_size);
+ data->emu_modified = 1;
+ break;
+ case JEDEC_SFDP:
+ if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
+ break;
+ if (writecnt < 4)
+ break;
+ offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+
+ /* SFDP expects one dummy byte after the address. */
+ if (writecnt == 4) {
+ /* The dummy byte was not written, make sure it is read instead.
+ * Shifting and shortening the read array does achieve this goal.
+ */
+ readarr++;
+ readcnt--;
+ } else {
+ /* The response is shifted if more than 5 bytes are written, because SFDP data is
+ * already shifted out by the chip while those superfluous bytes are written. */
+ offs += writecnt - 5;
+ }
+
+ /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
+ * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
+ * This is a reasonable implementation choice in hardware because it saves a few gates. */
+ if (offs >= sizeof(sfdp_table)) {
+ msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
+ "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
+ offs %= sizeof(sfdp_table);
+ }
+ toread = min(sizeof(sfdp_table) - offs, readcnt);
+ memcpy(readarr, sfdp_table + offs, toread);
+ if (toread < readcnt)
+ msg_pdbg("Crossing the SFDP table boundary in a single "
+ "continuous chunk produces undefined results "
+ "after that point.\n");
+ break;
+ default:
+ /* No special response. */
+ break;
+ }
+ if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
+ data->emu_status &= ~SPI_SR_WEL;
+ return 0;
+}
+#endif
+
+static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
+ unsigned int readcnt,
+ const unsigned char *writearr,
+ unsigned char *readarr)
+{
+ unsigned int i;
+ struct emu_data *emu_data = get_data_from_context(flash);
+ if (!emu_data) {
+ msg_perr("No data in flash context!\n");
+ return 1;
+ }
+
+ msg_pspew("%s:", __func__);
+
+ msg_pspew(" writing %u bytes:", writecnt);
+ for (i = 0; i < writecnt; i++)
+ msg_pspew(" 0x%02x", writearr[i]);
+
+ /* Response for unknown commands and missing chip is 0xff. */
+ memset(readarr, 0xff, readcnt);
+#if EMULATE_SPI_CHIP
+ switch (emu_data->emu_chip) {
+ case EMULATE_ST_M25P10_RES:
+ case EMULATE_SST_SST25VF040_REMS:
+ case EMULATE_SST_SST25VF032B:
+ case EMULATE_MACRONIX_MX25L6436:
+ case EMULATE_WINBOND_W25Q128FV:
+ case EMULATE_VARIABLE_SIZE:
+ if (emulate_spi_chip_response(writecnt, readcnt, writearr,
+ readarr, emu_data)) {
+ msg_pdbg("Invalid command sent to flash chip!\n");
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+ msg_pspew(" reading %u bytes:", readcnt);
+ for (i = 0; i < readcnt; i++)
+ msg_pspew(" 0x%02x", readarr[i]);
+ msg_pspew("\n");
+
+ programmer_delay((writecnt + readcnt) * emu_data->delay_us);
+ return 0;
+}
+
+
static struct spi_master spi_master_dummyflasher = {
.features = SPI_MASTER_4BA,
@@ -138,8 +633,6 @@
.chip_writen = dummy_chip_writen,
};
-static enum chipbustype dummy_buses_supported = BUS_NONE;
-
static int dummy_shutdown(void *data)
{
msg_pspew("%s\n", __func__);
@@ -541,511 +1034,6 @@
return 0;
}
-void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
-{
- msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
- __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
- return (void *)phys_addr;
-}
-
-void dummy_unmap(void *virt_addr, size_t len)
-{
- msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
-}
-
-static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%02x\n", __func__, addr, val);
-}
-
-static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%04x\n", __func__, addr, val);
-}
-
-static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08x\n", __func__, addr, val);
-}
-
-static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
-{
- size_t i;
- msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, writing data (hex):", __func__, addr, len);
- for (i = 0; i < len; i++) {
- if ((i % 16) == 0)
- msg_pspew("\n");
- msg_pspew("%02x ", buf[i]);
- }
-}
-
-static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xff\n", __func__, addr);
- return 0xff;
-}
-
-static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffff\n", __func__, addr);
- return 0xffff;
-}
-
-static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffffffff\n", __func__, addr);
- return 0xffffffff;
-}
-
-static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len)
-{
- msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, returning array of 0xff\n", __func__, addr, len);
- memset(buf, 0xff, len);
- return;
-}
-
-#if EMULATE_SPI_CHIP
-static int emulate_spi_chip_response(unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr,
- struct emu_data *data)
-{
- unsigned int offs, i, toread;
- static int unsigned aai_offs;
- const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
- const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
- const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
- const unsigned char w25q128fv_rems_response[2] = {0xef, 0x17};
-
- if (writecnt == 0) {
- msg_perr("No command sent to the chip!\n");
- return 1;
- }
- /* spi_blacklist has precedence over spi_ignorelist. */
- for (i = 0; i < data->spi_blacklist_size; i++) {
- if (writearr[0] == data->spi_blacklist[i]) {
- msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
- data->spi_blacklist[i]);
- return SPI_INVALID_OPCODE;
- }
- }
- for (i = 0; i < data->spi_ignorelist_size; i++) {
- if (writearr[0] == data->spi_ignorelist[i]) {
- msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
- data->spi_ignorelist[i]);
- /* Return success because the command does not fail,
- * it is simply ignored.
- */
- return 0;
- }
- }
-
- if (data->emu_max_aai_size && (data->emu_status & SPI_SR_AAI)) {
- if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
- writearr[0] != JEDEC_WRDI &&
- writearr[0] != JEDEC_RDSR) {
- msg_perr("Forbidden opcode (0x%02x) attempted during "
- "AAI sequence!\n", writearr[0]);
- return 0;
- }
- }
-
- switch (writearr[0]) {
- case JEDEC_RES:
- if (writecnt < JEDEC_RES_OUTSIZE)
- break;
- /* offs calculation is only needed for SST chips which treat RES like REMS. */
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- offs += writecnt - JEDEC_REMS_OUTSIZE;
- switch (data->emu_chip) {
- case EMULATE_ST_M25P10_RES:
- if (readcnt > 0)
- memset(readarr, 0x10, readcnt);
- break;
- case EMULATE_SST_SST25VF040_REMS:
- for (i = 0; i < readcnt; i++)
- readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
- break;
- case EMULATE_SST_SST25VF032B:
- for (i = 0; i < readcnt; i++)
- readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
- break;
- case EMULATE_MACRONIX_MX25L6436:
- if (readcnt > 0)
- memset(readarr, 0x16, readcnt);
- break;
- case EMULATE_WINBOND_W25Q128FV:
- if (readcnt > 0)
- memset(readarr, 0x17, readcnt);
- break;
- default: /* ignore */
- break;
- }
- break;
- case JEDEC_REMS:
- /* REMS response has wraparound and uses an address parameter. */
- if (writecnt < JEDEC_REMS_OUTSIZE)
- break;
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- offs += writecnt - JEDEC_REMS_OUTSIZE;
- switch (data->emu_chip) {
- case EMULATE_SST_SST25VF040_REMS:
- for (i = 0; i < readcnt; i++)
- readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
- break;
- case EMULATE_SST_SST25VF032B:
- for (i = 0; i < readcnt; i++)
- readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
- break;
- case EMULATE_MACRONIX_MX25L6436:
- for (i = 0; i < readcnt; i++)
- readarr[i] = mx25l6436_rems_response[(offs + i) % 2];
- break;
- case EMULATE_WINBOND_W25Q128FV:
- for (i = 0; i < readcnt; i++)
- readarr[i] = w25q128fv_rems_response[(offs + i) % 2];
- break;
- default: /* ignore */
- break;
- }
- break;
- case JEDEC_RDID:
- switch (data->emu_chip) {
- case EMULATE_SST_SST25VF032B:
- if (readcnt > 0)
- readarr[0] = 0xbf;
- if (readcnt > 1)
- readarr[1] = 0x25;
- if (readcnt > 2)
- readarr[2] = 0x4a;
- break;
- case EMULATE_MACRONIX_MX25L6436:
- if (readcnt > 0)
- readarr[0] = 0xc2;
- if (readcnt > 1)
- readarr[1] = 0x20;
- if (readcnt > 2)
- readarr[2] = 0x17;
- break;
- case EMULATE_WINBOND_W25Q128FV:
- if (readcnt > 0)
- readarr[0] = 0xef;
- if (readcnt > 1)
- readarr[1] = 0x40;
- if (readcnt > 2)
- readarr[2] = 0x18;
- break;
- case EMULATE_VARIABLE_SIZE:
- if (readcnt > 0)
- readarr[0] = (PROGMANUF_ID >> 8) & 0xff;
- if (readcnt > 1)
- readarr[1] = PROGMANUF_ID & 0xff;
- if (readcnt > 2)
- readarr[2] = (PROGDEV_ID >> 8) & 0xff;
- if (readcnt > 3)
- readarr[3] = PROGDEV_ID & 0xff;
- break;
- default: /* ignore */
- break;
- }
- break;
- case JEDEC_RDSR:
- memset(readarr, data->emu_status, readcnt);
- break;
- /* FIXME: this should be chip-specific. */
- case JEDEC_EWSR:
- case JEDEC_WREN:
- data->emu_status |= SPI_SR_WEL;
- break;
- case JEDEC_WRSR:
- if (!(data->emu_status & SPI_SR_WEL)) {
- msg_perr("WRSR attempted, but WEL is 0!\n");
- break;
- }
- /* FIXME: add some reasonable simulation of the busy flag */
- data->emu_status = writearr[1] & ~SPI_SR_WIP;
- msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status);
- break;
- case JEDEC_READ:
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- /* Truncate to emu_chip_size. */
- offs %= data->emu_chip_size;
- if (readcnt > 0)
- memcpy(readarr, flashchip_contents + offs, readcnt);
- break;
- case JEDEC_READ_4BA:
- offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
- /* Truncate to emu_chip_size. */
- offs %= data->emu_chip_size;
- if (readcnt > 0)
- memcpy(readarr, flashchip_contents + offs, readcnt);
- break;
- case JEDEC_BYTE_PROGRAM:
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- /* Truncate to emu_chip_size. */
- offs %= data->emu_chip_size;
- if (writecnt < 5) {
- msg_perr("BYTE PROGRAM size too short!\n");
- return 1;
- }
- if (writecnt - 4 > data->emu_max_byteprogram_size) {
- msg_perr("Max BYTE PROGRAM size exceeded!\n");
- return 1;
- }
- memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
- data->emu_modified = 1;
- break;
- case JEDEC_BYTE_PROGRAM_4BA:
- offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
- /* Truncate to emu_chip_size. */
- offs %= data->emu_chip_size;
- if (writecnt < 6) {
- msg_perr("BYTE PROGRAM size too short!\n");
- return 1;
- }
- if (writecnt - 5 > data->emu_max_byteprogram_size) {
- msg_perr("Max BYTE PROGRAM size exceeded!\n");
- return 1;
- }
- memcpy(flashchip_contents + offs, writearr + 5, writecnt - 5);
- data->emu_modified = 1;
- break;
- case JEDEC_AAI_WORD_PROGRAM:
- if (!data->emu_max_aai_size)
- break;
- if (!(data->emu_status & SPI_SR_AAI)) {
- if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
- msg_perr("Initial AAI WORD PROGRAM size too "
- "short!\n");
- return 1;
- }
- if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
- msg_perr("Initial AAI WORD PROGRAM size too "
- "long!\n");
- return 1;
- }
- data->emu_status |= SPI_SR_AAI;
- aai_offs = writearr[1] << 16 | writearr[2] << 8 |
- writearr[3];
- /* Truncate to emu_chip_size. */
- aai_offs %= data->emu_chip_size;
- memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
- aai_offs += 2;
- } else {
- if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
- msg_perr("Continuation AAI WORD PROGRAM size "
- "too short!\n");
- return 1;
- }
- if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
- msg_perr("Continuation AAI WORD PROGRAM size "
- "too long!\n");
- return 1;
- }
- memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
- aai_offs += 2;
- }
- data->emu_modified = 1;
- break;
- case JEDEC_WRDI:
- if (data->emu_max_aai_size)
- data->emu_status &= ~SPI_SR_AAI;
- break;
- case JEDEC_SE:
- if (!data->emu_jedec_se_size)
- break;
- if (writecnt != JEDEC_SE_OUTSIZE) {
- msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
- return 1;
- }
- if (readcnt != JEDEC_SE_INSIZE) {
- msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
- return 1;
- }
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- if (offs & (data->emu_jedec_se_size - 1))
- msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
- offs &= ~(data->emu_jedec_se_size - 1);
- memset(flashchip_contents + offs, 0xff, data->emu_jedec_se_size);
- data->emu_modified = 1;
- break;
- case JEDEC_BE_52:
- if (!data->emu_jedec_be_52_size)
- break;
- if (writecnt != JEDEC_BE_52_OUTSIZE) {
- msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
- return 1;
- }
- if (readcnt != JEDEC_BE_52_INSIZE) {
- msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
- return 1;
- }
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- if (offs & (data->emu_jedec_be_52_size - 1))
- msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
- offs &= ~(data->emu_jedec_be_52_size - 1);
- memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size);
- data->emu_modified = 1;
- break;
- case JEDEC_BE_D8:
- if (!data->emu_jedec_be_d8_size)
- break;
- if (writecnt != JEDEC_BE_D8_OUTSIZE) {
- msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
- return 1;
- }
- if (readcnt != JEDEC_BE_D8_INSIZE) {
- msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
- return 1;
- }
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
- if (offs & (data->emu_jedec_be_d8_size - 1))
- msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
- offs &= ~(data->emu_jedec_be_d8_size - 1);
- memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size);
- data->emu_modified = 1;
- break;
- case JEDEC_CE_60:
- if (!data->emu_jedec_ce_60_size)
- break;
- if (writecnt != JEDEC_CE_60_OUTSIZE) {
- msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
- return 1;
- }
- if (readcnt != JEDEC_CE_60_INSIZE) {
- msg_perr("CHIP ERASE 0x60 insize invalid!\n");
- return 1;
- }
- /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
- /* emu_jedec_ce_60_size is emu_chip_size. */
- memset(flashchip_contents, 0xff, data->emu_jedec_ce_60_size);
- data->emu_modified = 1;
- break;
- case JEDEC_CE_C7:
- if (!data->emu_jedec_ce_c7_size)
- break;
- if (writecnt != JEDEC_CE_C7_OUTSIZE) {
- msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
- return 1;
- }
- if (readcnt != JEDEC_CE_C7_INSIZE) {
- msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
- return 1;
- }
- /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
- /* emu_jedec_ce_c7_size is emu_chip_size. */
- memset(flashchip_contents, 0xff, data->emu_jedec_ce_c7_size);
- data->emu_modified = 1;
- break;
- case JEDEC_SFDP:
- if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
- break;
- if (writecnt < 4)
- break;
- offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
-
- /* SFDP expects one dummy byte after the address. */
- if (writecnt == 4) {
- /* The dummy byte was not written, make sure it is read instead.
- * Shifting and shortening the read array does achieve this goal.
- */
- readarr++;
- readcnt--;
- } else {
- /* The response is shifted if more than 5 bytes are written, because SFDP data is
- * already shifted out by the chip while those superfluous bytes are written. */
- offs += writecnt - 5;
- }
-
- /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
- * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
- * This is a reasonable implementation choice in hardware because it saves a few gates. */
- if (offs >= sizeof(sfdp_table)) {
- msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
- "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
- offs %= sizeof(sfdp_table);
- }
- toread = min(sizeof(sfdp_table) - offs, readcnt);
- memcpy(readarr, sfdp_table + offs, toread);
- if (toread < readcnt)
- msg_pdbg("Crossing the SFDP table boundary in a single "
- "continuous chunk produces undefined results "
- "after that point.\n");
- break;
- default:
- /* No special response. */
- break;
- }
- if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
- data->emu_status &= ~SPI_SR_WEL;
- return 0;
-}
-#endif
-
-static struct emu_data* get_data_from_context(const struct flashctx *flash)
-{
- if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
- return (struct emu_data *)flash->mst->par.data;
- else if (dummy_buses_supported & BUS_SPI)
- return (struct emu_data *)flash->mst->spi.data;
-
- return NULL; /* buses was set to BUS_NONE. */
-}
-
-static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- unsigned int i;
- struct emu_data *emu_data = get_data_from_context(flash);
- if (!emu_data) {
- msg_perr("No data in flash context!\n");
- return 1;
- }
-
- msg_pspew("%s:", __func__);
-
- msg_pspew(" writing %u bytes:", writecnt);
- for (i = 0; i < writecnt; i++)
- msg_pspew(" 0x%02x", writearr[i]);
-
- /* Response for unknown commands and missing chip is 0xff. */
- memset(readarr, 0xff, readcnt);
-#if EMULATE_SPI_CHIP
- switch (emu_data->emu_chip) {
- case EMULATE_ST_M25P10_RES:
- case EMULATE_SST_SST25VF040_REMS:
- case EMULATE_SST_SST25VF032B:
- case EMULATE_MACRONIX_MX25L6436:
- case EMULATE_WINBOND_W25Q128FV:
- case EMULATE_VARIABLE_SIZE:
- if (emulate_spi_chip_response(writecnt, readcnt, writearr,
- readarr, emu_data)) {
- msg_pdbg("Invalid command sent to flash chip!\n");
- return 1;
- }
- break;
- default:
- break;
- }
-#endif
- msg_pspew(" reading %u bytes:", readcnt);
- for (i = 0; i < readcnt; i++)
- msg_pspew(" 0x%02x", readarr[i]);
- msg_pspew("\n");
-
- programmer_delay((writecnt + readcnt) * emu_data->delay_us);
- return 0;
-}
-
-static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
-{
- return spi_write_chunked(flash, buf, start, len,
- spi_write_256_chunksize);
-}
-
#if EMULATE_CHIP && EMULATE_SPI_CHIP
int probe_variable_size(struct flashctx *flash)
{
diff --git a/ft2232_spi.c b/ft2232_spi.c
index 9060973..1fb795b 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -183,10 +183,93 @@
return 0;
}
+/* Returns 0 upon success, a negative number upon errors. */
static int ft2232_spi_send_command(const struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
- unsigned char *readarr);
+ 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;
+ size_t bufsize;
+ static size_t 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 (!buf || bufsize > oldbufsize) {
+ buf = realloc(buf, bufsize);
+ if (!buf) {
+ msg_perr("Out of memory!\n");
+ /* TODO: What to do with buf? */
+ return SPI_GENERIC_ERROR;
+ }
+ 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.
+ */
+ msg_pspew("Assert CS#\n");
+ buf[i++] = SET_BITS_LOW;
+ buf[i++] = ~ 0x08 & pinlvl; /* assert CS (3rd) bit only */
+ buf[i++] = pindir;
+
+ if (writecnt) {
+ buf[i++] = MPSSE_DO_WRITE | MPSSE_WRITE_NEG;
+ 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++] = MPSSE_DO_READ;
+ 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)
+ msg_perr("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)
+ msg_perr("get_buf failed: %i\n", ret);
+ }
+ }
+
+ msg_pspew("De-assert CS#\n");
+ buf[i++] = SET_BITS_LOW;
+ buf[i++] = pinlvl;
+ buf[i++] = pindir;
+ ret = send_buf(ftdic, buf, i);
+ failed |= ret;
+ if (ret)
+ msg_perr("send_buf failed at end: %i\n", ret);
+
+ return failed ? -1 : 0;
+}
static const struct spi_master spi_master_ft2232 = {
.features = SPI_MASTER_4BA,
@@ -532,92 +615,4 @@
return ret;
}
-/* Returns 0 upon success, a negative number upon errors. */
-static int ft2232_spi_send_command(const struct flashctx *flash,
- 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;
- size_t bufsize;
- static size_t 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 (!buf || bufsize > oldbufsize) {
- buf = realloc(buf, bufsize);
- if (!buf) {
- msg_perr("Out of memory!\n");
- /* TODO: What to do with buf? */
- return SPI_GENERIC_ERROR;
- }
- 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.
- */
- msg_pspew("Assert CS#\n");
- buf[i++] = SET_BITS_LOW;
- buf[i++] = ~ 0x08 & pinlvl; /* assert CS (3rd) bit only */
- buf[i++] = pindir;
-
- if (writecnt) {
- buf[i++] = MPSSE_DO_WRITE | MPSSE_WRITE_NEG;
- 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++] = MPSSE_DO_READ;
- 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)
- msg_perr("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)
- msg_perr("get_buf failed: %i\n", ret);
- }
- }
-
- msg_pspew("De-assert CS#\n");
- buf[i++] = SET_BITS_LOW;
- buf[i++] = pinlvl;
- buf[i++] = pindir;
- ret = send_buf(ftdic, buf, i);
- failed |= ret;
- if (ret)
- msg_perr("send_buf failed at end: %i\n", ret);
-
- return failed ? -1 : 0;
-}
-
#endif
diff --git a/ichspi.c b/ichspi.c
index 4209d60..e45b39a 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -286,12 +286,40 @@
#define REGWRITE8(off, val) mmio_writeb(val, ich_spibar+(off))
/* 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, enum ich_chipset ich_gen);
-static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_gen);
-static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
- uint8_t datalength, uint8_t * data);
+
+static int find_opcode(OPCODES *op, uint8_t opcode)
+{
+ int a;
+
+ if (op == NULL) {
+ msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+ return -1;
+ }
+
+ 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;
+
+ if (op == NULL) {
+ msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+ return -1;
+ }
+
+ for (a = 0; a < 2; a++) {
+ if (op->preop[a] == preop)
+ return a;
+ }
+
+ return -1;
+}
/* for pairing opcodes with their required preop */
struct preop_opcode_pair {
@@ -497,131 +525,6 @@
return 0xFF;
}
-static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
-{
- uint8_t spi_type;
-
- spi_type = lookup_spi_type(opcode);
- if (spi_type > 3) {
- /* Try to guess spi type from read/write sizes.
- * The following valid writecnt/readcnt combinations exist:
- * writecnt = 4, readcnt >= 0
- * writecnt = 1, readcnt >= 0
- * writecnt >= 4, readcnt = 0
- * writecnt >= 1, readcnt = 0
- * writecnt >= 1 is guaranteed for all commands.
- */
- if (readcnt == 0)
- /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
- * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
- * bytes are actual the address, they go to the bus anyhow
- */
- spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
- else if (writecnt == 1) // and readcnt is > 0
- spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
- else if (writecnt == 4) // and readcnt is > 0
- spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
- else // we have an invalid case
- return SPI_INVALID_LENGTH;
- }
- int oppos = 2; // use original JEDEC_BE_D8 offset
- curopcodes->opcode[oppos].opcode = opcode;
- curopcodes->opcode[oppos].spi_type = spi_type;
- program_opcodes(curopcodes, 0, ich_generation);
- oppos = find_opcode(curopcodes, opcode);
- msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
- return oppos;
-}
-
-static int find_opcode(OPCODES *op, uint8_t opcode)
-{
- int a;
-
- if (op == NULL) {
- msg_perr("\n%s: null OPCODES pointer!\n", __func__);
- return -1;
- }
-
- 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;
-
- if (op == NULL) {
- msg_perr("\n%s: null OPCODES pointer!\n", __func__);
- return -1;
- }
-
- for (a = 0; a < 2; a++) {
- if (op->preop[a] == preop)
- return a;
- }
-
- return -1;
-}
-
-/* Create a struct OPCODES based on what we find in the locked down chipset. */
-static int generate_opcodes(OPCODES * op, enum ich_chipset ich_gen)
-{
- int a;
- uint16_t preop, optype;
- uint32_t opmenu[2];
-
- if (op == NULL) {
- msg_perr("\n%s: null OPCODES pointer!\n", __func__);
- return -1;
- }
-
- switch (ich_gen) {
- case CHIPSET_ICH7:
- case CHIPSET_TUNNEL_CREEK:
- case CHIPSET_CENTERTON:
- 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 CHIPSET_ICH8:
- default: /* Future version might behave the same */
- preop = REGREAD16(swseq_data.reg_preop);
- optype = REGREAD16(swseq_data.reg_optype);
- opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
- opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
- break;
- }
-
- 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;
- }
-
- /* No preopcodes used by default. */
- for (a = 0; a < 8; a++)
- op->opcode[a].atomic = 0;
-
- return 0;
-}
-
static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_gen)
{
uint8_t a;
@@ -688,6 +591,42 @@
return 0;
}
+static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
+{
+ uint8_t spi_type;
+
+ spi_type = lookup_spi_type(opcode);
+ if (spi_type > 3) {
+ /* Try to guess spi type from read/write sizes.
+ * The following valid writecnt/readcnt combinations exist:
+ * writecnt = 4, readcnt >= 0
+ * writecnt = 1, readcnt >= 0
+ * writecnt >= 4, readcnt = 0
+ * writecnt >= 1, readcnt = 0
+ * writecnt >= 1 is guaranteed for all commands.
+ */
+ if (readcnt == 0)
+ /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
+ * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
+ * bytes are actual the address, they go to the bus anyhow
+ */
+ spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
+ else if (writecnt == 1) // and readcnt is > 0
+ spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
+ else if (writecnt == 4) // and readcnt is > 0
+ spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
+ else // we have an invalid case
+ return SPI_INVALID_LENGTH;
+ }
+ int oppos = 2; // use original JEDEC_BE_D8 offset
+ curopcodes->opcode[oppos].opcode = opcode;
+ curopcodes->opcode[oppos].spi_type = spi_type;
+ program_opcodes(curopcodes, 0, ich_generation);
+ oppos = find_opcode(curopcodes, opcode);
+ msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
+ return oppos;
+}
+
/*
* Returns -1 if at least one mandatory opcode is inaccessible, 0 otherwise.
* FIXME: this should also check for
@@ -754,49 +693,59 @@
min_addr, ichspi_bbar);
}
-/* Read len bytes from the fdata/spid register into the data array.
- *
- * Note that using len > flash->mst->spi.max_data_read will return garbage or
- * may even crash.
- */
-static void ich_read_data(uint8_t *data, int len, int reg0_off)
+/* Create a struct OPCODES based on what we find in the locked down chipset. */
+static int generate_opcodes(OPCODES * op, enum ich_chipset ich_gen)
{
- int i;
- uint32_t temp32 = 0;
+ int a;
+ uint16_t preop, optype;
+ uint32_t opmenu[2];
- for (i = 0; i < len; i++) {
- if ((i % 4) == 0)
- temp32 = REGREAD32(reg0_off + i);
-
- data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
+ if (op == NULL) {
+ msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+ return -1;
}
-}
-/* Fill len bytes from the data array into the fdata/spid registers.
- *
- * Note that using len > flash->mst->spi.max_data_write will trash the registers
- * following the data registers.
- */
-static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
-{
- uint32_t temp32 = 0;
- int i;
-
- if (len <= 0)
- return;
-
- for (i = 0; i < len; i++) {
- if ((i % 4) == 0)
- temp32 = 0;
-
- temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
-
- if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
- REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+ switch (ich_gen) {
+ case CHIPSET_ICH7:
+ case CHIPSET_TUNNEL_CREEK:
+ case CHIPSET_CENTERTON:
+ 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 CHIPSET_ICH8:
+ default: /* Future version might behave the same */
+ preop = REGREAD16(swseq_data.reg_preop);
+ optype = REGREAD16(swseq_data.reg_optype);
+ opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
+ opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
+ break;
}
- i--;
- if ((i % 4) != 3) /* Write remaining data to regs. */
- REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+
+ 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;
+ }
+
+ /* No preopcodes used by default. */
+ for (a = 0; a < 8; a++)
+ op->opcode[a].atomic = 0;
+
+ return 0;
}
/* This function generates OPCODES from or programs OPCODES to ICH according to
@@ -834,6 +783,51 @@
}
}
+/* Fill len bytes from the data array into the fdata/spid registers.
+ *
+ * Note that using len > flash->mst->spi.max_data_write will trash the registers
+ * following the data registers.
+ */
+static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
+{
+ uint32_t temp32 = 0;
+ int i;
+
+ if (len <= 0)
+ return;
+
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0)
+ temp32 = 0;
+
+ temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
+
+ if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
+ REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+ }
+ i--;
+ if ((i % 4) != 3) /* Write remaining data to regs. */
+ REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+}
+
+/* Read len bytes from the fdata/spid register into the data array.
+ *
+ * Note that using len > flash->mst->spi.max_data_read will return garbage or
+ * may even crash.
+ */
+static void ich_read_data(uint8_t *data, int len, int reg0_off)
+{
+ int i;
+ uint32_t temp32 = 0;
+
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0)
+ temp32 = REGREAD32(reg0_off + i);
+
+ data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
+ }
+}
+
static int ich7_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data, int maxdata)
{
diff --git a/linux_spi.c b/linux_spi.c
index 1ef8f2b..bbd45f3 100644
--- a/linux_spi.c
+++ b/linux_spi.c
@@ -48,15 +48,65 @@
#define BUF_SIZE_FROM_SYSFS "/sys/module/spidev/parameters/bufsiz"
static size_t max_kernel_buf_size;
-static int linux_spi_shutdown(void *data);
+static int linux_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+ /* Older kernels use a single buffer for combined input and output
+ data. So account for longest possible command + address, too. */
+ return spi_read_chunked(flash, buf, start, len, max_kernel_buf_size - 5);
+}
+
+static int linux_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+{
+ /* 5 bytes must be reserved for longest possible command + address. */
+ return spi_write_chunked(flash, buf, start, len, max_kernel_buf_size - 5);
+}
+
+static int linux_spi_shutdown(void *data)
+{
+ if (fd != -1) {
+ close(fd);
+ fd = -1;
+ }
+ return 0;
+}
+
static int linux_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
unsigned int readcnt,
const unsigned char *txbuf,
- unsigned char *rxbuf);
-static int linux_spi_read(struct flashctx *flash, uint8_t *buf,
- unsigned int start, unsigned int len);
-static int linux_spi_write_256(struct flashctx *flash, const uint8_t *buf,
- unsigned int start, unsigned int len);
+ unsigned char *rxbuf)
+{
+ int iocontrol_code;
+ struct spi_ioc_transfer msg[2] = {
+ {
+ .tx_buf = (uint64_t)(uintptr_t)txbuf,
+ .len = writecnt,
+ },
+ {
+ .rx_buf = (uint64_t)(uintptr_t)rxbuf,
+ .len = readcnt,
+ },
+ };
+
+ if (fd == -1)
+ return -1;
+ /* The implementation currently does not support requests that
+ don't start with sending a command. */
+ if (writecnt == 0)
+ return SPI_INVALID_LENGTH;
+
+ /* Just submit the first (write) request in case there is nothing
+ to read. Otherwise submit both requests. */
+ if (readcnt == 0)
+ iocontrol_code = SPI_IOC_MESSAGE(1);
+ else
+ iocontrol_code = SPI_IOC_MESSAGE(2);
+
+ if (ioctl(fd, iocontrol_code, msg) == -1) {
+ msg_cerr("%s: ioctl: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
static const struct spi_master spi_master_linux = {
.features = SPI_MASTER_4BA,
@@ -174,64 +224,4 @@
return 0;
}
-static int linux_spi_shutdown(void *data)
-{
- if (fd != -1) {
- close(fd);
- fd = -1;
- }
- return 0;
-}
-
-static int linux_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *txbuf,
- unsigned char *rxbuf)
-{
- int iocontrol_code;
- struct spi_ioc_transfer msg[2] = {
- {
- .tx_buf = (uint64_t)(uintptr_t)txbuf,
- .len = writecnt,
- },
- {
- .rx_buf = (uint64_t)(uintptr_t)rxbuf,
- .len = readcnt,
- },
- };
-
- if (fd == -1)
- return -1;
- /* The implementation currently does not support requests that
- don't start with sending a command. */
- if (writecnt == 0)
- return SPI_INVALID_LENGTH;
-
- /* Just submit the first (write) request in case there is nothing
- to read. Otherwise submit both requests. */
- if (readcnt == 0)
- iocontrol_code = SPI_IOC_MESSAGE(1);
- else
- iocontrol_code = SPI_IOC_MESSAGE(2);
-
- if (ioctl(fd, iocontrol_code, msg) == -1) {
- msg_cerr("%s: ioctl: %s\n", __func__, strerror(errno));
- return -1;
- }
- return 0;
-}
-
-static int linux_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
-{
- /* Older kernels use a single buffer for combined input and output
- data. So account for longest possible command + address, too. */
- return spi_read_chunked(flash, buf, start, len, max_kernel_buf_size - 5);
-}
-
-static int linux_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
-{
- /* 5 bytes must be reserved for longest possible command + address. */
- return spi_write_chunked(flash, buf, start, len, max_kernel_buf_size - 5);
-}
-
#endif // CONFIG_LINUX_SPI == 1
diff --git a/ni845x_spi.c b/ni845x_spi.c
index 7b2bea3..153e03e 100644
--- a/ni845x_spi.c
+++ b/ni845x_spi.c
@@ -50,10 +50,6 @@
static uint16_t io_voltage_in_mV;
static bool ignore_io_voltage_limits;
-static int ni845x_spi_shutdown(void *data);
-static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle);
-static void ni845x_spi_print_available_devices(void);
-
// USB-8452 supported voltages, keep this array in ascending order!
static const uint8_t usb8452_io_voltages_in_100mV[5] = {
kNi845x12Volts,
@@ -129,6 +125,28 @@
}
/**
+ * @brief ni845x_spi_open_resource
+ * @param resource_handle the resource handle returned by the ni845xFindDevice or ni845xFindDeviceNext
+ * @param opened_handle the opened handle from the ni845xOpen
+ * @return the 0 on successful competition, negative error code on failure positive code on warning
+ */
+static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle)
+{
+ // NI-845x driver loads the FPGA bitfile at the first time
+ // which can take couple seconds
+ if (device_pid == USB8452)
+ msg_pwarn("Opening NI-8452, this might take a while for the first time\n");
+
+ int32 tmp = ni845xOpen(resource_handle, opened_handle);
+
+ if (tmp < 0)
+ ni845x_report_error("ni845xOpen", tmp);
+ else if (tmp > 0)
+ ni845x_report_warning("ni845xOpen", tmp);
+ return tmp;
+}
+
+/**
* @param serial a null terminated string containing the serial number of the specific device or NULL
* @return the 0 on successful completition, negative error code on failure
*/
@@ -194,28 +212,6 @@
}
/**
- * @brief ni845x_spi_open_resource
- * @param resource_handle the resource handle returned by the ni845xFindDevice or ni845xFindDeviceNext
- * @param opened_handle the opened handle from the ni845xOpen
- * @return the 0 on successful competition, negative error code on failure positive code on warning
- */
-static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle)
-{
- // NI-845x driver loads the FPGA bitfile at the first time
- // which can take couple seconds
- if (device_pid == USB8452)
- msg_pwarn("Opening NI-8452, this might take a while for the first time\n");
-
- int32 tmp = ni845xOpen(resource_handle, opened_handle);
-
- if (tmp < 0)
- ni845x_report_error("ni845xOpen", tmp);
- else if (tmp > 0)
- ni845x_report_warning("ni845xOpen", tmp);
- return tmp;
-}
-
-/**
* @brief usb8452_spi_set_io_voltage sets the IO voltage for the USB-8452 devices
* @param requested_io_voltage_mV the desired IO voltage in mVolts
* @param set_io_voltage_mV the IO voltage which was set in mVolts
@@ -389,6 +385,24 @@
ni845x_report_error("ni845xCloseFindDeviceHandle", tmp);
}
+static int ni845x_spi_shutdown(void *data)
+{
+ int32 ret = 0;
+
+ if (configuration_handle != 0) {
+ ret = ni845xSpiConfigurationClose(configuration_handle);
+ if (ret)
+ ni845x_report_error("ni845xSpiConfigurationClose", ret);
+ }
+
+ if (device_handle != 0) {
+ ret = ni845xClose(device_handle);
+ if (ret)
+ ni845x_report_error("ni845xClose", ret);
+ }
+ return 0;
+}
+
int ni845x_spi_init(void)
{
char *speed_str = NULL;
@@ -486,24 +500,6 @@
return 0;
}
-static int ni845x_spi_shutdown(void *data)
-{
- int32 ret = 0;
-
- if (configuration_handle != 0) {
- ret = ni845xSpiConfigurationClose(configuration_handle);
- if (ret)
- ni845x_report_error("ni845xSpiConfigurationClose", ret);
- }
-
- if (device_handle != 0) {
- ret = ni845xClose(device_handle);
- if (ret)
- ni845x_report_error("ni845xClose", ret);
- }
- return 0;
-}
-
static void ni845x_warn_over_max_voltage(const struct flashctx *flash)
{
if (device_pid == USB8451) {
diff --git a/serprog.c b/serprog.c
index 1befce1..d583a40 100644
--- a/serprog.c
+++ b/serprog.c
@@ -42,13 +42,6 @@
#define MSGHEADER "serprog: "
-/*
- * FIXME: This prototype was added to help reduce diffs for the shutdown
- * registration patch, which shifted many lines of code to place
- * serprog_shutdown() before serprog_init(). It should be removed soon.
- */
-static int serprog_shutdown(void *data);
-
static uint16_t sp_device_serbuf_size = 16;
static uint16_t sp_device_opbuf_size = 300;
/* Bitmap of supported commands */
@@ -295,10 +288,112 @@
return 0;
}
+/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */
+static int sp_pass_writen(void)
+{
+ unsigned char header[7];
+ msg_pspew(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)) {
+ if (sp_flush_stream() != 0) {
+ return 1;
+ }
+ }
+ /* 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];
+ if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
+ return 1;
+ sp_opbuf_usage += 5;
+ return 0;
+ }
+ 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 (serialport_write(header, 7) != 0) {
+ msg_perr(MSGHEADER "Error: cannot write write-n command\n");
+ return 1;
+ }
+ if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
+ msg_perr(MSGHEADER "Error: cannot write write-n data");
+ return 1;
+ }
+ 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;
+ return 0;
+}
+
+static int sp_execute_opbuf_noflush(void)
+{
+ if ((sp_max_write_n) && (sp_write_n_bytes)) {
+ if (sp_pass_writen() != 0) {
+ msg_perr("Error: could not transfer write buffer\n");
+ return 1;
+ }
+ }
+ if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
+ msg_perr("Error: could not execute command buffer\n");
+ return 1;
+ }
+ msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
+ sp_opbuf_usage = 0;
+ sp_prev_was_write = 0;
+ return 0;
+}
+
+static int sp_execute_opbuf(void)
+{
+ if (sp_execute_opbuf_noflush() != 0)
+ return 1;
+ if (sp_flush_stream() != 0)
+ return 1;
+
+ return 0;
+}
+
static int serprog_spi_send_command(const struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
- unsigned char *readarr);
+ unsigned char *readarr)
+{
+ unsigned char *parmbuf;
+ int ret;
+ msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
+ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
+ if (sp_execute_opbuf() != 0) {
+ msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
+ return 1;
+ }
+ }
+
+ parmbuf = malloc(writecnt + 6);
+ if (!parmbuf) {
+ msg_perr("Error: could not allocate SPI send param buffer.\n");
+ return 1;
+ }
+ parmbuf[0] = (writecnt >> 0) & 0xFF;
+ parmbuf[1] = (writecnt >> 8) & 0xFF;
+ parmbuf[2] = (writecnt >> 16) & 0xFF;
+ parmbuf[3] = (readcnt >> 0) & 0xFF;
+ parmbuf[4] = (readcnt >> 8) & 0xFF;
+ parmbuf[5] = (readcnt >> 16) & 0xFF;
+ memcpy(parmbuf + 6, writearr, writecnt);
+ ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
+ readarr);
+ free(parmbuf);
+ return ret;
+}
+
static struct spi_master spi_master_serprog = {
.features = SPI_MASTER_4BA,
.max_data_read = MAX_DATA_READ_UNLIMITED,
@@ -310,12 +405,108 @@
.write_aai = default_spi_write_aai,
};
+static int sp_check_opbuf_usage(int bytes_to_be_added)
+{
+ if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
+ /* If this happens in the middle of a page load the page load will probably fail. */
+ msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
+ if (sp_execute_opbuf() != 0)
+ return 1;
+ }
+ return 0;
+}
+
static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ msg_pspew("%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); // FIXME: return error
+ sp_opbuf_usage += 5;
+ }
+}
+
static uint8_t serprog_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
-static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
- const chipaddr addr, size_t len);
+ 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); // FIXME: return error
+ sp_flush_stream(); // FIXME: return error
+ if (serialport_read(&c, 1) != 0)
+ msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
+ msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
+ return c;
+}
+
+/* Local version that really does the job, doesn't care of max_read_n. */
+static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
+{
+ unsigned char sbuf[6];
+ msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, 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);
+ if (sp_flush_stream() != 0)
+ return 1;
+ if (serialport_read(buf, len) != 0) {
+ msg_perr(MSGHEADER "Error: cannot read read-n data");
+ return 1;
+ }
+ return 0;
+}
+
+/* The externally called version that makes sure that max_read_n is obeyed. */
+static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
+ const chipaddr addr, size_t len)
+{
+ size_t lenm = len;
+ chipaddr addrm = addr;
+ while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
+ sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
+ addrm += sp_max_read_n;
+ lenm -= sp_max_read_n;
+ }
+ if (lenm)
+ sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
+}
+
static const struct par_master par_master_serprog = {
.chip_readb = serprog_chip_readb,
.chip_readw = fallback_chip_readw,
@@ -327,6 +518,25 @@
.chip_writen = fallback_chip_writen,
};
+static int serprog_shutdown(void *data)
+{
+ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+ if (sp_execute_opbuf() != 0)
+ msg_pwarn("Could not flush command buffer.\n");
+ if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
+ uint8_t dis = 0;
+ if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
+ msg_pdbg(MSGHEADER "Output drivers disabled\n");
+ else
+ msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
+ }
+ /* FIXME: fix sockets on windows(?), especially closing */
+ serialport_shutdown(&sp_fd);
+ if (sp_max_write_n)
+ free(sp_write_n_buf);
+ return 0;
+}
+
static enum chipbustype serprog_buses_supported = BUS_NONE;
int serprog_init(void)
@@ -679,200 +889,6 @@
return 0;
}
-/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */
-static int sp_pass_writen(void)
-{
- unsigned char header[7];
- msg_pspew(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)) {
- if (sp_flush_stream() != 0) {
- return 1;
- }
- }
- /* 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];
- if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
- return 1;
- sp_opbuf_usage += 5;
- return 0;
- }
- 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 (serialport_write(header, 7) != 0) {
- msg_perr(MSGHEADER "Error: cannot write write-n command\n");
- return 1;
- }
- if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
- msg_perr(MSGHEADER "Error: cannot write write-n data");
- return 1;
- }
- 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;
- return 0;
-}
-
-static int sp_execute_opbuf_noflush(void)
-{
- if ((sp_max_write_n) && (sp_write_n_bytes)) {
- if (sp_pass_writen() != 0) {
- msg_perr("Error: could not transfer write buffer\n");
- return 1;
- }
- }
- if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
- msg_perr("Error: could not execute command buffer\n");
- return 1;
- }
- msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
- sp_opbuf_usage = 0;
- sp_prev_was_write = 0;
- return 0;
-}
-
-static int sp_execute_opbuf(void)
-{
- if (sp_execute_opbuf_noflush() != 0)
- return 1;
- if (sp_flush_stream() != 0)
- return 1;
-
- return 0;
-}
-
-static int serprog_shutdown(void *data)
-{
- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
- if (sp_execute_opbuf() != 0)
- msg_pwarn("Could not flush command buffer.\n");
- if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
- uint8_t dis = 0;
- if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
- msg_pdbg(MSGHEADER "Output drivers disabled\n");
- else
- msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
- }
- /* FIXME: fix sockets on windows(?), especially closing */
- serialport_shutdown(&sp_fd);
- if (sp_max_write_n)
- free(sp_write_n_buf);
- return 0;
-}
-
-static int sp_check_opbuf_usage(int bytes_to_be_added)
-{
- if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
- /* If this happens in the middle of a page load the page load will probably fail. */
- msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
- if (sp_execute_opbuf() != 0)
- return 1;
- }
- return 0;
-}
-
-static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- msg_pspew("%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); // FIXME: return error
- sp_opbuf_usage += 5;
- }
-}
-
-static uint8_t serprog_chip_readb(const struct flashctx *flash,
- 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); // FIXME: return error
- sp_flush_stream(); // FIXME: return error
- if (serialport_read(&c, 1) != 0)
- msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
- msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
- return c;
-}
-
-/* Local version that really does the job, doesn't care of max_read_n. */
-static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
-{
- unsigned char sbuf[6];
- msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, 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);
- if (sp_flush_stream() != 0)
- return 1;
- if (serialport_read(buf, len) != 0) {
- msg_perr(MSGHEADER "Error: cannot read read-n data");
- return 1;
- }
- return 0;
-}
-
-/* The externally called version that makes sure that max_read_n is obeyed. */
-static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
- const chipaddr addr, size_t len)
-{
- size_t lenm = len;
- chipaddr addrm = addr;
- while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
- sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
- addrm += sp_max_read_n;
- lenm -= sp_max_read_n;
- }
- if (lenm)
- sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
-}
-
void serprog_delay(unsigned int usecs)
{
unsigned char buf[4];
@@ -894,39 +910,6 @@
sp_prev_was_write = 0;
}
-static int serprog_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- unsigned char *parmbuf;
- int ret;
- msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
- if (sp_execute_opbuf() != 0) {
- msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
- return 1;
- }
- }
-
- parmbuf = malloc(writecnt + 6);
- if (!parmbuf) {
- msg_perr("Error: could not allocate SPI send param buffer.\n");
- return 1;
- }
- parmbuf[0] = (writecnt >> 0) & 0xFF;
- parmbuf[1] = (writecnt >> 8) & 0xFF;
- parmbuf[2] = (writecnt >> 16) & 0xFF;
- parmbuf[3] = (readcnt >> 0) & 0xFF;
- parmbuf[4] = (readcnt >> 8) & 0xFF;
- parmbuf[5] = (readcnt >> 16) & 0xFF;
- memcpy(parmbuf + 6, writearr, writecnt);
- ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
- readarr);
- free(parmbuf);
- return ret;
-}
-
void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
{
/* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
To view, visit change 50711. To unsubscribe, or for help writing mail filters, visit settings.