From patchwork Mon Jan 27 05:06:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Raghavendra, Vignesh" X-Patchwork-Id: 1229498 X-Patchwork-Delegate: jagannadh.teki@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ti.com header.i=@ti.com header.a=rsa-sha256 header.s=ti-com-17Q1 header.b=Hf36hR9W; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 485d5b419dz9sRR for ; Mon, 27 Jan 2020 16:06:59 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 3BD3C816DA; Mon, 27 Jan 2020 06:06:42 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ti.com header.i=@ti.com header.b="Hf36hR9W"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 32AE4814DE; Mon, 27 Jan 2020 06:06:35 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from fllv0015.ext.ti.com (fllv0015.ext.ti.com [198.47.19.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 92152814DA for ; Mon, 27 Jan 2020 06:06:30 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=vigneshr@ti.com Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id 00R56R4c023941; Sun, 26 Jan 2020 23:06:27 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1580101587; bh=rfYIlO5dbpza2aMUMYayN9ucNKH0PUTGpADztYUe69g=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=Hf36hR9WK11MEkmo3naRgNDpzIr37TwjppvodooSzotv6wjM3d4Wb4APyWkF8IKQB 3vdbtYZn1we8YtMM0liWuWxO52RcJPEr0rT3hVI6yc3fr5Y1NaJjojUW/uPo+Yl8md TXJCX3EFXG2NfLpVhekhPn7bNFIMmZNDfv4XsGAQ= Received: from DFLE103.ent.ti.com (dfle103.ent.ti.com [10.64.6.24]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTP id 00R56R0F068354; Sun, 26 Jan 2020 23:06:27 -0600 Received: from DFLE111.ent.ti.com (10.64.6.32) by DFLE103.ent.ti.com (10.64.6.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1847.3; Sun, 26 Jan 2020 23:06:27 -0600 Received: from lelv0327.itg.ti.com (10.180.67.183) by DFLE111.ent.ti.com (10.64.6.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1847.3 via Frontend Transport; Sun, 26 Jan 2020 23:06:27 -0600 Received: from a0132425.dhcp.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by lelv0327.itg.ti.com (8.15.2/8.15.2) with ESMTP id 00R56K9o111828; Sun, 26 Jan 2020 23:06:25 -0600 From: Vignesh Raghavendra To: Jagan Teki Subject: [RESEND v2 2/2] spi: cadence-qspi: Add direct mode support Date: Mon, 27 Jan 2020 10:36:40 +0530 Message-ID: <20200127050640.12532-3-vigneshr@ti.com> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200127050640.12532-1-vigneshr@ti.com> References: <20200127050640.12532-1-vigneshr@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, Tom Rini Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean Add support for Direct Access Controller mode of Cadence QSPI. This allows MMIO access to SPI NOR flash providing better read performance. Direct mode is only exercised if AHB window size is greater than 8MB. Support for flash address remapping is also not supported at the moment and can be added in future. For better performance, driver uses DMA to copy data from flash in direct mode using dma_memcpy(). Signed-off-by: Vignesh Raghavendra Tested-by: Simon Goldschmidt --- drivers/spi/cadence_qspi.c | 40 ++++++++++++--------- drivers/spi/cadence_qspi.h | 19 +++++----- drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++----- 3 files changed, 91 insertions(+), 33 deletions(-) diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 86c910a8dac3..619fff70de2f 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -13,12 +13,13 @@ #include #include #include +#include #include "cadence_qspi.h" #define CQSPI_STIG_READ 0 #define CQSPI_STIG_WRITE 1 -#define CQSPI_INDIRECT_READ 2 -#define CQSPI_INDIRECT_WRITE 3 +#define CQSPI_READ 2 +#define CQSPI_WRITE 3 static int cadence_spi_write_speed(struct udevice *bus, uint hz) { @@ -190,6 +191,7 @@ static int cadence_spi_remove(struct udevice *dev) static int cadence_spi_set_mode(struct udevice *bus, uint mode) { + struct cadence_spi_platdata *plat = bus->platdata; struct cadence_spi_priv *priv = dev_get_priv(bus); /* Disable QSPI */ @@ -198,6 +200,10 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode) /* Set SPI mode */ cadence_qspi_apb_set_clk_mode(priv->regbase, mode); + /* Enable Direct Access Controller */ + if (plat->use_dac_mode) + cadence_qspi_apb_dac_mode_enable(priv->regbase); + /* Enable QSPI */ cadence_qspi_apb_controller_enable(priv->regbase); @@ -222,12 +228,12 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi, if (!op->addr.nbytes) mode = CQSPI_STIG_READ; else - mode = CQSPI_INDIRECT_READ; + mode = CQSPI_READ; } else { if (!op->addr.nbytes || !op->data.buf.out) mode = CQSPI_STIG_WRITE; else - mode = CQSPI_INDIRECT_WRITE; + mode = CQSPI_WRITE; } switch (mode) { @@ -237,19 +243,15 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi, case CQSPI_STIG_WRITE: err = cadence_qspi_apb_command_write(base, op); break; - case CQSPI_INDIRECT_READ: - err = cadence_qspi_apb_indirect_read_setup(plat, op); - if (!err) { - err = cadence_qspi_apb_indirect_read_execute - (plat, op->data.nbytes, op->data.buf.in); - } + case CQSPI_READ: + err = cadence_qspi_apb_read_setup(plat, op); + if (!err) + err = cadence_qspi_apb_read_execute(plat, op); break; - case CQSPI_INDIRECT_WRITE: - err = cadence_qspi_apb_indirect_write_setup(plat, op); - if (!err) { - err = cadence_qspi_apb_indirect_write_execute - (plat, op->data.nbytes, op->data.buf.out); - } + case CQSPI_WRITE: + err = cadence_qspi_apb_write_setup(plat, op); + if (!err) + err = cadence_qspi_apb_write_execute(plat, op); break; default: err = -1; @@ -267,13 +269,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus) int ret; plat->regbase = (void *)devfdt_get_addr_index(bus, 0); - plat->ahbbase = (void *)devfdt_get_addr_index(bus, 1); + plat->ahbbase = (void *)devfdt_get_addr_size_index(bus, 1, + &plat->ahbsize); plat->is_decoded_cs = dev_read_bool(bus, "cdns,is-decoded-cs"); plat->fifo_depth = dev_read_u32_default(bus, "cdns,fifo-depth", 128); plat->fifo_width = dev_read_u32_default(bus, "cdns,fifo-width", 4); plat->trigger_address = dev_read_u32_default(bus, "cdns,trigger-address", 0); + /* Use DAC mode only when MMIO window is at least 8M wide */ + if (plat->ahbsize >= SZ_8M) + plat->use_dac_mode = true; /* All other paramters are embedded in the child node */ subnode = dev_read_first_subnode(bus); diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index d66201ec923d..ae459c74a192 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -24,6 +24,8 @@ struct cadence_spi_platdata { u32 fifo_depth; u32 fifo_width; u32 trigger_address; + fdt_addr_t ahbsize; + bool use_dac_mode; /* Flash parameters */ u32 page_size; @@ -53,20 +55,21 @@ struct cadence_spi_priv { void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat); void cadence_qspi_apb_controller_enable(void *reg_base_addr); void cadence_qspi_apb_controller_disable(void *reg_base_addr); +void cadence_qspi_apb_dac_mode_enable(void *reg_base); int cadence_qspi_apb_command_read(void *reg_base_addr, const struct spi_mem_op *op); int cadence_qspi_apb_command_write(void *reg_base_addr, const struct spi_mem_op *op); -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, - const struct spi_mem_op *op); -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, - unsigned int rxlen, u8 *rxbuf); -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, - const struct spi_mem_op *op); -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, - unsigned int txlen, const u8 *txbuf); +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op); +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op); +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op); +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op); void cadence_qspi_apb_chipselect(void *reg_base, unsigned int chip_select, unsigned int decoder_enable); diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 8dd0495dfcf4..a0e14f93e020 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base) writel(reg, reg_base + CQSPI_REG_CONFIG); } +void cadence_qspi_apb_dac_mode_enable(void *reg_base) +{ + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg |= CQSPI_REG_CONFIG_DIRECT; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + /* Return 1 if idle, otherwise return 0 (busy). */ static unsigned int cadence_qspi_wait_idle(void *reg_base) { @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op) } /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */ -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, - const struct spi_mem_op *op) +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op) { unsigned int reg; unsigned int rd_reg; @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat) return -ETIMEDOUT; } -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, - unsigned int n_rx, u8 *rxbuf) +static int +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, + unsigned int n_rx, u8 *rxbuf) { unsigned int remaining = n_rx; unsigned int bytes_to_read = 0; @@ -639,9 +650,29 @@ failrd: return ret; } +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op) +{ + u32 from = op->addr.val; + void *buf = op->data.buf.in; + size_t len = op->data.nbytes; + + if (plat->use_dac_mode && (from + len < plat->ahbsize)) { + if (len < 256 || + dma_memcpy(buf, plat->ahbbase + from, len) < 0) { + memcpy_fromio(buf, plat->ahbbase + from, len); + } + if (!cadence_qspi_wait_idle(plat->regbase)) + return -EIO; + return 0; + } + + return cadence_qspi_apb_indirect_read_execute(plat, len, buf); +} + /* Opcode + Address (3/4 bytes) */ -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, - const struct spi_mem_op *op) +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op) { unsigned int reg; @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, return 0; } -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, - unsigned int n_tx, const u8 *txbuf) +static int +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, + unsigned int n_tx, const u8 *txbuf) { unsigned int page_size = plat->page_size; unsigned int remaining = n_tx; @@ -735,6 +767,23 @@ failwr: return ret; } +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat, + const struct spi_mem_op *op) +{ + u32 to = op->addr.val; + const void *buf = op->data.buf.out; + size_t len = op->data.nbytes; + + if (plat->use_dac_mode && (to + len < plat->ahbsize)) { + memcpy_toio(plat->ahbbase + to, buf, len); + if (!cadence_qspi_wait_idle(plat->regbase)) + return -EIO; + return 0; + } + + return cadence_qspi_apb_indirect_write_execute(plat, len, buf); +} + void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy) { unsigned int reg;