[U-Boot] [PATCH v3 09/16] mtd/nand/tegra: alignment workaround

Marcel Ziswiler marcel at ziswiler.com
Thu Aug 6 00:47:06 CEST 2015


From: Marcel Ziswiler <marcel.ziswiler at toradex.com>

Integrate cache alignment bounce buffer to workaround issues as follows:

Loading file '/boot/zImage' to addr 0x01000000 with size 4499152 (0x0044a6d0)...
ERROR: v7_dcache_inval_range - start address is not aligned - 0x1f7f0108
ERROR: v7_dcache_inval_range - stop address is not aligned - 0x1f7f1108
Done
Kernel image @ 0x1000000 [ 0x000000 - 0x44a6d0 ]

Starting kernel ...

undefined instruction
pc : [<005ff03c>]          lr : [<0000800c>]
sp : 0144b6e8  ip : 01000188     fp : 0144a6c8
r10: 00000000  r9 : 411fc090     r8 : 00000100
r7 : 00000cfb  r6 : 0144a6d0     r5 : 00000000  r4 : 00008000
r3 : 0000000c  r2 : 00000100     r1 : 00000cfb  r0 : 00000000
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
Resetting CPU ...

Signed-off-by: Marcel Ziswiler <marcel.ziswiler at toradex.com>
Acked-by: Stephen Warren <swarren at nvidia.com>
---
Changes in v2:
Migrated to using generic bounce buffer implementation as suggested by Simon.

 drivers/mtd/nand/tegra_nand.c | 87 ++++++++++++++++++-------------------------
 1 file changed, 36 insertions(+), 51 deletions(-)

diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index ca19625..723d0ec 100644
--- a/drivers/mtd/nand/tegra_nand.c
+++ b/drivers/mtd/nand/tegra_nand.c
@@ -16,6 +16,7 @@
 #include <asm/errno.h>
 #include <asm/gpio.h>
 #include <fdtdec.h>
+#include <bouncebuf.h>
 #include "tegra_nand.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -93,35 +94,6 @@ static struct nand_drv nand_ctrl;
 static struct mtd_info *our_mtd;
 static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
 
-#ifdef CONFIG_SYS_DCACHE_OFF
-static inline void dma_prepare(void *start, unsigned long length,
-			       int is_writing)
-{
-}
-#else
-/**
- * Prepare for a DMA transaction
- *
- * For a write we flush out our data. For a read we invalidate, since we
- * need to do this before we read from the buffer after the DMA has
- * completed, so may as well do it now.
- *
- * @param start		Start address for DMA buffer (should be cache-aligned)
- * @param length	Length of DMA buffer in bytes
- * @param is_writing	0 if reading, non-zero if writing
- */
-static void dma_prepare(void *start, unsigned long length, int is_writing)
-{
-	unsigned long addr = (unsigned long)start;
-
-	length = ALIGN(length, ARCH_DMA_MINALIGN);
-	if (is_writing)
-		flush_dcache_range(addr, addr + length);
-	else
-		invalidate_dcache_range(addr, addr + length);
-}
-#endif
-
 /**
  * Wait for command completion
  *
@@ -531,6 +503,8 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
 	char *tag_ptr;
 	struct nand_drv *info;
 	struct fdt_nand *config;
+	unsigned int bbflags;
+	struct bounce_buffer bbstate, bbstate_oob;
 
 	if ((uintptr_t)buf & 0x03) {
 		printf("buf %p has to be 4-byte aligned\n", buf);
@@ -547,21 +521,21 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 	stop_command(info->reg);
 
+	if (is_writing)
+		bbflags = GEN_BB_READ;
+	else
+		bbflags = GEN_BB_WRITE;
+
+	bounce_buffer_start(&bbstate, (void *)buf, 1 << chip->page_shift,
+			    bbflags);
 	writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a);
-	writel(virt_to_phys(buf), &info->reg->data_block_ptr);
+	writel(virt_to_phys(bbstate.bounce_buffer), &info->reg->data_block_ptr);
 
+	/* Set ECC selection, configure ECC settings */
 	if (with_ecc) {
-		writel(virt_to_phys(tag_ptr), &info->reg->tag_ptr);
 		if (is_writing)
 			memcpy(tag_ptr, chip->oob_poi + free->offset,
-				chip->ecc.layout->oobavail +
-				TAG_ECC_BYTES);
-	} else {
-		writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr);
-	}
-
-	/* Set ECC selection, configure ECC settings */
-	if (with_ecc) {
+			       chip->ecc.layout->oobavail + TAG_ECC_BYTES);
 		tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES;
 		reg_val |= (CFG_SKIP_SPARE_SEL_4
 			| CFG_SKIP_SPARE_ENABLE
@@ -574,7 +548,8 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 		if (!is_writing)
 			tag_size += SKIPPED_SPARE_BYTES;
-		dma_prepare(tag_ptr, tag_size, is_writing);
+		bounce_buffer_start(&bbstate_oob, (void *)tag_ptr, tag_size,
+				    bbflags);
 	} else {
 		tag_size = mtd->oobsize;
 		reg_val |= (CFG_SKIP_SPARE_DISABLE
@@ -582,14 +557,12 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
 			| CFG_ECC_EN_TAG_DISABLE
 			| CFG_HW_ECC_DISABLE
 			| (tag_size - 1));
-		dma_prepare(chip->oob_poi, tag_size, is_writing);
+		bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi,
+				    tag_size, bbflags);
 	}
 	writel(reg_val, &info->reg->config);
