diff options
author | Marek Vasut <marex@denx.de> | 2016-04-28 00:38:05 +0300 |
---|---|---|
committer | Marek Vasut <marex@denx.de> | 2016-05-06 19:41:49 +0300 |
commit | 5a824c493a31d06f04a6736fab8f67bf78145003 (patch) | |
tree | 97ed67070ca2b81431dc436c9ea9f83d272b70ab /drivers/spi/cadence_qspi_apb.c | |
parent | 26da6353e17111d7f0882866950cf26a679b8d5f (diff) | |
download | u-boot-5a824c493a31d06f04a6736fab8f67bf78145003.tar.xz |
mtd: cqspi: Simplify indirect read code
The indirect read code is a pile of nastiness. This patch replaces
the whole unmaintainable indirect read implementation with the one
from upcoming Linux CQSPI driver, which went through multiple rounds
of thorough review and testing. All the patch does is it plucks out
duplicate ad-hoc code distributed across the driver and replaces it
with more compact code doing exactly the same thing. There is no
speed change of the read operation.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Anatolij Gustschin <agust@denx.de>
Cc: Chin Liang See <clsee@altera.com>
Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
Cc: Jagan Teki <jteki@openedev.com>
Cc: Pavel Machek <pavel@denx.de>
Cc: Stefan Roese <sr@denx.de>
Cc: Vignesh R <vigneshr@ti.com>
Diffstat (limited to 'drivers/spi/cadence_qspi_apb.c')
-rw-r--r-- | drivers/spi/cadence_qspi_apb.c | 128 |
1 files changed, 57 insertions, 71 deletions
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 5e84144940..a71531d309 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -193,64 +193,6 @@ static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf, return addr; } -static void cadence_qspi_apb_read_fifo_data(void *dest, - const void *src_ahb_addr, unsigned int bytes) -{ - unsigned int temp; - int remaining = bytes; - unsigned int *dest_ptr = (unsigned int *)dest; - unsigned int *src_ptr = (unsigned int *)src_ahb_addr; - - while (remaining >= sizeof(dest_ptr)) { - *dest_ptr = readl(src_ptr); - remaining -= sizeof(src_ptr); - dest_ptr++; - } - if (remaining) { - /* dangling bytes */ - temp = readl(src_ptr); - memcpy(dest_ptr, &temp, remaining); - } - - return; -} - -/* Read from SRAM FIFO with polling SRAM fill level. */ -static int qspi_read_sram_fifo_poll(const void *reg_base, void *dest_addr, - const void *src_addr, unsigned int num_bytes) -{ - unsigned int remaining = num_bytes; - unsigned int retry; - unsigned int sram_level = 0; - unsigned char *dest = (unsigned char *)dest_addr; - - while (remaining > 0) { - retry = CQSPI_REG_RETRY; - while (retry--) { - sram_level = CQSPI_GET_RD_SRAM_LEVEL(reg_base); - if (sram_level) - break; - udelay(1); - } - - if (!retry) { - printf("QSPI: No receive data after polling for %d times\n", - CQSPI_REG_RETRY); - return -1; - } - - sram_level *= CQSPI_FIFO_WIDTH; - sram_level = sram_level > remaining ? remaining : sram_level; - - /* Read data from FIFO. */ - cadence_qspi_apb_read_fifo_data(dest, src_addr, sram_level); - dest += sram_level; - remaining -= sram_level; - udelay(1); - } - return 0; -} - void cadence_qspi_apb_controller_enable(void *reg_base) { unsigned int reg; @@ -679,40 +621,84 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, return 0; } +static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_platdata *plat) +{ + u32 reg = readl(plat->regbase + CQSPI_REG_SDRAMLEVEL); + reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; + return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; +} + +static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat) +{ + unsigned int timeout = 10000; + u32 reg; + + while (timeout--) { + reg = cadence_qspi_get_rd_sram_level(plat); + if (reg) + return reg; + udelay(1); + } + + return -ETIMEDOUT; +} + int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, - unsigned int rxlen, u8 *rxbuf) + unsigned int n_rx, u8 *rxbuf) { - unsigned int reg; + unsigned int remaining = n_rx; + unsigned int bytes_to_read = 0; + int ret; - writel(rxlen, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); + writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); /* Start the indirect read transfer */ writel(CQSPI_REG_INDIRECTRD_START_MASK, plat->regbase + CQSPI_REG_INDIRECTRD); - if (qspi_read_sram_fifo_poll(plat->regbase, (void *)rxbuf, - (const void *)plat->ahbbase, rxlen)) - goto failrd; + while (remaining > 0) { + ret = cadence_qspi_wait_for_data(plat); + if (ret < 0) { + printf("Indirect write timed out (%i)\n", ret); + goto failrd; + } + + bytes_to_read = ret; + + while (bytes_to_read != 0) { + bytes_to_read *= CQSPI_FIFO_WIDTH; + bytes_to_read = bytes_to_read > remaining ? + remaining : bytes_to_read; + /* Handle non-4-byte aligned access to avoid data abort. */ + if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4)) + readsb(plat->ahbbase, rxbuf, bytes_to_read); + else + readsl(plat->ahbbase, rxbuf, bytes_to_read >> 2); + rxbuf += bytes_to_read; + remaining -= bytes_to_read; + bytes_to_read = cadence_qspi_get_rd_sram_level(plat); + } + } - /* Check flash indirect controller */ - reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD); - if (!(reg & CQSPI_REG_INDIRECTRD_DONE_MASK)) { - reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD); - printf("QSPI: indirect completion status error with reg 0x%08x\n", - reg); + /* Check indirect done status */ + ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_INDIRECTRD, + CQSPI_REG_INDIRECTRD_DONE_MASK, 1, 10, 0); + if (ret) { + printf("Indirect read completion error (%i)\n", ret); goto failrd; } /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTRD_DONE_MASK, plat->regbase + CQSPI_REG_INDIRECTRD); + return 0; failrd: /* Cancel the indirect read */ writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK, plat->regbase + CQSPI_REG_INDIRECTRD); - return -1; + return ret; } /* Opcode + Address (3/4 bytes) */ |