mturney mturney has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
sc7180: Add SPI-NOR support
This implements the SPI-NOR driver for the Qualcomm QSPI core.
Developer/Reviewer, be aware of this patch from Napali: https://review.coreboot.org/c/coreboot/+/27483/58
Change-Id: I2eb8cf90aa4559541ba293b3fd2870896bed20b7 Signed-off-by: Akash Asthana akashast@codeaurora.org --- M src/soc/qualcomm/sc7180/Kconfig M src/soc/qualcomm/sc7180/Makefile.inc M src/soc/qualcomm/sc7180/bootblock.c A src/soc/qualcomm/sc7180/include/soc/qspi.h A src/soc/qualcomm/sc7180/qspi.c M src/soc/qualcomm/sc7180/spi.c 6 files changed, 452 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/35501/1
diff --git a/src/soc/qualcomm/sc7180/Kconfig b/src/soc/qualcomm/sc7180/Kconfig index a1a7f03..df5d116 100644 --- a/src/soc/qualcomm/sc7180/Kconfig +++ b/src/soc/qualcomm/sc7180/Kconfig @@ -28,4 +28,13 @@ help Select the QUP instance to be used for UART console output.
+config SC7180_QSPI + bool + default y if COMMON_CBFS_SPI_WRAPPER + prompt "Build Flash Using SPI-NOR" + +config BOOT_DEVICE_SPI_FLASH_BUS + int + default 16 + endif diff --git a/src/soc/qualcomm/sc7180/Makefile.inc b/src/soc/qualcomm/sc7180/Makefile.inc index 5a4b68c..7ad0328 100644 --- a/src/soc/qualcomm/sc7180/Makefile.inc +++ b/src/soc/qualcomm/sc7180/Makefile.inc @@ -12,6 +12,7 @@ bootblock-y += qupv3_fw_config.c bootblock-y += qupv3_config.c bootblock-y += qcom_qup_se.c +bootblock-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################ verstage-y += timer.c @@ -20,6 +21,7 @@ verstage-y += clock.c verstage-y += qcom_qup_se.c verstage-$(CONFIG_DRIVERS_UART) += uart.c +verstage-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################ romstage-y += cbmem.c @@ -32,6 +34,7 @@ romstage-y += clock.c romstage-y += qcom_qup_se.c romstage-$(CONFIG_DRIVERS_UART) += uart.c +romstage-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################ ramstage-y += soc.c @@ -44,6 +47,7 @@ ramstage-y += qupv3_config.c ramstage-y += qcom_qup_se.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c +ramstage-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################
diff --git a/src/soc/qualcomm/sc7180/bootblock.c b/src/soc/qualcomm/sc7180/bootblock.c index b0cd9f2..8ee04d2 100644 --- a/src/soc/qualcomm/sc7180/bootblock.c +++ b/src/soc/qualcomm/sc7180/bootblock.c @@ -18,10 +18,12 @@ #include <soc/mmu.h> #include <soc/clock.h> #include <soc/qupv3_fw_config.h> +#include <soc/qspi.h>
void bootblock_soc_init(void) { sc7180_mmu_init(); clock_init(); + quadspi_init(25 * MHz); qupv3_fw_init(); } diff --git a/src/soc/qualcomm/sc7180/include/soc/qspi.h b/src/soc/qualcomm/sc7180/include/soc/qspi.h new file mode 100644 index 0000000..c3d1f78 --- /dev/null +++ b/src/soc/qualcomm/sc7180/include/soc/qspi.h @@ -0,0 +1,121 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2019 Qualcomm Technologies. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 <types.h> +#include <soc/addressmap.h> +#include <spi-generic.h> + +#ifndef __SOC_QUALCOMM_SC7180_QSPI_H__ +#define __SOC_QUALCOMM_SC7180_QSPI_H__ + +struct sc7180_qspi_regs { + u32 mstr_cfg; + u32 ahb_mstr_cfg; + u32 reserve_0; + u32 mstr_int_en; + u32 mstr_int_sts; + u32 pio_xfer_ctrl; + u32 pio_xfer_cfg; + u32 pio_xfer_sts; + u32 pio_dataout_1byte; + u32 pio_dataout_4byte; + u32 rd_fifo_cfg; + u32 rd_fifo_sts; + u32 rd_fifo_rst; + u32 reserve_1[3]; + u32 next_dma_desc_addr; + u32 current_dma_desc_addr; + u32 current_mem_addr; + u32 hw_version; + u32 rd_fifo[16]; +}; + +check_member(sc7180_qspi_regs, rd_fifo, 0x50); +static struct sc7180_qspi_regs * const sc7180_qspi = (void *) QSPI_BASE; + +// MSTR_CONFIG register + +#define TX_DATA_OE_DELAY_SHIFT 24 +#define TX_DATA_OE_DELAY_MASK (0x3 << TX_DATA_OE_DELAY_SHIFT) +#define TX_CS_N_DELAY_SHIFT 22 +#define TX_CS_N_DELAY_MASK (0x3 << TX_CS_N_DELAY_SHIFT) +#define TX_CLK_DELAY_SHIFT 20 +#define TX_CLK_DELAY_MASK (0x3 << TX_CLK_DELAY_SHIFT) +#define TX_DATA_DELAY_SHIFT 18 +#define TX_DATA_DELAY_MASK (0x3 << TX_DATA_DELAY_SHIFT) +#define LPA_BASE_SHIFT 14 +#define LPA_BASE_MASK (0xF << LPA_BASE_SHIFT) +#define SBL_EN BIT(13) +#define CHIP_SELECT_NUM BIT(12) +#define SPI_MODE_SHIFT 10 +#define SPI_MODE_MASK (0x3 << SPI_MODE_SHIFT) +#define BIG_ENDIAN_MODE BIT(9) +#define DMA_ENABLE BIT(8) +#define PIN_WPN BIT(7) +#define PIN_HOLDN BIT(6) +#define FB_CLK_EN BIT(4) +#define FULL_CYCLE_MODE BIT(3) + +// MSTR_INT_ENABLE and MSTR_INT_STATUS register + +#define DMA_CHAIN_DONE BIT(31) +#define TRANSACTION_DONE BIT(16) +#define WRITE_FIFO_OVERRUN BIT(11) +#define WRITE_FIFO_FULL BIT(10) +#define HRESP_FROM_NOC_ERR BIT(3) +#define RESP_FIFO_RDY BIT(2) +#define RESP_FIFO_NOT_EMPTY BIT(1) +#define RESP_FIFO_UNDERRUN BIT(0) + +// PIO_TRANSFER_CONFIG register + +#define TRANSFER_FRAGMENT BIT(8) +#define MULTI_IO_MODE_SHIFT 1 +#define MULTI_IO_MODE_MASK (0x7 << MULTI_IO_MODE_SHIFT) +#define TRANSFER_DIRECTION BIT(0) + +// PIO_TRANSFER_STATUS register + +#define WR_FIFO_BYTES_SHIFT 16 +#define WR_FIFO_BYTES_MASK (0xFFFF << WR_FIFO_BYTES_SHIFT) + +// RD_FIFO_CONFIG register + +#define CONTINUOUS_MODE BIT(0) + +// RD_FIFO_STATUS register + +#define FIFO_EMPTY BIT(11) +#define WR_CNTS_SHIFT 4 +#define WR_CNTS_MASK (0x7F << WR_CNTS_SHIFT) +#define RDY_64BYTE BIT(3) +#define RDY_32BYTE BIT(2) +#define RDY_16BYTE BIT(1) +#define FIFO_RDY BIT(0) + +// RD_FIFO_RESET register + +#define RESET_FIFO BIT(0) + +#define QSPI_MAX_PACKET_COUNT 0xFFC0 + +void quadspi_init(uint32_t hz); +int sc7180_claim_bus(const struct spi_slave *slave); +int sc7180_setup_bus(const struct spi_slave *slave); +void sc7180_release_bus(const struct spi_slave *slave); +int sc7180_xfer(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes); +int sc7180_xfer_dual(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes); +#endif /* __SOC_QUALCOMM_SC7180_QSPI_H__ */ diff --git a/src/soc/qualcomm/sc7180/qspi.c b/src/soc/qualcomm/sc7180/qspi.c new file mode 100644 index 0000000..c589415 --- /dev/null +++ b/src/soc/qualcomm/sc7180/qspi.c @@ -0,0 +1,306 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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-generic.h> +#include <spi_flash.h> +#include <arch/cache.h> +#include <device/mmio.h> +#include <soc/addressmap.h> +#include <soc/qspi.h> +#include <soc/gpio.h> +#include <soc/clock.h> +#include <symbols.h> +#include <assert.h> +#include <gpio.h> +#include <string.h> + +#define CACHE_LINE_SIZE 64 + +static int curr_desc_idx = -1; + +struct cmd_desc { + uint32_t data_address; + uint32_t next_descriptor; + uint32_t direction:1; + uint32_t multi_io_mode:3; + uint32_t reserved1:4; + uint32_t fragment:1; + uint32_t reserved2:7; + uint32_t length:16; + //------------------------// + uint32_t bounce_src; + uint32_t bounce_dst; + uint32_t bounce_length; + uint64_t padding[5]; +}; + +enum qspi_mode { + SDR_1BIT = 1, + SDR_2BIT = 2, + SDR_4BIT = 3, + DDR_1BIT = 5, + DDR_2BIT = 6, + DDR_4BIT = 7, +}; + +enum cs_state { + CS_DEASSERT, + CS_ASSERT +}; + +struct xfer_cfg { + enum qspi_mode mode; +}; + +enum bus_xfer_direction { + MASTER_READ = 0, + MASTER_WRITE = 1, +}; + +struct { + struct cmd_desc descriptors[3]; + uint8_t buffers[3][CACHE_LINE_SIZE]; +} *dma = (void *)_dma_coherent; + +static void dma_transfer_chain(struct cmd_desc *chain) +{ + uint32_t mstr_int_status; + + write32(&sc7180_qspi->mstr_int_sts, 0xFFFFFFFF); + write32(&sc7180_qspi->next_dma_desc_addr, (uint32_t)(uintptr_t) chain); + + while (1) { + mstr_int_status = read32(&sc7180_qspi->mstr_int_sts); + if (mstr_int_status & DMA_CHAIN_DONE) + break; + } +} + +static void flush_chain(void) +{ + struct cmd_desc *desc = &dma->descriptors[0]; + uint8_t *src; + uint8_t *dst; + + dma_transfer_chain(desc); + + while (desc) { + if (desc->direction == MASTER_READ) { + if (desc->bounce_length == 0) + dcache_invalidate_by_mva( + (void *)(uintptr_t) desc->data_address, + desc->length); + else { + src = (void *)(uintptr_t) desc->bounce_src; + dst = (void *)(uintptr_t) desc->bounce_dst; + memcpy(dst, src, desc->bounce_length); + } + } + desc = (void *)(uintptr_t) desc->next_descriptor; + } + curr_desc_idx = -1; +} + +static struct cmd_desc *allocate_descriptor(void) +{ + struct cmd_desc *current; + struct cmd_desc *next; + uint8_t index; + + current = (curr_desc_idx == -1) ? + NULL : &dma->descriptors[curr_desc_idx]; + + index = ++curr_desc_idx; + next = &dma->descriptors[index]; + + next->data_address = (uint32_t) (uintptr_t) dma->buffers[index]; + + next->next_descriptor = 0; + next->direction = MASTER_READ; + next->multi_io_mode = 0; + next->reserved1 = 0; + next->fragment = 0; + next->reserved2 = 0; + next->length = 0; + next->bounce_src = 0; + next->bounce_dst = 0; + next->bounce_length = 0; + + if (current) { + current->next_descriptor = (uint32_t)(uintptr_t) next; + current->fragment = 1; + } + + return next; +} + +static void cs_change(enum cs_state state) +{ + gpio_set(GPIO(68), state == CS_DEASSERT); +} + +static void configure_gpios(void) +{ + gpio_output(GPIO(68), 1); + + gpio_configure(GPIO(64), GPIO64_FUNC_QSPI_DATA_0, + GPIO_NO_PULL, GPIO_2MA, GPIO_ENABLE); + + gpio_configure(GPIO(65), GPIO65_FUNC_QSPI_DATA_1, + GPIO_NO_PULL, GPIO_2MA, GPIO_ENABLE); + + gpio_configure(GPIO(63), GPIO63_FUNC_QSPI_CLK, + GPIO_NO_PULL, GPIO_2MA, GPIO_ENABLE); +} + +static void queue_bounce_data(uint8_t *data, uint32_t data_bytes, + enum qspi_mode data_mode, bool write) +{ + struct cmd_desc *desc; + uint8_t *ptr; + + desc = allocate_descriptor(); + desc->direction = write; + desc->multi_io_mode = data_mode; + ptr = (void *)(uintptr_t) desc->data_address; + + if (write) { + memcpy(ptr, data, data_bytes); + } else { + desc->bounce_src = (uint32_t)(uintptr_t) ptr; + desc->bounce_dst = (uint32_t)(uintptr_t) data; + desc->bounce_length = data_bytes; + } + + desc->length = data_bytes; +} + +static void queue_direct_data(uint8_t *data, uint32_t data_bytes, + enum qspi_mode data_mode, bool write) +{ + struct cmd_desc *desc; + + desc = allocate_descriptor(); + desc->direction = write; + desc->multi_io_mode = data_mode; + desc->data_address = (uint32_t)(uintptr_t) data; + desc->length = data_bytes; + + if (write) + dcache_clean_by_mva(data, data_bytes); + else + dcache_invalidate_by_mva(data, data_bytes); +} + +static void queue_data(uint8_t *data, uint32_t data_bytes, + enum qspi_mode data_mode, bool write) +{ + uint8_t *aligned_ptr; + uint8_t *epilog_ptr; + uint32_t prolog_bytes, aligned_bytes, epilog_bytes; + + if (data_bytes == 0) + return; + + aligned_ptr = + (uint8_t *)ALIGN_UP((uintptr_t)data, CACHE_LINE_SIZE); + + prolog_bytes = MIN(data_bytes, aligned_ptr - data); + aligned_bytes = ALIGN_DOWN(data_bytes - prolog_bytes, CACHE_LINE_SIZE); + epilog_bytes = data_bytes - prolog_bytes - aligned_bytes; + + epilog_ptr = data + prolog_bytes + aligned_bytes; + + if (prolog_bytes) + queue_bounce_data(data, prolog_bytes, data_mode, write); + if (aligned_bytes) + queue_direct_data(aligned_ptr, aligned_bytes, data_mode, write); + if (epilog_bytes) + queue_bounce_data(epilog_ptr, epilog_bytes, data_mode, write); +} + +static void reg_init(void) +{ + uint32_t spi_mode; + uint32_t tx_data_oe_delay, tx_data_delay; + uint32_t mstr_config; + + spi_mode = 0; + + tx_data_oe_delay = 0; + tx_data_delay = 0; + + mstr_config = (tx_data_oe_delay << TX_DATA_OE_DELAY_SHIFT) | + (tx_data_delay << TX_DATA_DELAY_SHIFT) | (SBL_EN) | + (spi_mode << SPI_MODE_SHIFT) | + (PIN_HOLDN) | + (FB_CLK_EN) | + (DMA_ENABLE) | + (FULL_CYCLE_MODE); + + write32(&sc7180_qspi->mstr_cfg, mstr_config); + write32(&sc7180_qspi->ahb_mstr_cfg, 0xA42); + write32(&sc7180_qspi->mstr_int_en, 0x0); + write32(&sc7180_qspi->mstr_int_sts, 0xFFFFFFFF); + write32(&sc7180_qspi->rd_fifo_cfg, 0x0); + write32(&sc7180_qspi->rd_fifo_rst, RESET_FIFO); +} + +void quadspi_init(uint32_t hz) +{ + assert(dcache_line_bytes() == CACHE_LINE_SIZE); + clock_configure_qspi(hz * 4); + configure_gpios(); + reg_init(); +} + +int sc7180_claim_bus(const struct spi_slave *slave) +{ + cs_change(CS_ASSERT); + return 0; +} + +void sc7180_release_bus(const struct spi_slave *slave) +{ + cs_change(CS_DEASSERT); +} + +static int xfer(enum qspi_mode mode, const void *dout, size_t out_bytes, + void *din, size_t in_bytes) +{ + if ((out_bytes && !dout) || (in_bytes && !din) || + (in_bytes && out_bytes)) { + return -1; + } + + queue_data((uint8_t *) (out_bytes ? dout : din), + in_bytes | out_bytes, mode, !!out_bytes); + + flush_chain(); + + return 0; +} + +int sc7180_xfer(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes) +{ + return xfer(SDR_1BIT, dout, out_bytes, din, in_bytes); +} + +int sc7180_xfer_dual(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes) +{ + return xfer(SDR_2BIT, dout, out_bytes, din, in_bytes); +} diff --git a/src/soc/qualcomm/sc7180/spi.c b/src/soc/qualcomm/sc7180/spi.c index 5abb81a..c6d4cb1 100644 --- a/src/soc/qualcomm/sc7180/spi.c +++ b/src/soc/qualcomm/sc7180/spi.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,12 +15,19 @@
#include <spi-generic.h> #include <spi_flash.h> +#include <soc/qspi.h>
-static const struct spi_ctrlr spi_ctrlr; +static const struct spi_ctrlr qspi_ctrlr = { + .claim_bus = sc7180_claim_bus, + .release_bus = sc7180_release_bus, + .xfer = sc7180_xfer, + .xfer_dual = sc7180_xfer_dual, + .max_xfer_size = QSPI_MAX_PACKET_COUNT, +};
const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { { - .ctrlr = &spi_ctrlr, + .ctrlr = &qspi_ctrlr, .bus_start = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS, .bus_end = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS, },
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 11: Code-Review+2
Hello Julius Werner, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/35501
to look at the new patch set (#12).
Change subject: sc7180: Add SPI-NOR support ......................................................................
sc7180: Add SPI-NOR support
This implements the SPI-NOR driver for the Qualcomm QSPI core.
Developer/Reviewer, be aware of this patch from Napali: https://review.coreboot.org/c/coreboot/+/27483/58
Change-Id: I2eb8cf90aa4559541ba293b3fd2870896bed20b7 Signed-off-by: Akash Asthana akashast@codeaurora.org --- M src/soc/qualcomm/sc7180/Kconfig M src/soc/qualcomm/sc7180/Makefile.inc M src/soc/qualcomm/sc7180/bootblock.c A src/soc/qualcomm/sc7180/include/soc/qspi.h A src/soc/qualcomm/sc7180/qspi.c M src/soc/qualcomm/sc7180/spi.c 6 files changed, 452 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/35501/12
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 13: Code-Review+2
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 18:
A lot of these patches are ready to commit and not dependent on the QUP stuff (which I assume will still take a while). If you reorder them to the front we could already get them out of the way?
Hello Julius Werner, Ravi kumar, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/35501
to look at the new patch set (#19).
Change subject: sc7180: Add SPI-NOR support ......................................................................
sc7180: Add SPI-NOR support
This implements the SPI-NOR driver for the Qualcomm QSPI core.
Developer/Reviewer, be aware of this patch from Napali: https://review.coreboot.org/c/coreboot/+/27483/58
Change-Id: I2eb8cf90aa4559541ba293b3fd2870896bed20b7 Signed-off-by: Akash Asthana akashast@codeaurora.org --- M src/soc/qualcomm/sc7180/Kconfig M src/soc/qualcomm/sc7180/Makefile.inc M src/soc/qualcomm/sc7180/bootblock.c A src/soc/qualcomm/sc7180/include/soc/qspi.h A src/soc/qualcomm/sc7180/qspi.c M src/soc/qualcomm/sc7180/spi.c 6 files changed, 452 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/35501/19
mturney mturney has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 19:
Patch Set 18:
A lot of these patches are ready to commit and not dependent on the QUP stuff (which I assume will still take a while). If you reorder them to the front we could already get them out of the way?
We re-ordered the patch-train like this: * libpayload header file (only patch that doesn't depend on clock and/or qup) * clock patch * all patches that depend on clock patch (most/all of these are +2) * qupV3 FW patch * all patches that depend on qupV3 FW patch * everything else
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 19: Code-Review+2
Hello Julius Werner, Ravi kumar, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/35501
to look at the new patch set (#20).
Change subject: sc7180: Add SPI-NOR support ......................................................................
sc7180: Add SPI-NOR support
This implements the SPI-NOR driver for the Qualcomm QSPI core.
Developer/Reviewer, be aware of this patch from Napali: https://review.coreboot.org/c/coreboot/+/27483/58
Change-Id: I2eb8cf90aa4559541ba293b3fd2870896bed20b7 Signed-off-by: Akash Asthana akashast@codeaurora.org --- M src/soc/qualcomm/sc7180/Kconfig M src/soc/qualcomm/sc7180/Makefile.inc M src/soc/qualcomm/sc7180/bootblock.c A src/soc/qualcomm/sc7180/include/soc/qspi.h A src/soc/qualcomm/sc7180/qspi.c M src/soc/qualcomm/sc7180/spi.c 6 files changed, 452 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/35501/20
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 20: Code-Review+2
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 21:
Approval from non-uploader required
Oh god Gerrit, come on... I shouldn't need another approver now just because I hit the damn "rebase" button! -.-
T.Mike, it wouldn't let me merge this as it was for some reason... if you could just fetch the latest ToT again, rebase the whole train on top of that and reupload, I should be able to merge the +2ed ones.
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
Patch Set 21: Code-Review+2
Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/35501 )
Change subject: sc7180: Add SPI-NOR support ......................................................................
sc7180: Add SPI-NOR support
This implements the SPI-NOR driver for the Qualcomm QSPI core.
Developer/Reviewer, be aware of this patch from Napali: https://review.coreboot.org/c/coreboot/+/27483/58
Change-Id: I2eb8cf90aa4559541ba293b3fd2870896bed20b7 Signed-off-by: Akash Asthana akashast@codeaurora.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/35501 Reviewed-by: Patrick Georgi pgeorgi@google.com Reviewed-by: Julius Werner jwerner@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/soc/qualcomm/sc7180/Kconfig M src/soc/qualcomm/sc7180/Makefile.inc M src/soc/qualcomm/sc7180/bootblock.c A src/soc/qualcomm/sc7180/include/soc/qspi.h A src/soc/qualcomm/sc7180/qspi.c M src/soc/qualcomm/sc7180/spi.c 6 files changed, 452 insertions(+), 3 deletions(-)
Approvals: build bot (Jenkins): Verified Patrick Georgi: Looks good to me, approved Julius Werner: Looks good to me, approved
diff --git a/src/soc/qualcomm/sc7180/Kconfig b/src/soc/qualcomm/sc7180/Kconfig index 70737e9..4093c93 100644 --- a/src/soc/qualcomm/sc7180/Kconfig +++ b/src/soc/qualcomm/sc7180/Kconfig @@ -22,4 +22,13 @@ select VBOOT_MUST_REQUEST_DISPLAY select VBOOT_STARTS_IN_BOOTBLOCK
+config SC7180_QSPI + bool + default y if COMMON_CBFS_SPI_WRAPPER + prompt "Build Flash Using SPI-NOR" + +config BOOT_DEVICE_SPI_FLASH_BUS + int + default 16 + endif diff --git a/src/soc/qualcomm/sc7180/Makefile.inc b/src/soc/qualcomm/sc7180/Makefile.inc index 6b492d5..e1d0492 100644 --- a/src/soc/qualcomm/sc7180/Makefile.inc +++ b/src/soc/qualcomm/sc7180/Makefile.inc @@ -9,6 +9,7 @@ bootblock-y += gpio.c bootblock-$(CONFIG_DRIVERS_UART) += uart_bitbang.c bootblock-y += clock.c +bootblock-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################ verstage-y += timer.c @@ -16,6 +17,7 @@ verstage-y += gpio.c verstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c verstage-y += clock.c +verstage-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################ romstage-y += cbmem.c @@ -28,6 +30,7 @@ romstage-y += gpio.c romstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c romstage-y += clock.c +romstage-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################ ramstage-y += soc.c @@ -36,6 +39,7 @@ ramstage-y += gpio.c ramstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c ramstage-y += clock.c +ramstage-$(CONFIG_SC7180_QSPI) += qspi.c
################################################################################
diff --git a/src/soc/qualcomm/sc7180/bootblock.c b/src/soc/qualcomm/sc7180/bootblock.c index bf80bff..4f97d76 100644 --- a/src/soc/qualcomm/sc7180/bootblock.c +++ b/src/soc/qualcomm/sc7180/bootblock.c @@ -16,9 +16,11 @@ #include <bootblock_common.h> #include <soc/clock.h> #include <soc/mmu.h> +#include <soc/qspi.h>
void bootblock_soc_init(void) { sc7180_mmu_init(); clock_init(); + quadspi_init(25 * MHz); } diff --git a/src/soc/qualcomm/sc7180/include/soc/qspi.h b/src/soc/qualcomm/sc7180/include/soc/qspi.h new file mode 100644 index 0000000..c3d1f78 --- /dev/null +++ b/src/soc/qualcomm/sc7180/include/soc/qspi.h @@ -0,0 +1,121 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2019 Qualcomm Technologies. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 <types.h> +#include <soc/addressmap.h> +#include <spi-generic.h> + +#ifndef __SOC_QUALCOMM_SC7180_QSPI_H__ +#define __SOC_QUALCOMM_SC7180_QSPI_H__ + +struct sc7180_qspi_regs { + u32 mstr_cfg; + u32 ahb_mstr_cfg; + u32 reserve_0; + u32 mstr_int_en; + u32 mstr_int_sts; + u32 pio_xfer_ctrl; + u32 pio_xfer_cfg; + u32 pio_xfer_sts; + u32 pio_dataout_1byte; + u32 pio_dataout_4byte; + u32 rd_fifo_cfg; + u32 rd_fifo_sts; + u32 rd_fifo_rst; + u32 reserve_1[3]; + u32 next_dma_desc_addr; + u32 current_dma_desc_addr; + u32 current_mem_addr; + u32 hw_version; + u32 rd_fifo[16]; +}; + +check_member(sc7180_qspi_regs, rd_fifo, 0x50); +static struct sc7180_qspi_regs * const sc7180_qspi = (void *) QSPI_BASE; + +// MSTR_CONFIG register + +#define TX_DATA_OE_DELAY_SHIFT 24 +#define TX_DATA_OE_DELAY_MASK (0x3 << TX_DATA_OE_DELAY_SHIFT) +#define TX_CS_N_DELAY_SHIFT 22 +#define TX_CS_N_DELAY_MASK (0x3 << TX_CS_N_DELAY_SHIFT) +#define TX_CLK_DELAY_SHIFT 20 +#define TX_CLK_DELAY_MASK (0x3 << TX_CLK_DELAY_SHIFT) +#define TX_DATA_DELAY_SHIFT 18 +#define TX_DATA_DELAY_MASK (0x3 << TX_DATA_DELAY_SHIFT) +#define LPA_BASE_SHIFT 14 +#define LPA_BASE_MASK (0xF << LPA_BASE_SHIFT) +#define SBL_EN BIT(13) +#define CHIP_SELECT_NUM BIT(12) +#define SPI_MODE_SHIFT 10 +#define SPI_MODE_MASK (0x3 << SPI_MODE_SHIFT) +#define BIG_ENDIAN_MODE BIT(9) +#define DMA_ENABLE BIT(8) +#define PIN_WPN BIT(7) +#define PIN_HOLDN BIT(6) +#define FB_CLK_EN BIT(4) +#define FULL_CYCLE_MODE BIT(3) + +// MSTR_INT_ENABLE and MSTR_INT_STATUS register + +#define DMA_CHAIN_DONE BIT(31) +#define TRANSACTION_DONE BIT(16) +#define WRITE_FIFO_OVERRUN BIT(11) +#define WRITE_FIFO_FULL BIT(10) +#define HRESP_FROM_NOC_ERR BIT(3) +#define RESP_FIFO_RDY BIT(2) +#define RESP_FIFO_NOT_EMPTY BIT(1) +#define RESP_FIFO_UNDERRUN BIT(0) + +// PIO_TRANSFER_CONFIG register + +#define TRANSFER_FRAGMENT BIT(8) +#define MULTI_IO_MODE_SHIFT 1 +#define MULTI_IO_MODE_MASK (0x7 << MULTI_IO_MODE_SHIFT) +#define TRANSFER_DIRECTION BIT(0) + +// PIO_TRANSFER_STATUS register + +#define WR_FIFO_BYTES_SHIFT 16 +#define WR_FIFO_BYTES_MASK (0xFFFF << WR_FIFO_BYTES_SHIFT) + +// RD_FIFO_CONFIG register + +#define CONTINUOUS_MODE BIT(0) + +// RD_FIFO_STATUS register + +#define FIFO_EMPTY BIT(11) +#define WR_CNTS_SHIFT 4 +#define WR_CNTS_MASK (0x7F << WR_CNTS_SHIFT) +#define RDY_64BYTE BIT(3) +#define RDY_32BYTE BIT(2) +#define RDY_16BYTE BIT(1) +#define FIFO_RDY BIT(0) + +// RD_FIFO_RESET register + +#define RESET_FIFO BIT(0) + +#define QSPI_MAX_PACKET_COUNT 0xFFC0 + +void quadspi_init(uint32_t hz); +int sc7180_claim_bus(const struct spi_slave *slave); +int sc7180_setup_bus(const struct spi_slave *slave); +void sc7180_release_bus(const struct spi_slave *slave); +int sc7180_xfer(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes); +int sc7180_xfer_dual(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes); +#endif /* __SOC_QUALCOMM_SC7180_QSPI_H__ */ diff --git a/src/soc/qualcomm/sc7180/qspi.c b/src/soc/qualcomm/sc7180/qspi.c new file mode 100644 index 0000000..30dc1c3 --- /dev/null +++ b/src/soc/qualcomm/sc7180/qspi.c @@ -0,0 +1,306 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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-generic.h> +#include <spi_flash.h> +#include <arch/cache.h> +#include <device/mmio.h> +#include <soc/addressmap.h> +#include <soc/qspi.h> +#include <soc/gpio.h> +#include <soc/clock.h> +#include <symbols.h> +#include <assert.h> +#include <gpio.h> +#include <string.h> + +#define CACHE_LINE_SIZE 64 + +static int curr_desc_idx = -1; + +struct cmd_desc { + uint32_t data_address; + uint32_t next_descriptor; + uint32_t direction:1; + uint32_t multi_io_mode:3; + uint32_t reserved1:4; + uint32_t fragment:1; + uint32_t reserved2:7; + uint32_t length:16; + //------------------------// + uint32_t bounce_src; + uint32_t bounce_dst; + uint32_t bounce_length; + uint64_t padding[5]; +}; + +enum qspi_mode { + SDR_1BIT = 1, + SDR_2BIT = 2, + SDR_4BIT = 3, + DDR_1BIT = 5, + DDR_2BIT = 6, + DDR_4BIT = 7, +}; + +enum cs_state { + CS_DEASSERT, + CS_ASSERT +}; + +struct xfer_cfg { + enum qspi_mode mode; +}; + +enum bus_xfer_direction { + MASTER_READ = 0, + MASTER_WRITE = 1, +}; + +struct { + struct cmd_desc descriptors[3]; + uint8_t buffers[3][CACHE_LINE_SIZE]; +} *dma = (void *)_dma_coherent; + +static void dma_transfer_chain(struct cmd_desc *chain) +{ + uint32_t mstr_int_status; + + write32(&sc7180_qspi->mstr_int_sts, 0xFFFFFFFF); + write32(&sc7180_qspi->next_dma_desc_addr, (uint32_t)(uintptr_t) chain); + + while (1) { + mstr_int_status = read32(&sc7180_qspi->mstr_int_sts); + if (mstr_int_status & DMA_CHAIN_DONE) + break; + } +} + +static void flush_chain(void) +{ + struct cmd_desc *desc = &dma->descriptors[0]; + uint8_t *src; + uint8_t *dst; + + dma_transfer_chain(desc); + + while (desc) { + if (desc->direction == MASTER_READ) { + if (desc->bounce_length == 0) + dcache_invalidate_by_mva( + (void *)(uintptr_t) desc->data_address, + desc->length); + else { + src = (void *)(uintptr_t) desc->bounce_src; + dst = (void *)(uintptr_t) desc->bounce_dst; + memcpy(dst, src, desc->bounce_length); + } + } + desc = (void *)(uintptr_t) desc->next_descriptor; + } + curr_desc_idx = -1; +} + +static struct cmd_desc *allocate_descriptor(void) +{ + struct cmd_desc *current; + struct cmd_desc *next; + uint8_t index; + + current = (curr_desc_idx == -1) ? + NULL : &dma->descriptors[curr_desc_idx]; + + index = ++curr_desc_idx; + next = &dma->descriptors[index]; + + next->data_address = (uint32_t) (uintptr_t) dma->buffers[index]; + + next->next_descriptor = 0; + next->direction = MASTER_READ; + next->multi_io_mode = 0; + next->reserved1 = 0; + next->fragment = 0; + next->reserved2 = 0; + next->length = 0; + next->bounce_src = 0; + next->bounce_dst = 0; + next->bounce_length = 0; + + if (current) { + current->next_descriptor = (uint32_t)(uintptr_t) next; + current->fragment = 1; + } + + return next; +} + +static void cs_change(enum cs_state state) +{ + gpio_set(GPIO(68), state == CS_DEASSERT); +} + +static void configure_gpios(void) +{ + gpio_output(GPIO(68), 1); + + gpio_configure(GPIO(64), GPIO64_FUNC_QSPI_DATA_0, + GPIO_NO_PULL, GPIO_2MA, GPIO_OUTPUT_ENABLE); + + gpio_configure(GPIO(65), GPIO65_FUNC_QSPI_DATA_1, + GPIO_NO_PULL, GPIO_2MA, GPIO_OUTPUT_ENABLE); + + gpio_configure(GPIO(63), GPIO63_FUNC_QSPI_CLK, + GPIO_NO_PULL, GPIO_2MA, GPIO_OUTPUT_ENABLE); +} + +static void queue_bounce_data(uint8_t *data, uint32_t data_bytes, + enum qspi_mode data_mode, bool write) +{ + struct cmd_desc *desc; + uint8_t *ptr; + + desc = allocate_descriptor(); + desc->direction = write; + desc->multi_io_mode = data_mode; + ptr = (void *)(uintptr_t) desc->data_address; + + if (write) { + memcpy(ptr, data, data_bytes); + } else { + desc->bounce_src = (uint32_t)(uintptr_t) ptr; + desc->bounce_dst = (uint32_t)(uintptr_t) data; + desc->bounce_length = data_bytes; + } + + desc->length = data_bytes; +} + +static void queue_direct_data(uint8_t *data, uint32_t data_bytes, + enum qspi_mode data_mode, bool write) +{ + struct cmd_desc *desc; + + desc = allocate_descriptor(); + desc->direction = write; + desc->multi_io_mode = data_mode; + desc->data_address = (uint32_t)(uintptr_t) data; + desc->length = data_bytes; + + if (write) + dcache_clean_by_mva(data, data_bytes); + else + dcache_invalidate_by_mva(data, data_bytes); +} + +static void queue_data(uint8_t *data, uint32_t data_bytes, + enum qspi_mode data_mode, bool write) +{ + uint8_t *aligned_ptr; + uint8_t *epilog_ptr; + uint32_t prolog_bytes, aligned_bytes, epilog_bytes; + + if (data_bytes == 0) + return; + + aligned_ptr = + (uint8_t *)ALIGN_UP((uintptr_t)data, CACHE_LINE_SIZE); + + prolog_bytes = MIN(data_bytes, aligned_ptr - data); + aligned_bytes = ALIGN_DOWN(data_bytes - prolog_bytes, CACHE_LINE_SIZE); + epilog_bytes = data_bytes - prolog_bytes - aligned_bytes; + + epilog_ptr = data + prolog_bytes + aligned_bytes; + + if (prolog_bytes) + queue_bounce_data(data, prolog_bytes, data_mode, write); + if (aligned_bytes) + queue_direct_data(aligned_ptr, aligned_bytes, data_mode, write); + if (epilog_bytes) + queue_bounce_data(epilog_ptr, epilog_bytes, data_mode, write); +} + +static void reg_init(void) +{ + uint32_t spi_mode; + uint32_t tx_data_oe_delay, tx_data_delay; + uint32_t mstr_config; + + spi_mode = 0; + + tx_data_oe_delay = 0; + tx_data_delay = 0; + + mstr_config = (tx_data_oe_delay << TX_DATA_OE_DELAY_SHIFT) | + (tx_data_delay << TX_DATA_DELAY_SHIFT) | (SBL_EN) | + (spi_mode << SPI_MODE_SHIFT) | + (PIN_HOLDN) | + (FB_CLK_EN) | + (DMA_ENABLE) | + (FULL_CYCLE_MODE); + + write32(&sc7180_qspi->mstr_cfg, mstr_config); + write32(&sc7180_qspi->ahb_mstr_cfg, 0xA42); + write32(&sc7180_qspi->mstr_int_en, 0x0); + write32(&sc7180_qspi->mstr_int_sts, 0xFFFFFFFF); + write32(&sc7180_qspi->rd_fifo_cfg, 0x0); + write32(&sc7180_qspi->rd_fifo_rst, RESET_FIFO); +} + +void quadspi_init(uint32_t hz) +{ + assert(dcache_line_bytes() == CACHE_LINE_SIZE); + clock_configure_qspi(hz * 4); + configure_gpios(); + reg_init(); +} + +int sc7180_claim_bus(const struct spi_slave *slave) +{ + cs_change(CS_ASSERT); + return 0; +} + +void sc7180_release_bus(const struct spi_slave *slave) +{ + cs_change(CS_DEASSERT); +} + +static int xfer(enum qspi_mode mode, const void *dout, size_t out_bytes, + void *din, size_t in_bytes) +{ + if ((out_bytes && !dout) || (in_bytes && !din) || + (in_bytes && out_bytes)) { + return -1; + } + + queue_data((uint8_t *) (out_bytes ? dout : din), + in_bytes | out_bytes, mode, !!out_bytes); + + flush_chain(); + + return 0; +} + +int sc7180_xfer(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes) +{ + return xfer(SDR_1BIT, dout, out_bytes, din, in_bytes); +} + +int sc7180_xfer_dual(const struct spi_slave *slave, const void *dout, + size_t out_bytes, void *din, size_t in_bytes) +{ + return xfer(SDR_2BIT, dout, out_bytes, din, in_bytes); +} diff --git a/src/soc/qualcomm/sc7180/spi.c b/src/soc/qualcomm/sc7180/spi.c index 5abb81a..c6d4cb1 100644 --- a/src/soc/qualcomm/sc7180/spi.c +++ b/src/soc/qualcomm/sc7180/spi.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,12 +15,19 @@
#include <spi-generic.h> #include <spi_flash.h> +#include <soc/qspi.h>
-static const struct spi_ctrlr spi_ctrlr; +static const struct spi_ctrlr qspi_ctrlr = { + .claim_bus = sc7180_claim_bus, + .release_bus = sc7180_release_bus, + .xfer = sc7180_xfer, + .xfer_dual = sc7180_xfer_dual, + .max_xfer_size = QSPI_MAX_PACKET_COUNT, +};
const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { { - .ctrlr = &spi_ctrlr, + .ctrlr = &qspi_ctrlr, .bus_start = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS, .bus_end = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS, },