Luc Verhaegen has uploaded this change for review. ( https://review.coreboot.org/29090
Change subject: ati: add r600_spi_command and r600_spi_master ......................................................................
ati: add r600_spi_command and r600_spi_master
Change-Id: I3d0bc682898f8eadadfe1f6db0d1383eb7639054 Signed-off-by: Luc Verhaegen libv@skynet.be --- M ati_spi.c M programmer.h 2 files changed, 117 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/90/29090/1
diff --git a/ati_spi.c b/ati_spi.c index 7d1e909..8f09618 100644 --- a/ati_spi.c +++ b/ati_spi.c @@ -24,6 +24,7 @@
/* improve readability */ #define mmio_read(reg) flashrom_pci_mmio_long_read(device, (reg)) +#define mmio_read_byte(reg) flashrom_pci_mmio_byte_read(device, (reg)) #define mmio_write(reg, val) flashrom_pci_mmio_long_write(device, (reg), (val)) #define mmio_mask(reg, val, mask) flashrom_pci_mmio_long_mask(device, (reg), (val), (mask))
@@ -33,6 +34,8 @@ int (*save) (struct flashrom_pci_device *device); int (*restore) (struct flashrom_pci_device *device); int (*enable) (struct flashrom_pci_device *device); + + struct spi_master *master; };
#define R600_GENERAL_PWRMGT 0x0618 @@ -45,7 +48,13 @@
#define R600_ROM_CNTL 0x1600 #define R600_ROM_CLK_CTRL 0x1604 +#define R600_ROM_SW_CNTL 0x1618 #define R600_ROM_SW_STATUS 0x161C +#define R600_ROM_SW_COMMAND 0x1620 +#define R600_ROM_SW_DATA_0x00 0x1624 +/* ... */ +#define R600_ROM_SW_DATA_0xFC 0x1720 +#define R600_ROM_SW_DATA(off) (R600_ROM_SW_DATA_0x00 + (off))
#define R600_GPIOPAD_MASK 0x1798 #define R600_GPIOPAD_A 0x179C @@ -53,6 +62,8 @@
#define R600_ROM_SW_STATUS_LOOP_COUNT 1000
+#define R600_SPI_TRANSFER_SIZE 0x100 + struct r600_spi_data { uint32_t reg_general_pwrmgt; uint32_t reg_lower_gpio_enable; @@ -209,11 +220,110 @@ return 0; }
+/* + * + */ +static int +r600_spi_command(struct flashctx *flash, + unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + const struct spi_master spi_master = flash->mst->spi; + struct flashrom_pci_device *device = + (struct flashrom_pci_device *) spi_master.data; + 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); + + if (!device) { + msg_perr("%s: no device specified!\n", __func__); + return -1; + } + + command = *((uint32_t *) writearr); + if (writecnt < 4) { + uint32_t mask = 1 << (8 * writecnt); + + command &= (mask - 1); + command_size = writecnt; + } else + command_size = 4; + + mmio_write(R600_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; + + mmio_write(R600_ROM_SW_DATA(i - 4), value); + } + + control = (command_size - 1) << 0x10; + if (readcnt) + control |= 0x40000 | readcnt; + else if (writecnt > 4) + control |= writecnt - 4; + mmio_write(R600_ROM_SW_CNTL, control); + + for (i = 0; i < R600_ROM_SW_STATUS_LOOP_COUNT; i++) { + if (mmio_read(R600_ROM_SW_STATUS)) + break; + programmer_delay(1000); + } + + if (i == R600_ROM_SW_STATUS_LOOP_COUNT) { + msg_perr("%s: still waiting for R600_ROM_SW_STATUS\n", + __func__); + return -1; + } + mmio_write(R600_ROM_SW_STATUS, 0); + + for (i = 0; i < readcnt; i++) + readarr[i] = mmio_read_byte(R600_ROM_SW_DATA(i)); + + return 0; +} + +static struct spi_master r600_spi_master = { + .type = SPI_CONTROLLER_ATI, + .features = 0, + .max_data_read = R600_SPI_TRANSFER_SIZE, + .max_data_write = R600_SPI_TRANSFER_SIZE + 1, + .command = r600_spi_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, + .write_aai = default_spi_write_aai, + .data = NULL, /* make this our flashrom_pci_device... */ +}; + static const struct ati_spi_pci_private r600_spi_pci_private = { .io_bar = 2, .save = r600_spi_save, .restore = r600_spi_restore, .enable = r600_spi_enable, + .master = &r600_spi_master, };
const struct flashrom_pci_match ati_spi_pci_devices[] = { @@ -259,5 +369,9 @@ if (ret) return ret;
+ private->master->data = device; + if (register_spi_master(private->master)) + return 1; + return 0; } diff --git a/programmer.h b/programmer.h index 3398427..73b4ec9 100644 --- a/programmer.h +++ b/programmer.h @@ -659,6 +659,9 @@ #if CONFIG_DIGILENT_SPI == 1 SPI_CONTROLLER_DIGILENT_SPI, #endif +#if CONFIG_ATI_SPI == 1 + SPI_CONTROLLER_ATI, +#endif };
#define MAX_DATA_UNSPECIFIED 0