summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward O'Callaghan <quasisec@google.com>2020-07-31 12:21:02 +1000
committerEdward O'Callaghan <quasisec@chromium.org>2020-12-16 10:29:41 +0000
commit855d6b6f11e220b94c8d10059110f37797933a3e (patch)
treebc4f7953b78fa83ebaa30de55e45ffaf9dae5d57
parent9f90f4c01b6b22aa425e8e8abc34ef76b422c507 (diff)
downloadflashrom-855d6b6f11e220b94c8d10059110f37797933a3e.tar.gz
flashrom-855d6b6f11e220b94c8d10059110f37797933a3e.tar.bz2
flashrom-855d6b6f11e220b94c8d10059110f37797933a3e.zip
sb600spi.c: Add support for 0x790b rev 0x61 (AMD Zen)
Adds support for rev 0x59 || 0x61 of did 0x790b. This is quite confusing however it turns out FCH chipsets called 'Promontory' contain the so-called SPI100 ip core that uses memory mapping and not a ring buffer for transactions. Typically this is found on both Stoney Ridge and Zen platforms. In light of this, separate out the promontory path into its own callback struct state tracker so that it's implementation does not interfere with previous generations that predate the SPI100 controller. Since there is some life-time state required to track the mapping during between the first attempted read and the final tear-down of the spi master we take the opportunity to avoid static locals and instead implement the functionality in a re-entrant way for follow up clean ups. BUG=none BRANCH=none TEST= Zork => 'Promontory (rev 0x61) detected.' && Grunt => 'Promontory (rev 0x4b) detected.' Change-Id: I5ce63b5de863aed0442cb4ffeff981e9b2fa445b Signed-off-by: Edward O'Callaghan <quasisec@google.com> Reviewed-on: https://review.coreboot.org/c/flashrom/+/44073 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Sam McNally <sammc@google.com>
-rw-r--r--sb600spi.c67
1 files changed, 64 insertions, 3 deletions
diff --git a/sb600spi.c b/sb600spi.c
index 40434f0f5..2e27cee77 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -55,6 +55,10 @@ enum amd_chipset {
#define FIFO_SIZE_OLD 8
#define FIFO_SIZE_YANGTZE 71
+struct sb600spi_data {
+ struct flashctx *flash;
+};
+
static int find_smbus_dev_rev(uint16_t vendor, uint16_t device)
{
struct pci_dev *smbus_dev = pci_dev_find(vendor, device);
@@ -116,8 +120,17 @@ static enum amd_chipset determine_generation(struct pci_dev *dev)
if (rev == 0x4a) {
msg_pdbg("Yangtze detected.\n");
return CHIPSET_YANGTZE;
- } else if (rev == 0x4b) {
- msg_pdbg("Promontory detected.\n");
+ /**
+ * FCH chipsets called 'Promontory' are one's with the
+ * so-called SPI100 ip core that uses memory mapping and
+ * not a ring buffer for transactions. Typically this is
+ * found on both Stoney Ridge and Zen platforms.
+ *
+ * The revisions I have found by searching various lspci
+ * outputs are as follows: 0x4b, 0x59 & 0x61.
+ */
+ } else if (rev == 0x4b || rev == 0x59 || rev == 0x61) {
+ msg_pdbg("Promontory (rev 0x%02x) detected.\n", rev);
return CHIPSET_PROMONTORY;
} else {
msg_pwarn("FCH device found but SMBus revision 0x%02x does not match known values.\n"
@@ -541,6 +554,18 @@ static int handle_imc(struct pci_dev *dev, enum amd_chipset amd_gen)
return amd_imc_shutdown(dev);
}
+static int promontory_read_memmapped(struct flashctx *flash, uint8_t *buf,
+ unsigned int start, unsigned int len)
+{
+ struct sb600spi_data * data = (struct sb600spi_data *)flash->mst->spi.data;
+ if (!data->flash) {
+ map_flash(flash);
+ data->flash = flash; /* keep a copy of flashctx for unmap() on tear-down. */
+ }
+ mmio_readn((void *)(flash->virtual_memory + start), buf, len);
+ return 0;
+}
+
static struct spi_master spi_master_sb600 = {
.max_data_read = FIFO_SIZE_OLD,
.max_data_write = FIFO_SIZE_OLD - 3,
@@ -561,6 +586,25 @@ static struct spi_master spi_master_yangtze = {
.write_aai = default_spi_write_aai,
};
+static struct spi_master spi_master_promontory = {
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = FIFO_SIZE_YANGTZE - 3,
+ .command = spi100_spi_send_command,
+ .multicommand = default_spi_send_multicommand,
+ .read = promontory_read_memmapped,
+ .write_256 = default_spi_write_256,
+ .write_aai = default_spi_write_aai,
+};
+
+static int sb600spi_shutdown(void *data)
+{
+ struct flashctx *flash = ((struct sb600spi_data *)data)->flash;
+ if (flash)
+ finalize_flash_access(flash);
+ free(data);
+ return 0;
+}
+
int sb600_probe_spi(struct pci_dev *dev)
{
struct pci_dev *smbus_dev;
@@ -726,11 +770,28 @@ int sb600_probe_spi(struct pci_dev *dev)
if (handle_imc(dev, amd_gen) != 0)
return ERROR_FATAL;
+ struct sb600spi_data *data = calloc(1, sizeof(struct sb600spi_data));
+ if (!data) {
+ msg_perr("Unable to allocate space for extra SPI master data.\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ data->flash = NULL;
+
+ register_shutdown(sb600spi_shutdown, data);
+ spi_master_sb600.data = data;
+ spi_master_yangtze.data = data;
+ spi_master_promontory.data = data;
+
+
/* Starting with Yangtze the SPI controller got a different interface with a much bigger buffer. */
if (amd_gen < CHIPSET_YANGTZE)
register_spi_master(&spi_master_sb600);
- else
+ else if (amd_gen == CHIPSET_YANGTZE)
register_spi_master(&spi_master_yangtze);
+ else
+ register_spi_master(&spi_master_promontory);
+
return 0;
}