Michał Żygowski has uploaded this change for review. ( https://review.coreboot.org/28719
Change subject: sb/amd/pi/hudson: Add SPI controller support ......................................................................
sb/amd/pi/hudson: Add SPI controller support
Change-Id: Icc6feb433a19337e09fc394cbf30288f53b195dd Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com --- M src/southbridge/amd/pi/hudson/Makefile.inc A src/southbridge/amd/pi/hudson/spi.c 2 files changed, 176 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/28719/1
diff --git a/src/southbridge/amd/pi/hudson/Makefile.inc b/src/southbridge/amd/pi/hudson/Makefile.inc index 251cb6c..e06973a 100644 --- a/src/southbridge/amd/pi/hudson/Makefile.inc +++ b/src/southbridge/amd/pi/hudson/Makefile.inc @@ -55,6 +55,7 @@ ramstage-y += sm.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi_util.c +ramstage-$(CONFIG_SPI_FLASH) += spi.c ramstage-$(CONFIG_HUDSON_UART) += uart.c ramstage-y += usb.c
diff --git a/src/southbridge/amd/pi/hudson/spi.c b/src/southbridge/amd/pi/hudson/spi.c new file mode 100644 index 0000000..76373c4 --- /dev/null +++ b/src/southbridge/amd/pi/hudson/spi.c @@ -0,0 +1,175 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <arch/io.h> +#include <console/console.h> +#include <spi_flash.h> +#include <spi-generic.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ops.h> + +#include <Proc/Fch/FchPlatform.h> + +#define SPI_REG_OPCODE 0x0 +#define SPI_REG_CNTRL02 0x2 + #define CNTRL02_FIFO_RESET (1 << 4) + #define CNTRL02_EXEC_OPCODE (1 << 0) +#define SPI_REG_CNTRL03 0x3 + #define CNTRL03_SPIBUSY (1 << 7) +#define SPI_REG_FIFO 0xc +#define SPI_REG_CNTRL11 0xd + #define CNTRL11_FIFOPTR_MASK 0x07 +#define SPI_EXT_REG_INDX 0x1e + #define SPI_EXT_REG_TXCOUNT 0x5 + #define SPI_EXT_REG_RXCOUNT 0x6 +#define SPI_EXT_REG_DATA 0x1f + +#define AMD_SB_SPI_TX_LEN 64 + +static uintptr_t spibar; + +static inline uint8_t spi_read(uint8_t reg) +{ + return read8((void *)(spibar + reg)); +} + +static inline void spi_write(uint8_t reg, uint8_t val) +{ + write8((void *)(spibar + reg), val); +} + +static void reset_internal_fifo_pointer(void) +{ + uint8_t reg8; + + do { + reg8 = spi_read(SPI_REG_CNTRL02); + reg8 |= CNTRL02_FIFO_RESET; + spi_write(SPI_REG_CNTRL02, reg8); + } while (spi_read(SPI_REG_CNTRL11) & CNTRL11_FIFOPTR_MASK); +} + +static void execute_command(void) +{ + uint8_t reg8; + + reg8 = spi_read(SPI_REG_CNTRL02); + reg8 |= CNTRL02_EXEC_OPCODE; + spi_write(SPI_REG_CNTRL02, reg8); + + while ((spi_read(SPI_REG_CNTRL02) & CNTRL02_EXEC_OPCODE) && + (spi_read(SPI_REG_CNTRL03) & CNTRL03_SPIBUSY)); +} + +void spi_init(void) +{ + device_t dev; + + dev = dev_find_slot(0, PCI_DEVFN(0x14, 3)); + spibar = pci_read_config32(dev, 0xA0) & ~0x1F; +} + +static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, + size_t bytesout, void *din, size_t bytesin) +{ + /* First byte is cmd which can not being sent through FIFO. */ + u8 cmd = *(u8 *)dout++; + size_t count; + + bytesout--; + + /* + * Check if this is a write command attempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (bytesout > AMD_SB_SPI_TX_LEN) { + printk(BIOS_WARNING, "FCH SPI: Too much to write. Does your SPI chip driver use" + " spi_crop_chunk()?\n"); + return -1; + } + + spi_write(SPI_EXT_REG_INDX, SPI_EXT_REG_TXCOUNT); + spi_write(SPI_EXT_REG_DATA, bytesout); + spi_write(SPI_EXT_REG_INDX, SPI_EXT_REG_RXCOUNT); + spi_write(SPI_EXT_REG_DATA, bytesin); + + spi_write(SPI_REG_OPCODE, cmd); + + reset_internal_fifo_pointer(); + for (count = 0; count < bytesout; count++, dout++) { + spi_write(SPI_REG_FIFO, *(uint8_t *)dout); + } + + reset_internal_fifo_pointer(); + execute_command(); + + reset_internal_fifo_pointer(); + /* Skip the bytes we sent. */ + for (count = 0; count < bytesout; count++) { + cmd = spi_read(SPI_REG_FIFO); + } + + for (count = 0; count < bytesin; count++, din++) { + *(uint8_t *)din = spi_read(SPI_REG_FIFO); + } + + return 0; +} + +int chipset_volatile_group_begin(const struct spi_flash *flash) +{ + if (!IS_ENABLED (CONFIG_HUDSON_IMC_FWM)) + return 0; + + ImcSleep(NULL); + return 0; +} + +int chipset_volatile_group_end(const struct spi_flash *flash) +{ + if (!IS_ENABLED (CONFIG_HUDSON_IMC_FWM)) + return 0; + + ImcWakeup(NULL); + return 0; +} + +static int xfer_vectors(const struct spi_slave *slave, + struct spi_op vectors[], size_t count) +{ + return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); +} + +static const struct spi_ctrlr spi_ctrlr = { + .xfer_vector = xfer_vectors, + .max_xfer_size = AMD_SB_SPI_TX_LEN, + .flags = SPI_CNTRLR_DEDUCT_CMD_LEN, +}; + +const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { + { + .ctrlr = &spi_ctrlr, + .bus_start = 0, + .bus_end = 0, + }, +}; + +const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);