From: Marcel Ziswiler <marcel.ziswi...@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.ziswi...@toradex.com>
---
Changes in v2:
Migrated to using generic bounce buffer implementation as suggested by Simon.

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

diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index 9f90683..02d8aed 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
  *
@@ -534,6 +506,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);
@@ -550,21 +524,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((u32)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
@@ -577,7 +551,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
@@ -585,14 +560,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((u32)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);
@@ -638,6 +611,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);
@@ -755,6 +731,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;
@@ -764,8 +742,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)
@@ -779,13 +755,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((u32)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);
@@ -822,6 +805,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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to