Skip to content

Commit

Permalink
mtd: Blackfin NFC: fix handling of page sizes
Browse files Browse the repository at this point in the history
Rather than forcing the platform resources to declare the desired page
size, simply use the existing information passed down to us by the higher
layers.  This way we work out of the box with all flash chips that the
kernel knows about.

Signed-off-by: Barry Song <barry.song@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
Barry Song authored and David Woodhouse committed Aug 5, 2010
1 parent 752b957 commit 4429917
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 41 deletions.
3 changes: 0 additions & 3 deletions arch/blackfin/include/asm/nand.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
* partitions = mtd partition list
*/

#define NFC_PG_SIZE_256 0
#define NFC_PG_SIZE_512 1
#define NFC_PG_SIZE_OFFSET 9

#define NFC_NWIDTH_8 0
Expand All @@ -30,7 +28,6 @@

struct bf5xx_nand_platform {
/* NAND chip information */
unsigned short page_size;
unsigned short data_width;

/* RD/WR strobe delay timing information, all times in SCLK cycles */
Expand Down
86 changes: 48 additions & 38 deletions drivers/mtd/nand/bf5xx_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,18 +314,16 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct bf5xx_nand_platform *plat = info->platform;
unsigned short page_size = (plat->page_size ? 512 : 256);
struct nand_chip *chip = mtd->priv;
int ret;

ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);

/* If page size is 512, correct second 256 bytes */
if (page_size == 512) {
/* If ecc size is 512, correct second 256 bytes */
if (chip->ecc.size == 512) {
dat += 256;
read_ecc += 8;
calc_ecc += 8;
read_ecc += 3;
calc_ecc += 3;
ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
}

Expand All @@ -341,26 +339,24 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct bf5xx_nand_platform *plat = info->platform;
u16 page_size = (plat->page_size ? 512 : 256);
struct nand_chip *chip = mtd->priv;
u16 ecc0, ecc1;
u32 code[2];
u8 *p;

/* first 4 bytes ECC code for 256 page size */
/* first 3 bytes ECC code for 256 page size */
ecc0 = bfin_read_NFC_ECC0();
ecc1 = bfin_read_NFC_ECC1();

code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);

dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);

/* first 3 bytes in ecc_code for 256 page size */
p = (u8 *) code;
memcpy(ecc_code, p, 3);

/* second 4 bytes ECC code for 512 page size */
if (page_size == 512) {
/* second 3 bytes ECC code for 512 ecc size */
if (chip->ecc.size == 512) {
ecc0 = bfin_read_NFC_ECC2();
ecc1 = bfin_read_NFC_ECC3();
code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
Expand Down Expand Up @@ -480,8 +476,7 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
uint8_t *buf, int is_read)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct bf5xx_nand_platform *plat = info->platform;
unsigned short page_size = (plat->page_size ? 512 : 256);
struct nand_chip *chip = mtd->priv;
unsigned short val;

dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
Expand All @@ -495,10 +490,10 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
*/
if (is_read)
invalidate_dcache_range((unsigned int)buf,
(unsigned int)(buf + page_size));
(unsigned int)(buf + chip->ecc.size));
else
flush_dcache_range((unsigned int)buf,
(unsigned int)(buf + page_size));
(unsigned int)(buf + chip->ecc.size));

/*
* This register must be written before each page is
Expand All @@ -519,13 +514,13 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd,

/* The DMAs have different size on BF52x and BF54x */
#ifdef CONFIG_BF52x
set_dma_x_count(CH_NFC, (page_size >> 1));
set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
set_dma_x_modify(CH_NFC, 2);
val = DI_EN | WDSIZE_16;
#endif

#ifdef CONFIG_BF54x
set_dma_x_count(CH_NFC, (page_size >> 2));
set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
set_dma_x_modify(CH_NFC, 4);
val = DI_EN | WDSIZE_32;
#endif
Expand All @@ -547,12 +542,11 @@ static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
uint8_t *buf, int len)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct bf5xx_nand_platform *plat = info->platform;
unsigned short page_size = (plat->page_size ? 512 : 256);
struct nand_chip *chip = mtd->priv;

dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);

if (len == page_size)
if (len == chip->ecc.size)
bf5xx_nand_dma_rw(mtd, buf, 1);
else
bf5xx_nand_read_buf(mtd, buf, len);
Expand All @@ -562,12 +556,11 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct bf5xx_nand_platform *plat = info->platform;
unsigned short page_size = (plat->page_size ? 512 : 256);
struct nand_chip *chip = mtd->priv;

dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);

if (len == page_size)
if (len == chip->ecc.size)
bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
else
bf5xx_nand_write_buf(mtd, buf, len);
Expand Down Expand Up @@ -642,12 +635,11 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)

/* setup NFC_CTL register */
dev_info(info->device,
"page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n",
(plat->page_size ? 512 : 256),
"data_width=%d, wr_dly=%d, rd_dly=%d\n",
(plat->data_width ? 16 : 8),
plat->wr_dly, plat->rd_dly);

val = (plat->page_size << NFC_PG_SIZE_OFFSET) |
val = (1 << NFC_PG_SIZE_OFFSET) |
(plat->data_width << NFC_NWIDTH_OFFSET) |
(plat->rd_dly << NFC_RDDLY_OFFSET) |
(plat->wr_dly << NFC_WRDLY_OFFSET);
Expand Down Expand Up @@ -713,6 +705,33 @@ static int __devexit bf5xx_nand_remove(struct platform_device *pdev)
return 0;
}

static int bf5xx_nand_scan(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
int ret;

ret = nand_scan_ident(mtd, 1);
if (ret)
return ret;

if (hardware_ecc) {
/*
* for nand with page size > 512B, think it as several sections with 512B
*/
if (likely(mtd->writesize >= 512)) {
chip->ecc.size = 512;
chip->ecc.bytes = 6;
} else {
chip->ecc.size = 256;
chip->ecc.bytes = 3;
bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
SSYNC();
}
}

return nand_scan_tail(mtd);
}

/*
* bf5xx_nand_probe
*
Expand Down Expand Up @@ -798,15 +817,6 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
chip->badblock_pattern = &bootrom_bbt;
chip->ecc.layout = &bootrom_ecclayout;
#endif

if (plat->page_size == NFC_PG_SIZE_256) {
chip->ecc.bytes = 3;
chip->ecc.size = 256;
} else if (plat->page_size == NFC_PG_SIZE_512) {
chip->ecc.bytes = 6;
chip->ecc.size = 512;
}

chip->read_buf = bf5xx_nand_dma_read_buf;
chip->write_buf = bf5xx_nand_dma_write_buf;
chip->ecc.calculate = bf5xx_nand_calculate_ecc;
Expand All @@ -820,7 +830,7 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
}

/* scan hardware nand chip and setup mtd info data struct */
if (nand_scan(mtd, 1)) {
if (bf5xx_nand_scan(mtd)) {
err = -ENXIO;
goto out_err_nand_scan;
}
Expand Down

0 comments on commit 4429917

Please sign in to comment.