diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/amd/stoneyridge/include/soc/southbridge.h | 33 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/spi.c | 110 |
2 files changed, 65 insertions, 78 deletions
diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h index f77640e70d..fa427eedc1 100644 --- a/src/soc/amd/stoneyridge/include/soc/southbridge.h +++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h @@ -193,8 +193,6 @@ #define SPI_FROM_HOST_PREFETCH_EN BIT(0) /* SPI Controller */ -#define SPI_FIFO_DEPTH 8 - #define SPI_CNTRL0 0x00 #define SPI_BUSY BIT(31) #define SPI_READ_MODE_MASK (BIT(30) | BIT(29) | BIT(18)) @@ -209,13 +207,21 @@ #define SPI_FIFO_PTR_CLR BIT(20) #define SPI_ARB_ENABLE BIT(19) #define EXEC_OPCODE BIT(16) -#define SPI_REG_CNTRL01 0x01 -#define SPI_REG_CNTRL02 0x02 -#define SPI_FIFO_PTR_CLR02 (SPI_FIFO_PTR_CLR >> 16) #define SPI_CNTRL1 0x0c -#define SPI_FIFO_PTR_MASK (BIT(8) | BIT(9) | BIT(10)) -#define SPI_CNTRL11 0x0d -#define SPI_FIFO_PTR_MASK11 (SPI_FIFO_PTR_MASK >> 8) +#define SPI_CMD_CODE 0x45 +#define SPI_CMD_TRIGGER 0x47 +#define SPI_CMD_TRIGGER_EXECUTE (BIT(7)) +#define SPI_TX_BYTE_COUNT 0x48 +#define SPI_RX_BYTE_COUNT 0x4B +#define SPI_STATUS 0x4c +#define SPI_DONE_BYTE_COUNT_SHIFT 0 +#define SPI_DONE_BYTE_COUNT_MASK 0xff +#define SPI_FIFO_WR_PTR_SHIFT 8 +#define SPI_FIFO_WR_PTR_MASK 0x7f +#define SPI_FIFO_RD_PTR_SHIFT 16 +#define SPI_FIFO_RD_PTR_MASK 0x7f +#define SPI_FIFO 0x80 +#define SPI_FIFO_DEPTH (0xc7 - SPI_FIFO) #define SPI100_SPEED_CONFIG 0x22 /* Use SPI_SPEED_16M-SPI_SPEED_66M below for the southbridge */ @@ -223,17 +229,6 @@ #define SPI_NORM_SPEED_SH 12 #define SPI_FAST_SPEED_SH 8 -#define SPI_EXT_INDEX 0x1e -#define SPI_EXT_DATA 0x1f -#define SPI_DDR_CMD 0x0 -#define SPI_QDR_CMD 0x1 -#define SPI_DPR_CMD 0x2 -#define SPI_QPR_CMD 0x3 -#define SPI_MODE_BYTE 0x4 -#define SPI_TX_BYTE_COUNT 0x5 -#define SPI_RX_BYTE_COUNT 0x6 -#define SPI_SPI_DATA_FIFO_PTR 0x7 - #define SPI100_ENABLE 0x20 #define SPI_USE_SPI100 BIT(0) diff --git a/src/soc/amd/stoneyridge/spi.c b/src/soc/amd/stoneyridge/spi.c index b27d00ca74..0e2afe3128 100644 --- a/src/soc/amd/stoneyridge/spi.c +++ b/src/soc/amd/stoneyridge/spi.c @@ -18,6 +18,7 @@ #include <string.h> #include <arch/io.h> #include <arch/early_variables.h> +#include <lib.h> #include <timer.h> #include <console/console.h> #include <commonlib/helpers.h> @@ -30,6 +31,8 @@ #include <soc/pci_devs.h> #include <soc/imc.h> +#define SPI_DEBUG_DRIVER IS_ENABLED(CONFIG_DEBUG_SPI_FLASH) + static uintptr_t spibar CAR_GLOBAL; static uintptr_t get_spibase(void) @@ -62,46 +65,48 @@ static inline void spi_write32(uint8_t reg, uint32_t val) write32((void *)(get_spibase() + reg), val); } -static int reset_internal_fifo_pointer(void) +static void dump_state(const char *str) +{ + if (!SPI_DEBUG_DRIVER) + return; + + printk(BIOS_DEBUG, "SPI: %s\n", str); + printk(BIOS_DEBUG, "Cntrl0: %x\n", spi_read32(SPI_CNTRL0)); + printk(BIOS_DEBUG, "Status: %x\n", spi_read32(SPI_STATUS)); + printk(BIOS_DEBUG, "TxByteCount: %x\n", spi_read8(SPI_TX_BYTE_COUNT)); + printk(BIOS_DEBUG, "RxByteCount: %x\n", spi_read8(SPI_RX_BYTE_COUNT)); + printk(BIOS_DEBUG, "CmdCode: %x\n", spi_read8(SPI_CMD_CODE)); + hexdump((void *)(get_spibase() + SPI_FIFO), SPI_FIFO_DEPTH); +} + +static int wait_for_ready(void) { - uint8_t reg; const uint32_t timeout_ms = 500; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, timeout_ms); do { - reg = spi_read8(SPI_REG_CNTRL02); - reg |= SPI_FIFO_PTR_CLR02; - spi_write8(SPI_REG_CNTRL02, reg); - /* wait for ptr=0 */ - if (!(spi_read8(SPI_CNTRL11) & (SPI_FIFO_PTR_MASK11))) + if (!(spi_read32(SPI_STATUS) & SPI_BUSY)) return 0; } while (!stopwatch_expired(&sw)); - printk(BIOS_DEBUG, "FCH SPI Error: FIFO reset failed\n"); return -1; } static int execute_command(void) { - uint32_t reg; - const uint32_t timeout_ms = 500; - struct stopwatch sw; + dump_state("Before Execute"); - stopwatch_init_msecs_expire(&sw, timeout_ms); + spi_write8(SPI_CMD_TRIGGER, SPI_CMD_TRIGGER_EXECUTE); - reg = spi_read32(SPI_CNTRL0); - reg |= EXEC_OPCODE; - spi_write32(SPI_CNTRL0, reg); + if (wait_for_ready()) + printk(BIOS_DEBUG, + "FCH SPI Error: Timeout executing command\n"); - do { - if (!(spi_read32(SPI_CNTRL0) & (EXEC_OPCODE | SPI_BUSY))) - return 0; - } while (!stopwatch_expired(&sw)); + dump_state("Transaction finished"); - printk(BIOS_DEBUG, "FCH SPI Error: Timeout executing command\n"); - return -1; + return 0; } void spi_init(void) @@ -113,45 +118,21 @@ void spi_init(void) set_spibar(bar); } -static int do_command(uint8_t cmd, const void *dout, - size_t bytesout, uint8_t **din, size_t *bytesin) -{ - size_t count; - size_t max_in = MIN(*bytesin, SPI_FIFO_DEPTH); - - spi_write8(SPI_EXT_INDEX, SPI_TX_BYTE_COUNT); - spi_write8(SPI_EXT_DATA, bytesout); - spi_write8(SPI_EXT_INDEX, SPI_RX_BYTE_COUNT); - spi_write8(SPI_EXT_DATA, max_in); - spi_write8(SPI_CNTRL0, cmd); - - if (reset_internal_fifo_pointer()) - return -1; - for (count = 0; count < bytesout; count++, dout++) - spi_write8(SPI_CNTRL1, *(uint8_t *)dout); - - if (execute_command()) - return -1; - - if (reset_internal_fifo_pointer()) - return -1; - for (count = 0; count < bytesout; count++) - spi_read8(SPI_CNTRL1); /* skip the bytes we sent */ - - for (count = 0; count < max_in; count++, (*din)++) - **din = spi_read8(SPI_CNTRL1); - - *bytesin -= max_in; - return 0; -} - static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, size_t bytesout, void *din, size_t bytesin) { + size_t count; uint8_t cmd; + uint8_t *bufin = din; + const uint8_t *bufout = dout; + + if (SPI_DEBUG_DRIVER) + printk(BIOS_DEBUG, "%s(%lx, %lx)\n", __func__, bytesout, + bytesin); /* First byte is cmd which cannot be sent through FIFO */ - cmd = *(uint8_t *)dout++; + cmd = bufout[0]; + bufout++; bytesout--; /* @@ -161,16 +142,27 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, * and followed by other SPI commands, and this sequence is controlled * by the SPI chip driver. */ - if (bytesout > SPI_FIFO_DEPTH) { + if (bytesout + bytesin > SPI_FIFO_DEPTH) { printk(BIOS_DEBUG, "FCH SPI: Too much to write. Does your SPI" " chip driver use spi_crop_chunk()?\n"); return -1; } - do { - if (do_command(cmd, dout, bytesout, (uint8_t **)&din, &bytesin)) - return -1; - } while (bytesin); + if (wait_for_ready()) + return -1; + + spi_write8(SPI_CMD_CODE, cmd); + spi_write8(SPI_TX_BYTE_COUNT, bytesout); + spi_write8(SPI_RX_BYTE_COUNT, bytesin); + + for (count = 0; count < bytesout; count++) + spi_write8(SPI_FIFO + count, bufout[count]); + + if (execute_command()) + return -1; + + for (count = 0; count < bytesin; count++) + bufin[count] = spi_read8(SPI_FIFO + count + bytesout); return 0; } |