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/Makefile.inc | 1 + src/southbridge/amd/sb700/early_setup.c | 39 +++++++-- src/southbridge/amd/sb700/lpc.c | 12 ++- src/southbridge/amd/sb700/sb700.h | 3 + src/southbridge/amd/sb700/spi.c | 148 ++++++++++++++++++++++++++++++++ src/southbridge/amd/sb700/spi.h | 21 +++++ 6 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 src/southbridge/amd/sb700/spi.c create mode 100644 src/southbridge/amd/sb700/spi.h diff --git a/src/southbridge/amd/sb700/Makefile.inc b/src/southbridge/amd/sb700/Makefile.inc index 5ec84312a385..538a7c1ccd53 100644 --- a/src/southbridge/amd/sb700/Makefile.inc +++ b/src/southbridge/amd/sb700/Makefile.inc @@ -12,6 +12,7 @@ ramstage-y += pci.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += fadt.c romstage-y += reset.c ramstage-y += reset.c +ramstage-y += spi.c romstage-$(CONFIG_USBDEBUG_IN_ROMSTAGE) += enable_usbdebug.c ramstage-$(CONFIG_USBDEBUG) += enable_usbdebug.c diff --git a/src/southbridge/amd/sb700/early_setup.c b/src/southbridge/amd/sb700/early_setup.c index 8ab97adce1a4..4a3a5a8140f1 100644 --- a/src/southbridge/amd/sb700/early_setup.c +++ b/src/southbridge/amd/sb700/early_setup.c @@ -474,8 +474,10 @@ static void sb700_devices_por_init(void) /* LPC Device, BDF:0-20-3 */ printk(BIOS_INFO, "sb700_devices_por_init(): LPC Device, BDF:0-20-3\n"); dev = pci_locate_device(PCI_ID(0x1002, 0x439D), 0); - /* DMA enable */ - pci_write_config8(dev, 0x40, 0x04); + if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) { + /* DMA enable */ + pci_write_config8(dev, 0x40, 0x04); + } /* IO Port Decode Enable */ pci_write_config8(dev, 0x44, 0xFF); @@ -618,6 +620,17 @@ static void sb700_pmio_por_init(void) byte = pmio_read(0xB2); byte |= 1 << 0; pmio_write(0xB2, byte); + + // FIXME: Enabling this causes boot to hang while initializing processors. +// /* Enable automatic C1e state switch */ +// byte = pmio_read(0xc9); +// byte |= 0x11; +// pmio_write(0xc9, byte); + + /* Enable precision HPET clock and automatic C state switch */ + byte = pmio_read(0xbb); + byte |= 0xc0; + pmio_write(0xbb, byte); } /* @@ -653,10 +666,12 @@ static void sb700_pci_cfg(void) * mentioned in RPR. But I keep them. The registers and the * comments are compatible. */ dev = pci_locate_device(PCI_ID(0x1002, 0x439D), 0); - /* Enabling LPC DMA function. */ - byte = pci_read_config8(dev, 0x40); - byte |= (1 << 2); - pci_write_config8(dev, 0x40, byte); + if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) { + /* Enabling LPC DMA function. */ + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 2); + pci_write_config8(dev, 0x40, byte); + } /* Disabling LPC TimeOut. 0x48[7] clear. */ byte = pci_read_config8(dev, 0x48); byte &= 0x7f; @@ -746,6 +761,18 @@ int acpi_get_sleep_type(void) return ((tmp & (7 << 10)) >> 10); } +void set_lpc_sticky_ctl(bool enable) +{ + uint8_t byte; + + byte = pmio_read(0xbb); + if (enable) + byte |= 0x20; + else + byte &= ~0x20; + pmio_write(0xbb, byte); +} + #if IS_ENABLED(CONFIG_LATE_CBMEM_INIT) unsigned long get_top_of_ram(void) { diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c index 0cc1e8bd3cac..145a01f50d8e 100644 --- a/src/southbridge/amd/sb700/lpc.c +++ b/src/southbridge/amd/sb700/lpc.c @@ -61,10 +61,12 @@ static void lpc_init(device_t dev) isa_dma_init(); #endif - /* Enable DMA transaction on the LPC bus */ - byte = pci_read_config8(dev, 0x40); - byte |= (1 << 2); - pci_write_config8(dev, 0x40, byte); + if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) { + /* Enable DMA transaction on the LPC bus */ + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 2); + pci_write_config8(dev, 0x40, byte); + } /* Disable the timeout mechanism on LPC */ byte = pci_read_config8(dev, 0x48); @@ -85,11 +87,13 @@ static void lpc_init(device_t dev) cmos_check_update_date(); } +#if (!IS_ENABLED(CONFIG_EARLY_CBMEM_INIT)) int acpi_get_sleep_type(void) { u16 tmp = inw(ACPI_PM1_CNT_BLK); return ((tmp & (7 << 10)) >> 10); } +#endif #if IS_ENABLED(CONFIG_LATE_CBMEM_INIT) void backup_top_of_ram(uint64_t ramtop) diff --git a/src/southbridge/amd/sb700/sb700.h b/src/southbridge/amd/sb700/sb700.h index ca020a56db29..b477091939b1 100644 --- a/src/southbridge/amd/sb700/sb700.h +++ b/src/southbridge/amd/sb700/sb700.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson , Raptor Engineering * * 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 @@ -75,6 +76,8 @@ void sb7xx_51xx_setup_sata_phys(struct device *dev); #endif +void set_lpc_sticky_ctl(bool enable); + int s3_save_nvram_early(u32 dword, int size, int nvram_pos); int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos); diff --git a/src/southbridge/amd/sb700/spi.c b/src/southbridge/amd/sb700/spi.c new file mode 100644 index 000000000000..a38ca2b8e7d4 --- /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 diff --git a/src/southbridge/amd/sb700/spi.h b/src/southbridge/amd/sb700/spi.h new file mode 100644 index 000000000000..9b76b35d8d35 --- /dev/null +++ b/src/southbridge/amd/sb700/spi.h @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson , Raptor Engineering + * + * 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 + */ + +int spi_claim_bus(struct spi_slave *slave); +void spi_release_bus(struct spi_slave *slave); \ No newline at end of file -- cgit v1.2.3