diff options
Diffstat (limited to 'src/soc/qualcomm/sc7180/qspi.c')
-rw-r--r-- | src/soc/qualcomm/sc7180/qspi.c | 296 |
1 files changed, 0 insertions, 296 deletions
diff --git a/src/soc/qualcomm/sc7180/qspi.c b/src/soc/qualcomm/sc7180/qspi.c deleted file mode 100644 index 825e298a73..0000000000 --- a/src/soc/qualcomm/sc7180/qspi.c +++ /dev/null @@ -1,296 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#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; - /* - * QSPI controller doesn't support transfer starts with read segment. - * So to support read transfers that are not preceded by write, set - * transfer fragment bit = 1 - */ - next->fragment = 1; - 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; - - 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); - - gpio_configure(GPIO(65), GPIO65_FUNC_QSPI_DATA_1, - GPIO_NO_PULL, GPIO_2MA, GPIO_OUTPUT); - - gpio_configure(GPIO(63), GPIO63_FUNC_QSPI_CLK, - GPIO_NO_PULL, GPIO_8MA, GPIO_OUTPUT); -} - -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); -} |