From patchwork Wed Jun 25 12:43:32 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Mack X-Patchwork-Id: 363994 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 9793114001A for ; Wed, 25 Jun 2014 22:44:13 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 88A10A7676; Wed, 25 Jun 2014 14:44:05 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de 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 1vy0N72PDqfO; Wed, 25 Jun 2014 14:44:05 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 68393A7678; Wed, 25 Jun 2014 14:44:00 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C285BA766E for ; Wed, 25 Jun 2014 14:43:55 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de 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 dj-FD3aOgukV for ; Wed, 25 Jun 2014 14:43:52 +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-wi0-f177.google.com (mail-wi0-f177.google.com [209.85.212.177]) by theia.denx.de (Postfix) with ESMTPS id 3FC40A765D for ; Wed, 25 Jun 2014 14:43:49 +0200 (CEST) Received: by mail-wi0-f177.google.com with SMTP id r20so2432928wiv.16 for ; Wed, 25 Jun 2014 05:43:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=cNi3Uz5UFOaYrVfpMt9R57zhvmi5PZvu7vTv1BYFpf4=; b=pvJLvRa8cT3WG6TACWukIOsWCtP3FrlwXZyx8v2uJKEdDxL3hpH6YI+R8pJscK6Qmt QZAD0CszdzYjsZMbKmnATAS8fKucY6jX7AhvA37GCs4IipEATBBr1k6kGtHoF6DfiUO6 APkPvCcaQuk/dVFW7MgRw3KCyLPrCDb6Y7TN1s4iP+fsmeS36S8PJoZE4UrPQDdmJvel 5bEtzaDAyPNiZhf+GSwtBVfU0TbFILEIL8b0il/z0cBKW+4saaL5nmHzZyAdZXNGTWvI iQZ8bGlgh3XA5wURTfrwbAlEF6+mQKpIwpLM+Zj4Km+AAw/xLnI9BhqN8kd1ZYfU2yoa F2jQ== X-Received: by 10.194.189.230 with SMTP id gl6mr3464298wjc.118.1403700226632; Wed, 25 Jun 2014 05:43:46 -0700 (PDT) Received: from tamtam.fritz.box (e179001013.adsl.alicedsl.de. [85.179.1.13]) by mx.google.com with ESMTPSA id fn1sm11999361wib.18.2014.06.25.05.43.45 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 25 Jun 2014 05:43:45 -0700 (PDT) From: Daniel Mack To: u-boot@lists.denx.de Date: Wed, 25 Jun 2014 14:43:32 +0200 Message-Id: <1403700213-16114-2-git-send-email-zonque@gmail.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1403700213-16114-1-git-send-email-zonque@gmail.com> References: <1403700213-16114-1-git-send-email-zonque@gmail.com> Cc: trini@ti.com, Daniel Mack Subject: [U-Boot] [PATCH v2 1/2] mtd: OMAP: Enable GPMC prefetch mode X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Enable GPMC's prefetch feature for NAND access. This speeds up NAND read access a lot by pre-fetching contents in the background and reading them through the FIFO address. The current implementation has two limitations: a) it only works in 8-bit mode b) it only supports read access Both is easily fixable by someone who has hardware to implement it. Note that U-Boot code uses non word-aligned buffers to read data into, and request read lengths that are not multiples of 4, so both partial buffers (head and tail) have to be addressed. Tested on AM335x hardware. Signed-off-by: Daniel Mack --- doc/README.nand | 5 ++ drivers/mtd/nand/omap_gpmc.c | 115 +++++++++++++++++++++++++++++++++++++++++- include/linux/mtd/omap_gpmc.h | 6 ++- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/doc/README.nand b/doc/README.nand index 70cf768..6459f2a 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -292,6 +292,11 @@ Platform specific options Thus BCH16 can be supported on 4K page NAND. + CONFIG_NAND_OMAP_PREFETCH + On OMAP platforms that use the GPMC controller (CONFIG_NAND_OMAP_GPMC), + this options enables the code that uses the prefetch mode to speed up + read operations. + NOTE: ===== diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 1acf06b..e2d57bd 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -446,6 +446,113 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, return (err) ? err : error_count; } +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH + +#define PREFETCH_CONFIG1_CS_SHIFT 24 +#define PREFETCH_FIFOTHRESHOLD_MAX 0x40 +#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8) +#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff) +#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F) +#define ENABLE_PREFETCH (1 << 7) + +/** + * omap_prefetch_enable - configures and starts prefetch transfer + * @fifo_th: fifo threshold to be used for read/ write + * @count: number of bytes to be transferred + * @is_write: prefetch read(0) or write post(1) mode + */ +static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write) +{ + uint32_t val; + + if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) + return -EINVAL; + + if (readl(&gpmc_cfg->prefetch_control)) + return -EBUSY; + + /* Set the amount of bytes to be prefetched */ + writel(count, &gpmc_cfg->prefetch_config2); + + val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) | + PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH; + writel(val, &gpmc_cfg->prefetch_config1); + + /* Start the prefetch engine */ + writel(1, &gpmc_cfg->prefetch_control); + + return 0; +} + +/** + * omap_prefetch_reset - disables and stops the prefetch engine + */ +static void omap_prefetch_reset(void) +{ + writel(0, &gpmc_cfg->prefetch_control); + writel(0, &gpmc_cfg->prefetch_config1); +} + +static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len) +{ + int ret; + uint32_t cnt; + + ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0); + if (ret < 0) + return ret; + + do { + int i; + + cnt = readl(&gpmc_cfg->prefetch_status); + cnt = PREFETCH_STATUS_FIFO_CNT(cnt); + + for (i = 0; i < cnt / 4; i++) { + *buf++ = readl(CONFIG_SYS_NAND_BASE); + len -= 4; + } + } while (len); + + omap_prefetch_reset(); + + return 0; +} + +static void omap_nand_read_prefetch8(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int ret; + uint32_t head, tail; + struct nand_chip *chip = mtd->priv; + + /* + * If the destination buffer is unaligned, start with reading + * the overlap byte-wise. + */ + head = ((uint32_t) buf) % 4; + if (head) { + nand_read_buf(mtd, buf, head); + buf += head; + len -= head; + } + + /* + * Only transfer multiples of 4 bytes in a pre-fetched fashion. + * If there's a residue, care for it byte-wise afterwards. + */ + tail = len % 4; + + ret = __read_prefetch_aligned(chip, (uint32_t *) buf, len - tail); + if (ret < 0) { + /* fallback in case the prefetch engine is busy */ + nand_read_buf(mtd, buf, len); + } else if (tail) { + buf += len - tail; + nand_read_buf(mtd, buf, tail); + } +} +#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */ + /** * omap_read_page_bch - hardware ecc based page read function * @mtd: mtd info structure @@ -883,11 +990,15 @@ int board_nand_init(struct nand_chip *nand) if (err) return err; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH + /* TODO: Implement for 16-bit bus width */ if (nand->options & NAND_BUSWIDTH_16) nand->read_buf = nand_read_buf16; else - nand->read_buf = nand_read_buf; + nand->read_buf = omap_nand_read_prefetch8; +#endif + +#ifdef CONFIG_SPL_BUILD nand->dev_ready = omap_spl_dev_ready; #endif diff --git a/include/linux/mtd/omap_gpmc.h b/include/linux/mtd/omap_gpmc.h index 9a86582..6cbae45 100644 --- a/include/linux/mtd/omap_gpmc.h +++ b/include/linux/mtd/omap_gpmc.h @@ -66,7 +66,11 @@ struct gpmc { u32 status; /* 0x54 */ u8 res5[0x8]; /* 0x58 */ struct gpmc_cs cs[8]; /* 0x60, 0x90, .. */ - u8 res6[0x14]; /* 0x1E0 */ + u32 prefetch_config1; /* 0x1E0 */ + u32 prefetch_config2; /* 0x1E4 */ + u32 res6; /* 0x1E8 */ + u32 prefetch_control; /* 0x1EC */ + u32 prefetch_status; /* 0x1F0 */ u32 ecc_config; /* 0x1F4 */ u32 ecc_control; /* 0x1F8 */ u32 ecc_size_config; /* 0x1FC */