From 85c39a4ce51f0a33ba1849c85198abdebbd61a41 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sat, 5 Sep 2015 18:14:25 -0500 Subject: southbridge/amd/sb700: Add Suspend to RAM (S3) support Change-Id: Ic643e31b721f11a90d8fb5f8c8f8a3b7892c0d73 Signed-off-by: Timothy Pearson Reviewed-on: http://review.coreboot.org/11949 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/southbridge/amd/sb700/spi.c | 148 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/southbridge/amd/sb700/spi.c (limited to 'src/southbridge/amd/sb700/spi.c') diff --git a/src/southbridge/amd/sb700/spi.c b/src/southbridge/amd/sb700/spi.c new file mode 100644 index 0000000000..a38ca2b8e7 --- /dev/null +++ b/src/southbridge/amd/sb700/spi.c @@ -0,0 +1,148 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson , Raptor Engineering + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AMD_SB_SPI_TX_LEN 8 + +static uint32_t get_spi_bar(void) +{ + device_t dev; + + dev = dev_find_slot(0, PCI_DEVFN(0x14, 3)); + return pci_read_config32(dev, 0xa0) & ~0x1f; +} + +void spi_init(void) +{ + /* Not needed */ +} + +unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len) +{ + return min(AMD_SB_SPI_TX_LEN - cmd_len, buf_len); +} + +static void reset_internal_fifo_pointer(void) +{ + uint32_t spibar = get_spi_bar(); + + do { + write8((void *)(spibar + 2), + read8((void *)(spibar + 2)) | 0x10); + } while (read8((void *)(spibar + 0xd)) & 0x7); +} + +static void execute_command(void) +{ + uint32_t spibar = get_spi_bar(); + + write8((void *)(spibar + 2), read8((void *)(spibar + 2)) | 1); + + while ((read8((void *)(spibar + 2)) & 1) && + (read8((void *)(spibar+3)) & 0x80)); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled internally by the SB700 */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled internally by the SB700 */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) +{ + struct spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + return slave; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bytesout, void *din, unsigned int bytesin) +{ + /* First byte is cmd which cannot be sent through the FIFO. */ + u8 cmd = *(u8 *)dout++; + u8 readoffby1; + u8 readwrite; + u8 count; + + uint32_t spibar = get_spi_bar(); + + 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_DEBUG, "FCH SPI: Too much to write. Does your SPI chip driver use" + " spi_crop_chunk()?\n"); + return -1; + } + + readoffby1 = bytesout ? 0 : 1; + + readwrite = (bytesin + readoffby1) << 4 | bytesout; + write8((void *)(spibar + 1), readwrite); + write8((void *)(spibar + 0), cmd); + + reset_internal_fifo_pointer(); + for (count = 0; count < bytesout; count++, dout++) { + write8((void *)(spibar + 0x0C), *(u8 *)dout); + } + + reset_internal_fifo_pointer(); + execute_command(); + + reset_internal_fifo_pointer(); + /* Skip the bytes we sent. */ + for (count = 0; count < bytesout; count++) { + cmd = read8((void *)(spibar + 0x0C)); + } + + reset_internal_fifo_pointer(); + for (count = 0; count < bytesin; count++, din++) { + *(u8 *)din = read8((void *)(spibar + 0x0C)); + } + + return 0; +} \ No newline at end of file -- cgit v1.2.3