summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-08-06 00:47:06 +0200
committerTom Warren <twarren@nvidia.com>2015-08-13 13:06:02 -0700
commitadf4800d8570a1212be329ab6fcead4c284ede89 (patch)
tree5d0766efad295f9ba7feab8ba4e3fbab12149ea0 /drivers
parent1bc66a57c067eba5f687c2ab0a70956821dc7220 (diff)
downloadblackbird-obmc-uboot-adf4800d8570a1212be329ab6fcead4c284ede89.tar.gz
blackbird-obmc-uboot-adf4800d8570a1212be329ab6fcead4c284ede89.zip
mtd/nand/tegra: alignment workaround
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@toradex.com> Acked-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Tom Warren <twarren@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/tegra_nand.c87
1 files changed, 36 insertions, 51 deletions
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index ca19625705..723d0ecad7 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),
OpenPOWER on IntegriCloud