From: Simon Schwarz <simonschwarzcor@googlemail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 1/2] nand_spl_simple: Add omap3 DMA usage to SPL
Date: Sun, 16 Oct 2011 12:10:03 +0200 [thread overview]
Message-ID: <1318759804-18688-2-git-send-email-simonschwarzcor@gmail.com> (raw)
In-Reply-To: <1318759804-18688-1-git-send-email-simonschwarzcor@gmail.com>
This adds DMA copy for the nand spl implementation. If CONFIG_SPL_DMA_SUPPORT
is defined the DMA is used.
Based on DMA driver patch:
http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/109744/focus=109747
Signed-off-by: Simon Schwarz <simonschwarzcor@gmail.com>
Cc: scottwood at freescale.com
Cc: s-paulraj at ti.com
---
drivers/mtd/nand/nand_spl_simple.c | 185 ++++++++++++++++++++++++++++++++++--
1 files changed, 176 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/nand_spl_simple.c
index 71491d4..b45322b 100644
--- a/drivers/mtd/nand/nand_spl_simple.c
+++ b/drivers/mtd/nand/nand_spl_simple.c
@@ -2,6 +2,9 @@
* (C) Copyright 2006-2008
* Stefan Roese, DENX Software Engineering, sr at denx.de.
*
+ * Copyright (C) 2011
+ * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
@@ -21,10 +24,21 @@
#include <common.h>
#include <nand.h>
#include <asm/io.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/cpu.h>
static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
static nand_info_t mtd;
static struct nand_chip nand_chip;
+static struct nand_chip *this;
+
+struct ecc_wait_entry {
+ int valid;
+ uint8_t *p;
+ u_char *ecc_code;
+ u_char *ecc_calc;
+};
+static struct ecc_wait_entry ecc_wait;
#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)
/*
@@ -33,7 +47,6 @@ static struct nand_chip nand_chip;
static int nand_command(int block, int page, uint32_t offs,
u8 cmd)
{
- struct nand_chip *this = mtd.priv;
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
while (!this->dev_ready(&mtd))
@@ -46,11 +59,11 @@ static int nand_command(int block, int page, uint32_t offs,
this->cmd_ctrl(&mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
this->cmd_ctrl(&mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */
this->cmd_ctrl(&mtd, (page_addr >> 8) & 0xff,
- NAND_CTRL_ALE); /* A[24:17] */
+ NAND_CTRL_ALE); /* A[24:17] */
#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE
/* One more address cycle for devices > 32MiB */
this->cmd_ctrl(&mtd, (page_addr >> 16) & 0x0f,
- NAND_CTRL_ALE); /* A[28:25] */
+ NAND_CTRL_ALE); /* A[28:25] */
#endif
/* Latch in address */
this->cmd_ctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
@@ -93,20 +106,20 @@ static int nand_command(int block, int page, uint32_t offs,
/* Set ALE and clear CLE to start address cycle */
/* Column address */
hwctrl(&mtd, offs & 0xff,
- NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
+ NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
/* Row address */
hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
hwctrl(&mtd, ((page_addr >> 8) & 0xff),
- NAND_CTRL_ALE); /* A[27:20] */
+ NAND_CTRL_ALE); /* A[27:20] */
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
/* One more address cycle for devices > 128MiB */
hwctrl(&mtd, (page_addr >> 16) & 0x0f,
- NAND_CTRL_ALE); /* A[31:28] */
+ NAND_CTRL_ALE); /* A[31:28] */
#endif
/* Latch in address */
hwctrl(&mtd, NAND_CMD_READSTART,
- NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
@@ -121,7 +134,6 @@ static int nand_command(int block, int page, uint32_t offs,
static int nand_is_bad_block(int block)
{
- struct nand_chip *this = mtd.priv;
nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS,
NAND_CMD_READOOB);
@@ -187,7 +199,7 @@ static int nand_read_page(int block, int page, void *dst)
return 0;
}
-int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+int nand_spl_load_image_nondma(uint32_t offs, unsigned int size, void *dst)
{
unsigned int block, lastblock;
unsigned int page;
@@ -221,16 +233,171 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
return 0;
}
+#ifdef CONFIG_SPL_DMA_SUPPORT
+void correct_ecc_dma(void)
+{
+ int eccsize = CONFIG_SYS_NAND_ECCSIZE;
+ int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
+ int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+ int i;
+ uint8_t *p = ecc_wait.p;
+
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ /* No chance to do something with the possible error message
+ * from correct_data(). We just hope that all possible errors
+ * are corrected by this routine.
+ */
+ this->ecc.correct(&mtd, ecc_wait.p, &ecc_wait.ecc_code[i],
+ &ecc_wait.ecc_calc[i]);
+ }
+ ecc_wait.valid = 0;
+}
+
+static int nand_read_page_dma(int block, int page, void *dst)
+{
+ u_char *ecc_calc;
+ u_char *ecc_code;
+ u_char *oob_data;
+ int i;
+ int res;
+ int eccsize = CONFIG_SYS_NAND_ECCSIZE;
+ int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
+ int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+ uint8_t *p = dst;
+
+ nand_command(block, page, 0, NAND_CMD_READ0);
+
+ /* No malloc available for now, just use some temporary locations
+ * in SDRAM
+ */
+ ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
+ ecc_code = ecc_calc + 0x100;
+ oob_data = ecc_calc + 0x200;
+ res = 0;
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ res += omap3_dma_conf_transfer(0, nand_chip.IO_ADDR_R,
+ (uint32_t *)p, CONFIG_SYS_NAND_ECCSIZE/4);
+ this->ecc.hwctl(&mtd, NAND_ECC_READ);
+ res += omap3_dma_start_transfer(0);
+ /* correct ecc from former transfer */
+ if (ecc_wait.valid != 0)
+ correct_ecc_dma();
+ res += omap3_dma_wait_for_transfer(0);
+ this->ecc.calculate(&mtd, p, &ecc_calc[i]);
+ if (res) {
+ printf("spl: DMA error while data read\n");
+ return -1;
+ }
+ }
+
+ /*this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);*/
+ res = omap3_dma_conf_transfer(0, nand_chip.IO_ADDR_R,
+ (uint32_t *)oob_data, CONFIG_SYS_NAND_OOBSIZE/4);
+ res += omap3_dma_start_transfer(0);
+ res += omap3_dma_wait_for_transfer(0);
+ if (res) {
+ printf("spl: DMA error while oob read\n");
+ return -1;
+ }
+
+ /* Pick the ECC bytes out of the oob data */
+ for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
+ ecc_code[i] = oob_data[nand_ecc_pos[i]];
+
+ /* add to ecc_wait - just ok until the nex ecc.calc!*/
+ ecc_wait.valid = 1;
+ ecc_wait.p = dst;
+ ecc_wait.ecc_code = ecc_code;
+ ecc_wait.ecc_calc = ecc_calc;
+ return 0;
+}
+
+int nand_spl_load_image_dma(uint32_t offs, unsigned int size, void *dst)
+{
+ unsigned int block, lastblock;
+ unsigned int page;
+
+ /*
+ * offs has to be aligned to a page address!
+ */
+ block = offs / CONFIG_SYS_NAND_BLOCK_SIZE;
+ lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE;
+ page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE;
+ ecc_wait.valid = 0;
+ while (block <= lastblock) {
+ if (!nand_is_bad_block(block)) {
+ /*
+ * Skip bad blocks
+ */
+ while (page < CONFIG_SYS_NAND_PAGE_COUNT) {
+ nand_read_page_dma(block, page, dst);
+ dst += CONFIG_SYS_NAND_PAGE_SIZE;
+ page++;
+ }
+ if (ecc_wait.valid != 0)
+ correct_ecc_dma();
+
+ page = 0;
+ } else {
+ lastblock++;
+ }
+
+ block++;
+ }
+ return 0;
+}
+
+/* Read from NAND with DMA if appropriate
+ * offs: Offset in NAND to read from
+ * size: site to read
+ * dst: destination pointer (multiple of page sizes ->
+ * CONFIG_SYS_NAND_PAGE_SIZE*roundup(size/CONFIG_SYS_NAND_PAGE_SIZE))
+ *
+ * RETURN non-null means error
+ */
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+ struct dma4_chan cfg;
+ debug("using DMA load...\n");
+ omap3_dma_init();
+
+ /* config the channel */
+ omap3_dma_get_conf_chan(0, &cfg);
+ cfg.csdp = CSDP_DATA_TYPE_32BIT | CSDP_SRC_BURST_EN_64BYTES |
+ CSDP_DST_BURST_EN_64BYTES | CSDP_DST_ENDIAN_LOCK_ADAPT |
+ CSDP_DST_ENDIAN_LITTLE | CSDP_SRC_ENDIAN_LOCK_ADAPT |
+ CSDP_SRC_ENDIAN_LITTLE;
+ cfg.cfn = 1;
+ cfg.ccr = CCR_READ_PRIORITY_HIGH | CCR_SRC_AMODE_CONSTANT |
+ CCR_DST_AMODE_POST_INC;
+ cfg.cicr = (1 << 5) | (1 << 11) | (1 << 10) | (1 << 8);
+ omap3_dma_conf_chan(0, &cfg);
+
+
+ nand_spl_load_image_dma(offs, size, dst);
+ return 0;
+}
+
+#else /* use cpu copy */
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+ __attribute__ ((alias("nand_spl_load_image_nondma")));
+
+#endif /* CONFIG_SPL_DMA_SUPPORT */
+
+
+
/* nand_init() - initialize data to make nand usable by SPL */
void nand_init(void)
{
/*
* Init board specific nand support
*/
+ debug(">>nand_init()\n");
mtd.priv = &nand_chip;
nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
(void __iomem *)CONFIG_SYS_NAND_BASE;
nand_chip.options = 0;
+ this = mtd.priv;
board_nand_init(&nand_chip);
if (nand_chip.select_chip)
--
1.7.4.1
next prev parent reply other threads:[~2011-10-16 10:10 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-16 10:10 [U-Boot] [PATCH 0/2] Use DMA in SPL Simon Schwarz
2011-10-16 10:10 ` Simon Schwarz [this message]
2011-10-23 18:40 ` [U-Boot] [PATCH 1/2] nand_spl_simple: Add omap3 DMA usage to SPL Wolfgang Denk
2011-10-25 18:24 ` Scott Wood
2011-10-31 8:56 ` Simon Schwarz
2011-10-31 21:22 ` Scott Wood
2011-11-02 9:57 ` Simon Schwarz
2011-11-02 17:29 ` Scott Wood
2011-10-16 10:10 ` [U-Boot] [PATCH 2/2] devkit8000: Activate DMA support in SPL Simon Schwarz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1318759804-18688-2-git-send-email-simonschwarzcor@gmail.com \
--to=simonschwarzcor@googlemail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.