spi: Get rid of flash_programmer_probe in spi_slave structure

flash_programmer_probe is a property of the spi flash driver and does
not belong in the spi_slave structure. Thus, make
spi_flash_programmer_probe a callback from the spi_flash_probe
function. Logic still remains the same as before (order matters):
1. Try spi_flash_programmer_probe without force option
2. Try generic flash probing
3. Try spi_flash_programmer_probe with force option

If none of the above steps work, fail probing. Flash controller is
expected to honor force option to decide whether to perform specialized
probing or to defer to generic probing.

BUG=None
BRANCH=None
TEST=Compiles successfully

Change-Id: I4163593eea034fa044ec2216e56d0ea3fbc86c7d
Signed-off-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: https://review.coreboot.org/17465
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Furquan Shaikh 2016-11-17 20:38:07 -08:00 committed by Furquan Shaikh
parent dc34fb60b4
commit d2fb6ae813
9 changed files with 68 additions and 56 deletions

View File

@ -296,46 +296,39 @@ static struct {
}; };
#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) #define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN)
struct spi_flash *
/* Public API implementations. */ __attribute__((weak)) spi_flash_programmer_probe(struct spi_slave *spi,
struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs) int force)
{
/* Default weak implementation. Do nothing. */
return NULL;
}
static struct spi_flash *__spi_flash_probe(struct spi_slave *spi)
{ {
struct spi_slave *spi;
struct spi_flash *flash = NULL;
int ret, i, shift; int ret, i, shift;
u8 idcode[IDCODE_LEN], *idp; u8 idcode[IDCODE_LEN], *idp;
struct spi_flash *flash = NULL;
spi = spi_setup_slave(bus, cs);
if (!spi) {
printk(BIOS_WARNING, "SF: Failed to set up slave\n");
return NULL;
}
if (spi->force_programmer_specific && spi->programmer_specific_probe) {
flash = spi->programmer_specific_probe (spi);
if (!flash)
goto err_read_id;
goto flash_detected;
}
/* Read the ID codes */ /* Read the ID codes */
ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
if (ret) if (ret)
goto err_read_id; return NULL;
#if CONFIG_DEBUG_SPI_FLASH if (IS_ENABLED(CONFIG_DEBUG_SPI_FLASH)) {
printk(BIOS_SPEW, "SF: Got idcode: "); printk(BIOS_SPEW, "SF: Got idcode: ");
for (i = 0; i < sizeof(idcode); i++) for (i = 0; i < sizeof(idcode); i++)
printk(BIOS_SPEW, "%02x ", idcode[i]); printk(BIOS_SPEW, "%02x ", idcode[i]);
printk(BIOS_SPEW, "\n"); printk(BIOS_SPEW, "\n");
#endif }
/* count the number of continuation bytes */ /* count the number of continuation bytes */
for (shift = 0, idp = idcode; for (shift = 0, idp = idcode; shift < IDCODE_CONT_LEN && *idp == 0x7f;
shift < IDCODE_CONT_LEN && *idp == 0x7f;
++shift, ++idp) ++shift, ++idp)
continue; continue;
printk(BIOS_INFO, "Manufacturer: %02x\n", *idp);
/* search the table for matches in shift and id */ /* search the table for matches in shift and id */
for (i = 0; i < ARRAY_SIZE(flashes); ++i) for (i = 0; i < ARRAY_SIZE(flashes); ++i)
if (flashes[i].shift == shift && flashes[i].idcode == *idp) { if (flashes[i].shift == shift && flashes[i].idcode == *idp) {
@ -345,15 +338,37 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs)
break; break;
} }
if (!flash && spi->programmer_specific_probe) { return flash;
flash = spi->programmer_specific_probe (spi); }
}
if (!flash) { struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs)
printk(BIOS_WARNING, "SF: Unsupported manufacturer %02x\n", *idp); {
goto err_manufacturer_probe; struct spi_slave *spi;
struct spi_flash *flash;
spi = spi_setup_slave(bus, cs);
if (!spi) {
printk(BIOS_WARNING, "SF: Failed to set up slave\n");
return NULL;
}
/* Try special programmer probe if any (without force). */
flash = spi_flash_programmer_probe(spi, 0);
/* If flash is not found, try generic spi flash probe. */
if (!flash)
flash = __spi_flash_probe(spi);
/* If flash is not yet found, force special programmer probe if any. */
if (!flash)
flash = spi_flash_programmer_probe(spi, 1);
/* Give up -- nothing more to try if flash is not found. */
if (!flash) {
printk(BIOS_WARNING, "SF: Unsupported manufacturer!\n");
return NULL;
} }
flash_detected:
printk(BIOS_INFO, "SF: Detected %s with sector size 0x%x, total 0x%x\n", printk(BIOS_INFO, "SF: Detected %s with sector size 0x%x, total 0x%x\n",
flash->name, flash->sector_size, flash->size); flash->name, flash->sector_size, flash->size);
@ -366,10 +381,6 @@ flash_detected:
spi_flash_dev = flash; spi_flash_dev = flash;
return flash; return flash;
err_manufacturer_probe:
err_read_id:
return NULL;
} }
int spi_flash_read(const struct spi_flash *flash, u32 offset, size_t len, int spi_flash_read(const struct spi_flash *flash, u32 offset, size_t len,

View File

@ -27,16 +27,12 @@
/*----------------------------------------------------------------------- /*-----------------------------------------------------------------------
* Representation of a SPI slave, i.e. what we're communicating with. * Representation of a SPI slave, i.e. what we're communicating with.
* *
* Drivers are expected to extend this with controller-specific data.
*
* bus: ID of the bus that the slave is attached to. * bus: ID of the bus that the slave is attached to.
* cs: ID of the chip select connected to the slave. * cs: ID of the chip select connected to the slave.
*/ */
struct spi_slave { struct spi_slave {
unsigned int bus; unsigned int bus;
unsigned int cs; unsigned int cs;
int force_programmer_specific;
struct spi_flash * (*programmer_specific_probe) (struct spi_slave *spi);
}; };
/*----------------------------------------------------------------------- /*-----------------------------------------------------------------------

View File

@ -45,6 +45,13 @@ void lb_spi_flash(struct lb_header *header);
/* SPI Flash Driver Public API */ /* SPI Flash Driver Public API */
struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs); struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs);
/*
* Specialized probing performed by platform. This is a weak function which can
* be overriden by platform driver.
* spi = Pointer to spi_slave structure.
* force = Indicates if the platform driver can skip specialized probing.
*/
struct spi_flash *spi_flash_programmer_probe(struct spi_slave *spi, int force);
/* All the following functions return 0 on success and non-zero on error. */ /* All the following functions return 0 on success and non-zero on error. */
int spi_flash_read(const struct spi_flash *flash, u32 offset, size_t len, int spi_flash_read(const struct spi_flash *flash, u32 offset, size_t len,

View File

@ -354,7 +354,7 @@ static struct spi_flash boot_flash CAR_GLOBAL;
* The size of the flash component is always taken from density field in the * The size of the flash component is always taken from density field in the
* SFDP table. FLCOMP.C0DEN is no longer used by the Flash Controller. * SFDP table. FLCOMP.C0DEN is no longer used by the Flash Controller.
*/ */
static struct spi_flash *nuclear_flash_probe(struct spi_slave *spi) struct spi_flash *spi_flash_programmer_probe(struct spi_slave *spi, int force)
{ {
BOILERPLATE_CREATE_CTX(ctx); BOILERPLATE_CREATE_CTX(ctx);
struct spi_flash *flash; struct spi_flash *flash;
@ -403,8 +403,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
slave->bus = bus; slave->bus = bus;
slave->cs = cs; slave->cs = cs;
slave->programmer_specific_probe = nuclear_flash_probe;
slave->force_programmer_specific = 1;
return slave; return slave;
} }

View File

@ -345,7 +345,7 @@ int pch_hwseq_read_status(const struct spi_flash *flash, u8 *reg)
static struct spi_slave boot_spi CAR_GLOBAL; static struct spi_slave boot_spi CAR_GLOBAL;
static struct spi_flash boot_flash CAR_GLOBAL; static struct spi_flash boot_flash CAR_GLOBAL;
static struct spi_flash *spi_flash_hwseq_probe(struct spi_slave *spi) struct spi_flash *spi_flash_programmer_probe(struct spi_slave *spi, int force)
{ {
struct spi_flash *flash; struct spi_flash *flash;
@ -380,8 +380,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
slave->bus = bus; slave->bus = bus;
slave->cs = cs; slave->cs = cs;
slave->force_programmer_specific = 1;
slave->programmer_specific_probe = spi_flash_hwseq_probe;
return slave; return slave;
} }

View File

@ -233,7 +233,7 @@ static int nor_erase(const struct spi_flash *flash, u32 offset, size_t len)
return 0; return 0;
} }
struct spi_flash *mt8173_nor_flash_probe(struct spi_slave *spi) struct spi_flash *spi_flash_programmer_probe(struct spi_slave *spi, int force)
{ {
static struct spi_flash flash = {0}; static struct spi_flash flash = {0};

View File

@ -87,5 +87,4 @@ struct mt8173_nor_regs {
check_member(mt8173_nor_regs, fdma_end_dadr, 0x724); check_member(mt8173_nor_regs, fdma_end_dadr, 0x724);
static struct mt8173_nor_regs * const mt8173_nor = (void *)SFLASH_REG_BASE; static struct mt8173_nor_regs * const mt8173_nor = (void *)SFLASH_REG_BASE;
struct spi_flash *mt8173_nor_flash_probe(struct spi_slave *spi);
#endif /* __SOC_MEDIATEK_MT8173_FLASH_CONTROLLER_H__ */ #endif /* __SOC_MEDIATEK_MT8173_FLASH_CONTROLLER_H__ */

View File

@ -173,8 +173,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
case CONFIG_BOOT_DEVICE_SPI_FLASH_BUS: case CONFIG_BOOT_DEVICE_SPI_FLASH_BUS:
slave.bus = bus; slave.bus = bus;
slave.cs = cs; slave.cs = cs;
slave.force_programmer_specific = 1;
slave.programmer_specific_probe = &mt8173_nor_flash_probe;
return &slave; return &slave;
default: default:
die ("wrong bus number.\n"); die ("wrong bus number.\n");

View File

@ -66,7 +66,6 @@
#endif /* !__SMM__ */ #endif /* !__SMM__ */
static int spi_is_multichip(void); static int spi_is_multichip(void);
static struct spi_flash *spi_flash_hwseq(struct spi_slave *spi);
typedef struct spi_slave ich_spi_slave; typedef struct spi_slave ich_spi_slave;
@ -299,8 +298,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
slave->bus = bus; slave->bus = bus;
slave->cs = cs; slave->cs = cs;
slave->force_programmer_specific = spi_is_multichip ();
slave->programmer_specific_probe = spi_flash_hwseq;
return slave; return slave;
} }
@ -920,11 +917,19 @@ static int ich_hwseq_write(const struct spi_flash *flash, u32 addr, size_t len,
} }
static struct spi_flash *spi_flash_hwseq(struct spi_slave *spi) struct spi_flash *spi_flash_programmer_probe(struct spi_slave *spi, int force)
{ {
struct spi_flash *flash = NULL; struct spi_flash *flash = NULL;
uint32_t flcomp; uint32_t flcomp;
/*
* Perform SPI flash probing only if:
* 1. spi_is_multichip returns 1 or
* 2. Specialized probing is forced by SPI flash driver.
*/
if (!spi_is_multichip() && !force)
return NULL;
flash = malloc(sizeof(*flash)); flash = malloc(sizeof(*flash));
if (!flash) { if (!flash) {
printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); printk(BIOS_WARNING, "SF: Failed to allocate memory\n");