Luc Verhaegen has uploaded this change for review. ( https://review.coreboot.org/29213
Change subject: ati: implement sea-island spi_command ......................................................................
ati: implement sea-island spi_command
Bonaire is special in that its data registers 0xd8 through 0xE4 are shifted up by 0x10.
Change-Id: Iab69973af56beb5818411932db1d8a3e6519b468 Signed-off-by: Luc Verhaegen libv@skynet.be --- M ati_spi.c 1 file changed, 94 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/13/29213/1
diff --git a/ati_spi.c b/ati_spi.c index dc0ed2d..e9e049e 100644 --- a/ati_spi.c +++ b/ati_spi.c @@ -436,7 +436,13 @@
#define CI_ROM_CNTL 0xC0600000 #define CI_PAGE_MIRROR_CNTL 0xC0600004 +#define CI_ROM_SW_CNTL 0xC060001C #define CI_ROM_SW_STATUS 0xC0600020 +#define CI_ROM_SW_COMMAND 0xC0600024 +#define CI_ROM_SW_DATA_0x00 0xC0600028 +/* ... */ +#define CI_ROM_SW_DATA_0xFC 0xC0600124 +#define CI_ROM_SW_DATA(off) (CI_ROM_SW_DATA_0x00 + (off))
#define CI_ROM_SW_STATUS_LOOP_COUNT 1000
@@ -625,6 +631,9 @@ const struct spi_master spi_master = flash->mst->spi; struct flashrom_pci_device *device = (struct flashrom_pci_device *) spi_master.data; + const struct ati_spi_pci_private *private = device->private; + uint32_t command, control; + int i, command_size;
msg_pdbg("%s(%p(%p), %d, %d, %p (0x%02X), %p);\n", __func__, flash, device, writecnt, readcnt, writearr, writearr[0], readarr); @@ -634,6 +643,91 @@ return -1; }
+ command = writearr[0]; + if (writecnt > 1) + command |= writearr[1] << 24; + if (writecnt > 2) + command |= writearr[2] << 16; + if (writecnt > 3) + command |= writearr[3] << 8; + + if (writecnt < 4) + command_size = writecnt; + else + command_size = 4; + + smc_write(CI_ROM_SW_COMMAND, command); + + /* + * For some reason, we have an endianness difference between reading + * and writing. Also, ati hw only does 32bit register write accesses. + * If you write 8bits, the upper bytes will be nulled. Reading is fine. + * Furthermore, due to flashrom infrastructure, we need to skip the + * command in the writearr. + */ + for (i = 4; i < writecnt; i += 4) { + uint32_t value = 0; + int remainder = writecnt - i; + + if (remainder > 4) + remainder = 4; + + if (remainder > 0) + value |= writearr[i + 0] << 24; + if (remainder > 1) + value |= writearr[i + 1] << 16; + if (remainder > 2) + value |= writearr[i + 2] << 8; + if (remainder > 3) + value |= writearr[i + 3] << 0; + + /* Bonaire has a gap between 0xD8 and 0xE8 */ + if ((private->type == ATI_SPI_TYPE_BONAIRE) && (i >= 0xdc)) + smc_write(CI_ROM_SW_DATA(i + 0x0C), value); + else + smc_write(CI_ROM_SW_DATA(i - 4), value); + } + + control = (command_size - 1) << 0x10; + if (readcnt) + control |= 0x40000 | readcnt; + else if (writecnt > 4) + control |= writecnt - 4; + smc_write(CI_ROM_SW_CNTL, control); + + for (i = 0; i < CI_ROM_SW_STATUS_LOOP_COUNT; i++) { + if (smc_read(CI_ROM_SW_STATUS)) + break; + programmer_delay(1000); + } + + if (i == CI_ROM_SW_STATUS_LOOP_COUNT) { + msg_perr("%s: still waiting for CI_ROM_SW_STATUS\n", + __func__); + return -1; + } + smc_write(CI_ROM_SW_STATUS, 0); + + for (i = 0; i < readcnt; i += 4) { + uint32_t value; + int remainder = readcnt - i; + + /* Bonaire has a gap between 0xD8 and 0xE8 */ + if ((private->type == ATI_SPI_TYPE_BONAIRE) && (i >= 0xd8)) + value = smc_read(CI_ROM_SW_DATA(i + 0x10)); + else + value = smc_read(CI_ROM_SW_DATA(i)); + + if (remainder > 0) + readarr[i] = value; + if (remainder > 1) + readarr[i + 1] = value >> 8; + if (remainder > 2) + readarr[i + 2] = value >> 16; + if (remainder > 3) + readarr[i + 3] = value >> 24; + } + return 0; }