forked from Minki/linux
mtd: Blackfin NFC: fix handling of page sizes
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>
This commit is contained in:
parent
752b957a37
commit
44299179c0
@ -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
|
||||
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@ -341,13 +339,12 @@ 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();
|
||||
|
||||
@ -355,12 +352,11 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
|
||||
|
||||
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);
|
||||
@ -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",
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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
|
||||
*
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user