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>
This commit is contained in:
parent
1bc66a57c0
commit
adf4800d85
@ -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);
|
||||
|
||||
writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a);
|
||||
writel(virt_to_phys(buf), &info->reg->data_block_ptr);
|
||||
if (is_writing)
|
||||
bbflags = GEN_BB_READ;
|
||||
else
|
||||
bbflags = GEN_BB_WRITE;
|
||||
|
||||
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);
|
||||
}
|
||||
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(bbstate.bounce_buffer), &info->reg->data_block_ptr);
|
||||
|
||||
/* Set ECC selection, configure ECC settings */
|
||||
if (with_ecc) {
|
||||
if (is_writing)
|
||||
memcpy(tag_ptr, chip->oob_poi + free->offset,
|
||||
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),
|
||||
|
Loading…
Reference in New Issue
Block a user