-
-	dma_prepare(buf, 1 << chip->page_shift, is_writing);
-
+	writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr);
 	writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config);
-
 	writel(tag_size - 1, &info->reg->dma_cfg_b);
 
 	nand_clear_interrupt_status(info->reg);
@@ -635,6 +608,9 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
 		return -EIO;
 	}
 
+	bounce_buffer_stop(&bbstate_oob);
+	bounce_buffer_stop(&bbstate);
+
 	if (with_ecc && !is_writing) {
 		memcpy(chip->oob_poi, tag_ptr,
 			SKIPPED_SPARE_BYTES);
@@ -752,6 +728,8 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
 	int tag_size;
 	struct nand_oobfree *free = chip->ecc.layout->oobfree;
 	struct nand_drv *info;
+	unsigned int bbflags;
+	struct bounce_buffer bbstate_oob;
 
 	if (((int)chip->oob_poi) & 0x03)
 		return -EINVAL;
@@ -761,8 +739,6 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
 
 	stop_command(info->reg);
 
-	writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr);
-
 	/* Set ECC selection */
 	tag_size = mtd->oobsize;
 	if (with_ecc)
@@ -776,13 +752,20 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
 		CFG_HW_ECC_DISABLE);
 	writel(reg_val, &info->reg->config);
 
-	dma_prepare(chip->oob_poi, tag_size, is_writing);
-
-	writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config);
-
 	if (is_writing && with_ecc)
 		tag_size -= TAG_ECC_BYTES;
 
+	if (is_writing)
+		bbflags = GEN_BB_READ;
+	else
+		bbflags = GEN_BB_WRITE;
+
+	bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, tag_size,
+			    bbflags);
+	writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr);
+
+	writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config);
+
 	writel(tag_size - 1, &info->reg->dma_cfg_b);
 
 	nand_clear_interrupt_status(info->reg);
@@ -819,6 +802,8 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
 		return -EIO;
 	}
 
+	bounce_buffer_stop(&bbstate_oob);
+
 	if (with_ecc && !is_writing) {
 		reg_val = (u32)check_ecc_error(info->reg, 0, 0,
 			(u8 *)(chip->oob_poi + free->offset),
-- 
2.4.3



More information about the U-Boot mailing list