From patchwork Tue May 3 17:25:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 618108 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3qzp4H4hbfz9sdg for ; Wed, 4 May 2016 03:26:23 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5EBFBA77F7; Tue, 3 May 2016 19:26:21 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EJTn6y-u-LMW; Tue, 3 May 2016 19:26:21 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F11B1A7794; Tue, 3 May 2016 19:26:20 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 431A2A7794 for ; Tue, 3 May 2016 19:26:17 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IUbT4cwIbBrM for ; Tue, 3 May 2016 19:26:17 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-out.m-online.net (mail-out.m-online.net [212.18.0.9]) by theia.denx.de (Postfix) with ESMTPS id AC6BBA77D1 for ; Tue, 3 May 2016 19:26:15 +0200 (CEST) Received: from mail.nefkom.net (unknown [192.168.8.184]) by mail-out.m-online.net (Postfix) with ESMTP id 3qzp4730pJz3hjQw; Tue, 3 May 2016 19:26:15 +0200 (CEST) X-Auth-Info: RiVHNdQDAU0vTCGtLtixw+uiq/Z5EaNJaYOs2gAt43Y= Received: from chi.lan (unknown [195.140.253.167]) by smtp-auth.mnet-online.de (Postfix) with ESMTPA id 3qzp3w3WP7zvdWS; Tue, 3 May 2016 19:26:03 +0200 (CEST) From: Marek Vasut To: u-boot@lists.denx.de Date: Tue, 3 May 2016 19:25:57 +0200 Message-Id: <1462296357-5921-2-git-send-email-marex@denx.de> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1462296357-5921-1-git-send-email-marex@denx.de> References: <1462296357-5921-1-git-send-email-marex@denx.de> Cc: Marek Vasut , Stefan Roese , Pavel Machek , Chin Liang See , Jagan Teki Subject: [U-Boot] [PATCH V2 2/2] mtd: cqspi: Simplify indirect read code X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 Cc: Anatolij Gustschin Cc: Chin Liang See Cc: Dinh Nguyen Cc: Jagan Teki Cc: Pavel Machek Cc: Stefan Roese Cc: Vignesh R Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- V2: Handle non-4-byte aligned transfers --- drivers/spi/cadence_qspi_apb.c | 128 ++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 71 deletions(-) diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 5e84144..a71531d 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) */