From patchwork Tue Jul 28 08:41:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vignesh Raghavendra X-Patchwork-Id: 6880461 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6D65A9F380 for ; Tue, 28 Jul 2015 08:44:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6566B2069F for ; Tue, 28 Jul 2015 08:44:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5C3C2206F1 for ; Tue, 28 Jul 2015 08:44:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752507AbbG1Io1 (ORCPT ); Tue, 28 Jul 2015 04:44:27 -0400 Received: from bear.ext.ti.com ([192.94.94.41]:60873 "EHLO bear.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755589AbbG1In0 (ORCPT ); Tue, 28 Jul 2015 04:43:26 -0400 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id t6S8gfVH002388; Tue, 28 Jul 2015 03:42:41 -0500 Received: from DLEE70.ent.ti.com (dlemailx.itg.ti.com [157.170.170.113]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id t6S8gfRY030027; Tue, 28 Jul 2015 03:42:41 -0500 Received: from dlep33.itg.ti.com (157.170.170.75) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.224.2; Tue, 28 Jul 2015 03:42:41 -0500 Received: from uda0132425.apr.dhcp.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep33.itg.ti.com (8.14.3/8.13.8) with ESMTP id t6S8gQCC028779; Tue, 28 Jul 2015 03:42:37 -0500 From: Vignesh R To: Mark Brown , David Woodhouse , Brian Norris , Tony Lindgren , Russell King CC: Huang Shijie , Vignesh R , , , , , , Subject: [RFC PATCH 2/5] spi: spi-ti-qspi: Add memory mapped read support Date: Tue, 28 Jul 2015 14:11:13 +0530 Message-ID: <1438072876-16338-3-git-send-email-vigneshr@ti.com> X-Mailer: git-send-email 2.4.6 In-Reply-To: <1438072876-16338-1-git-send-email-vigneshr@ti.com> References: <1438072876-16338-1-git-send-email-vigneshr@ti.com> MIME-Version: 1.0 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP TI QSPI controller has memory mapped port through which SPI flash memories can be read using memcpy call. This patch adds support for memory mapped read based on use_mmap_read flag. When use_mmap_read flag is set, the controller is switched to memory mapped interface by writing to QSPI_SPI_SWITCH_REG. The read_opcode, read mode, dummy bytes are configured in QSPI_SPI_SETUPx_REG, then memcpy is called to copy the requested data from flash to the rx_buf. With this patch, the read speed increased from ~100kB/s to ~2.5MB/s on DRA74 EVM. Signed-off-by: Vignesh R --- drivers/spi/spi-ti-qspi.c | 129 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 5c0616870358..45844a227c5e 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -71,11 +71,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG (0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG (0x54) +#define QSPI_SPI_SETUP_REG(n) (0x54 + 4 * n) #define QSPI_SPI_SWITCH_REG (0x64) -#define QSPI_SPI_SETUP1_REG (0x58) -#define QSPI_SPI_SETUP2_REG (0x5c) -#define QSPI_SPI_SETUP3_REG (0x60) #define QSPI_SPI_DATA_REG_1 (0x68) #define QSPI_SPI_DATA_REG_2 (0x6c) #define QSPI_SPI_DATA_REG_3 (0x70) @@ -118,6 +115,16 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) << 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 << 12) +#define QSPI_SETUP_RD_DUAL (0x1 << 12) +#define QSPI_SETUP_RD_QUAD (0x3 << 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -335,6 +342,117 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val |= MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val &= ~MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 + read_opcode, u8 addr_width, + u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 mode = spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD); + u32 memval = read_opcode; + + switch (mode) { + case SPI_RX_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_RX_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi->chip_select)); +} + +static unsigned int ti_qspi_cmd2addr(u8 *cmd, u8 addr_width) +{ + u32 addr; + + /* cmd[0] is read opcode */ + addr = cmd[1] << ((addr_width - 1) * 8); + addr |= cmd[2] << ((addr_width - 2) * 8); + addr |= cmd[3] << ((addr_width - 3) * 8); + addr |= cmd[4] << ((addr_width - 4) * 8); + + return addr; +} + +static int ti_qspi_mmap_read(struct spi_master *master, + struct spi_message *m) +{ + struct ti_qspi *qspi = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + u8 read_opcode = 0x3; /* Default normal read */ + void *to = NULL; + u8 addr_width = 4, dummy_bytes = 0; + unsigned int len = 0, from = 0; + int status = 0; + + mutex_lock(&qspi->list_lock); + + /* disable WC interrupt during memcpy */ + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); + ti_qspi_enable_memory_map(spi); + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf) { + read_opcode = *((u8 *)t->tx_buf); + dummy_bytes = t->len - (addr_width + 1); + from = ti_qspi_cmd2addr((u8 *)t->tx_buf, addr_width); + } + if (t->rx_buf) { + to = ((void *)t->rx_buf); + len = t->len; + } + m->actual_length += t->len; + } + ti_qspi_setup_mmap_read(spi, read_opcode, addr_width, + dummy_bytes); + + if (qspi_is_busy(qspi)) { + status = -EBUSY; + goto err; + } + memcpy(to, qspi->mmap_base + from, len); + +err: + ti_qspi_disable_memory_map(spi); + mutex_unlock(&qspi->list_lock); + m->status = status; + spi_finalize_current_message(master); + + return status; +} + static int ti_qspi_start_transfer_one(struct spi_master *master, struct spi_message *m) { @@ -344,6 +462,9 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, int status = 0, ret; int frame_length; + if (m->use_mmap_mode) + return ti_qspi_mmap_read(master, m); + /* setup device control reg */ qspi->dc = 0;