Aaron Durbin has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
soc/amd/common/block/spi: remove code duplication
This removes all the duplicated code and logic and leverages the existing ones in libraries themselves. The current side effect is that protection cannot be fully enabled because the read, write, and write enable command are not exposed in struct spi_flash currently. We can add this later.
BUG=b:146928174 Signed-off-by: Aaron Durbin adurbin@chromium.org
Change-Id: I8faf9cc719ee33dd9f03fb74b579b02bbc6a5e2e --- D src/soc/amd/common/block/include/amdblocks/fch_spi.h M src/soc/amd/common/block/spi/Makefile.inc M src/soc/amd/common/block/spi/fch_spi_ctrl.c D src/soc/amd/common/block/spi/fch_spi_flash.c D src/soc/amd/common/block/spi/fch_spi_special.c D src/soc/amd/common/block/spi/fch_spi_table.c 6 files changed, 32 insertions(+), 703 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/57/37957/1
diff --git a/src/soc/amd/common/block/include/amdblocks/fch_spi.h b/src/soc/amd/common/block/include/amdblocks/fch_spi.h deleted file mode 100644 index 8e28828..0000000 --- a/src/soc/amd/common/block/include/amdblocks/fch_spi.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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. - */ - -#ifndef _FCH_SPI_H_ -#define _FCH_SPI_H_ - -#include <stdint.h> -#include <stddef.h> - -#define GRANULARITY_TEST_4k 0x0000f000 /* bits 15-12 */ -#define WORD_TO_DWORD_UPPER(x) ((x << 16) & 0xffff0000) -#define SPI_PAGE_WRITE 0x02 -#define SPI_WRITE_ENABLE 0x06 -/* - * IDCODE_CONT_LEN may be redefined if a device needs to declare a - * larger "shift" value. IDCODE_PART_LEN generally shouldn't be - * changed. This is the max number of bytes probe functions may - * examine when looking up part-specific identification info. - */ -#define IDCODE_CONT_CODE 0x7f -#define IDCODE_CONT_LEN 1 /* currently support only bank 0 */ -#define IDCODE_PART_LEN 5 -#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) - -/* SPI MMIO registers */ -#define SPI_RESTRICTED_CMD1 0x04 -#define SPI_RESTRICTED_CMD2 0x08 -#define SPI_CNTRL1 0x0c -#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 - -/* Special SST write commands */ -#define CMD_SST_BP 0x02 /* Byte Program */ -#define CMD_SST_AAI_WP 0xad /* Auto Address Increment Word Program */ - -#define SST_256 0x004b /* Only SST that programs 256 bytes at once */ - -enum non_standard_spi { - NON_STANDARD_SPI_NONE = 0, - NON_STANDARD_SPI_SST, -}; - -struct spi_flash_table { - const u8 shift; - const u8 idcode; - int (*probe)(const struct spi_slave *spi, u8 *idcode, - struct spi_flash *flash); -}; - -struct spi_data { - const char *name; - u32 size; - u32 sector_size; - u32 page_size; - u8 status_cmd; - u8 erase_cmd; - u8 write_cmd; - u8 write_enable_cmd; - u8 read_cmd; - u8 read_cmd_len; - enum non_standard_spi non_standard; -}; - -void fch_spi_init(void); -void fch_spi_flash_ops_init(struct spi_flash *flash); -int fch_spi_flash_cmd(const void *dout, size_t bytes_out, void *din, size_t bytes_in); -int fch_spi_flash_cmd_write(const u8 *cmd, size_t cmd_len, const void *data, size_t data_len); -int fch_spi_wait_cmd_ready(unsigned long timeout); -int non_standard_sst_byte_write(u32 offset, const void *buf); -int non_standard_sst_write_aai(u32 offset, size_t len, const void *buf, size_t start); -const struct spi_flash_table *get_spi_flash_table(int *table_size); -const struct spi_data *get_ctrl_spi_data(void); - -static inline int fch_spi_enable_write(void) -{ - u8 cmd_enable = SPI_WRITE_ENABLE; - return fch_spi_flash_cmd(&cmd_enable, 1, NULL, 0); -} - -#endif /* _FCH_SPI_H_ */ diff --git a/src/soc/amd/common/block/spi/Makefile.inc b/src/soc/amd/common/block/spi/Makefile.inc index b94eda4..0e706ef 100644 --- a/src/soc/amd/common/block/spi/Makefile.inc +++ b/src/soc/amd/common/block/spi/Makefile.inc @@ -1,30 +1,12 @@ ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_SPI),y)
bootblock-y += fch_spi_ctrl.c -bootblock-y += fch_spi_flash.c -bootblock-y += fch_spi_special.c -bootblock-y += fch_spi_table.c romstage-y += fch_spi_ctrl.c -romstage-y += fch_spi_flash.c -romstage-y += fch_spi_special.c -romstage-y += fch_spi_table.c verstage-y += fch_spi_ctrl.c -verstage-y += fch_spi_flash.c -verstage-y += fch_spi_special.c -verstage-y += fch_spi_table.c postcar-y += fch_spi_ctrl.c -postcar-y += fch_spi_flash.c -postcar-y += fch_spi_special.c -postcar-y += fch_spi_table.c ramstage-y += fch_spi_ctrl.c -ramstage-y += fch_spi_flash.c -ramstage-y += fch_spi_special.c -ramstage-y += fch_spi_table.c ifeq ($(CONFIG_SPI_FLASH_SMM),y) smm-y += fch_spi_ctrl.c -smm-y += fch_spi_flash.c -smm-y += fch_spi_special.c -smm-y += fch_spi_table.c endif
endif diff --git a/src/soc/amd/common/block/spi/fch_spi_ctrl.c b/src/soc/amd/common/block/spi/fch_spi_ctrl.c index a7d9c77..cb0e372 100644 --- a/src/soc/amd/common/block/spi/fch_spi_ctrl.c +++ b/src/soc/amd/common/block/spi/fch_spi_ctrl.c @@ -17,14 +17,30 @@ #include <spi_flash.h> #include <soc/southbridge.h> #include <soc/pci_devs.h> -#include <amdblocks/fch_spi.h> #include <amdblocks/lpc.h> -#include <drivers/spi/spi_flash_internal.h> #include <device/pci_ops.h> -#include <timer.h> #include <lib.h>
-static struct spi_data ctrl_spi_data; +#define GRANULARITY_TEST_4k 0x0000f000 /* bits 15-12 */ +#define WORD_TO_DWORD_UPPER(x) ((x << 16) & 0xffff0000) + +/* SPI MMIO registers */ +#define SPI_RESTRICTED_CMD1 0x04 +#define SPI_RESTRICTED_CMD2 0x08 +#define SPI_CNTRL1 0x0c +#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 + static uint32_t spibar;
static inline uint8_t spi_read8(uint8_t reg) @@ -110,11 +126,6 @@ printk(BIOS_DEBUG, "%s: Spibar at 0x%08x\n", __func__, spibar); }
-const struct spi_data *get_ctrl_spi_data(void) -{ - return &ctrl_spi_data; -} - static int spi_ctrlr_xfer(const void *dout, size_t bytesout, void *din, size_t bytesin) { size_t count; @@ -161,161 +172,10 @@ return 0; }
-static int amd_xfer_vectors(struct spi_op vectors[], size_t count) +static int xfer_vectors(const struct spi_slave *slave, + struct spi_op vectors[], size_t count) { - int ret; - void *din; - size_t bytes_in; - - if (count < 1 || count > 2) - return -1; - - /* SPI flash commands always have a command first... */ - if (!vectors[0].dout || !vectors[0].bytesout) - return -1; - /* And not read any data during the command. */ - if (vectors[0].din || vectors[0].bytesin) - return -1; - - if (count == 2) { - /* If response bytes requested ensure the buffer is valid. */ - if (vectors[1].bytesin && !vectors[1].din) - return -1; - /* No sends can accompany a receive. */ - if (vectors[1].dout || vectors[1].bytesout) - return -1; - din = vectors[1].din; - bytes_in = vectors[1].bytesin; - } else { - din = NULL; - bytes_in = 0; - } - - ret = spi_ctrlr_xfer(vectors[0].dout, vectors[0].bytesout, din, bytes_in); - - if (ret) { - vectors[0].status = SPI_OP_FAILURE; - if (count == 2) - vectors[1].status = SPI_OP_FAILURE; - } else { - vectors[0].status = SPI_OP_SUCCESS; - if (count == 2) - vectors[1].status = SPI_OP_SUCCESS; - } - - return ret; -} - -int fch_spi_flash_cmd(const void *dout, size_t bytes_out, void *din, size_t bytes_in) -{ - /* - * SPI flash requires command-response kind of behavior. Thus, two - * separate SPI vectors are required -- first to transmit dout and other - * to receive in din. - */ - struct spi_op vectors[] = { - [0] = { .dout = dout, .bytesout = bytes_out, - .din = NULL, .bytesin = 0, }, - [1] = { .dout = NULL, .bytesout = 0, - .din = din, .bytesin = bytes_in }, - }; - size_t count = ARRAY_SIZE(vectors); - if (!bytes_in) - count = 1; - - return amd_xfer_vectors(vectors, count); -} - -static void set_ctrl_spi_data(struct spi_flash *flash) -{ - u8 cmd = SPI_PAGE_WRITE; - - ctrl_spi_data.name = flash->name; - ctrl_spi_data.size = flash->size; - ctrl_spi_data.sector_size = flash->sector_size; - ctrl_spi_data.status_cmd = flash->status_cmd; - ctrl_spi_data.erase_cmd = flash->erase_cmd; - ctrl_spi_data.write_enable_cmd = SPI_WRITE_ENABLE; - - if (flash->vendor == VENDOR_ID_SST) { - ctrl_spi_data.non_standard = NON_STANDARD_SPI_SST; - if ((flash->model & 0x00ff) == SST_256) - ctrl_spi_data.page_size = 256; - else { - ctrl_spi_data.page_size = 2; - cmd = CMD_SST_AAI_WP; - } - } else { - ctrl_spi_data.page_size = flash->page_size; - ctrl_spi_data.non_standard = NON_STANDARD_SPI_NONE; - } - ctrl_spi_data.write_cmd = cmd; - - if (CONFIG(SPI_FLASH_NO_FAST_READ)) { - ctrl_spi_data.read_cmd_len = 4; - ctrl_spi_data.read_cmd = CMD_READ_ARRAY_SLOW; - } else { - ctrl_spi_data.read_cmd_len = 5; - ctrl_spi_data.read_cmd = CMD_READ_ARRAY_FAST; - } -} - -static int fch_spi_flash_probe(const struct spi_slave *spi, struct spi_flash *flash) -{ - int ret, i, shift, table_size; - u8 idcode[IDCODE_LEN], *idp, cmd = CMD_READ_ID; - const struct spi_flash_table *flash_ptr = get_spi_flash_table(&table_size); - - /* Read the ID codes */ - ret = fch_spi_flash_cmd(&cmd, 1, idcode, sizeof(idcode)); - if (ret) - return -1; - - if (CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG)) { - printk(BIOS_SPEW, "SF: Got idcode: "); - for (i = 0; i < sizeof(idcode); i++) - printk(BIOS_SPEW, "%02x ", idcode[i]); - printk(BIOS_SPEW, "\n"); - } - - /* - * All solid state devices have vendor id defined by JEDEC specification JEP106, - * which originally allocated only 7 bits for it plus parity. When number of - * vendors exploded beyond 126, a banking proposition came maintaining - * compatibility with older vendors while allowing for 4 extra bits (16 banks) - * through the introduction of the concept "Continuation Code", denoted by the - * byte value of 0x7f. - * Examples: - * 0xfe, 0x60, 0x18, 0x00, 0x00, 0x00 => vendor 0xfe of bank o - * 0x7f, 0x7f, 0xfe, 0x60, 0x18, 0x00 => vendor 0xfe of bank 2 - * count the number of continuation code bytes - */ - for (shift = 0, idp = idcode; *idp == IDCODE_CONT_CODE; ++shift, ++idp) { - if (shift < IDCODE_CONT_LEN) - continue; - printk(BIOS_ERR, "unsupported ID code bank\n"); - return -1; - } - - printk(BIOS_INFO, "Manufacturer: %02x on bank %d\n", *idp, shift); - - /* search the table for matches in shift and id */ - for (i = 0; i < table_size; ++i) { - if (flash_ptr->shift == shift && flash_ptr->idcode == *idp) { - /* we have a match, call probe */ - if (flash_ptr->probe(spi, idp, flash) == 0) { - flash->vendor = idp[0]; - flash->model = (idp[1] << 8) | idp[2]; - set_ctrl_spi_data(flash); - fch_spi_flash_ops_init(flash); - return 0; - } - } - flash_ptr++; - } - - /* No match, return error. */ - return -1; + return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); }
static int protect_a_range(u32 value) @@ -408,12 +268,14 @@ /* define commands to be blocked if in range */ reg32 = 0; if (type & WRITE_PROTECT) { - reg32 |= (ctrl_spi_data.write_enable_cmd << 24); - reg32 |= (ctrl_spi_data.write_cmd << 16); - reg32 |= (ctrl_spi_data.erase_cmd << 8); + /* FIXME */ + printk(BIOS_INFO, "%s: Write Enable and Write Cmd not blocked\n", __func__); + reg32 |= (flash->erase_cmd << 8); } - if (type & READ_PROTECT) - reg32 |= ctrl_spi_data.read_cmd; + if (type & READ_PROTECT) { + /* FIXME */ + printk(BIOS_INFO, "%s: READ_PROTECT not supported.\n", __func__); + }
/* Final steps to protect region */ pci_write_config32(SOC_LPC_DEV, SPI_RESTRICTED_CMD1, reg32); @@ -425,8 +287,9 @@ }
const struct spi_ctrlr fch_spi_flash_ctrlr = { + .xfer_vector = xfer_vectors, .max_xfer_size = SPI_FIFO_DEPTH, - .flash_probe = fch_spi_flash_probe, + .flags = SPI_CNTRLR_DEDUCT_OPCODE_LEN, .flash_protect = fch_spi_flash_protect, };
diff --git a/src/soc/amd/common/block/spi/fch_spi_flash.c b/src/soc/amd/common/block/spi/fch_spi_flash.c deleted file mode 100644 index b05c1a4..0000000 --- a/src/soc/amd/common/block/spi/fch_spi_flash.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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 <commonlib/helpers.h> -#include <console/console.h> -#include <spi_flash.h> -#include <soc/southbridge.h> -#include <amdblocks/fch_spi.h> -#include <drivers/spi/spi_flash_internal.h> -#include <timer.h> -#include <string.h> - -static void spi_flash_addr(u32 addr, u8 *cmd) -{ - /* cmd[0] is actual command */ - cmd[1] = addr >> 16; - cmd[2] = addr >> 8; - cmd[3] = addr >> 0; -} - -static int crop_chunk(unsigned int cmd_len, unsigned int buf_len) -{ - return MIN((SPI_FIFO_DEPTH - (cmd_len - 1)), buf_len); -} - -int fch_spi_flash_cmd_write(const u8 *cmd, size_t cmd_len, const void *data, size_t data_len) -{ - int ret; - u8 buff[SPI_FIFO_DEPTH + 1]; - - /* Ensure FIFO is large enough. First byte of command does not go in the FIFO. */ - if ((cmd_len - 1 + data_len) > SPI_FIFO_DEPTH) - return -1; - memcpy(buff, cmd, cmd_len); - memcpy(buff + cmd_len, data, data_len); - - ret = fch_spi_flash_cmd(buff, cmd_len + data_len, NULL, 0); - if (ret) { - printk(BIOS_WARNING, "FCH_SF: Failed to send write command (%zu bytes): %d\n", - data_len, ret); - } - - return ret; -} - -static int fch_spi_flash_status(const struct spi_flash *flash, uint8_t *reg) -{ - int ret; - u8 status, cmd = CMD_READ_STATUS; - - ret = fch_spi_flash_cmd(&cmd, 1, &status, 1); - if (!ret) - *reg = status; - return ret; -} - -int fch_spi_wait_cmd_ready(unsigned long timeout) -{ - struct mono_time current, end; - int ret; - u8 status; - - timer_monotonic_get(¤t); - end = current; - mono_time_add_msecs(&end, timeout); - - do { - ret = fch_spi_flash_status(NULL, &status); - if (ret) - return -1; - if ((status & STATUS_WIP) == 0) - return 0; - timer_monotonic_get(¤t); - } while (!mono_time_after(¤t, &end)); - - printk(BIOS_DEBUG, "FCH_SF: timeout at %ld msec\n", timeout); - return -1; -} - -static int fch_spi_flash_erase(const struct spi_flash *flash, uint32_t offset, size_t len) -{ - u32 start, end, erase_size; - const struct spi_data *spi_data_ptr = get_ctrl_spi_data(); - int ret = -1; - u8 cmd[4]; - - erase_size = spi_data_ptr->sector_size; - if (offset % erase_size || len % erase_size) { - printk(BIOS_WARNING, "%s: Erase offset/length not multiple of erase size\n", - spi_data_ptr->name); - return -1; - } - if (len == 0) { - printk(BIOS_WARNING, "%s: Erase length cannot be 0\n", spi_data_ptr->name); - return -1; - } - - cmd[0] = spi_data_ptr->erase_cmd; - start = offset; - end = start + len; - - while (offset < end) { - spi_flash_addr(offset, cmd); - offset += erase_size; - -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "FCH_SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); -#endif - ret = fch_spi_enable_write(); - if (ret) - goto out; - - ret = fch_spi_flash_cmd_write(cmd, sizeof(cmd), NULL, 0); - if (ret) - goto out; - - ret = fch_spi_wait_cmd_ready(SPI_FLASH_PAGE_ERASE_TIMEOUT_MS); - if (ret) - goto out; - } - - printk(BIOS_DEBUG, "%s: Successfully erased %zu bytes @ %#x\n", spi_data_ptr->name, len, - start); - -out: - return ret; -} - -static int fch_spi_flash_read(const struct spi_flash *flash, uint32_t offset, size_t len, - void *buf) -{ - const struct spi_data *spi_data_ptr = get_ctrl_spi_data(); - uint8_t *data = buf; - int ret; - size_t xfer_len; - u8 cmd[5]; - - cmd[0] = spi_data_ptr->read_cmd; - cmd[4] = 0; - while (len) { - xfer_len = crop_chunk(spi_data_ptr->read_cmd_len, len); - spi_flash_addr(offset, cmd); - ret = fch_spi_flash_cmd(cmd, spi_data_ptr->read_cmd_len, data, xfer_len); - if (ret) { - printk(BIOS_WARNING, - "FCH_SF: Failed to send read command %#.2x(%#x, %#zx): %d\n", - cmd[0], offset, xfer_len, ret); - return ret; - } - offset += xfer_len; - data += xfer_len; - len -= xfer_len; - } - return 0; -} - -static int fch_spi_flash_write(const struct spi_flash *flash, uint32_t offset, size_t len, - const void *buf) -{ - unsigned long byte_addr; - unsigned long page_size; - const struct spi_data *spi_data_ptr = get_ctrl_spi_data(); - size_t chunk_len; - size_t actual, start = 0; - int ret = 0; - u8 cmd[4]; - - page_size = spi_data_ptr->page_size; - if (spi_data_ptr->non_standard == NON_STANDARD_SPI_SST) { - if (offset % 2) { - ret = non_standard_sst_byte_write(offset, buf); - len--; - start++; - offset++; - if (ret) - return ret; - } - if (page_size == 2) - return non_standard_sst_write_aai(offset, len, buf, start); - } - - for (actual = start; actual < len; actual += chunk_len) { - byte_addr = offset % page_size; - chunk_len = MIN(len - actual, page_size - byte_addr); - chunk_len = crop_chunk(sizeof(cmd), chunk_len); - - cmd[0] = spi_data_ptr->write_cmd; - cmd[1] = (offset >> 16) & 0xff; - cmd[2] = (offset >> 8) & 0xff; - cmd[3] = offset & 0xff; -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu" - "\n", buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); -#endif - - ret = fch_spi_enable_write(); - if (ret < 0) { - printk(BIOS_WARNING, "%s: Enabling Write failed\n", spi_data_ptr->name); - goto out; - } - - ret = fch_spi_flash_cmd_write(cmd, sizeof(cmd), buf + actual, chunk_len); - if (ret < 0) { - printk(BIOS_WARNING, "%s: Page Program failed\n", spi_data_ptr->name); - goto out; - } - - ret = fch_spi_wait_cmd_ready(SPI_FLASH_PROG_TIMEOUT_MS); - if (ret) - goto out; - - offset += chunk_len; - } - -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "%s: Successfully programmed %zu bytes @ 0x%lx\n", - spi_data_ptr->name, len, (unsigned long)(offset - len)); -#endif - ret = 0; - -out: - return ret; -} - -static const struct spi_flash_ops fch_spi_flash_ops = { - .read = fch_spi_flash_read, - .write = fch_spi_flash_write, - .erase = fch_spi_flash_erase, - .status = fch_spi_flash_status, -}; - -void fch_spi_flash_ops_init(struct spi_flash *flash) -{ - flash->ops = &fch_spi_flash_ops; -} diff --git a/src/soc/amd/common/block/spi/fch_spi_special.c b/src/soc/amd/common/block/spi/fch_spi_special.c deleted file mode 100644 index 27bea05..0000000 --- a/src/soc/amd/common/block/spi/fch_spi_special.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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 <console/console.h> -#include <spi-generic.h> -#include <amdblocks/fch_spi.h> - -int non_standard_sst_byte_write(u32 offset, const void *buf) -{ - int ret; - u8 cmd[4] = { - CMD_SST_BP, - offset >> 16, - offset >> 8, - offset, - }; - - ret = fch_spi_enable_write(); - if (ret) - return ret; - - ret = fch_spi_flash_cmd_write(cmd, sizeof(cmd), buf, 1); - if (ret) - return ret; - - return fch_spi_wait_cmd_ready(SPI_FLASH_PROG_TIMEOUT_MS); -} - -int non_standard_sst_write_aai(u32 offset, size_t len, const void *buf, size_t start) -{ - size_t actual, cmd_len; - int ret = 0; - u8 cmd[4]; - - ret = fch_spi_enable_write(); - if (ret) - goto done; - - cmd_len = 4; - cmd[0] = CMD_SST_AAI_WP; - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - cmd[3] = offset; - - for (actual = start; actual < len - 1; actual += 2) { -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "PP: %p => cmd = { 0x%02x 0x%06lx }" - " chunk_len = 2\n", - buf + actual, cmd[0], (offset + actual)); -#endif - - ret = fch_spi_enable_write(); - if (ret < 0) { - printk(BIOS_WARNING, "SF: Enabling Write failed\n"); - break; - } - - ret = fch_spi_flash_cmd_write(cmd, cmd_len, buf + actual, 2); - if (ret < 0) { - printk(BIOS_WARNING, "SF: SST word Program failed\n"); - break; - } - - ret = fch_spi_wait_cmd_ready(SPI_FLASH_PROG_TIMEOUT_MS); - if (ret) - break; - - offset += 2; - cmd_len = 1; - } - /* If there is a single trailing byte, write it out */ - if (!ret && actual != len) - ret = non_standard_sst_byte_write(offset, buf + actual); -done: - return ret; -} diff --git a/src/soc/amd/common/block/spi/fch_spi_table.c b/src/soc/amd/common/block/spi/fch_spi_table.c deleted file mode 100644 index acea241..0000000 --- a/src/soc/amd/common/block/spi/fch_spi_table.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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 <spi_flash.h> -#include <amdblocks/fch_spi.h> -#include <drivers/spi/spi_flash_internal.h> - -/* - * The following table holds all device probe functions - * - * shift: number of continuation bytes before the ID - * idcode: the expected IDCODE or 0xff for non JEDEC devices - * probe: the function to call - * - * Non JEDEC devices should be ordered in the table such that - * the probe functions with best detection algorithms come first. - * - * Several matching entries are permitted, they will be tried - * in sequence until a probe function returns non NULL. - * - * Probe functions will be given the idcode buffer starting at their - * manu id byte (the "idcode" in the table below). In other words, - * all of the continuation bytes will be skipped (the "shift" below). - */ - -const struct spi_flash_table flashes[] = { - /* Keep it sorted by define name */ -#if CONFIG(SPI_FLASH_ADESTO) - { 0, VENDOR_ID_ADESTO, spi_flash_probe_adesto, }, -#endif -#if CONFIG(SPI_FLASH_AMIC) - { 0, VENDOR_ID_AMIC, spi_flash_probe_amic, }, -#endif -#if CONFIG(SPI_FLASH_ATMEL) - { 0, VENDOR_ID_ATMEL, spi_flash_probe_atmel, }, -#endif -#if CONFIG(SPI_FLASH_EON) - { 0, VENDOR_ID_EON, spi_flash_probe_eon, }, -#endif -#if CONFIG(SPI_FLASH_GIGADEVICE) - { 0, VENDOR_ID_GIGADEVICE, spi_flash_probe_gigadevice, }, -#endif -#if CONFIG(SPI_FLASH_MACRONIX) - { 0, VENDOR_ID_MACRONIX, spi_flash_probe_macronix, }, -#endif -#if CONFIG(SPI_FLASH_SPANSION) - { 0, VENDOR_ID_SPANSION, spi_flash_probe_spansion, }, -#endif -#if CONFIG(SPI_FLASH_SST) - { 0, VENDOR_ID_SST, spi_flash_probe_sst, }, -#endif -#if CONFIG(SPI_FLASH_STMICRO) - { 0, VENDOR_ID_STMICRO, spi_flash_probe_stmicro, }, - { 0, VENDOR_ID_STMICRO_FF, spi_flash_probe_stmicro, }, -#endif -#if CONFIG(SPI_FLASH_WINBOND) - { 0, VENDOR_ID_WINBOND, spi_flash_probe_winbond, }, -#endif - /* Keep it sorted by best detection */ -}; - -const struct spi_flash_table *get_spi_flash_table(int *table_size) -{ - *table_size = (int)ARRAY_SIZE(flashes); - return &flashes[0]; -}
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
Patch Set 1:
I think this gets us back to where we were originally w/ stoney. The protection logic needs some additional help which I think we can add to the spi_flash subsystem.
Hello Kyösti Mälkki, Eric Peers, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/37957
to look at the new patch set (#2).
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
soc/amd/common/block/spi: remove code duplication
This removes all the duplicated code and logic and leverages the existing ones in libraries themselves. The current side effect is that protection cannot be fully enabled because the read, write, and write enable command are not exposed in struct spi_flash currently. We can add this later.
BUG=b:146928174 Signed-off-by: Aaron Durbin adurbin@chromium.org
Change-Id: I8faf9cc719ee33dd9f03fb74b579b02bbc6a5e2e --- D src/soc/amd/common/block/include/amdblocks/fch_spi.h M src/soc/amd/common/block/spi/Makefile.inc M src/soc/amd/common/block/spi/fch_spi_ctrl.c D src/soc/amd/common/block/spi/fch_spi_flash.c D src/soc/amd/common/block/spi/fch_spi_special.c D src/soc/amd/common/block/spi/fch_spi_table.c 6 files changed, 33 insertions(+), 704 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/57/37957/2
Hello Kyösti Mälkki, Eric Peers, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/37957
to look at the new patch set (#3).
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
soc/amd/common/block/spi: remove code duplication
This removes all the duplicated code and logic and leverages the existing ones in libraries themselves. The current side effect is that protection cannot be fully enabled because the read, write, and write enable command are not exposed in struct spi_flash currently. We can add this later.
BUG=b:146928174 Signed-off-by: Aaron Durbin adurbin@chromium.org
Change-Id: I8faf9cc719ee33dd9f03fb74b579b02bbc6a5e2e --- D src/soc/amd/common/block/include/amdblocks/fch_spi.h M src/soc/amd/common/block/spi/Makefile.inc M src/soc/amd/common/block/spi/fch_spi_ctrl.c D src/soc/amd/common/block/spi/fch_spi_flash.c D src/soc/amd/common/block/spi/fch_spi_special.c D src/soc/amd/common/block/spi/fch_spi_table.c 6 files changed, 36 insertions(+), 705 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/57/37957/3
Hello Kyösti Mälkki, Eric Peers, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/37957
to look at the new patch set (#4).
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
soc/amd/common/block/spi: remove code duplication
This removes all the duplicated code and logic and leverages the existing ones in libraries themselves. The current side effect is that protection cannot be fully enabled because the read, write, and write enable command are not exposed in struct spi_flash currently. We can add this later.
BUG=b:146928174 Signed-off-by: Aaron Durbin adurbin@chromium.org
Change-Id: I8faf9cc719ee33dd9f03fb74b579b02bbc6a5e2e --- D src/soc/amd/common/block/include/amdblocks/fch_spi.h M src/soc/amd/common/block/spi/Makefile.inc M src/soc/amd/common/block/spi/fch_spi_ctrl.c D src/soc/amd/common/block/spi/fch_spi_flash.c D src/soc/amd/common/block/spi/fch_spi_special.c D src/soc/amd/common/block/spi/fch_spi_table.c 6 files changed, 36 insertions(+), 705 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/57/37957/4
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG@17 PS4, Line 17: Remove the blank line?
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
Patch Set 4:
(1 comment)
LGTM. I can test it on Mandolin or Grunt in a few days, unless you did that already.
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG@13 PS4, Line 13: We can add this later. I don't yet see what's missing here. If I'm reading it correctly, struct spi_ctrlr's *flash_protect is intended to only program region protect registers in the controller/bridge if they exist. However struct spi_flash_ops's *set_write_protection is for the device itself (e.g. how to behave when WP# is asserted). That said, I only see set_write_protection() implemented in winbond, and I'd bet all the various devices' regions probably don't coincide well with the controllers' capabilities.
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
Patch Set 4:
(3 comments)
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG@13 PS4, Line 13: We can add this later.
I don't yet see what's missing here. […]
The spi controller protection needs some help. See my TODOs in the file. I think that support needs another investigation because when reading the BKDG I don't think it's working the way it was originally written.
Eric did test a quickly yesterday. This code could definitely use some more testing, but I'm pretty sure it should work.
https://review.coreboot.org/c/coreboot/+/37957/4//COMMIT_MSG@17 PS4, Line 17:
Remove the blank line?
ok
https://review.coreboot.org/c/coreboot/+/37957/4/src/soc/amd/common/block/sp... File src/soc/amd/common/block/spi/fch_spi_ctrl.c:
https://review.coreboot.org/c/coreboot/+/37957/4/src/soc/amd/common/block/sp... PS4, Line 274: printk(BIOS_INFO, "%s: Write Enable and Write Cmd not blocked\n", __func__); Marshall, see this diff. Because these commands aren't being exposed in the general support one can't program the registers like they were originally. That said, I'm not convinced this code is correct when reading the datasheet. We need to do some more investigation in the behavior of the chipset on this as it talks about blocking certain commands for address ranges. But I don't know for certain if the controller is interrogating the first 3 bytes in the fifo for address matching or not. Likewise the BKDG also talks about CPU reads and writes being converted into SPI transactions. Reading makes sense because of the memory map, but I find the write conversions to be interesting in that one has to erase to make the write be valid. I'm not sure how the chipset works in this area.
Hello Kyösti Mälkki, Eric Peers, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/37957
to look at the new patch set (#5).
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
soc/amd/common/block/spi: remove code duplication
This removes all the duplicated code and logic and leverages the existing ones in libraries themselves. The current side effect is that protection cannot be fully enabled because the read, write, and write enable command are not exposed in struct spi_flash currently. That support can be revised if protection scheme makes sense for our use-cases once it's better understood.
BUG=b:146928174 Signed-off-by: Aaron Durbin adurbin@chromium.org
Change-Id: I8faf9cc719ee33dd9f03fb74b579b02bbc6a5e2e --- D src/soc/amd/common/block/include/amdblocks/fch_spi.h M src/soc/amd/common/block/spi/Makefile.inc M src/soc/amd/common/block/spi/fch_spi_ctrl.c D src/soc/amd/common/block/spi/fch_spi_flash.c D src/soc/amd/common/block/spi/fch_spi_special.c D src/soc/amd/common/block/spi/fch_spi_table.c 6 files changed, 36 insertions(+), 705 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/57/37957/5
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
Patch Set 5:
(3 comments)
https://review.coreboot.org/c/coreboot/+/37957/4/src/soc/amd/common/block/sp... File src/soc/amd/common/block/spi/fch_spi_ctrl.c:
https://review.coreboot.org/c/coreboot/+/37957/4/src/soc/amd/common/block/sp... PS4, Line 248: /* Create reg32 to be written into a range register and program required ranges */ : reg32 = rom_base & ROM_BASE_MASK; : reg32 |= range_base; The BKDG's wording looks deceptive to me, so I'm not convinced this is correct. (I'm using the Stoney Ridge BKDG because I find it easier to read.) It looks to me like the affected address is (very simplified):
RomBase <= addr <= fn(Range)
In other words, I don't believe RomBase in D14F3x[5C,58,54,50] is the same as rom_base above...
https://review.coreboot.org/c/coreboot/+/37957/4/src/soc/amd/common/block/sp... PS4, Line 258: for (range = 0; range < total_ranges; range++) { : ret = protect_a_range(reg32); : if (ret) : return ret; : /* : * Next range (lower 8 bits). Range points to the start address of a region. : * The range value must be multiplied by the granularity (which is also the : * size of the region) to get the actual offset from the SPI start address. : */ : reg32++; : } ...and if I'm right, then it doesn't make sense that we'd burn a register for each multiple of the RangeUnit. Each multiple should instead affect the Range field.
https://review.coreboot.org/c/coreboot/+/37957/4/src/soc/amd/common/block/sp... PS4, Line 274: printk(BIOS_INFO, "%s: Write Enable and Write Cmd not blocked\n", __func__);
Marshall, see this diff. […]
Thanks for pointing this out and making me look at it again - ugh, I'd forgotten about specifying the commands in the controller. FWIW, I'd never quite believed that write cycles were bridged from the host. But I wonder if WREN is never sent when the x86 does a mem write, and that's why nothing happens. OTOH, it seems like I'd looked closely at the SPI signals years ago and didn't see any wiggling on x86 write cycles - it's hard to say now. If we have Eric double-check, he should be aware that write cycles can also be blocked at the northbridge (e.g. D18F1x80 in Stoney Ridge). Picasso surely has a similar configuration somewhere but I'd need to find it.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
Patch Set 5: Code-Review+2
Aaron Durbin has submitted this change. ( https://review.coreboot.org/c/coreboot/+/37957 )
Change subject: soc/amd/common/block/spi: remove code duplication ......................................................................
soc/amd/common/block/spi: remove code duplication
This removes all the duplicated code and logic and leverages the existing ones in libraries themselves. The current side effect is that protection cannot be fully enabled because the read, write, and write enable command are not exposed in struct spi_flash currently. That support can be revised if protection scheme makes sense for our use-cases once it's better understood.
BUG=b:146928174 Signed-off-by: Aaron Durbin adurbin@chromium.org
Change-Id: I8faf9cc719ee33dd9f03fb74b579b02bbc6a5e2e Reviewed-on: https://review.coreboot.org/c/coreboot/+/37957 Reviewed-by: Marshall Dawson marshalldawson3rd@gmail.com Tested-by: build bot (Jenkins) no-reply@coreboot.org --- D src/soc/amd/common/block/include/amdblocks/fch_spi.h M src/soc/amd/common/block/spi/Makefile.inc M src/soc/amd/common/block/spi/fch_spi_ctrl.c D src/soc/amd/common/block/spi/fch_spi_flash.c D src/soc/amd/common/block/spi/fch_spi_special.c D src/soc/amd/common/block/spi/fch_spi_table.c 6 files changed, 36 insertions(+), 705 deletions(-)
Approvals: build bot (Jenkins): Verified Marshall Dawson: Looks good to me, approved
diff --git a/src/soc/amd/common/block/include/amdblocks/fch_spi.h b/src/soc/amd/common/block/include/amdblocks/fch_spi.h deleted file mode 100644 index 8e28828..0000000 --- a/src/soc/amd/common/block/include/amdblocks/fch_spi.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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. - */ - -#ifndef _FCH_SPI_H_ -#define _FCH_SPI_H_ - -#include <stdint.h> -#include <stddef.h> - -#define GRANULARITY_TEST_4k 0x0000f000 /* bits 15-12 */ -#define WORD_TO_DWORD_UPPER(x) ((x << 16) & 0xffff0000) -#define SPI_PAGE_WRITE 0x02 -#define SPI_WRITE_ENABLE 0x06 -/* - * IDCODE_CONT_LEN may be redefined if a device needs to declare a - * larger "shift" value. IDCODE_PART_LEN generally shouldn't be - * changed. This is the max number of bytes probe functions may - * examine when looking up part-specific identification info. - */ -#define IDCODE_CONT_CODE 0x7f -#define IDCODE_CONT_LEN 1 /* currently support only bank 0 */ -#define IDCODE_PART_LEN 5 -#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) - -/* SPI MMIO registers */ -#define SPI_RESTRICTED_CMD1 0x04 -#define SPI_RESTRICTED_CMD2 0x08 -#define SPI_CNTRL1 0x0c -#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 - -/* Special SST write commands */ -#define CMD_SST_BP 0x02 /* Byte Program */ -#define CMD_SST_AAI_WP 0xad /* Auto Address Increment Word Program */ - -#define SST_256 0x004b /* Only SST that programs 256 bytes at once */ - -enum non_standard_spi { - NON_STANDARD_SPI_NONE = 0, - NON_STANDARD_SPI_SST, -}; - -struct spi_flash_table { - const u8 shift; - const u8 idcode; - int (*probe)(const struct spi_slave *spi, u8 *idcode, - struct spi_flash *flash); -}; - -struct spi_data { - const char *name; - u32 size; - u32 sector_size; - u32 page_size; - u8 status_cmd; - u8 erase_cmd; - u8 write_cmd; - u8 write_enable_cmd; - u8 read_cmd; - u8 read_cmd_len; - enum non_standard_spi non_standard; -}; - -void fch_spi_init(void); -void fch_spi_flash_ops_init(struct spi_flash *flash); -int fch_spi_flash_cmd(const void *dout, size_t bytes_out, void *din, size_t bytes_in); -int fch_spi_flash_cmd_write(const u8 *cmd, size_t cmd_len, const void *data, size_t data_len); -int fch_spi_wait_cmd_ready(unsigned long timeout); -int non_standard_sst_byte_write(u32 offset, const void *buf); -int non_standard_sst_write_aai(u32 offset, size_t len, const void *buf, size_t start); -const struct spi_flash_table *get_spi_flash_table(int *table_size); -const struct spi_data *get_ctrl_spi_data(void); - -static inline int fch_spi_enable_write(void) -{ - u8 cmd_enable = SPI_WRITE_ENABLE; - return fch_spi_flash_cmd(&cmd_enable, 1, NULL, 0); -} - -#endif /* _FCH_SPI_H_ */ diff --git a/src/soc/amd/common/block/spi/Makefile.inc b/src/soc/amd/common/block/spi/Makefile.inc index b94eda4..0e706ef 100644 --- a/src/soc/amd/common/block/spi/Makefile.inc +++ b/src/soc/amd/common/block/spi/Makefile.inc @@ -1,30 +1,12 @@ ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_SPI),y)
bootblock-y += fch_spi_ctrl.c -bootblock-y += fch_spi_flash.c -bootblock-y += fch_spi_special.c -bootblock-y += fch_spi_table.c romstage-y += fch_spi_ctrl.c -romstage-y += fch_spi_flash.c -romstage-y += fch_spi_special.c -romstage-y += fch_spi_table.c verstage-y += fch_spi_ctrl.c -verstage-y += fch_spi_flash.c -verstage-y += fch_spi_special.c -verstage-y += fch_spi_table.c postcar-y += fch_spi_ctrl.c -postcar-y += fch_spi_flash.c -postcar-y += fch_spi_special.c -postcar-y += fch_spi_table.c ramstage-y += fch_spi_ctrl.c -ramstage-y += fch_spi_flash.c -ramstage-y += fch_spi_special.c -ramstage-y += fch_spi_table.c ifeq ($(CONFIG_SPI_FLASH_SMM),y) smm-y += fch_spi_ctrl.c -smm-y += fch_spi_flash.c -smm-y += fch_spi_special.c -smm-y += fch_spi_table.c endif
endif diff --git a/src/soc/amd/common/block/spi/fch_spi_ctrl.c b/src/soc/amd/common/block/spi/fch_spi_ctrl.c index a7d9c77..0a629a3 100644 --- a/src/soc/amd/common/block/spi/fch_spi_ctrl.c +++ b/src/soc/amd/common/block/spi/fch_spi_ctrl.c @@ -17,14 +17,31 @@ #include <spi_flash.h> #include <soc/southbridge.h> #include <soc/pci_devs.h> -#include <amdblocks/fch_spi.h> #include <amdblocks/lpc.h> -#include <drivers/spi/spi_flash_internal.h> #include <device/pci_ops.h> -#include <timer.h> #include <lib.h> +#include <timer.h>
-static struct spi_data ctrl_spi_data; +#define GRANULARITY_TEST_4k 0x0000f000 /* bits 15-12 */ +#define WORD_TO_DWORD_UPPER(x) ((x << 16) & 0xffff0000) + +/* SPI MMIO registers */ +#define SPI_RESTRICTED_CMD1 0x04 +#define SPI_RESTRICTED_CMD2 0x08 +#define SPI_CNTRL1 0x0c +#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 + static uint32_t spibar;
static inline uint8_t spi_read8(uint8_t reg) @@ -110,12 +127,8 @@ printk(BIOS_DEBUG, "%s: Spibar at 0x%08x\n", __func__, spibar); }
-const struct spi_data *get_ctrl_spi_data(void) -{ - return &ctrl_spi_data; -} - -static int spi_ctrlr_xfer(const void *dout, size_t bytesout, void *din, size_t bytesin) +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; @@ -161,161 +174,10 @@ return 0; }
-static int amd_xfer_vectors(struct spi_op vectors[], size_t count) +static int xfer_vectors(const struct spi_slave *slave, + struct spi_op vectors[], size_t count) { - int ret; - void *din; - size_t bytes_in; - - if (count < 1 || count > 2) - return -1; - - /* SPI flash commands always have a command first... */ - if (!vectors[0].dout || !vectors[0].bytesout) - return -1; - /* And not read any data during the command. */ - if (vectors[0].din || vectors[0].bytesin) - return -1; - - if (count == 2) { - /* If response bytes requested ensure the buffer is valid. */ - if (vectors[1].bytesin && !vectors[1].din) - return -1; - /* No sends can accompany a receive. */ - if (vectors[1].dout || vectors[1].bytesout) - return -1; - din = vectors[1].din; - bytes_in = vectors[1].bytesin; - } else { - din = NULL; - bytes_in = 0; - } - - ret = spi_ctrlr_xfer(vectors[0].dout, vectors[0].bytesout, din, bytes_in); - - if (ret) { - vectors[0].status = SPI_OP_FAILURE; - if (count == 2) - vectors[1].status = SPI_OP_FAILURE; - } else { - vectors[0].status = SPI_OP_SUCCESS; - if (count == 2) - vectors[1].status = SPI_OP_SUCCESS; - } - - return ret; -} - -int fch_spi_flash_cmd(const void *dout, size_t bytes_out, void *din, size_t bytes_in) -{ - /* - * SPI flash requires command-response kind of behavior. Thus, two - * separate SPI vectors are required -- first to transmit dout and other - * to receive in din. - */ - struct spi_op vectors[] = { - [0] = { .dout = dout, .bytesout = bytes_out, - .din = NULL, .bytesin = 0, }, - [1] = { .dout = NULL, .bytesout = 0, - .din = din, .bytesin = bytes_in }, - }; - size_t count = ARRAY_SIZE(vectors); - if (!bytes_in) - count = 1; - - return amd_xfer_vectors(vectors, count); -} - -static void set_ctrl_spi_data(struct spi_flash *flash) -{ - u8 cmd = SPI_PAGE_WRITE; - - ctrl_spi_data.name = flash->name; - ctrl_spi_data.size = flash->size; - ctrl_spi_data.sector_size = flash->sector_size; - ctrl_spi_data.status_cmd = flash->status_cmd; - ctrl_spi_data.erase_cmd = flash->erase_cmd; - ctrl_spi_data.write_enable_cmd = SPI_WRITE_ENABLE; - - if (flash->vendor == VENDOR_ID_SST) { - ctrl_spi_data.non_standard = NON_STANDARD_SPI_SST; - if ((flash->model & 0x00ff) == SST_256) - ctrl_spi_data.page_size = 256; - else { - ctrl_spi_data.page_size = 2; - cmd = CMD_SST_AAI_WP; - } - } else { - ctrl_spi_data.page_size = flash->page_size; - ctrl_spi_data.non_standard = NON_STANDARD_SPI_NONE; - } - ctrl_spi_data.write_cmd = cmd; - - if (CONFIG(SPI_FLASH_NO_FAST_READ)) { - ctrl_spi_data.read_cmd_len = 4; - ctrl_spi_data.read_cmd = CMD_READ_ARRAY_SLOW; - } else { - ctrl_spi_data.read_cmd_len = 5; - ctrl_spi_data.read_cmd = CMD_READ_ARRAY_FAST; - } -} - -static int fch_spi_flash_probe(const struct spi_slave *spi, struct spi_flash *flash) -{ - int ret, i, shift, table_size; - u8 idcode[IDCODE_LEN], *idp, cmd = CMD_READ_ID; - const struct spi_flash_table *flash_ptr = get_spi_flash_table(&table_size); - - /* Read the ID codes */ - ret = fch_spi_flash_cmd(&cmd, 1, idcode, sizeof(idcode)); - if (ret) - return -1; - - if (CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG)) { - printk(BIOS_SPEW, "SF: Got idcode: "); - for (i = 0; i < sizeof(idcode); i++) - printk(BIOS_SPEW, "%02x ", idcode[i]); - printk(BIOS_SPEW, "\n"); - } - - /* - * All solid state devices have vendor id defined by JEDEC specification JEP106, - * which originally allocated only 7 bits for it plus parity. When number of - * vendors exploded beyond 126, a banking proposition came maintaining - * compatibility with older vendors while allowing for 4 extra bits (16 banks) - * through the introduction of the concept "Continuation Code", denoted by the - * byte value of 0x7f. - * Examples: - * 0xfe, 0x60, 0x18, 0x00, 0x00, 0x00 => vendor 0xfe of bank o - * 0x7f, 0x7f, 0xfe, 0x60, 0x18, 0x00 => vendor 0xfe of bank 2 - * count the number of continuation code bytes - */ - for (shift = 0, idp = idcode; *idp == IDCODE_CONT_CODE; ++shift, ++idp) { - if (shift < IDCODE_CONT_LEN) - continue; - printk(BIOS_ERR, "unsupported ID code bank\n"); - return -1; - } - - printk(BIOS_INFO, "Manufacturer: %02x on bank %d\n", *idp, shift); - - /* search the table for matches in shift and id */ - for (i = 0; i < table_size; ++i) { - if (flash_ptr->shift == shift && flash_ptr->idcode == *idp) { - /* we have a match, call probe */ - if (flash_ptr->probe(spi, idp, flash) == 0) { - flash->vendor = idp[0]; - flash->model = (idp[1] << 8) | idp[2]; - set_ctrl_spi_data(flash); - fch_spi_flash_ops_init(flash); - return 0; - } - } - flash_ptr++; - } - - /* No match, return error. */ - return -1; + return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); }
static int protect_a_range(u32 value) @@ -408,12 +270,14 @@ /* define commands to be blocked if in range */ reg32 = 0; if (type & WRITE_PROTECT) { - reg32 |= (ctrl_spi_data.write_enable_cmd << 24); - reg32 |= (ctrl_spi_data.write_cmd << 16); - reg32 |= (ctrl_spi_data.erase_cmd << 8); + /* FIXME */ + printk(BIOS_INFO, "%s: Write Enable and Write Cmd not blocked\n", __func__); + reg32 |= (flash->erase_cmd << 8); } - if (type & READ_PROTECT) - reg32 |= ctrl_spi_data.read_cmd; + if (type & READ_PROTECT) { + /* FIXME */ + printk(BIOS_INFO, "%s: READ_PROTECT not supported.\n", __func__); + }
/* Final steps to protect region */ pci_write_config32(SOC_LPC_DEV, SPI_RESTRICTED_CMD1, reg32); @@ -424,9 +288,10 @@ return 0; }
-const struct spi_ctrlr fch_spi_flash_ctrlr = { +static const struct spi_ctrlr fch_spi_flash_ctrlr = { + .xfer_vector = xfer_vectors, .max_xfer_size = SPI_FIFO_DEPTH, - .flash_probe = fch_spi_flash_probe, + .flags = SPI_CNTRLR_DEDUCT_CMD_LEN | SPI_CNTRLR_DEDUCT_OPCODE_LEN, .flash_protect = fch_spi_flash_protect, };
diff --git a/src/soc/amd/common/block/spi/fch_spi_flash.c b/src/soc/amd/common/block/spi/fch_spi_flash.c deleted file mode 100644 index b05c1a4..0000000 --- a/src/soc/amd/common/block/spi/fch_spi_flash.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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 <commonlib/helpers.h> -#include <console/console.h> -#include <spi_flash.h> -#include <soc/southbridge.h> -#include <amdblocks/fch_spi.h> -#include <drivers/spi/spi_flash_internal.h> -#include <timer.h> -#include <string.h> - -static void spi_flash_addr(u32 addr, u8 *cmd) -{ - /* cmd[0] is actual command */ - cmd[1] = addr >> 16; - cmd[2] = addr >> 8; - cmd[3] = addr >> 0; -} - -static int crop_chunk(unsigned int cmd_len, unsigned int buf_len) -{ - return MIN((SPI_FIFO_DEPTH - (cmd_len - 1)), buf_len); -} - -int fch_spi_flash_cmd_write(const u8 *cmd, size_t cmd_len, const void *data, size_t data_len) -{ - int ret; - u8 buff[SPI_FIFO_DEPTH + 1]; - - /* Ensure FIFO is large enough. First byte of command does not go in the FIFO. */ - if ((cmd_len - 1 + data_len) > SPI_FIFO_DEPTH) - return -1; - memcpy(buff, cmd, cmd_len); - memcpy(buff + cmd_len, data, data_len); - - ret = fch_spi_flash_cmd(buff, cmd_len + data_len, NULL, 0); - if (ret) { - printk(BIOS_WARNING, "FCH_SF: Failed to send write command (%zu bytes): %d\n", - data_len, ret); - } - - return ret; -} - -static int fch_spi_flash_status(const struct spi_flash *flash, uint8_t *reg) -{ - int ret; - u8 status, cmd = CMD_READ_STATUS; - - ret = fch_spi_flash_cmd(&cmd, 1, &status, 1); - if (!ret) - *reg = status; - return ret; -} - -int fch_spi_wait_cmd_ready(unsigned long timeout) -{ - struct mono_time current, end; - int ret; - u8 status; - - timer_monotonic_get(¤t); - end = current; - mono_time_add_msecs(&end, timeout); - - do { - ret = fch_spi_flash_status(NULL, &status); - if (ret) - return -1; - if ((status & STATUS_WIP) == 0) - return 0; - timer_monotonic_get(¤t); - } while (!mono_time_after(¤t, &end)); - - printk(BIOS_DEBUG, "FCH_SF: timeout at %ld msec\n", timeout); - return -1; -} - -static int fch_spi_flash_erase(const struct spi_flash *flash, uint32_t offset, size_t len) -{ - u32 start, end, erase_size; - const struct spi_data *spi_data_ptr = get_ctrl_spi_data(); - int ret = -1; - u8 cmd[4]; - - erase_size = spi_data_ptr->sector_size; - if (offset % erase_size || len % erase_size) { - printk(BIOS_WARNING, "%s: Erase offset/length not multiple of erase size\n", - spi_data_ptr->name); - return -1; - } - if (len == 0) { - printk(BIOS_WARNING, "%s: Erase length cannot be 0\n", spi_data_ptr->name); - return -1; - } - - cmd[0] = spi_data_ptr->erase_cmd; - start = offset; - end = start + len; - - while (offset < end) { - spi_flash_addr(offset, cmd); - offset += erase_size; - -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "FCH_SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); -#endif - ret = fch_spi_enable_write(); - if (ret) - goto out; - - ret = fch_spi_flash_cmd_write(cmd, sizeof(cmd), NULL, 0); - if (ret) - goto out; - - ret = fch_spi_wait_cmd_ready(SPI_FLASH_PAGE_ERASE_TIMEOUT_MS); - if (ret) - goto out; - } - - printk(BIOS_DEBUG, "%s: Successfully erased %zu bytes @ %#x\n", spi_data_ptr->name, len, - start); - -out: - return ret; -} - -static int fch_spi_flash_read(const struct spi_flash *flash, uint32_t offset, size_t len, - void *buf) -{ - const struct spi_data *spi_data_ptr = get_ctrl_spi_data(); - uint8_t *data = buf; - int ret; - size_t xfer_len; - u8 cmd[5]; - - cmd[0] = spi_data_ptr->read_cmd; - cmd[4] = 0; - while (len) { - xfer_len = crop_chunk(spi_data_ptr->read_cmd_len, len); - spi_flash_addr(offset, cmd); - ret = fch_spi_flash_cmd(cmd, spi_data_ptr->read_cmd_len, data, xfer_len); - if (ret) { - printk(BIOS_WARNING, - "FCH_SF: Failed to send read command %#.2x(%#x, %#zx): %d\n", - cmd[0], offset, xfer_len, ret); - return ret; - } - offset += xfer_len; - data += xfer_len; - len -= xfer_len; - } - return 0; -} - -static int fch_spi_flash_write(const struct spi_flash *flash, uint32_t offset, size_t len, - const void *buf) -{ - unsigned long byte_addr; - unsigned long page_size; - const struct spi_data *spi_data_ptr = get_ctrl_spi_data(); - size_t chunk_len; - size_t actual, start = 0; - int ret = 0; - u8 cmd[4]; - - page_size = spi_data_ptr->page_size; - if (spi_data_ptr->non_standard == NON_STANDARD_SPI_SST) { - if (offset % 2) { - ret = non_standard_sst_byte_write(offset, buf); - len--; - start++; - offset++; - if (ret) - return ret; - } - if (page_size == 2) - return non_standard_sst_write_aai(offset, len, buf, start); - } - - for (actual = start; actual < len; actual += chunk_len) { - byte_addr = offset % page_size; - chunk_len = MIN(len - actual, page_size - byte_addr); - chunk_len = crop_chunk(sizeof(cmd), chunk_len); - - cmd[0] = spi_data_ptr->write_cmd; - cmd[1] = (offset >> 16) & 0xff; - cmd[2] = (offset >> 8) & 0xff; - cmd[3] = offset & 0xff; -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu" - "\n", buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); -#endif - - ret = fch_spi_enable_write(); - if (ret < 0) { - printk(BIOS_WARNING, "%s: Enabling Write failed\n", spi_data_ptr->name); - goto out; - } - - ret = fch_spi_flash_cmd_write(cmd, sizeof(cmd), buf + actual, chunk_len); - if (ret < 0) { - printk(BIOS_WARNING, "%s: Page Program failed\n", spi_data_ptr->name); - goto out; - } - - ret = fch_spi_wait_cmd_ready(SPI_FLASH_PROG_TIMEOUT_MS); - if (ret) - goto out; - - offset += chunk_len; - } - -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "%s: Successfully programmed %zu bytes @ 0x%lx\n", - spi_data_ptr->name, len, (unsigned long)(offset - len)); -#endif - ret = 0; - -out: - return ret; -} - -static const struct spi_flash_ops fch_spi_flash_ops = { - .read = fch_spi_flash_read, - .write = fch_spi_flash_write, - .erase = fch_spi_flash_erase, - .status = fch_spi_flash_status, -}; - -void fch_spi_flash_ops_init(struct spi_flash *flash) -{ - flash->ops = &fch_spi_flash_ops; -} diff --git a/src/soc/amd/common/block/spi/fch_spi_special.c b/src/soc/amd/common/block/spi/fch_spi_special.c deleted file mode 100644 index 27bea05..0000000 --- a/src/soc/amd/common/block/spi/fch_spi_special.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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 <console/console.h> -#include <spi-generic.h> -#include <amdblocks/fch_spi.h> - -int non_standard_sst_byte_write(u32 offset, const void *buf) -{ - int ret; - u8 cmd[4] = { - CMD_SST_BP, - offset >> 16, - offset >> 8, - offset, - }; - - ret = fch_spi_enable_write(); - if (ret) - return ret; - - ret = fch_spi_flash_cmd_write(cmd, sizeof(cmd), buf, 1); - if (ret) - return ret; - - return fch_spi_wait_cmd_ready(SPI_FLASH_PROG_TIMEOUT_MS); -} - -int non_standard_sst_write_aai(u32 offset, size_t len, const void *buf, size_t start) -{ - size_t actual, cmd_len; - int ret = 0; - u8 cmd[4]; - - ret = fch_spi_enable_write(); - if (ret) - goto done; - - cmd_len = 4; - cmd[0] = CMD_SST_AAI_WP; - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - cmd[3] = offset; - - for (actual = start; actual < len - 1; actual += 2) { -#if CONFIG(SOC_AMD_COMMON_BLOCK_SPI_DEBUG) - printk(BIOS_DEBUG, "PP: %p => cmd = { 0x%02x 0x%06lx }" - " chunk_len = 2\n", - buf + actual, cmd[0], (offset + actual)); -#endif - - ret = fch_spi_enable_write(); - if (ret < 0) { - printk(BIOS_WARNING, "SF: Enabling Write failed\n"); - break; - } - - ret = fch_spi_flash_cmd_write(cmd, cmd_len, buf + actual, 2); - if (ret < 0) { - printk(BIOS_WARNING, "SF: SST word Program failed\n"); - break; - } - - ret = fch_spi_wait_cmd_ready(SPI_FLASH_PROG_TIMEOUT_MS); - if (ret) - break; - - offset += 2; - cmd_len = 1; - } - /* If there is a single trailing byte, write it out */ - if (!ret && actual != len) - ret = non_standard_sst_byte_write(offset, buf + actual); -done: - return ret; -} diff --git a/src/soc/amd/common/block/spi/fch_spi_table.c b/src/soc/amd/common/block/spi/fch_spi_table.c deleted file mode 100644 index acea241..0000000 --- a/src/soc/amd/common/block/spi/fch_spi_table.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2019 Silverback Ltd. - * - * 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 <spi_flash.h> -#include <amdblocks/fch_spi.h> -#include <drivers/spi/spi_flash_internal.h> - -/* - * The following table holds all device probe functions - * - * shift: number of continuation bytes before the ID - * idcode: the expected IDCODE or 0xff for non JEDEC devices - * probe: the function to call - * - * Non JEDEC devices should be ordered in the table such that - * the probe functions with best detection algorithms come first. - * - * Several matching entries are permitted, they will be tried - * in sequence until a probe function returns non NULL. - * - * Probe functions will be given the idcode buffer starting at their - * manu id byte (the "idcode" in the table below). In other words, - * all of the continuation bytes will be skipped (the "shift" below). - */ - -const struct spi_flash_table flashes[] = { - /* Keep it sorted by define name */ -#if CONFIG(SPI_FLASH_ADESTO) - { 0, VENDOR_ID_ADESTO, spi_flash_probe_adesto, }, -#endif -#if CONFIG(SPI_FLASH_AMIC) - { 0, VENDOR_ID_AMIC, spi_flash_probe_amic, }, -#endif -#if CONFIG(SPI_FLASH_ATMEL) - { 0, VENDOR_ID_ATMEL, spi_flash_probe_atmel, }, -#endif -#if CONFIG(SPI_FLASH_EON) - { 0, VENDOR_ID_EON, spi_flash_probe_eon, }, -#endif -#if CONFIG(SPI_FLASH_GIGADEVICE) - { 0, VENDOR_ID_GIGADEVICE, spi_flash_probe_gigadevice, }, -#endif -#if CONFIG(SPI_FLASH_MACRONIX) - { 0, VENDOR_ID_MACRONIX, spi_flash_probe_macronix, }, -#endif -#if CONFIG(SPI_FLASH_SPANSION) - { 0, VENDOR_ID_SPANSION, spi_flash_probe_spansion, }, -#endif -#if CONFIG(SPI_FLASH_SST) - { 0, VENDOR_ID_SST, spi_flash_probe_sst, }, -#endif -#if CONFIG(SPI_FLASH_STMICRO) - { 0, VENDOR_ID_STMICRO, spi_flash_probe_stmicro, }, - { 0, VENDOR_ID_STMICRO_FF, spi_flash_probe_stmicro, }, -#endif -#if CONFIG(SPI_FLASH_WINBOND) - { 0, VENDOR_ID_WINBOND, spi_flash_probe_winbond, }, -#endif - /* Keep it sorted by best detection */ -}; - -const struct spi_flash_table *get_spi_flash_table(int *table_size) -{ - *table_size = (int)ARRAY_SIZE(flashes); - return &flashes[0]; -}