[U-Boot] [PATCH v2 09/16] mtd/nand/tegra: alignment workaround
Marcel Ziswiler
marcel at ziswiler.com
Tue Jul 21 00:35:43 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>
---
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
More information about the U-Boot
mailing list