diff --git a/bitbang_spi.c b/bitbang_spi.c index 5ee52f542..51fc9c606 100644 --- a/bitbang_spi.c +++ b/bitbang_spi.c @@ -25,42 +25,37 @@ #include "programmer.h" #include "spi.h" -/* Length of half a clock period in usecs. */ -static int bitbang_spi_half_period; - -static const struct bitbang_spi_master *bitbang_spi_master = NULL; - /* Note that CS# is active low, so val=0 means the chip is active. */ -static void bitbang_spi_set_cs(int val) +static void bitbang_spi_set_cs(const const struct bitbang_spi_master *master, int val) { - bitbang_spi_master->set_cs(val); + master->set_cs(val); } -static void bitbang_spi_set_sck(int val) +static void bitbang_spi_set_sck(const const struct bitbang_spi_master *master, int val) { - bitbang_spi_master->set_sck(val); + master->set_sck(val); } -static void bitbang_spi_set_mosi(int val) +static void bitbang_spi_set_mosi(const const struct bitbang_spi_master *master, int val) { - bitbang_spi_master->set_mosi(val); + master->set_mosi(val); } -static int bitbang_spi_get_miso(void) +static int bitbang_spi_get_miso(const const struct bitbang_spi_master *master) { - return bitbang_spi_master->get_miso(); + return master->get_miso(); } -static void bitbang_spi_request_bus(void) +static void bitbang_spi_request_bus(const const struct bitbang_spi_master *master) { - if (bitbang_spi_master->request_bus) - bitbang_spi_master->request_bus(); + if (master->request_bus) + master->request_bus(); } -static void bitbang_spi_release_bus(void) +static void bitbang_spi_release_bus(const const struct bitbang_spi_master *master) { - if (bitbang_spi_master->release_bus) - bitbang_spi_master->release_bus(); + if (master->release_bus) + master->release_bus(); } static int bitbang_spi_send_command(struct flashctx *flash, @@ -78,67 +73,59 @@ static const struct spi_programmer spi_programmer_bitbang = { .write_256 = default_spi_write_256, }; -int bitbang_spi_init(const struct bitbang_spi_master *master, int halfperiod) +#if 0 // until it is needed +static int bitbang_spi_shutdown(const struct bitbang_spi_master *master) { + /* FIXME: Run bitbang_spi_release_bus here or per command? */ + return 0; +} +#endif + +int bitbang_spi_init(const struct bitbang_spi_master *master) +{ + struct spi_programmer pgm = spi_programmer_bitbang; /* BITBANG_SPI_INVALID is 0, so if someone forgot to initialize ->type, * we catch it here. Same goes for missing initialization of bitbanging * functions. */ if (!master || master->type == BITBANG_SPI_INVALID || !master->set_cs || - !master->set_sck || !master->set_mosi || !master->get_miso) { + !master->set_sck || !master->set_mosi || !master->get_miso || + (master->request_bus && !master->release_bus) || + (!master->request_bus && master->release_bus)) { msg_perr("Incomplete SPI bitbang master setting!\n" "Please report a bug at flashrom@flashrom.org\n"); - return 1; - } - if (bitbang_spi_master) { - msg_perr("SPI bitbang master already initialized!\n" - "Please report a bug at flashrom@flashrom.org\n"); - return 1; + return ERROR_FLASHROM_BUG; } - bitbang_spi_master = master; - bitbang_spi_half_period = halfperiod; + pgm.data = master; + register_spi_programmer(&pgm); - register_spi_programmer(&spi_programmer_bitbang); - - /* FIXME: Run bitbang_spi_request_bus here or in programmer init? */ - bitbang_spi_set_cs(1); - bitbang_spi_set_sck(0); - bitbang_spi_set_mosi(0); + /* Only mess with the bus if we're sure nobody else uses it. */ + bitbang_spi_request_bus(master); + bitbang_spi_set_cs(master, 1); + bitbang_spi_set_sck(master, 0); + bitbang_spi_set_mosi(master, 0); + /* FIXME: Release SPI bus here and request it again for each command or + * don't release it now and only release it on programmer shutdown? + */ + bitbang_spi_release_bus(master); return 0; } -int bitbang_spi_shutdown(const struct bitbang_spi_master *master) -{ - if (!bitbang_spi_master) { - msg_perr("Shutting down an uninitialized SPI bitbang master!\n" - "Please report a bug at flashrom@flashrom.org\n"); - return 1; - } - if (master != bitbang_spi_master) { - msg_perr("Shutting down a mismatched SPI bitbang master!\n" - "Please report a bug at flashrom@flashrom.org\n"); - return 1; - } - - /* FIXME: Run bitbang_spi_release_bus here or per command? */ - bitbang_spi_master = NULL; - return 0; -} - -static uint8_t bitbang_spi_readwrite_byte(uint8_t val) +static uint8_t bitbang_spi_rw_byte(const struct bitbang_spi_master *master, + uint8_t val) { uint8_t ret = 0; int i; for (i = 7; i >= 0; i--) { - bitbang_spi_set_mosi((val >> i) & 1); - programmer_delay(bitbang_spi_half_period); - bitbang_spi_set_sck(1); + bitbang_spi_set_mosi(master, (val >> i) & 1); + programmer_delay(master->half_period); + bitbang_spi_set_sck(master, 1); ret <<= 1; - ret |= bitbang_spi_get_miso(); - programmer_delay(bitbang_spi_half_period); - bitbang_spi_set_sck(0); + ret |= bitbang_spi_get_miso(master); + programmer_delay(master->half_period); + bitbang_spi_set_sck(master, 0); } return ret; } @@ -149,23 +136,24 @@ static int bitbang_spi_send_command(struct flashctx *flash, unsigned char *readarr) { int i; + const struct bitbang_spi_master *master = flash->pgm->spi.data; /* FIXME: Run bitbang_spi_request_bus here or in programmer init? * Requesting and releasing the SPI bus is handled in here to allow the * programmer to use its own SPI engine for native accesses. */ - bitbang_spi_request_bus(); - bitbang_spi_set_cs(0); + bitbang_spi_request_bus(master); + bitbang_spi_set_cs(master, 0); for (i = 0; i < writecnt; i++) - bitbang_spi_readwrite_byte(writearr[i]); + bitbang_spi_rw_byte(master, writearr[i]); for (i = 0; i < readcnt; i++) - readarr[i] = bitbang_spi_readwrite_byte(0); + readarr[i] = bitbang_spi_rw_byte(master, 0); - programmer_delay(bitbang_spi_half_period); - bitbang_spi_set_cs(1); - programmer_delay(bitbang_spi_half_period); + programmer_delay(master->half_period); + bitbang_spi_set_cs(master, 1); + programmer_delay(master->half_period); /* FIXME: Run bitbang_spi_release_bus here or in programmer init? */ - bitbang_spi_release_bus(); + bitbang_spi_release_bus(master); return 0; } diff --git a/cli_classic.c b/cli_classic.c index bb8c29f8d..543b644f4 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -172,7 +172,7 @@ int main(int argc, char *argv[]) struct flashctx flashes[3]; struct flashctx *fill_flash; const char *name; - int namelen, opt, i; + int namelen, opt, i, j; int startchip = 0, chipcount = 0, option_index = 0, force = 0; #if CONFIG_PRINT_WIKI == 1 int list_supported_wiki = 0; @@ -444,17 +444,21 @@ int main(int argc, char *argv[]) ret = 1; goto out_shutdown; } - tempstr = flashbuses_to_text(buses_supported); - msg_pdbg("This programmer supports the following protocols: %s.\n", + tempstr = flashbuses_to_text(get_buses_supported()); + msg_pdbg("The following protocols are supported: %s.\n", tempstr); free(tempstr); - for (i = 0; i < ARRAY_SIZE(flashes); i++) { - startchip = probe_flash(startchip, &flashes[i], 0); - if (startchip == -1) - break; - chipcount++; - startchip++; + for (j = 0; j < registered_programmer_count; j++) { + startchip = 0; + for (i = 0; i < ARRAY_SIZE(flashes); i++) { + startchip = probe_flash(®istered_programmers[j], + startchip, &flashes[i], 0); + if (startchip == -1) + break; + chipcount++; + startchip++; + } } if (chipcount > 1) { @@ -472,6 +476,7 @@ int main(int argc, char *argv[]) printf("Note: flashrom can never write if the flash " "chip isn't found automatically.\n"); } +#if 0 // FIXME: What happens for a forced chip read if multiple compatible programmers are registered? if (force && read_it && chip_to_probe) { printf("Force read (-f -r -c) requested, pretending " "the chip is there:\n"); @@ -486,6 +491,7 @@ int main(int argc, char *argv[]) "contain garbage.\n"); return read_flash_to_file(&flashes[0], filename); } +#endif ret = 1; goto out_shutdown; } else if (!chip_to_probe) { @@ -502,7 +508,7 @@ int main(int argc, char *argv[]) check_chip_supported(fill_flash); size = fill_flash->total_size * 1024; - if (check_max_decode((buses_supported & fill_flash->bustype), size) && + if (check_max_decode(fill_flash->pgm->buses_supported & fill_flash->bustype, size) && (!force)) { fprintf(stderr, "Chip is too big for this programmer " "(-V gives details). Use --force to override.\n"); diff --git a/flash.h b/flash.h index 29ba1932e..e21a98615 100644 --- a/flash.h +++ b/flash.h @@ -171,6 +171,7 @@ struct flashctx { chipaddr virtual_memory; /* Some flash devices have an additional register space. */ chipaddr virtual_registers; + struct registered_programmer *pgm; }; #define TEST_UNTESTED 0 @@ -224,14 +225,13 @@ enum write_granularity { write_gran_1byte, write_gran_256bytes, }; -extern enum chipbustype buses_supported; extern int verbose; extern const char flashrom_version[]; extern char *chip_to_probe; void map_flash_registers(struct flashctx *flash); int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); int erase_flash(struct flashctx *flash); -int probe_flash(int startchip, struct flashctx *fill_flash, int force); +int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *fill_flash, int force); int read_flash_to_file(struct flashctx *flash, const char *filename); int min(int a, int b); int max(int a, int b); @@ -256,6 +256,13 @@ int write_buf_to_file(unsigned char *buf, unsigned long size, const char *filena /* Something happened that shouldn't happen, we'll abort. */ #define ERROR_FATAL -0xee +#define ERROR_FLASHROM_BUG -200 +/* We reached one of the hardcoded limits of flashrom. This can be fixed by + * increasing the limit of a compile-time allocation or by switching to dynamic + * allocation. + * Note: If this warning is triggered, check first for runaway registrations. + */ +#define ERROR_FLASHROM_LIMIT -201 /* cli_output.c */ /* Let gcc and clang check for correct printf-style format strings. */ @@ -297,4 +304,5 @@ int spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int int spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds); uint32_t spi_get_valid_read_addr(struct flashctx *flash); +enum chipbustype get_buses_supported(void); #endif /* !__FLASH_H__ */ diff --git a/flashrom.c b/flashrom.c index f7a17d139..f1a61656a 100644 --- a/flashrom.c +++ b/flashrom.c @@ -46,9 +46,6 @@ static enum programmer programmer = PROGRAMMER_INVALID; static char *programmer_param = NULL; -/* Supported buses for the current programmer. */ -enum chipbustype buses_supported; - /* * Programmers supporting multiple buses can have differing size limits on * each bus. Store the limits for each bus in a common struct. @@ -314,7 +311,6 @@ int programmer_init(enum programmer prog, char *param) .fwh = 0xffffffff, .spi = 0xffffffff, }; - buses_supported = BUS_NONE; /* Default to top aligned flash at 4 GB. */ flashbase = 0; /* Registering shutdown functions is now allowed. */ @@ -361,44 +357,44 @@ void programmer_unmap_flash_region(void *virt_addr, size_t len) void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr) { - par_programmer->chip_writeb(flash, val, addr); + flash->pgm->par.chip_writeb(flash, val, addr); } void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr) { - par_programmer->chip_writew(flash, val, addr); + flash->pgm->par.chip_writew(flash, val, addr); } void chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr) { - par_programmer->chip_writel(flash, val, addr); + flash->pgm->par.chip_writel(flash, val, addr); } void chip_writen(const struct flashctx *flash, uint8_t *buf, chipaddr addr, size_t len) { - par_programmer->chip_writen(flash, buf, addr, len); + flash->pgm->par.chip_writen(flash, buf, addr, len); } uint8_t chip_readb(const struct flashctx *flash, const chipaddr addr) { - return par_programmer->chip_readb(flash, addr); + return flash->pgm->par.chip_readb(flash, addr); } uint16_t chip_readw(const struct flashctx *flash, const chipaddr addr) { - return par_programmer->chip_readw(flash, addr); + return flash->pgm->par.chip_readw(flash, addr); } uint32_t chip_readl(const struct flashctx *flash, const chipaddr addr) { - return par_programmer->chip_readl(flash, addr); + return flash->pgm->par.chip_readl(flash, addr); } void chip_readn(const struct flashctx *flash, uint8_t *buf, chipaddr addr, size_t len) { - par_programmer->chip_readn(flash, buf, addr, len); + flash->pgm->par.chip_readn(flash, buf, addr, len); } void programmer_delay(int usecs) @@ -942,7 +938,8 @@ int check_max_decode(enum chipbustype buses, uint32_t size) return 1; } -int probe_flash(int startchip, struct flashctx *fill_flash, int force) +int probe_flash(struct registered_programmer *pgm, int startchip, + struct flashctx *fill_flash, int force) { const struct flashchip *flash; unsigned long base = 0; @@ -954,20 +951,9 @@ int probe_flash(int startchip, struct flashctx *fill_flash, int force) for (flash = flashchips + startchip; flash && flash->name; flash++) { if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0) continue; - buses_common = buses_supported & flash->bustype; - if (!buses_common) { - msg_gspew("Probing for %s %s, %d kB: skipped. ", - flash->vendor, flash->name, flash->total_size); - tmp = flashbuses_to_text(buses_supported); - msg_gspew("Host bus type %s ", tmp); - free(tmp); - tmp = flashbuses_to_text(flash->bustype); - msg_gspew("and chip bus type %s are incompatible.", - tmp); - free(tmp); - msg_gspew("\n"); + buses_common = pgm->buses_supported & flash->bustype; + if (!buses_common) continue; - } msg_gdbg("Probing for %s %s, %d kB: ", flash->vendor, flash->name, flash->total_size); if (!flash->probe && !force) { @@ -981,6 +967,7 @@ int probe_flash(int startchip, struct flashctx *fill_flash, int force) /* Start filling in the dynamic data. */ memcpy(fill_flash, flash, sizeof(struct flashchip)); + fill_flash->pgm = pgm; base = flashbase ? flashbase : (0xffffffff - size + 1); fill_flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size); diff --git a/ichspi.c b/ichspi.c index 6bcea45eb..163ecf1d2 100644 --- a/ichspi.c +++ b/ichspi.c @@ -635,7 +635,7 @@ static void ich_set_bbar(uint32_t min_addr) /* Read len bytes from the fdata/spid register into the data array. * - * Note that using len > spi_programmer->max_data_read will return garbage or + * Note that using len > flash->pgm->spi.max_data_read will return garbage or * may even crash. */ static void ich_read_data(uint8_t *data, int len, int reg0_off) @@ -653,7 +653,7 @@ static void ich_read_data(uint8_t *data, int len, int reg0_off) /* Fill len bytes from the data array into the fdata/spid registers. * - * Note that using len > spi_programmer->max_data_write will trash the registers + * Note that using len > flash->pgm->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) @@ -960,9 +960,9 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset, uint8_t datalength, uint8_t * data) { /* max_data_read == max_data_write for all Intel/VIA SPI masters */ - uint8_t maxlength = spi_programmer->max_data_read; + uint8_t maxlength = flash->pgm->spi.max_data_read; - if (spi_programmer->type == SPI_CONTROLLER_NONE) { + if (ich_generation == CHIPSET_ICH_UNKNOWN) { msg_perr("%s: unsupported chipset\n", __func__); return -1; } @@ -1297,7 +1297,7 @@ static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf, REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); while (len > 0) { - block_len = min(len, opaque_programmer->max_data_read); + block_len = min(len, flash->pgm->opaque.max_data_read); ich_hwseq_set_addr(addr); hsfc = REGREAD16(ICH9_REG_HSFC); hsfc &= ~HSFC_FCYCLE; /* set read operation */ @@ -1336,7 +1336,7 @@ static int ich_hwseq_write(struct flashctx *flash, uint8_t *buf, while (len > 0) { ich_hwseq_set_addr(addr); - block_len = min(len, opaque_programmer->max_data_write); + block_len = min(len, flash->pgm->opaque.max_data_write); ich_fill_data(buf, block_len, ICH9_REG_FDATA0); hsfc = REGREAD16(ICH9_REG_HSFC); hsfc &= ~HSFC_FCYCLE; /* clear operation */ diff --git a/mcp6x_spi.c b/mcp6x_spi.c index d2c31bef5..23f39a533 100644 --- a/mcp6x_spi.c +++ b/mcp6x_spi.c @@ -98,6 +98,7 @@ static const struct bitbang_spi_master bitbang_spi_master_mcp6x = { .get_miso = mcp6x_bitbang_get_miso, .request_bus = mcp6x_request_spibus, .release_bus = mcp6x_release_spibus, + .half_period = 0, }; int mcp6x_spi_init(int want_spi) @@ -159,8 +160,7 @@ int mcp6x_spi_init(int want_spi) (status >> MCP6X_SPI_GRANT) & 0x1); mcp_gpiostate = status & 0xff; - /* Zero halfperiod delay. */ - if (bitbang_spi_init(&bitbang_spi_master_mcp6x, 0)) { + if (bitbang_spi_init(&bitbang_spi_master_mcp6x)) { /* This should never happen. */ msg_perr("MCP6X bitbang SPI master init failed!\n"); return 1; diff --git a/nicintel_spi.c b/nicintel_spi.c index aacd68c72..f9432eca0 100644 --- a/nicintel_spi.c +++ b/nicintel_spi.c @@ -137,6 +137,7 @@ static const struct bitbang_spi_master bitbang_spi_master_nicintel = { .get_miso = nicintel_bitbang_get_miso, .request_bus = nicintel_request_spibus, .release_bus = nicintel_release_spibus, + .half_period = 1, }; static int nicintel_spi_shutdown(void *data) @@ -181,8 +182,7 @@ int nicintel_spi_init(void) if (register_shutdown(nicintel_spi_shutdown, NULL)) return 1; - /* 1 usec halfperiod delay for now. */ - if (bitbang_spi_init(&bitbang_spi_master_nicintel, 1)) + if (bitbang_spi_init(&bitbang_spi_master_nicintel)) return 1; return 0; diff --git a/ogp_spi.c b/ogp_spi.c index dbaa57a0e..812420c5f 100644 --- a/ogp_spi.c +++ b/ogp_spi.c @@ -91,6 +91,7 @@ static const struct bitbang_spi_master bitbang_spi_master_ogp = { .get_miso = ogp_bitbang_get_miso, .request_bus = ogp_request_spibus, .release_bus = ogp_release_spibus, + .half_period = 0, }; static int ogp_spi_shutdown(void *data) @@ -136,8 +137,7 @@ int ogp_spi_init(void) if (register_shutdown(ogp_spi_shutdown, NULL)) return 1; - /* no delay for now. */ - if (bitbang_spi_init(&bitbang_spi_master_ogp, 0)) + if (bitbang_spi_init(&bitbang_spi_master_ogp)) return 1; return 0; diff --git a/opaque.c b/opaque.c index 43ddb07ef..6acaa6355 100644 --- a/opaque.c +++ b/opaque.c @@ -30,70 +30,37 @@ #include "chipdrivers.h" #include "programmer.h" -const struct opaque_programmer opaque_programmer_none = { - .max_data_read = MAX_DATA_UNSPECIFIED, - .max_data_write = MAX_DATA_UNSPECIFIED, - .probe = NULL, - .read = NULL, - .write = NULL, - .erase = NULL, -}; - -const struct opaque_programmer *opaque_programmer = &opaque_programmer_none; - int probe_opaque(struct flashctx *flash) { - if (!opaque_programmer->probe) { - msg_perr("%s called before register_opaque_programmer. " - "Please report a bug at flashrom@flashrom.org\n", - __func__); - return 0; - } - - return opaque_programmer->probe(flash); + return flash->pgm->opaque.probe(flash); } int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - if (!opaque_programmer->read) { - msg_perr("%s called before register_opaque_programmer. " - "Please report a bug at flashrom@flashrom.org\n", - __func__); - return 1; - } - return opaque_programmer->read(flash, buf, start, len); + return flash->pgm->opaque.read(flash, buf, start, len); } int write_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - if (!opaque_programmer->write) { - msg_perr("%s called before register_opaque_programmer. " - "Please report a bug at flashrom@flashrom.org\n", - __func__); - return 1; - } - return opaque_programmer->write(flash, buf, start, len); + return flash->pgm->opaque.write(flash, buf, start, len); } int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) { - if (!opaque_programmer->erase) { - msg_perr("%s called before register_opaque_programmer. " - "Please report a bug at flashrom@flashrom.org\n", - __func__); - return 1; - } - return opaque_programmer->erase(flash, blockaddr, blocklen); + return flash->pgm->opaque.erase(flash, blockaddr, blocklen); } -void register_opaque_programmer(const struct opaque_programmer *pgm) +int register_opaque_programmer(const struct opaque_programmer *pgm) { + struct registered_programmer rpgm; + if (!pgm->probe || !pgm->read || !pgm->write || !pgm->erase) { - msg_perr("%s called with one of probe/read/write/erase being " - "NULL. Please report a bug at flashrom@flashrom.org\n", + msg_perr("%s called with incomplete programmer definition. " + "Please report a bug at flashrom@flashrom.org\n", __func__); - return; + return ERROR_FLASHROM_BUG; } - opaque_programmer = pgm; - buses_supported |= BUS_PROG; + rpgm.buses_supported = BUS_PROG; + rpgm.opaque = *pgm; + return register_programmer(&rpgm); } diff --git a/programmer.c b/programmer.c index 2928d68b3..3b4def0dc 100644 --- a/programmer.c +++ b/programmer.c @@ -21,19 +21,6 @@ #include "flash.h" #include "programmer.h" -static const struct par_programmer par_programmer_none = { - .chip_readb = noop_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, - .chip_writeb = noop_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, -}; - -const struct par_programmer *par_programmer = &par_programmer_none; - /* No-op shutdown() for programmers which don't need special handling */ int noop_shutdown(void) { @@ -52,13 +39,7 @@ void fallback_unmap(void *virt_addr, size_t len) { } -/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ -uint8_t noop_chip_readb(const struct flashctx *flash, const chipaddr addr) -{ - return 0xff; -} - -/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ +/* No-op chip_writeb() for parallel style drivers not supporting writes */ void noop_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr) { } @@ -115,8 +96,50 @@ void fallback_chip_readn(const struct flashctx *flash, uint8_t *buf, return; } -void register_par_programmer(const struct par_programmer *pgm, const enum chipbustype buses) +int register_par_programmer(const struct par_programmer *pgm, + const enum chipbustype buses) { - par_programmer = pgm; - buses_supported |= buses; + struct registered_programmer rpgm; + if (!pgm->chip_writeb || !pgm->chip_writew || !pgm->chip_writel || + !pgm->chip_writen || !pgm->chip_readb || !pgm->chip_readw || + !pgm->chip_readl || !pgm->chip_readn) { + msg_perr("%s called with incomplete programmer definition. " + "Please report a bug at flashrom@flashrom.org\n", + __func__); + return ERROR_FLASHROM_BUG; + } + + rpgm.buses_supported = buses; + rpgm.par = *pgm; + return register_programmer(&rpgm); +} + +/* The limit of 4 is totally arbitrary. */ +#define PROGRAMMERS_MAX 4 +struct registered_programmer registered_programmers[PROGRAMMERS_MAX]; +int registered_programmer_count = 0; + +/* This function copies the struct registered_programmer parameter. */ +int register_programmer(struct registered_programmer *pgm) +{ + if (registered_programmer_count >= PROGRAMMERS_MAX) { + msg_perr("Tried to register more than %i programmer " + "interfaces.\n", PROGRAMMERS_MAX); + return ERROR_FLASHROM_LIMIT; + } + registered_programmers[registered_programmer_count] = *pgm; + registered_programmer_count++; + + return 0; +} + +enum chipbustype get_buses_supported(void) +{ + int i; + enum chipbustype ret = BUS_NONE; + + for (i = 0; i < registered_programmer_count; i++) + ret |= registered_programmers[i].buses_supported; + + return ret; } diff --git a/programmer.h b/programmer.h index 9942686b3..a40d037c4 100644 --- a/programmer.h +++ b/programmer.h @@ -133,6 +133,8 @@ struct bitbang_spi_master { int (*get_miso) (void); void (*request_bus) (void); void (*release_bus) (void); + /* Length of half a clock period in usecs. */ + unsigned int half_period; }; #if CONFIG_INTERNAL == 1 @@ -208,6 +210,7 @@ void internal_delay(int usecs); #if NEED_PCI == 1 /* pcidev.c */ +// FIXME: These need to be local, not global extern uint32_t io_base_addr; extern struct pci_access *pacc; extern struct pci_dev *pcidev_dev; @@ -427,8 +430,7 @@ int rayer_spi_init(void); #endif /* bitbang_spi.c */ -int bitbang_spi_init(const struct bitbang_spi_master *master, int halfperiod); -int bitbang_spi_shutdown(const struct bitbang_spi_master *master); +int bitbang_spi_init(const struct bitbang_spi_master *master); /* buspirate_spi.c */ #if CONFIG_BUSPIRATE_SPI == 1 @@ -452,6 +454,7 @@ struct decode_sizes { uint32_t fwh; uint32_t spi; }; +// FIXME: These need to be local, not global extern struct decode_sizes max_rom_decode; extern int programmer_may_write; extern unsigned long flashbase; @@ -498,7 +501,6 @@ enum spi_controller { SPI_CONTROLLER_SERPROG, #endif }; -extern const int spi_programmer_count; #define MAX_DATA_UNSPECIFIED 0 #define MAX_DATA_READ_UNLIMITED 64 * 1024 @@ -514,15 +516,15 @@ struct spi_programmer { /* Optimized functions for this programmer */ int (*read)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); int (*write_256)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); + const void *data; }; -extern const struct spi_programmer *spi_programmer; int default_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); int default_spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds); int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); int default_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); -void register_spi_programmer(const struct spi_programmer *programmer); +int register_spi_programmer(const struct spi_programmer *programmer); /* ichspi.c */ #if CONFIG_INTERNAL == 1 @@ -570,15 +572,14 @@ struct opaque_programmer { int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); int (*write) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); int (*erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen); + const void *data; }; -extern const struct opaque_programmer *opaque_programmer; -void register_opaque_programmer(const struct opaque_programmer *pgm); +int register_opaque_programmer(const struct opaque_programmer *pgm); /* programmer.c */ int noop_shutdown(void); void *fallback_map(const char *descr, unsigned long phys_addr, size_t len); void fallback_unmap(void *virt_addr, size_t len); -uint8_t noop_chip_readb(const struct flashctx *flash, const chipaddr addr); void noop_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr); void fallback_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr); void fallback_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr); @@ -595,9 +596,20 @@ struct par_programmer { uint16_t (*chip_readw) (const struct flashctx *flash, const chipaddr addr); uint32_t (*chip_readl) (const struct flashctx *flash, const chipaddr addr); void (*chip_readn) (const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len); + const void *data; }; -extern const struct par_programmer *par_programmer; -void register_par_programmer(const struct par_programmer *pgm, const enum chipbustype buses); +int register_par_programmer(const struct par_programmer *pgm, const enum chipbustype buses); +struct registered_programmer { + enum chipbustype buses_supported; + union { + struct par_programmer par; + struct spi_programmer spi; + struct opaque_programmer opaque; + }; +}; +extern struct registered_programmer registered_programmers[]; +extern int registered_programmer_count; +int register_programmer(struct registered_programmer *pgm); /* serprog.c */ #if CONFIG_SERPROG == 1 diff --git a/rayer_spi.c b/rayer_spi.c index 417fde99d..0011bc0e7 100644 --- a/rayer_spi.c +++ b/rayer_spi.c @@ -92,6 +92,7 @@ static const struct bitbang_spi_master bitbang_spi_master_rayer = { .set_sck = rayer_bitbang_set_sck, .set_mosi = rayer_bitbang_set_mosi, .get_miso = rayer_bitbang_get_miso, + .half_period = 0, }; int rayer_spi_init(void) @@ -171,8 +172,7 @@ int rayer_spi_init(void) /* Get the initial value before writing to any line. */ lpt_outbyte = INB(lpt_iobase); - /* Zero halfperiod delay. */ - if (bitbang_spi_init(&bitbang_spi_master_rayer, 0)) + if (bitbang_spi_init(&bitbang_spi_master_rayer)) return 1; return 0; diff --git a/spi.c b/spi.c index 02c83f7bf..b2d3eb0c7 100644 --- a/spi.c +++ b/spi.c @@ -1,7 +1,7 @@ /* * This file is part of the flashrom project. * - * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger + * Copyright (C) 2007, 2008, 2009, 2010, 2011 Carl-Daniel Hailfinger * Copyright (C) 2008 coresystems GmbH * * This program is free software; you can redistribute it and/or modify @@ -30,43 +30,17 @@ #include "programmer.h" #include "spi.h" -const struct spi_programmer spi_programmer_none = { - .type = SPI_CONTROLLER_NONE, - .max_data_read = MAX_DATA_UNSPECIFIED, - .max_data_write = MAX_DATA_UNSPECIFIED, - .command = NULL, - .multicommand = NULL, - .read = NULL, - .write_256 = NULL, -}; - -const struct spi_programmer *spi_programmer = &spi_programmer_none; - int spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { - if (!spi_programmer->command) { - msg_perr("%s called, but SPI is unsupported on this " - "hardware. Please report a bug at " - "flashrom@flashrom.org\n", __func__); - return 1; - } - - return spi_programmer->command(flash, writecnt, readcnt, writearr, + return flash->pgm->spi.command(flash, writecnt, readcnt, writearr, readarr); } int spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds) { - if (!spi_programmer->multicommand) { - msg_perr("%s called, but SPI is unsupported on this " - "hardware. Please report a bug at " - "flashrom@flashrom.org\n", __func__); - return 1; - } - - return spi_programmer->multicommand(flash, cmds); + return flash->pgm->spi.multicommand(flash, cmds); } int default_spi_send_command(struct flashctx *flash, unsigned int writecnt, @@ -104,7 +78,7 @@ int default_spi_send_multicommand(struct flashctx *flash, int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - unsigned int max_data = spi_programmer->max_data_read; + unsigned int max_data = flash->pgm->spi.max_data_read; if (max_data == MAX_DATA_UNSPECIFIED) { msg_perr("%s called, but SPI read chunk size not defined " "on this hardware. Please report a bug at " @@ -117,7 +91,7 @@ int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, int default_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - unsigned int max_data = spi_programmer->max_data_write; + unsigned int max_data = flash->pgm->spi.max_data_write; if (max_data == MAX_DATA_UNSPECIFIED) { msg_perr("%s called, but SPI write chunk size not defined " "on this hardware. Please report a bug at " @@ -131,12 +105,6 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { unsigned int addrbase = 0; - if (!spi_programmer->read) { - msg_perr("%s called, but SPI read is unsupported on this " - "hardware. Please report a bug at " - "flashrom@flashrom.org\n", __func__); - return 1; - } /* Check if the chip fits between lowest valid and highest possible * address. Highest possible address with the current SPI implementation @@ -157,7 +125,7 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, "access window.\n"); msg_perr("Read will probably return garbage.\n"); } - return spi_programmer->read(flash, buf, addrbase + start, len); + return flash->pgm->spi.read(flash, buf, addrbase + start, len); } /* @@ -170,14 +138,7 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, int spi_chip_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - if (!spi_programmer->write_256) { - msg_perr("%s called, but SPI page write is unsupported on this " - "hardware. Please report a bug at " - "flashrom@flashrom.org\n", __func__); - return 1; - } - - return spi_programmer->write_256(flash, buf, start, len); + return flash->pgm->spi.write_256(flash, buf, start, len); } /* @@ -187,7 +148,7 @@ int spi_chip_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, */ uint32_t spi_get_valid_read_addr(struct flashctx *flash) { - switch (spi_programmer->type) { + switch (flash->pgm->spi.type) { #if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) case SPI_CONTROLLER_ICH7: @@ -200,8 +161,22 @@ uint32_t spi_get_valid_read_addr(struct flashctx *flash) } } -void register_spi_programmer(const struct spi_programmer *pgm) +int register_spi_programmer(const struct spi_programmer *pgm) { - spi_programmer = pgm; - buses_supported |= BUS_SPI; + struct registered_programmer rpgm; + + if (!pgm->write_256 || !pgm->read || !pgm->command || + !pgm->multicommand || + ((pgm->command == default_spi_send_command) && + (pgm->multicommand == default_spi_send_multicommand))) { + msg_perr("%s called with incomplete programmer definition. " + "Please report a bug at flashrom@flashrom.org\n", + __func__); + return ERROR_FLASHROM_BUG; + } + + + rpgm.buses_supported = BUS_SPI; + rpgm.spi = *pgm; + return register_programmer(&rpgm); } diff --git a/spi25.c b/spi25.c index 1e3bed953..3ce7f08f2 100644 --- a/spi25.c +++ b/spi25.c @@ -179,7 +179,7 @@ int probe_spi_rdid4(struct flashctx *flash) /* Some SPI controllers do not support commands with writecnt=1 and * readcnt=4. */ - switch (spi_programmer->type) { + switch (flash->pgm->spi.type) { #if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) case SPI_CONTROLLER_IT87XX: @@ -1120,7 +1120,7 @@ int spi_aai_write(struct flashctx *flash, uint8_t *buf, unsigned int start, .readarr = NULL, }}; - switch (spi_programmer->type) { + switch (flash->pgm->spi.type) { #if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) case SPI_CONTROLLER_IT87XX: