Xiang Wang has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/33055
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces 3. to support HiFive Unleashed's ISSI Flash (IS25WP256D)
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/drivers/spi/Kconfig M src/drivers/spi/Makefile.inc A src/drivers/spi/issi.c M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 10 files changed, 946 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/1
diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig index b15a502..da46071 100644 --- a/src/drivers/spi/Kconfig +++ b/src/drivers/spi/Kconfig @@ -130,6 +130,13 @@ Select this option if your chipset driver needs to store certain data in the SPI flash and your SPI flash is made by SST.
+config SPI_FLASH_ISSI + bool + default y if SPI_FLASH_INCLUDE_ALL_DRIVERS + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by ISSI. + config SPI_FLASH_STMICRO bool default y if SPI_FLASH_INCLUDE_ALL_DRIVERS diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc index e55233e..b532398 100644 --- a/src/drivers/spi/Makefile.inc +++ b/src/drivers/spi/Makefile.inc @@ -25,6 +25,7 @@ $(1)-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.c $(1)-$(CONFIG_SPI_FLASH_SPANSION) += spansion.c $(1)-$(CONFIG_SPI_FLASH_SST) += sst.c +$(1)-$(CONFIG_SPI_FLASH_ISSI) += issi.c $(1)-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.c $(1)-$(CONFIG_SPI_FLASH_WINBOND) += winbond.c $(1)-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.c diff --git a/src/drivers/spi/issi.c b/src/drivers/spi/issi.c new file mode 100644 index 0000000..305f0ae --- /dev/null +++ b/src/drivers/spi/issi.c @@ -0,0 +1,367 @@ +/* + * This file is part of the coreboot project. + * + * 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 <stdlib.h> +#include <spi_flash.h> +#include <spi-generic.h> +#include <string.h> + +#include "spi_flash_internal.h" + +/* software reset enable */ +#define CMD_ISSI_RST 0x66 +/* software reset */ +#define CMD_ISSI_RST 0x99 +/* read status register */ +#define CMD_ISSI_RDSR 0x05 +/* write status register */ +#define CMD_ISSI_WRSR 0x01 +/* write enable */ +#define CMD_ISSI_WREN 0x06 +/* write disable */ +#define CMD_ISSI_WRDI 0x04 +/* read bank register */ +#define CMD_ISSI_RDBR 0x16 +/* write bank register */ +#define CMD_ISSI_WRBRV 0x17 +/* normal read */ +#define CMD_ISSI_NORD 0x03 +/* normal read with 4Bytes address*/ +#define CMD_ISSI_4NORD 0x13 +/* page program, up to 256bytes */ +#define CMD_ISSI_PP 0x02 +/* page program with 4Bytes address, up to 256bytes */ +#define CMD_ISSI_4PP 0x12 +/* sector erase, section size is 4kbytes */ +#define CMD_ISSI_SEC 0x20 +/* sector erase with 4Bytes address, section size is 4KBytes */ +#define CMD_ISSI_4SEC 0x21 + +struct issi_spi_flash_params { + u16 model; + u32 size; + u32 sector_size; + u8 status_cmd; + const char *name; + const struct spi_flash_ops *ops; +}; + +static const struct spi_flash_ops spi_flash_ops = { + .read = issi_flash_cmd_read, + .write = issi_flash_cmd_write, + .erase = issi_flash_cmd_erase, + .status = spi_flash_cmd_status, +}; + + +static struct issi_spi_flash_params issi_spi_flash_table[] = { + { + .model = 0x6019 + .size = 32 * 1024 * 1024, + .sector_size = 4 * 1024, + .status_cmd = CMD_ISSI_RDSR, + .name = "IS25LP256D", + .ops = spi_flash_ops + }, + { + .model = 0x7019, + .size = 32 * 1024 * 1024, + .sector_size = 4 * 1024, + .status_cmd = CMD_ISSI_RDSR, + .name = "IS25WP256D", + .ops = spi_flash_ops + } +}; + +static int issi_do_cmd(const struct spi_flash *flash, + void *cmd, size_t cmd_len) +{ + int ret = 0; + struct spi_op vectors[] = { + [0] = { .dout = cmd, .bytesout = cmd_len, + .din = NULL, .bytesin = 0, } + }; + do { + ret = spi_claim_bus(&flash->spi); + if (ret) + break; + ret = spi_xfer_vector(&flash->spi, vectors, 1); + if (ret) + break; + spi_release_bus(&flash->spi); + } while (0); + return ret; +} + +static int issi_do_read_cmd(const struct spi_flash *flash, + void *cmd, size_t cmd_len, + void *data, size_t data_len) +{ + int ret = 0; + struct spi_op vectors[] = { + [0] = { .dout = cmd, .bytesout = cmd_len, + .din = NULL, .bytesin = 0, }, + [1] = { .dout = NULL, .bytesout = 0, + .din = data, .bytesin = data_len }, + }; + size_t count = (data_len == 0 ? 1 : 2); + do { + ret = spi_claim_bus(&flash->spi); + if (ret) + break; + ret = spi_xfer_vector(&flash->spi, vectors, count); + if (ret) + break; + spi_release_bus(&flash->spi); + } while (0); + return ret; +} + +static int issi_do_write_cmd(const struct spi_flash *flash, + void *cmd, size_t cmd_len, + void *data, size_t data_len) +{ + int ret = 0; + struct spi_op vectors[] = { + [0] = { .dout = cmd, .bytesout = cmd_len, + .din = NULL, .bytesin = 0, }, + [1] = { .dout = data, .bytesout = data_len, + .din = NULL, .bytesin = 0 }, + }; + size_t count = (data_len == 0 ? 1 : 2); + do { + ret = spi_claim_bus(&flash->spi); + if (ret) + break; + ret = spi_xfer_vector(&flash->spi, vectors, count); + if (ret) + break; + spi_release_bus(&flash->spi); + } while (0); + return ret; +} + +static int issi_software_reset(const struct spi_flash *flash) +{ + int ret = 0; + static const u8 cmd_reset_enable = CMD_ISSI_RSTEN; + static const u8 cmd_reset = CMD_ISSI_RST; + do { + ret = issi_do_cmd(flash, &cmd_reset_enable, 1); + if (ret) + break; + ret = issi_do_cmd(flash, &cmd_reset, 1); + if (ret) + break; + } while (0); + if (ret) + printk(BIOS_WARNING, "SF: Resetting failed\n"); + return ret; +} + +static int issi_enable_writing(const struct spi_flash *flash) +{ + static const u8 cmd = CMD_ISSI_WREN; + int ret = issi_do_cmd(flash, &cmd, 1); + if (ret) + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + return ret; +} + +static int issi_disable_writing(const struct spi_flash *flash) +{ + static const u8 cmd = CMD_ISSI_WRDI; + int ret = issi_do_cmd(flash, &cmd, 1); + if (ret) + printk(BIOS_WARNING, "SF: Disabling Write failed\n"); + return ret; +} + +static int issi_flash_cmd_read(const struct spi_flash *flash, + u32 offset, size_t len, void *data) +{ + int ret = 0; + if (flash->size <= 32 * 1024 * 1024) { + u8 cmd[] = { + CMD_ISSI_NORD, + (offset >> 16) & 0xff, + (offset >> 8) & 0xff, + (offset >> 0) & 0xff, + }; + ret = issi_do_read_cmd(flash, cmd, sizeof(cmd), data, len); + } else { + u8 cmd[] = { + CMD_ISSI_4NORD, + (offset >> 24) & 0xff, + (offset >> 16) & 0xff, + (offset >> 8) & 0xff, + (offset >> 0) & 0xff, + } + ret = issi_do_read_cmd(flash, cmd, sizeof(cmd), data, len); + } + if (ret) + printk(BIOS_WARNING, "SF: Failed to send read command " + "(%zu bytes): %d\n", len, ret); + return ret; +} + +static int issi_flash_cmd_write(const struct spi_flash *flash, + u32 offset, size_t len, void *data) +{ + int ret = 0; + + ret = issi_enable_writing(flash); + if (ret) + return ret; + + do { + u8 bank = offset >> 24; + u8 cmd[4] = { + CMD_ISSI_PP, + (offset >> 2) & 0xff, + (offset >> 1) & 0xff, + (offset >> 0) & 0xff, + }; + + size_t wlen = (len > 256 ? 256 : len); + + if (flash->size <= 32 * 1024 * 1024) { + u8 cmd[4] = { + CMD_ISSI_PP, + (offset >> 16) & 0xff, + (offset >> 8) & 0xff, + (offset >> 0) & 0xff + }; + ret = issi_do_write_cmd(flash, cmd, sizeof(cmd), + data, wlen); + } else { + u8 cmd[5] = { + CMD_ISSI_4PP, + (offset >> 24) & 0xff, + (offset >> 16) & 0xff, + (offset >> 8) & 0xff, + (offset >> 0) & 0xff + }; + ret = issi_do_write_cmd(flash, cmd, sizeof(cmd), + data, wlen); + } + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send write command" + " (%zu bytes): %d\n", wlen, ret); + return ret; + } + + len = len - wlen; + offset = offset + wlen; + data = (void *)((uintptr_t)data + wlen); + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + return ret; + } while (len); + + ret = issi_disable_writing(flash); + + return ret; +} + +static int issi_flash_cmd_erase(const struct spi_flash *flash, u32 offset, + size_t len) +{ + int ret = 0; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_WARNING, "SF: Erase offset/length not multiple of" + " erase size\n"); + return -1; + } + if (len == 0) { + printk(BIOS_WARNING, "SF: Erase length cannot be 0\n"); + return -1; + } + + ret = issi_enable_writing(flash); + if (ret) + return ret; + + u32 end = offset + len; + + while (offset < end) { + if (flash->size <= 32 * 1024 * 1024) { + u8 cmd[4] = { + CMD_ISSI_PP, + (offset >> 16) & 0xff, + (offset >> 8) & 0xff, + (offset >> 0) & 0xff + }; + ret = issi_do_cmd(flash, cmd, sizeof(cmd)); + } else { + u8 cmd[5] = { + CMD_ISSI_4PP, + (offset >> 24) & 0xff, + (offset >> 16) & 0xff, + (offset >> 8) & 0xff, + (offset >> 0) & 0xff + }; + ret = issi_do_cmd(flash, cmd, sizeof(cmd)); + } + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send erase command" + " (offset: %#04x): %d\n", offset, ret); + return ret; + } + + offset = offset + erase_size; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + return ret; + } + + ret = issi_disable_writing(flash); + + return ret; +} + +int spi_flash_probe_issi(const struct spi_slave *spi, u8 *idcode, + struct spi_flash *flash) +{ + size_t i; + u16 model; + const struct issi_spi_flash_params *params; + + for (i = 0; i < ARRAY_SIZE(issi_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + model = (idcode[1] << 8) | idcode[2]; + if (params->model == model) + break; + } + + if (i == ARRAY_SIZE(issi_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported ISSI ID %04x\n", model); + return -1; + } + + memcpy(&flash->spi, spi, sizeof(*spi)); + flash->name = params->name; + flash->sector_size = params->sector_size; + flash->size = params->size; + flash->status_cmd = params->status_cmd; + + flash->ops = params->ops; + + issi_software_reset(flash); + + return 0; +} diff --git a/src/mainboard/sifive/hifive-unleashed/Makefile.inc b/src/mainboard/sifive/hifive-unleashed/Makefile.inc index 263297e..35a64d3 100644 --- a/src/mainboard/sifive/hifive-unleashed/Makefile.inc +++ b/src/mainboard/sifive/hifive-unleashed/Makefile.inc @@ -12,12 +12,15 @@ # GNU General Public License for more details.
bootblock-y += memlayout.ld +bootblock-y += media.c
romstage-y += memlayout.ld romstage-y += romstage.c +romstage-y += media.c
ramstage-y += memlayout.ld ramstage-y += fixup_fdt.c +ramstage-y += media.c
DTB=build/hifive-unleashed.dtb diff --git a/src/mainboard/sifive/hifive-unleashed/media.c b/src/mainboard/sifive/hifive-unleashed/media.c new file mode 100644 index 0000000..cd52bba --- /dev/null +++ b/src/mainboard/sifive/hifive-unleashed/media.c @@ -0,0 +1,54 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018 Jonathan Neuschäfer + * + * 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 <boot_device.h> +#include <soc/spi.h> + +/* At 0x20000000: A 256MiB long memory-mapped view of the flash at QSPI0 */ +static struct mem_region_device mdev = + MEM_REGION_DEV_RO_INIT((void *)0x20000000, CONFIG_ROM_SIZE); + +const struct region_device *boot_device_ro(void) +{ + return &mdev.rdev; +} + +const static struct fu540_spi_mmap_config spi_mmap_config = { + .cmd_en = 1, + .addr_len = 4, + .pad_cnt = 6, + .cmd_proto = FU540_SPI_PROTO_S, + .addr_proto = FU540_SPI_PROTO_Q, + .data_proto = FU540_SPI_PROTO_Q, + .cmd_code = 0xec, + .pad_code = 0 +}; + +void boot_device_init(void) +{ + const static uint8_t reset_en = 0x66; + const static uint8_t reset = 0x99; + struct spi_slave slave; + + /* initialize the spi controller */ + spi_setup_slave(0, 0, &slave); + + /* software reset flash chip */ + spi_xfer(&slave, &reset_en, 0, NULL, 0); + spi_xfer(&slave, &reset, 0, NULL, 0); + + /* map flash to memory space */ + fu540_spi_mmap(&slave, &spi_mmap_config); +} diff --git a/src/soc/sifive/fu540/Makefile.inc b/src/soc/sifive/fu540/Makefile.inc index 4f62f3e..3c97c08 100644 --- a/src/soc/sifive/fu540/Makefile.inc +++ b/src/soc/sifive/fu540/Makefile.inc @@ -15,13 +15,13 @@
bootblock-y += uart.c bootblock-y += clint.c -bootblock-y += media.c +bootblock-y += spi.c bootblock-y += bootblock.c bootblock-y += clock.c
romstage-y += uart.c romstage-y += clint.c -romstage-y += media.c +romstage-y += spi.c romstage-y += sdram.c romstage-y += cbmem.c romstage-y += otp.c @@ -29,7 +29,7 @@
ramstage-y += uart.c ramstage-y += clint.c -ramstage-y += media.c +ramstage-y += spi.c ramstage-y += sdram.c ramstage-y += cbmem.c ramstage-y += otp.c diff --git a/src/soc/sifive/fu540/include/soc/spi.h b/src/soc/sifive/fu540/include/soc/spi.h new file mode 100644 index 0000000..543f9b2 --- /dev/null +++ b/src/soc/sifive/fu540/include/soc/spi.h @@ -0,0 +1,83 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 SiFive, 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. + */ + +#ifndef __SOC_SIFIVE_HIFIVE_U_SPI_H__ +#define __SOC_SIFIVE_HIFIVE_U_SPI_H__ +#include <spi-generic.h> + +/* Data Pins: MOSI MISO */ +#define FU540_SPI_PROTO_S 0 +/* Data Pins: DQ0 DQ1 */ +#define FU540_SPI_PROTO_D 1 +/* Data Pins: DQ0 DQ1 DQ2 DQ3 */ +#define FU540_SPI_PROTO_Q 2 + +/* send MSB first */ +#define FU540_SPI_ENDIAN_BIG 0 +/* send LSB first */ +#define FU540_SPI_ENDIAN_LITTLE 1 + +/* inactive state of SCK is logical 0 */ +#define FU540_SPI_PHA_LOW 0 +/* inactive state of SCK is logical 1 */ +#define FU540_SPI_PHA_HIGH 1 + +/* data is sampled on leading edge */ +#define FU540_SPI_POL_LEADING 0 +/* data is sampled on trailing edge */ +#define FU540_SPI_POL_TRAILING 1 + +struct fu540_spi_config { + /* speed of spi interface */ + unsigned int freq; + /* serial clock phase */ + unsigned int pha; + /* serial clock polarity */ + unsigned int pol; + unsigned int protocol; + unsigned int endianness; + /* up to 8bits */ + unsigned int bits_per_frame; +}; + +/* more detailed spi configuration */ +int fu540_spi_setup(unsigned int bus, unsigned int cs, struct spi_slave *slave, + struct fu540_spi_config *config); + +/* This structure is used to describe the read command of SPI FLASH. */ +struct fu540_spi_mmap_config { + /* enable sending of command */ + unsigned int cmd_en; + /* number of address bytes (0-4) */ + unsigned int addr_len; + /* number of dummy cycles */ + unsigned int pad_cnt; + /* protocol for transmitting command */ + unsigned int cmd_proto; + /* protocol for transmitting address and padding */ + unsigned int addr_proto; + /* protocol for receiving data bytes */ + unsigned int data_proto; + /* value of command byte */ + unsigned int cmd_code; + /* first 8 bits to transmit during dummy cycles */ + unsigned int pad_code; +}; + +int fu540_spi_mmap( + const struct spi_slave *slave, + const struct fu540_spi_mmap_config *config); + +#endif /* __SOC_SIFIVE_HIFIVE_U_SPI_H__ */ diff --git a/src/soc/sifive/fu540/media.c b/src/soc/sifive/fu540/media.c deleted file mode 100644 index 7b9ccb0..0000000 --- a/src/soc/sifive/fu540/media.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2018 Jonathan Neuschäfer - * - * 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 <boot_device.h> - -/* At 0x20000000: A 256MiB long memory-mapped view of the flash at QSPI0 */ -static struct mem_region_device mdev = - MEM_REGION_DEV_RO_INIT((void *)0x20000000, CONFIG_ROM_SIZE); - -const struct region_device *boot_device_ro(void) -{ - return &mdev.rdev; -} diff --git a/src/soc/sifive/fu540/spi.c b/src/soc/sifive/fu540/spi.c new file mode 100644 index 0000000..b39a2fe --- /dev/null +++ b/src/soc/sifive/fu540/spi.c @@ -0,0 +1,186 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 SiFive, 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 <soc/spi.h> +#include <soc/clock.h> +#include <soc/addressmap.h> + +#include "spi_internal.h" + +static struct spi_ctrl *spictrls[] = { + (struct spi_ctrl *)FU540_QSPI0, + (struct spi_ctrl *)FU540_QSPI1, + (struct spi_ctrl *)FU540_QSPI2 +}; + + +/** + * Wait until SPI is ready for transmission and transmit byte. + */ +static void spi_tx(volatile struct spi_ctrl *spictrl, uint8_t in) +{ +#if __riscv_atomic + int32_t r; + do { + asm volatile ( + "amoor.w %0, %2, %1\n" + : "=r" (r), "+A" (spictrl->txdata.raw_bits) + : "r" (in) + ); + } while (r < 0); +#else + while ((int32_t) spictrl->txdata.raw_bits < 0) + ; + spictrl->txdata.data = in; +#endif +} + + +/** + * Wait until SPI receive queue has data and read byte. + */ +static uint8_t spi_rx(volatile struct spi_ctrl *spictrl) +{ + int32_t out; + while ((out = (int32_t) spictrl->rxdata.raw_bits) < 0) + ; + return (uint8_t) out; +} + +static int spi_xfer_(const struct spi_slave *slave, + const void *dout, size_t bytesout, + void *din, size_t bytesin) +{ + struct spi_ctrl *spictrl = spictrls[slave->cs]; + while (bytesout || bytesin) { + if (bytesout) { + spi_tx(spictrl, *(uint8_t *)dout++); + bytesout--; + } + if (bytesin) { + *(uint8_t *)din++ = spi_rx(spictrl); + bytesin--; + } + } + return 0; +} + +static int spi_setup_(const struct spi_slave *slave) +{ + if ((slave->cs > 2) || (slave->bus != 0)) + return -1; + + struct spi_ctrl *spictrl = spictrls[slave->cs]; + + spictrl->sckdiv = spi_min_clk_divisor(clock_get_tlclk_khz(), 10000); + + spictrl->sckmode.pha = FU540_SPI_PHA_LOW; + spictrl->sckmode.pol = FU540_SPI_POL_LEADING; + + spictrl->csmode.mode = FU540_SPI_CSMODE_AUTO; + + spictrl->fmt.proto = FU540_SPI_PROTO_S; + spictrl->fmt.endian = FU540_SPI_ENDIAN_BIG; + spictrl->fmt.dir = 1; + spictrl->fmt.len = 8; + + return 0; +} + +struct spi_ctrlr fu540_spi_ctrlr = { + .xfer = spi_xfer_, + .setup = spi_setup_, +}; + +const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { + { + .bus_start = 0, + .bus_end = 0, + .ctrlr = &fu540_spi_ctrlr, + } +}; + +const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map); + +int fu540_spi_setup(unsigned int bus, unsigned int cs, + struct spi_slave *slave, + struct fu540_spi_config *config) +{ + if ((cs > 2) || (bus != 0)) + return -1; + + if ((config->pha > 1) + || (config->pol > 1) + || (config->protocol > 2) + || (config->endianness > 1) + || (config->bits_per_frame > 8)) + return -1; + + slave->bus = 0; + slave->cs = cs; + slave->ctrlr = &fu540_spi_ctrlr; + + struct spi_ctrl *spictrl = spictrls[slave->cs]; + + spictrl->sckdiv = spi_min_clk_divisor(clock_get_tlclk_khz(), + config->freq / 1000); + + spictrl->sckmode.pha = config->pha; + spictrl->sckmode.pol = config->pol; + + spictrl->csmode.mode = FU540_SPI_CSMODE_AUTO; + + spictrl->fmt.proto = config->protocol; + spictrl->fmt.endian = config->endianness; + spictrl->fmt.dir = 1; + spictrl->fmt.len = config->bits_per_frame; + + return 0; +} + +int fu540_spi_mmap( + const struct spi_slave *slave, + const struct fu540_spi_mmap_config *config) +{ + if (slave->cs > 2) + return -1; + + if ((config->cmd_en > 1) + || (config->addr_len > 4) + || (config->pad_cnt > 15) + || (config->cmd_proto > 2) + || (config->addr_proto > 2) + || (config->data_proto > 2) + || (config->cmd_code > 255) + || (config->pad_code > 255)) + return -1; + + struct spi_ctrl *spictrl = spictrls[slave->cs]; + + spictrl->fctrl.en = 0; + + spictrl->ffmt.cmd_en = config->cmd_en; + spictrl->ffmt.addr_len = config->addr_len; + spictrl->ffmt.pad_cnt = config->pad_cnt; + spictrl->ffmt.command_proto = config->cmd_proto; + spictrl->ffmt.addr_proto = config->addr_proto; + spictrl->ffmt.data_proto = config->data_proto; + spictrl->ffmt.command_code = config->cmd_code; + spictrl->ffmt.pad_code = config->pad_code; + + spictrl->fctrl.en = 1; + + return 0; +} diff --git a/src/soc/sifive/fu540/spi_internal.h b/src/soc/sifive/fu540/spi_internal.h new file mode 100644 index 0000000..97094c1 --- /dev/null +++ b/src/soc/sifive/fu540/spi_internal.h @@ -0,0 +1,242 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 SiFive, 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. + */ +#ifndef __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ +#define __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ + +#include <stdint.h> + +#define _ASSERT_SIZEOF(type, size) _Static_assert( \ + sizeof(type) == (size), \ + #type " must be " #size " bytes wide") + +#define FU540_SPI_CSMODE_AUTO 0 +#define FU540_SPI_CSMODE_HOLD 2 +#define FU540_SPI_CSMODE_OFF 3 + +typedef union { + struct { + uint32_t pha : 1; + uint32_t pol : 1; + uint32_t reserved : 30; + }; + uint32_t raw_bits; +} spi_reg_sckmode; +_ASSERT_SIZEOF(spi_reg_sckmode, 4); + + +typedef union { + struct { + uint32_t mode : 2; + uint32_t reserved : 30; + }; + uint32_t raw_bits; +} spi_reg_csmode; +_ASSERT_SIZEOF(spi_reg_csmode, 4); + + +typedef union { + struct { + uint32_t cssck : 8; + uint32_t reserved0 : 8; + uint32_t sckcs : 8; + uint32_t reserved1 : 8; + }; + uint32_t raw_bits; +} spi_reg_delay0; +_ASSERT_SIZEOF(spi_reg_delay0, 4); + + +typedef union { + struct { + uint32_t intercs : 8; + uint32_t reserved0 : 8; + uint32_t interxfr : 8; + uint32_t reserved1 : 8; + }; + uint32_t raw_bits; +} spi_reg_delay1; +_ASSERT_SIZEOF(spi_reg_delay1, 4); + + +typedef union { + struct { + uint32_t proto : 2; + uint32_t endian : 1; + uint32_t dir : 1; + uint32_t reserved0 : 12; + uint32_t len : 4; + uint32_t reserved1 : 12; + }; + uint32_t raw_bits; +} spi_reg_fmt; +_ASSERT_SIZEOF(spi_reg_fmt, 4); + + +typedef union { + struct { + uint32_t data : 8; + uint32_t reserved : 23; + uint32_t full : 1; + }; + uint32_t raw_bits; +} spi_reg_txdata; +_ASSERT_SIZEOF(spi_reg_txdata, 4); + + +typedef union { + struct { + uint32_t data : 8; + uint32_t reserved : 23; + uint32_t empty : 1; + }; + uint32_t raw_bits; +} spi_reg_rxdata; +_ASSERT_SIZEOF(spi_reg_rxdata, 4); + + +typedef union { + struct { + uint32_t txmark : 3; + uint32_t reserved : 29; + }; + uint32_t raw_bits; +} spi_reg_txmark; +_ASSERT_SIZEOF(spi_reg_txmark, 4); + + +typedef union { + struct { + uint32_t rxmark : 3; + uint32_t reserved : 29; + }; + uint32_t raw_bits; +} spi_reg_rxmark; +_ASSERT_SIZEOF(spi_reg_rxmark, 4); + + +typedef union { + struct { + uint32_t en : 1; + uint32_t reserved : 31; + }; + uint32_t raw_bits; +} spi_reg_fctrl; +_ASSERT_SIZEOF(spi_reg_fctrl, 4); + + +typedef union { + struct { + uint32_t cmd_en : 1; + uint32_t addr_len : 3; + uint32_t pad_cnt : 4; + uint32_t command_proto : 2; + uint32_t addr_proto : 2; + uint32_t data_proto : 2; + uint32_t reserved : 2; + uint32_t command_code : 8; + uint32_t pad_code : 8; + }; + uint32_t raw_bits; +} spi_reg_ffmt; +_ASSERT_SIZEOF(spi_reg_ffmt, 4); + + +typedef union { + struct { + uint32_t txwm : 1; + uint32_t rxwm : 1; + uint32_t reserved : 30; + }; + uint32_t raw_bits; +} spi_reg_ie; +typedef spi_reg_ie spi_reg_ip; +_ASSERT_SIZEOF(spi_reg_ie, 4); +_ASSERT_SIZEOF(spi_reg_ip, 4); + +#undef _ASSERT_SIZEOF + + +/** + * SPI control register memory map. + * + * All functions take a pointer to a SPI device's control registers. + */ +struct spi_ctrl { + uint32_t sckdiv; + spi_reg_sckmode sckmode; + uint32_t reserved08; + uint32_t reserved0c; + + uint32_t csid; + uint32_t csdef; + spi_reg_csmode csmode; + uint32_t reserved1c; + + uint32_t reserved20; + uint32_t reserved24; + spi_reg_delay0 delay0; + spi_reg_delay1 delay1; + + uint32_t reserved30; + uint32_t reserved34; + uint32_t reserved38; + uint32_t reserved3c; + + spi_reg_fmt fmt; + uint32_t reserved44; + spi_reg_txdata txdata; + spi_reg_rxdata rxdata; + + spi_reg_txmark txmark; + spi_reg_rxmark rxmark; + uint32_t reserved58; + uint32_t reserved5c; + + spi_reg_fctrl fctrl; + spi_reg_ffmt ffmt; + uint32_t reserved68; + uint32_t reserved6c; + + spi_reg_ie ie; + spi_reg_ip ip; +}; + +/** + * Get smallest clock divisor that divides input_khz to a quotient less than or + * equal to max_target_khz; + */ +static inline unsigned int +spi_min_clk_divisor(unsigned int input_khz, unsigned int max_target_khz) +{ + // f_sck = f_in / (2 * (div + 1)) => div = (f_in / (2*f_sck)) - 1 + // + // The nearest integer solution for div requires rounding up as to not + // exceed max_target_khz. + // + // div = ceil(f_in / (2*f_sck)) - 1 + // = floor((f_in - 1 + 2*f_sck) / (2*f_sck)) - 1 + // + // This should not overflow as long as (f_in - 1 + 2*f_sck) does not + // exceed 2^32 - 1, which is unlikely since we represent frequencies + // in kHz. + unsigned int quotient = + (input_khz + 2 * max_target_khz - 1) / (2 * max_target_khz); + // Avoid underflow + if (quotient == 0) + return 0; + return quotient - 1; +} + +#endif /* __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ */
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#2).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces 3. to support HiFive Unleashed's ISSI Flash (IS25WP256D)
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/drivers/spi/Kconfig M src/drivers/spi/Makefile.inc A src/drivers/spi/issi.c M src/drivers/spi/spi_flash_internal.h M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 11 files changed, 948 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/2
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 2:
(5 comments)
Thanks for working on it. It would be nice if you could add the fu540 SPI interface in one commit and the ISSI flash in a seperate one, to make it easier to review.
https://review.coreboot.org/#/c/33055/2/src/drivers/spi/issi.c File src/drivers/spi/issi.c:
https://review.coreboot.org/#/c/33055/2/src/drivers/spi/issi.c@3 PS2, Line 3: * missing copyright
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@68 PS1, Line 68: if (bytesout) { don't you need to transmit something in order to receive something?
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@103 PS1, Line 103: .xfer = spi_xfer_, spi_xfer_vector is commonly used for non duplex transfers
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@110 PS1, Line 110: .bus_end = 0, there are 3 SPI controllers, thus bus_end = 2
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@137 PS1, Line 137: spictrl->sckdiv = spi_min_clk_divisor(clock_get_tlclk_khz(), use read64()/write64() for volatile memory access
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#3).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces 3. to support HiFive Unleashed's ISSI Flash (IS25WP256D)
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/drivers/spi/Kconfig M src/drivers/spi/Makefile.inc A src/drivers/spi/issi.c M src/drivers/spi/spi_flash_internal.h M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 11 files changed, 981 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/3
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#4).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces 3. to support HiFive Unleashed's ISSI Flash (IS25WP256D)
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/drivers/spi/Kconfig M src/drivers/spi/Makefile.inc A src/drivers/spi/issi.c M src/drivers/spi/spi_flash_internal.h M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 11 files changed, 985 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/4
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#5).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/drivers/spi/spi_flash_internal.h M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 8 files changed, 608 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/5
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#6).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 606 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/6
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#7).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 604 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/7
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#8).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 607 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/8
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#9).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 620 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/9
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 9:
(4 comments)
don't you need to transmit something in order to receive something?
https://review.coreboot.org/#/c/33055/2/src/drivers/spi/issi.c File src/drivers/spi/issi.c:
https://review.coreboot.org/#/c/33055/2/src/drivers/spi/issi.c@3 PS2, Line 3: *
missing copyright
Done
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@68 PS1, Line 68: if (bytesout) {
don't you need to transmit something in order to receive something?
Corrected.
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@110 PS1, Line 110: .bus_end = 0,
there are 3 SPI controllers, thus bus_end = 2
Done
https://review.coreboot.org/#/c/33055/1/src/soc/sifive/fu540/spi.c@137 PS1, Line 137: spictrl->sckdiv = spi_min_clk_divisor(clock_get_tlclk_khz(),
use read64()/write64() for volatile memory access
Done
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 9:
(6 comments)
Tested on the unleashed board with CONFIG_COMMON_CBFS_SPI_WRAPPER=y
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... File src/mainboard/sifive/hifive-unleashed/media.c:
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 40: void boot_device_init(void) why is it board specific?
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 42: const static uint8_t reset_en = 0x66; why? it's already done for ISSI if you call spi_flash_generic_probe().
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 50: spi_xfer(&slave, &reset_en, 0, NULL, 0); 1
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 51: spi_xfer(&slave, &reset, 0, NULL, 0); 1
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@56 PS9, Line 56: static uint8_t spi_rx(volatile struct spi_ctrl *spictrl) that doesn't work for me. The method never returns. Shouldn't you transmit receive at the same time?
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@71 PS9, Line 71: if (fmt.proto == FU540_SPI_PROTO_S) { why do you check for active the bit mode?
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#10).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 620 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/10
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 10:
(6 comments)
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... File src/mainboard/sifive/hifive-unleashed/media.c:
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 40: void boot_device_init(void)
why is it board specific?
SPI flash can be linked to QSPI0/QSPI1/QSPI2, which is related to the connection of the specific motherboard.
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 42: const static uint8_t reset_en = 0x66;
why? it's already done for ISSI if you call spi_flash_generic_probe().
There is no spi_flash_probe used here, so needs to add code to reset spi flash
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 50: spi_xfer(&slave, &reset_en, 0, NULL, 0);
1
Done
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 51: spi_xfer(&slave, &reset, 0, NULL, 0);
1
Done
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@56 PS9, Line 56: static uint8_t spi_rx(volatile struct spi_ctrl *spictrl)
that doesn't work for me. The method never returns. […]
It separate call requires SPI work in DPI / QPI mode
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@71 PS9, Line 71: if (fmt.proto == FU540_SPI_PROTO_S) {
why do you check for active the bit mode?
The SPI is full-duplex and needs to send data to trigger receive. DPI/QPI is half-duplex and does not need to send data to trigger receive
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 10:
(5 comments)
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... File src/mainboard/sifive/hifive-unleashed/media.c:
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 40: void boot_device_init(void)
SPI flash can be linked to QSPI0/QSPI1/QSPI2, which is related to the connection of the specific mot […]
but in the end only MSEL decides which boot media to use. As MSEL is SoC specific can't this be moved to SoC code?
https://review.coreboot.org/#/c/33055/9/src/mainboard/sifive/hifive-unleashe... PS9, Line 42: const static uint8_t reset_en = 0x66;
There is no spi_flash_probe used here, so needs to add code to reset spi flash
Any reason not to call the generic code, i.e. use of spi_flash_generic_probe()?
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@56 PS9, Line 56: static uint8_t spi_rx(volatile struct spi_ctrl *spictrl)
It separate call requires SPI work in DPI / QPI mode
Ah yes, that makes totally sense. Thanks for explaining.
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@71 PS9, Line 71: if (fmt.proto == FU540_SPI_PROTO_S) {
The SPI is full-duplex and needs to send data to trigger receive. […]
Please add this information as inline comment, as it's not clear on the first sight.
https://review.coreboot.org/#/c/33055/9/src/soc/sifive/fu540/spi.c@78 PS9, Line 78: spi_tx(spictrl, out); 1) you can't use half duplex function here, as hardware operates in full duplex mode. As said, it hangs forever in spi_rx.
2) the xfer() method always assumes half duplex operation, even if hardware runs in full duplex mode
Hello build bot (Jenkins), Philipp Hug,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#11).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 624 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/11
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 11:
(4 comments)
https://review.coreboot.org/c/coreboot/+/33055/9/src/mainboard/sifive/hifive... File src/mainboard/sifive/hifive-unleashed/media.c:
https://review.coreboot.org/c/coreboot/+/33055/9/src/mainboard/sifive/hifive... PS9, Line 40: void boot_device_init(void)
but in the end only MSEL decides which boot media to use. […]
MSEL is only used to determine where ZSBL and FSBL (coreboot) are. How to use MSEL is then determined by coreboot, which is related to the motherboard.
https://review.coreboot.org/c/coreboot/+/33055/9/src/mainboard/sifive/hifive... PS9, Line 42: const static uint8_t reset_en = 0x66;
Any reason not to call the generic code, i.e. […]
This is not to initialize the spi flash, here is to tell the fu540 spi controller how to read the flash. spi_flash_read/spi_flash_write will not be called after
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c@... PS9, Line 71: if (fmt.proto == FU540_SPI_PROTO_S) {
Please add this information as inline comment, as it's not clear on the first sight.
Done
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c@... PS9, Line 78: spi_tx(spictrl, out);
- you can't use half duplex function here, as hardware operates in full duplex mode. […]
I tried to look at the spi-generic.h file, both xfer() and xfer_vector() work in full duplex. We can determine whether can perform half-duplex operation by check dout&&din
Hello build bot (Jenkins), Philipp Hug,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#12).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc A src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h D src/soc/sifive/fu540/media.c A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 7 files changed, 632 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/12
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
(1 comment)
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c@... PS9, Line 78: spi_tx(spictrl, out);
I tried to look at the spi-generic.h file, both xfer() and xfer_vector() work in full duplex. […]
I'm sorry that's not what I was trying to explain.
Check the other xfer impementations.
They all transmit "bytesouts" bytes and discard the received byte, then they receive "bytesin" bytes by transmitting 0. It's done like in the code below.
It never touches din and dout at the same time.
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
(1 comment)
Patch Set 12:
(1 comment)
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c@... PS9, Line 78: spi_tx(spictrl, out);
I'm sorry that's not what I was trying to explain. […]
Done
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
(3 comments)
https://review.coreboot.org/c/coreboot/+/33055/1/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/c/coreboot/+/33055/1/src/soc/sifive/fu540/spi.c@... PS1, Line 68: if (bytesout) {
Corrected.
Done
https://review.coreboot.org/c/coreboot/+/33055/1/src/soc/sifive/fu540/spi.c@... PS1, Line 103: .xfer = spi_xfer_,
spi_xfer_vector is commonly used for non duplex transfers
Done
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c File src/soc/sifive/fu540/spi.c:
https://review.coreboot.org/c/coreboot/+/33055/9/src/soc/sifive/fu540/spi.c@... PS9, Line 56: static uint8_t spi_rx(volatile struct spi_ctrl *spictrl)
Ah yes, that makes totally sense. Thanks for explaining.
Done
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
Have anything update?
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
Patch Set 12:
Have anything update?
I currently don't have hardware to test. I'll run test next week and give you feedback.
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
Patch Set 12:
Patch Set 12:
Have anything update?
I currently don't have hardware to test. I'll run test next week and give you feedback.
I tested.
Without this patch, you need to make the following modifications to run on real hardware.
diff --git a/src/mainboard/sifive/hifive-unleashed/Kconfig b/src/mainboard/sifive/hifive-unleashed/Kconfig Index 24531787ef..db1d9aa54a 100644 --- a/src/mainboard/sifive/hifive-unleashed/Kconfig +++ b/src/mainboard/sifive/hifive-unleashed/Kconfig @@ -16,9 +16,10 @@ if BOARD_SIFIVE_HIFIVE_UNLEASHED Config BOARD_SPECIFIC_OPTIONS Def_bool y Select SOC_SIFIVE_FU540 - select BOARD_ROMSIZE_KB_32768 + select BOARD_ROMSIZE_KB_16384
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
Patch Set 12:
Patch Set 12:
Patch Set 12:
Have anything update?
I currently don't have hardware to test. I'll run test next week and give you feedback.
I tested.
Without this patch, you need to make the following modifications to run on real hardware.
diff --git a/src/mainboard/sifive/hifive-unleashed/Kconfig b/src/mainboard/sifive/hifive-unleashed/Kconfig Index 24531787ef..db1d9aa54a 100644 --- a/src/mainboard/sifive/hifive-unleashed/Kconfig +++ b/src/mainboard/sifive/hifive-unleashed/Kconfig @@ -16,9 +16,10 @@ if BOARD_SIFIVE_HIFIVE_UNLEASHED Config BOARD_SPECIFIC_OPTIONS Def_bool y Select SOC_SIFIVE_FU540
- select BOARD_ROMSIZE_KB_32768
- select BOARD_ROMSIZE_KB_16384
I am sorry I have tested before But I am testing now and found some problems.
Hello ron minnich, Jonathan Neuschäfer, build bot (Jenkins), Patrick Georgi, Martin Roth, Philipp Hug,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#13).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang wxjstz@126.com --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc R src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 6 files changed, 609 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/13
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 12:
Fixed and tested on HiFIve Unleashed
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 13: Code-Review+2
Memory mapped QSPI mode works fine and allows to boot a payload. SPI mode needs tests, but as it's 4 times slower and the device is essential a brick right now, SPI can be fixed later if required.
Hello Patrick Rudolph, ron minnich, Jonathan Neuschäfer, build bot (Jenkins), Patrick Georgi, Martin Roth, Philipp Hug,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/33055
to look at the new patch set (#14).
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang merle@hardenedlinux.org --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc R src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 6 files changed, 609 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/55/33055/14
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 14:
Please verify and mark all comments as resolved to show that the patch is ready to be merged. Thanks!
Xiang Wang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
Patch Set 14:
(2 comments)
https://review.coreboot.org/c/coreboot/+/33055/9/src/mainboard/sifive/hifive... File src/mainboard/sifive/hifive-unleashed/media.c:
https://review.coreboot.org/c/coreboot/+/33055/9/src/mainboard/sifive/hifive... PS9, Line 40: void boot_device_init(void)
MSEL is only used to determine where ZSBL and FSBL (coreboot) are. […]
Done
https://review.coreboot.org/c/coreboot/+/33055/9/src/mainboard/sifive/hifive... PS9, Line 42: const static uint8_t reset_en = 0x66;
This is not to initialize the spi flash, here is to tell the fu540 spi controller how to read the fl […]
Done
Patrick Rudolph has submitted this change and it was merged. ( https://review.coreboot.org/c/coreboot/+/33055 )
Change subject: soc/sifive/fu540: add code for spi and map flash to memory spaces ......................................................................
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available.
1. add code for spi 2. add code to map flash to memory spaces
Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang merle@hardenedlinux.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/33055 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Patrick Rudolph siro@das-labor.org --- M src/mainboard/sifive/hifive-unleashed/Makefile.inc R src/mainboard/sifive/hifive-unleashed/media.c M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/spi.h A src/soc/sifive/fu540/spi.c A src/soc/sifive/fu540/spi_internal.h 6 files changed, 609 insertions(+), 3 deletions(-)
Approvals: build bot (Jenkins): Verified Patrick Rudolph: Looks good to me, approved
diff --git a/src/mainboard/sifive/hifive-unleashed/Makefile.inc b/src/mainboard/sifive/hifive-unleashed/Makefile.inc index 207898e..8ce266f 100644 --- a/src/mainboard/sifive/hifive-unleashed/Makefile.inc +++ b/src/mainboard/sifive/hifive-unleashed/Makefile.inc @@ -12,12 +12,15 @@ # GNU General Public License for more details.
bootblock-y += memlayout.ld +bootblock-y += media.c
romstage-y += memlayout.ld romstage-y += romstage.c +romstage-y += media.c
ramstage-y += memlayout.ld ramstage-y += fixup_fdt.c +ramstage-y += media.c
DTB=$(obj)/hifive-unleashed.dtb diff --git a/src/soc/sifive/fu540/media.c b/src/mainboard/sifive/hifive-unleashed/media.c similarity index 62% rename from src/soc/sifive/fu540/media.c rename to src/mainboard/sifive/hifive-unleashed/media.c index 7b9ccb0..b0198a7 100644 --- a/src/soc/sifive/fu540/media.c +++ b/src/mainboard/sifive/hifive-unleashed/media.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2018 Jonathan Neuschäfer + * Copyright (C) 2019 HardenedLinux * * 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 @@ -14,6 +15,7 @@ */
#include <boot_device.h> +#include <soc/spi.h>
/* At 0x20000000: A 256MiB long memory-mapped view of the flash at QSPI0 */ static struct mem_region_device mdev = @@ -23,3 +25,25 @@ { return &mdev.rdev; } + +const static struct fu540_spi_mmap_config spi_mmap_config = { + .cmd_en = 1, + .addr_len = 4, + .pad_cnt = 6, + .cmd_proto = FU540_SPI_PROTO_S, + .addr_proto = FU540_SPI_PROTO_Q, + .data_proto = FU540_SPI_PROTO_Q, + .cmd_code = 0xec, + .pad_code = 0 +}; + +void boot_device_init(void) +{ + struct spi_slave slave; + + /* initialize spi controller */ + spi_setup_slave(0, 0, &slave); + + /* map flash to memory space */ + fu540_spi_mmap(&slave, &spi_mmap_config); +} diff --git a/src/soc/sifive/fu540/Makefile.inc b/src/soc/sifive/fu540/Makefile.inc index 4f62f3e..3c97c08 100644 --- a/src/soc/sifive/fu540/Makefile.inc +++ b/src/soc/sifive/fu540/Makefile.inc @@ -15,13 +15,13 @@
bootblock-y += uart.c bootblock-y += clint.c -bootblock-y += media.c +bootblock-y += spi.c bootblock-y += bootblock.c bootblock-y += clock.c
romstage-y += uart.c romstage-y += clint.c -romstage-y += media.c +romstage-y += spi.c romstage-y += sdram.c romstage-y += cbmem.c romstage-y += otp.c @@ -29,7 +29,7 @@
ramstage-y += uart.c ramstage-y += clint.c -ramstage-y += media.c +ramstage-y += spi.c ramstage-y += sdram.c ramstage-y += cbmem.c ramstage-y += otp.c diff --git a/src/soc/sifive/fu540/include/soc/spi.h b/src/soc/sifive/fu540/include/soc/spi.h new file mode 100644 index 0000000..543f9b2 --- /dev/null +++ b/src/soc/sifive/fu540/include/soc/spi.h @@ -0,0 +1,83 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 SiFive, 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. + */ + +#ifndef __SOC_SIFIVE_HIFIVE_U_SPI_H__ +#define __SOC_SIFIVE_HIFIVE_U_SPI_H__ +#include <spi-generic.h> + +/* Data Pins: MOSI MISO */ +#define FU540_SPI_PROTO_S 0 +/* Data Pins: DQ0 DQ1 */ +#define FU540_SPI_PROTO_D 1 +/* Data Pins: DQ0 DQ1 DQ2 DQ3 */ +#define FU540_SPI_PROTO_Q 2 + +/* send MSB first */ +#define FU540_SPI_ENDIAN_BIG 0 +/* send LSB first */ +#define FU540_SPI_ENDIAN_LITTLE 1 + +/* inactive state of SCK is logical 0 */ +#define FU540_SPI_PHA_LOW 0 +/* inactive state of SCK is logical 1 */ +#define FU540_SPI_PHA_HIGH 1 + +/* data is sampled on leading edge */ +#define FU540_SPI_POL_LEADING 0 +/* data is sampled on trailing edge */ +#define FU540_SPI_POL_TRAILING 1 + +struct fu540_spi_config { + /* speed of spi interface */ + unsigned int freq; + /* serial clock phase */ + unsigned int pha; + /* serial clock polarity */ + unsigned int pol; + unsigned int protocol; + unsigned int endianness; + /* up to 8bits */ + unsigned int bits_per_frame; +}; + +/* more detailed spi configuration */ +int fu540_spi_setup(unsigned int bus, unsigned int cs, struct spi_slave *slave, + struct fu540_spi_config *config); + +/* This structure is used to describe the read command of SPI FLASH. */ +struct fu540_spi_mmap_config { + /* enable sending of command */ + unsigned int cmd_en; + /* number of address bytes (0-4) */ + unsigned int addr_len; + /* number of dummy cycles */ + unsigned int pad_cnt; + /* protocol for transmitting command */ + unsigned int cmd_proto; + /* protocol for transmitting address and padding */ + unsigned int addr_proto; + /* protocol for receiving data bytes */ + unsigned int data_proto; + /* value of command byte */ + unsigned int cmd_code; + /* first 8 bits to transmit during dummy cycles */ + unsigned int pad_code; +}; + +int fu540_spi_mmap( + const struct spi_slave *slave, + const struct fu540_spi_mmap_config *config); + +#endif /* __SOC_SIFIVE_HIFIVE_U_SPI_H__ */ diff --git a/src/soc/sifive/fu540/spi.c b/src/soc/sifive/fu540/spi.c new file mode 100644 index 0000000..6bf1700 --- /dev/null +++ b/src/soc/sifive/fu540/spi.c @@ -0,0 +1,254 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 SiFive, Inc + * Copyright (C) 2019 HardenedLinux + * + * 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 <arch/mmio.h> +#include <soc/spi.h> +#include <soc/clock.h> +#include <soc/addressmap.h> + +#include "spi_internal.h" + +static struct spi_ctrl *spictrls[] = { + (struct spi_ctrl *)FU540_QSPI0, + (struct spi_ctrl *)FU540_QSPI1, + (struct spi_ctrl *)FU540_QSPI2 +}; + + +/** + * Wait until SPI is ready for transmission and transmit byte. + */ +static void spi_tx(volatile struct spi_ctrl *spictrl, uint8_t in) +{ +#if __riscv_atomic + int32_t r; + do { + asm volatile ( + "amoor.w %0, %2, %1\n" + : "=r" (r), "+A" (spictrl->txdata.raw_bits) + : "r" (in) + ); + } while (r < 0); +#else + while ((int32_t) spictrl->txdata.raw_bits < 0) + ; + spictrl->txdata.data = in; +#endif +} + + +/** + * Wait until SPI receive queue has data and read byte. + */ +static uint8_t spi_rx(volatile struct spi_ctrl *spictrl) +{ + int32_t out; + while ((out = (int32_t) spictrl->rxdata.raw_bits) < 0) + ; + return (uint8_t) out; +} + +static int spi_xfer_(const struct spi_slave *slave, + const void *dout, size_t bytesout, + void *din, size_t bytesin) +{ + struct spi_ctrl *spictrl = spictrls[slave->bus]; + spi_reg_fmt fmt; + fmt.raw_bits = read32(&spictrl->fmt.raw_bits); + if (fmt.proto == FU540_SPI_PROTO_S) { + /* working in full-duplex mode + * receiving data needs to be triggered by sending data */ + while (bytesout || bytesin) { + uint8_t in, out = 0; + if (bytesout) { + out = *(uint8_t *)dout++; + bytesout--; + } + spi_tx(spictrl, out); + in = spi_rx(spictrl); + if (bytesin) { + *(uint8_t *)din++ = in; + bytesin--; + } + } + } else { + /* Working in half duplex + * send and receive can be done separately */ + if (dout && din) + return -1; + + if (dout) { + while (bytesout) { + spi_tx(spictrl, *(uint8_t *)dout++); + bytesout--; + } + } + + if (din) { + while (bytesin) { + *(uint8_t *)din++ = spi_rx(spictrl); + bytesin--; + } + } + } + return 0; +} + +static int spi_setup_(const struct spi_slave *slave) +{ + spi_reg_sckmode sckmode; + spi_reg_csmode csmode; + spi_reg_fmt fmt; + + if ((slave->bus > 2) || (slave->cs != 0)) + return -1; + + struct spi_ctrl *spictrl = spictrls[slave->bus]; + + write32(&spictrl->sckdiv, spi_min_clk_divisor(clock_get_tlclk_khz(), + 10000)); + + sckmode.raw_bits = 0; + sckmode.pha = FU540_SPI_PHA_LOW; + sckmode.pol = FU540_SPI_POL_LEADING; + write32(&spictrl->sckmode.raw_bits, sckmode.raw_bits); + + csmode.raw_bits = 0; + csmode.mode = FU540_SPI_CSMODE_AUTO; + write32(&spictrl->csmode.raw_bits, csmode.raw_bits); + + fmt.raw_bits = 0; + fmt.proto = FU540_SPI_PROTO_S; + fmt.endian = FU540_SPI_ENDIAN_BIG; + fmt.dir = 1; + fmt.len = 8; + write32(&spictrl->fmt.raw_bits, fmt.raw_bits); + + return 0; +} + +struct spi_ctrlr fu540_spi_ctrlr = { + .xfer = spi_xfer_, + .setup = spi_setup_, +}; + +const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { + { + .bus_start = 0, + .bus_end = 2, + .ctrlr = &fu540_spi_ctrlr, + } +}; + +const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map); + +int fu540_spi_setup(unsigned int bus, unsigned int cs, + struct spi_slave *slave, + struct fu540_spi_config *config) +{ + spi_reg_sckmode sckmode; + spi_reg_csmode csmode; + spi_reg_fmt fmt; + + if ((bus > 2) || (cs != 0)) + return -1; + + if ((config->pha > 1) + || (config->pol > 1) + || (config->protocol > 2) + || (config->endianness > 1) + || (config->bits_per_frame > 8)) + return -1; + + slave->bus = bus; + slave->cs = cs; + slave->ctrlr = &fu540_spi_ctrlr; + + struct spi_ctrl *spictrl = spictrls[slave->bus]; + + write32(&spictrl->sckdiv, spi_min_clk_divisor(clock_get_tlclk_khz(), + config->freq / 1000)); + + sckmode.raw_bits = 0; + sckmode.pha = config->pha; + sckmode.pol = config->pol; + write32(&spictrl->sckmode.raw_bits, sckmode.raw_bits); + + csmode.raw_bits = 0; + csmode.mode = FU540_SPI_CSMODE_AUTO; + write32(&spictrl->csmode.raw_bits, csmode.raw_bits); + + fmt.raw_bits = 0; + fmt.proto = config->protocol; + fmt.endian = config->endianness; + fmt.dir = 1; + fmt.len = config->bits_per_frame; + write32(&spictrl->fmt.raw_bits, fmt.raw_bits); + + return 0; +} + +int fu540_spi_mmap( + const struct spi_slave *slave, + const struct fu540_spi_mmap_config *config) +{ + spi_reg_fctrl fctrl; + spi_reg_ffmt ffmt; + + if (slave->bus > 2) + return -1; + + if ((config->cmd_en > 1) + || (config->addr_len > 4) + || (config->pad_cnt > 15) + || (config->cmd_proto > 2) + || (config->addr_proto > 2) + || (config->data_proto > 2) + || (config->cmd_code > 255) + || (config->pad_code > 255)) + return -1; + + struct spi_ctrl *spictrl = spictrls[slave->bus]; + + /* disable direct memory-mapped spi flash mode */ + fctrl.raw_bits = 0; + fctrl.en = 0; + write32(&spictrl->fctrl.raw_bits, fctrl.raw_bits); + + /* reset spi flash chip */ + spi_tx(spictrl, 0x66); + spi_tx(spictrl, 0x99); + + /* Pass the information of the flash read operation to the spi + * controller */ + ffmt.raw_bits = 0; + ffmt.cmd_en = config->cmd_en; + ffmt.addr_len = config->addr_len; + ffmt.pad_cnt = config->pad_cnt; + ffmt.command_proto = config->cmd_proto; + ffmt.addr_proto = config->addr_proto; + ffmt.data_proto = config->data_proto; + ffmt.command_code = config->cmd_code; + ffmt.pad_code = config->pad_code; + write32(&spictrl->ffmt.raw_bits, ffmt.raw_bits); + + /* enable direct memory-mapped spi flash mode */ + fctrl.raw_bits = 0; + fctrl.en = 1; + write32(&spictrl->fctrl.raw_bits, fctrl.raw_bits); + + return 0; +} diff --git a/src/soc/sifive/fu540/spi_internal.h b/src/soc/sifive/fu540/spi_internal.h new file mode 100644 index 0000000..97094c1 --- /dev/null +++ b/src/soc/sifive/fu540/spi_internal.h @@ -0,0 +1,242 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 SiFive, 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. + */ +#ifndef __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ +#define __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ + +#include <stdint.h> + +#define _ASSERT_SIZEOF(type, size) _Static_assert( \ + sizeof(type) == (size), \ + #type " must be " #size " bytes wide") + +#define FU540_SPI_CSMODE_AUTO 0 +#define FU540_SPI_CSMODE_HOLD 2 +#define FU540_SPI_CSMODE_OFF 3 + +typedef union { + struct { + uint32_t pha : 1; + uint32_t pol : 1; + uint32_t reserved : 30; + }; + uint32_t raw_bits; +} spi_reg_sckmode; +_ASSERT_SIZEOF(spi_reg_sckmode, 4); + + +typedef union { + struct { + uint32_t mode : 2; + uint32_t reserved : 30; + }; + uint32_t raw_bits; +} spi_reg_csmode; +_ASSERT_SIZEOF(spi_reg_csmode, 4); + + +typedef union { + struct { + uint32_t cssck : 8; + uint32_t reserved0 : 8; + uint32_t sckcs : 8; + uint32_t reserved1 : 8; + }; + uint32_t raw_bits; +} spi_reg_delay0; +_ASSERT_SIZEOF(spi_reg_delay0, 4); + + +typedef union { + struct { + uint32_t intercs : 8; + uint32_t reserved0 : 8; + uint32_t interxfr : 8; + uint32_t reserved1 : 8; + }; + uint32_t raw_bits; +} spi_reg_delay1; +_ASSERT_SIZEOF(spi_reg_delay1, 4); + + +typedef union { + struct { + uint32_t proto : 2; + uint32_t endian : 1; + uint32_t dir : 1; + uint32_t reserved0 : 12; + uint32_t len : 4; + uint32_t reserved1 : 12; + }; + uint32_t raw_bits; +} spi_reg_fmt; +_ASSERT_SIZEOF(spi_reg_fmt, 4); + + +typedef union { + struct { + uint32_t data : 8; + uint32_t reserved : 23; + uint32_t full : 1; + }; + uint32_t raw_bits; +} spi_reg_txdata; +_ASSERT_SIZEOF(spi_reg_txdata, 4); + + +typedef union { + struct { + uint32_t data : 8; + uint32_t reserved : 23; + uint32_t empty : 1; + }; + uint32_t raw_bits; +} spi_reg_rxdata; +_ASSERT_SIZEOF(spi_reg_rxdata, 4); + + +typedef union { + struct { + uint32_t txmark : 3; + uint32_t reserved : 29; + }; + uint32_t raw_bits; +} spi_reg_txmark; +_ASSERT_SIZEOF(spi_reg_txmark, 4); + + +typedef union { + struct { + uint32_t rxmark : 3; + uint32_t reserved : 29; + }; + uint32_t raw_bits; +} spi_reg_rxmark; +_ASSERT_SIZEOF(spi_reg_rxmark, 4); + + +typedef union { + struct { + uint32_t en : 1; + uint32_t reserved : 31; + }; + uint32_t raw_bits; +} spi_reg_fctrl; +_ASSERT_SIZEOF(spi_reg_fctrl, 4); + + +typedef union { + struct { + uint32_t cmd_en : 1; + uint32_t addr_len : 3; + uint32_t pad_cnt : 4; + uint32_t command_proto : 2; + uint32_t addr_proto : 2; + uint32_t data_proto : 2; + uint32_t reserved : 2; + uint32_t command_code : 8; + uint32_t pad_code : 8; + }; + uint32_t raw_bits; +} spi_reg_ffmt; +_ASSERT_SIZEOF(spi_reg_ffmt, 4); + + +typedef union { + struct { + uint32_t txwm : 1; + uint32_t rxwm : 1; + uint32_t reserved : 30; + }; + uint32_t raw_bits; +} spi_reg_ie; +typedef spi_reg_ie spi_reg_ip; +_ASSERT_SIZEOF(spi_reg_ie, 4); +_ASSERT_SIZEOF(spi_reg_ip, 4); + +#undef _ASSERT_SIZEOF + + +/** + * SPI control register memory map. + * + * All functions take a pointer to a SPI device's control registers. + */ +struct spi_ctrl { + uint32_t sckdiv; + spi_reg_sckmode sckmode; + uint32_t reserved08; + uint32_t reserved0c; + + uint32_t csid; + uint32_t csdef; + spi_reg_csmode csmode; + uint32_t reserved1c; + + uint32_t reserved20; + uint32_t reserved24; + spi_reg_delay0 delay0; + spi_reg_delay1 delay1; + + uint32_t reserved30; + uint32_t reserved34; + uint32_t reserved38; + uint32_t reserved3c; + + spi_reg_fmt fmt; + uint32_t reserved44; + spi_reg_txdata txdata; + spi_reg_rxdata rxdata; + + spi_reg_txmark txmark; + spi_reg_rxmark rxmark; + uint32_t reserved58; + uint32_t reserved5c; + + spi_reg_fctrl fctrl; + spi_reg_ffmt ffmt; + uint32_t reserved68; + uint32_t reserved6c; + + spi_reg_ie ie; + spi_reg_ip ip; +}; + +/** + * Get smallest clock divisor that divides input_khz to a quotient less than or + * equal to max_target_khz; + */ +static inline unsigned int +spi_min_clk_divisor(unsigned int input_khz, unsigned int max_target_khz) +{ + // f_sck = f_in / (2 * (div + 1)) => div = (f_in / (2*f_sck)) - 1 + // + // The nearest integer solution for div requires rounding up as to not + // exceed max_target_khz. + // + // div = ceil(f_in / (2*f_sck)) - 1 + // = floor((f_in - 1 + 2*f_sck) / (2*f_sck)) - 1 + // + // This should not overflow as long as (f_in - 1 + 2*f_sck) does not + // exceed 2^32 - 1, which is unlikely since we represent frequencies + // in kHz. + unsigned int quotient = + (input_khz + 2 * max_target_khz - 1) / (2 * max_target_khz); + // Avoid underflow + if (quotient == 0) + return 0; + return quotient - 1; +} + +#endif /* __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ */