Add MX25 support to nand_spl fsl nfc driver
Subsystems (3)
PATCH v4 3/8 Add MX25 support to nand_spl fsl nfc driver
MX25 has a different version of the fsl_nfc flash controller known as version 1.1.
Add support to the nand_spl fsl_nfc driver
Versioning differs from mainline mxc kernel driver no consensus yet on if the naming here and in Redboot or the kernel is "correct".
Signed-off-by John Rigby <[email protected]>
Signed-off-by Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>
--- include/fsl_nfc.h | 86 ++++++++++++++++++++++++++++++++++++------ nand_spl/nand_boot_fsl_nfc.c | 72 ++++++++++++++++++++++++++++------- 2 files changed, 131 insertions(+), 27 deletions(-)
include/fsl_nfc.h +74 -12
@@ -1,5 +1,4 @@/* -* * (c) 2009 Magnus Lilja <[email protected]> * * See file CREDITS for list of people who contributed to this
@@ -25,21 +24,57 @@#define __FSL_NFC_H/* +* TODO: Use same register defs for nand_spl mxc nand driver +* and mtd mxc nand driver. +* * Register map and bit definitions for the Freescale NAND Flash -* Controller present in i.MX31 and other devices. +* Controller present in various i.MX devices. +* +* MX31 and MX27 have version 1 which has +* 4 512 byte main buffers and +* 4 16 byte spare buffers +* to support up to 2K byte pagesize nand. +* Reading or writing a 2K page requires 4 FDI/FDO cycles. +* +* MX25 has version 1.1 which has +* 8 512 byte main buffers and +* 8 64 byte spare buffers +* to support up to 4K byte pagesize nand. +* Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. +* Also some of registers are moved and/or changed meaning as seen below. */ +#if defined(CONFIG_MX31 ) || defined(CONFIG_MX27 ) +#define MXC_NFC_V1 +#elif defined(CONFIG_MX25 ) +#define MXC_NFC_V1_1 +#else +#warning "MXC NFC version not defined" +#endif + +#if defined(MXC_NFC_V1 ) +#define NAND_MXC_NR_BUFS 4 +#define NAND_MXC_SPARE_BUF_SIZE 16 +#define NAND_MXC_REG_OFFSET 0xe00 +#define NAND_MXC_2K_MULTI_CYCLE 1 +#elif defined(MXC_NFC_V1_1 ) +#define NAND_MXC_NR_BUFS 8 +#define NAND_MXC_SPARE_BUF_SIZE 64 +#define NAND_MXC_REG_OFFSET 0x1e00 +#else +#error "define CONFIG_NAND_MXC_VXXX to use the mxc spl_nand driver" +#endif struct fsl_nfc_regs { -u32 main_area0[128 ];/* @0x000 */ -u32 main_area1[128 ]; -u32 main_area2[128 ]; -u32 main_area3[128 ]; -u32 spare_area0[4 ]; -u32 spare_area1[4 ]; -u32 spare_area2[4 ]; -u32 spare_area3[4 ]; -u32 reserved1[64 -16 +64 *5 ]; -u16 bufsiz;/* @ 0xe00 */ +u32 main_area[NAND_MXC_NR_BUFS ][512 /4 ]; +u32 spare_area[NAND_MXC_NR_BUFS ][NAND_MXC_SPARE_BUF_SIZE /4 ]; +/* +* reserved size is offset of nfc registers +* minus total main and spare sizes +*/ +u8 reserved1[NAND_MXC_REG_OFFSET + -NAND_MXC_NR_BUFS * (512 +NAND_MXC_SPARE_BUF_SIZE )]; +#if defined(MXC_NFC_V1 ) +u16 bufsiz;u16 reserved2;u16 buffer_address;u16 flash_add;
@@ -54,6 +89,30 @@ struct fsl_nfc_regs {u16 nand_flash_wr_pr_st;u16 nand_flash_config1;u16 nand_flash_config2; +#elif defined(MXC_NFC_V1_1 ) +u16 reserved2[2 ]; +u16 buffer_address; +u16 flash_add; +u16 flash_cmd; +u16 configuration; +u16 ecc_status_result; +u16 ecc_status_result2; +u16 spare_area_size; +u16 nf_wr_prot; +u16 reserved3[2 ]; +u16 nand_flash_wr_pr_st; +u16 nand_flash_config1; +u16 nand_flash_config2; +u16 reserved4; +u16 unlock_start_blk_add0; +u16 unlock_end_blk_add0; +u16 unlock_start_blk_add1; +u16 unlock_end_blk_add1; +u16 unlock_start_blk_add2; +u16 unlock_end_blk_add2; +u16 unlock_start_blk_add3; +u16 unlock_end_blk_add3; +#endif };/*
@@ -98,6 +157,9 @@ struct fsl_nfc_regs {*/ #define NFC_INT 0x8000 +#ifdef MXC_NFC_V1_1 +#define NFC_4_8N_ECC (1 << 0) +#endif #define NFC_SP_EN (1 << 2)#define NFC_ECC_EN (1 << 3)#define NFC_INT_MSK (1 << 4)
nand_spl/nand_boot_fsl_nfc.c +57 -15
148 lines not on this page · raw message
Signature · 1 line
1.6.4.2.236.gf324c
PATCH v4 4/8 Nand mxc_nand add v1.1 controller support
Add support for version 1.1 of the nfc nand flash
controller which is on the i.mx25 soc.
Signed-off-by John Rigby <[email protected]>
CC Scott Wood <[email protected]>
--- drivers/mtd/nand/mxc_nand.c | 617 ++++++++++++++++++++++++++++++++++++++----- 1 files changed, 546 insertions(+), 71 deletions(-)
drivers/mtd/nand/mxc_nand.c +546 -71
@@ -22,27 +22,65 @@#include <nand.h> #include <linux/err.h> #include <asm/io.h> -#ifdef CONFIG_MX27 +#if defined(CONFIG_MX27 ) || defined(CONFIG_MX25 )#include <asm/arch/imx-regs.h> #endif #define DRIVER_NAME "mxc_nand" +/* +* TODO: Use same register defs here as nand_spl mxc nand driver. +*/ +/* +* Register map and bit definitions for the Freescale NAND Flash Controller +* present in various i.MX devices. +* +* MX31 and MX27 have version 1 which has +* 4 512 byte main buffers and +* 4 16 byte spare buffers +* to support up to 2K byte pagesize nand. +* Reading or writing a 2K page requires 4 FDI/FDO cycles. +* +* MX25 has version 1.1 which has +* 8 512 byte main buffers and +* 8 64 byte spare buffers +* to support up to 4K byte pagesize nand. +* Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. +* Also some of registers are moved and/or changed meaning as seen below. +*/ +#if defined(CONFIG_MX31 ) || defined(CONFIG_MX27 ) +#define MXC_NFC_V1 +#elif defined(CONFIG_MX25 ) +#define MXC_NFC_V1_1 +#else +#warning "MXC NFC version not defined" +#endif + +#if defined(MXC_NFC_V1 ) +#define NAND_MXC_NR_BUFS 4 +#define NAND_MXC_SPARE_BUF_SIZE 16 +#define NAND_MXC_REG_OFFSET 0xe00 +#define is_mxc_nfc_11 () 0 +#elif defined(MXC_NFC_V1_1 ) +#define NAND_MXC_NR_BUFS 8 +#define NAND_MXC_SPARE_BUF_SIZE 64 +#define NAND_MXC_REG_OFFSET 0x1e00 +#define is_mxc_nfc_11 () 1 +#else +#error "define CONFIG_NAND_MXC_VXXX to use mtd mxc nand driver" +#endif struct nfc_regs { -/* NFC RAM BUFFER Main area 0 */ -uint8_t main_area0[0x200 ]; -uint8_t main_area1[0x200 ]; -uint8_t main_area2[0x200 ]; -uint8_t main_area3[0x200 ]; -/* SPARE BUFFER Spare area 0 */ -uint8_t spare_area0[0x10 ]; -uint8_t spare_area1[0x10 ]; -uint8_t spare_area2[0x10 ]; -uint8_t spare_area3[0x10 ]; -uint8_t pad[0x5c0 ]; -/* NFC registers */ +uint8_t main_area[NAND_MXC_NR_BUFS ][0x200 ]; +uint8_t spare_area[NAND_MXC_NR_BUFS ][NAND_MXC_SPARE_BUF_SIZE ]; +/* +* reserved size is offset of nfc registers +* minus total main and spare sizes +*/ +uint8_t reserved1[NAND_MXC_REG_OFFSET + -NAND_MXC_NR_BUFS * (512 +NAND_MXC_SPARE_BUF_SIZE )]; +#if defined(MXC_NFC_V1 )uint16_t nfc_buf_size; -uint16_t reserved; +uint16_t reserved2;uint16_t nfc_buf_addr;uint16_t nfc_flash_addr;uint16_t nfc_flash_cmd;
@@ -56,6 +94,30 @@ struct nfc_regs {uint16_t nfc_nf_wrprst;uint16_t nfc_config1;uint16_t nfc_config2; +#elif defined(MXC_NFC_V1_1 ) +uint16_t reserved2[2 ]; +uint16_t nfc_buf_addr; +uint16_t nfc_flash_addr; +uint16_t nfc_flash_cmd; +uint16_t nfc_config; +uint16_t nfc_ecc_status_result; +uint16_t nfc_ecc_status_result2; +uint16_t nfc_spare_area_size; +uint16_t nfc_wrprot; +uint16_t reserved3[2 ]; +uint16_t nfc_nf_wrprst; +uint16_t nfc_config1; +uint16_t nfc_config2; +uint16_t reserved4; +uint16_t nfc_unlockstart_blkaddr; +uint16_t nfc_unlockend_blkaddr; +uint16_t nfc_unlockstart_blkaddr1; +uint16_t nfc_unlockend_blkaddr1; +uint16_t nfc_unlockstart_blkaddr2; +uint16_t nfc_unlockend_blkaddr2; +uint16_t nfc_unlockstart_blkaddr3; +uint16_t nfc_unlockend_blkaddr3; +#endif };/*
@@ -100,6 +162,11 @@ struct nfc_regs {*/ #define NFC_INT 0x8000 +#ifdef MXC_NFC_V1_1 +#define NFC_4_8N_ECC (1 << 0) +#else +#define NFC_4_8N_ECC 0 +#endif #define NFC_SP_EN (1 << 2)#define NFC_ECC_EN (1 << 3)#define NFC_BIG (1 << 5)
@@ -119,6 +186,7 @@ struct mxc_nand_host {int pagesize_2k;int clk_act;uint16_t col_addr; +unsigned int page_addr; };static struct mxc_nand_host mxc_host;
@@ -135,26 +203,45 @@ static struct mxc_nand_host *host = &mxc_host;#define SPARE_SINGLEBIT_ERROR 0x1/* OOB placement block for use with hardware ecc generation */ -#ifdef CONFIG_MXC_NAND_HWECC +#if defined(MXC_NFC_V1 ) +#ifndef CONFIG_SYS_NAND_LARGEPAGE static struct nand_ecclayout nand_hw_eccoob = { .eccbytes =5 , .eccpos = {6 ,7 ,8 ,9 ,10 }, - .oobfree = {{0 ,5 }, {11 ,5 }, } + .oobfree = { {0 ,5 }, {11 ,5 }, } };#else -static struct nand_ecclayout nand_soft_eccoob = { - .eccbytes =6 , - .eccpos = {6 ,7 ,8 ,9 ,10 ,11 }, - .oobfree = {{0 ,5 }, {12 ,4 }, } +static struct nand_ecclayout nand_hw_eccoob2k = { + .eccbytes =20 , + .eccpos = { +6 ,7 ,8 ,9 ,10 , +22 ,23 ,24 ,25 ,26 , +38 ,39 ,40 ,41 ,42 , +54 ,55 ,56 ,57 ,58 , + }, + .oobfree = { {2 ,4 }, {11 ,11 }, {27 ,11 }, {43 ,11 }, {59 ,5 } }, };#endif - -static struct nand_ecclayout nand_hw_eccoob_largepage = { - .eccbytes =20 , - .eccpos = {6 ,7 ,8 ,9 ,10 ,22 ,23 ,24 ,25 ,26 , -38 ,39 ,40 ,41 ,42 ,54 ,55 ,56 ,57 ,58 }, - .oobfree = {{2 ,4 }, {11 ,10 }, {27 ,10 }, {43 ,10 }, {59 ,5 }, } +#elif defined(MXC_NFC_V1_1 ) +#ifndef CONFIG_SYS_NAND_LARGEPAGE +static struct nand_ecclayout nand_hw_eccoob = { + .eccbytes =9 , + .eccpos = {7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 }, + .oobfree = { {2 ,5 } } }; +#else +static struct nand_ecclayout nand_hw_eccoob2k = { + .eccbytes =36 , + .eccpos = { +7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 , +23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 , +39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 , +55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 , + }, + .oobfree = { {2 ,5 }, {16 ,7 }, {32 ,7 }, {48 ,7 } }, +}; +#endif +#endif #ifdef CONFIG_MX27 static int is_16bit_nand (void )
@@ -178,6 +265,17 @@ static int is_16bit_nand(void) else return 0; } +#elif defined(CONFIG_MX25) +static int is_16bit_nand (void ) +{ +struct ccm_regs *ccm = + (struct ccm_regs *)IMX_CCM_BASE ; + +if (readl (&ccm->rcsr) &CCM_RCSR_NF_16BIT_SEL ) +return 1 ; +else +return 0 ; +}#else #warning "8/16 bit NAND autodetection not supported"static int is_16bit_nand (void )
@@ -258,7 +356,24 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr)static void send_prog_page (struct mxc_nand_host *host,uint8_t buf_id,int spare_only) { -MTDDEBUG (MTD_DEBUG_LEVEL3 ,"send_prog_page (%d)\n" , spare_only); +if (spare_only) +MTDDEBUG (MTD_DEBUG_LEVEL1 ,"send_prog_page (%d)\n" , spare_only); + +if (is_mxc_nfc_11 ()) { +int i; +/* +* The controller copies the 64 bytes of spare data from +* the first 16 bytes of each of the 4 64 byte spare buffers. +* Copy the contiguous data starting in spare_area[0] to +* the four spare area buffers. +*/ +for (i =1 ; i <4 ; i++) { +void __iomem *src = &host->regs->spare_area[0 ][i *16 ]; +void __iomem *dst = &host->regs->spare_area[i][0 ]; + +mxc_nand_memcpy32 (dst, src,16 ); + } + }writew (buf_id, &host->regs->nfc_buf_addr);
@@ -303,6 +418,22 @@ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,/* Wait for operation to complete */ wait_op_done (host,TROP_US_DELAY , spare_only); + +if (is_mxc_nfc_11 ()) { +int i; + +/* +* The controller copies the 64 bytes of spare data to +* the first 16 bytes of each of the 4 spare buffers. +* Make the data contiguous starting in spare_area[0]. +*/ +for (i =1 ; i <4 ; i++) { +void __iomem *src = &host->regs->spare_area[i][0 ]; +void __iomem *dst = &host->regs->spare_area[0 ][i *16 ]; + +mxc_nand_memcpy32 (dst, src,16 ); + } + } }/* Request the NANDFC to perform a read of the NAND device ID. */
@@ -330,7 +461,7 @@ static void send_read_id(struct mxc_nand_host *host)*/ static uint16_t get_dev_status (struct mxc_nand_host *host) { -void __iomem *main_buf = host->regs->main_area1; +void __iomem *main_buf = host->regs->main_area[1 ];uint32_t store;uint16_t ret, tmp;/* Issue status request to NAND device */
@@ -379,6 +510,330 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)*/ } +#ifdef MXC_NFC_V1_1 +static void _mxc_nand_enable_hwecc (struct mtd_info *mtd,int on) +{ +struct nand_chip *nand_chip = mtd->priv; +struct mxc_nand_host *host = nand_chip->priv; +uint16_t tmp =readw (&host->regs->nfc_config1); + +if (on) + tmp |=NFC_ECC_EN ; +else + tmp &= ~NFC_ECC_EN ; +writew (tmp, &host->regs->nfc_config1); +} + +static int mxc_nand_read_oob_syndrome (struct mtd_info *mtd, +struct nand_chip *chip, +int page,int sndcmd) +{ +struct mxc_nand_host *host = chip->priv; +uint8_t *buf = chip->oob_poi; +int length = mtd->oobsize; +int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; +uint8_t *bufpoi = buf; +int i, toread; + +MTDDEBUG (MTD_DEBUG_LEVEL0 , +"%s: Reading OOB area of page %u to oob %p\n" , + __FUNCTION__, host->page_addr, buf); + + chip->cmdfunc (mtd,NAND_CMD_READOOB , mtd->writesize, page); +for (i =0 ; i < chip->ecc.steps; i++) { + toread =min_t (int, length, chip->ecc.prepad); +if (toread) { + chip->read_buf (mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + bufpoi += chip->ecc.bytes; + host->col_addr += chip->ecc.bytes; + length -= chip->ecc.bytes; + + toread =min_t (int, length, chip->ecc.postpad); +if (toread) { + chip->read_buf (mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + } +if (length >0 ) + chip->read_buf (mtd, bufpoi, length); + +_mxc_nand_enable_hwecc (mtd,0 ); + chip->cmdfunc (mtd,NAND_CMD_READOOB , + mtd->writesize + chip->ecc.prepad, page); + bufpoi = buf + chip->ecc.prepad; + length = mtd->oobsize - chip->ecc.prepad; +for (i =0 ; i < chip->ecc.steps; i++) { + toread =min_t (int, length, chip->ecc.bytes); + chip->read_buf (mtd, bufpoi, toread); + bufpoi += eccpitch; + length -= eccpitch; + host->col_addr += chip->ecc.postpad + chip->ecc.prepad; + } +_mxc_nand_enable_hwecc (mtd,1 ); +return 1 ; +} + +static int mxc_nand_read_page_raw_syndrome (struct mtd_info *mtd, +struct nand_chip *chip, +uint8_t *buf, +int page) +{ +struct mxc_nand_host *host = chip->priv; +int eccsize = chip->ecc.size; +int eccbytes = chip->ecc.bytes; +int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; +uint8_t *oob = chip->oob_poi; +int steps, size; +int n; + +_mxc_nand_enable_hwecc (mtd,0 ); + chip->cmdfunc (mtd,NAND_CMD_READ0 ,0x00 , host->page_addr); + +for (n =0 , steps = chip->ecc.steps; steps >0 ; n++, steps--) { + host->col_addr = n * eccsize; + chip->read_buf (mtd, buf, eccsize); + buf += eccsize; + + host->col_addr = mtd->writesize + n * eccpitch; +if (chip->ecc.prepad) { + chip->read_buf (mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->read_buf (mtd, oob, eccbytes); + oob += eccbytes; + +if (chip->ecc.postpad) { + chip->read_buf (mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); +if (size) + chip->read_buf (mtd, oob, size); +_mxc_nand_enable_hwecc (mtd,0 ); + +return 0 ; +} + +static int mxc_nand_read_page_syndrome (struct mtd_info *mtd, +struct nand_chip *chip, +uint8_t *buf, +int page) +{ +struct mxc_nand_host *host = chip->priv; +int n, eccsize = chip->ecc.size; +int eccbytes = chip->ecc.bytes; +int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; +int eccsteps = chip->ecc.steps; +uint8_t *p = buf; +uint8_t *oob = chip->oob_poi; + +MTDDEBUG (MTD_DEBUG_LEVEL1 ,"Reading page %u to buf %p oob %p\n" , + host->page_addr, buf, oob); + +/* first read out the data area and the available portion of OOB */ +for (n =0 ; eccsteps; n++, eccsteps--, p += eccsize) { +int stat; + + host->col_addr = n * eccsize; + + chip->read_buf (mtd, p, eccsize); + + host->col_addr = mtd->writesize + n * eccpitch; + +if (chip->ecc.prepad) { + chip->read_buf (mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + stat = chip->ecc.correct (mtd, p, oob,NULL ); + +if (stat <0 ) + mtd->ecc_stats.failed++; +else + mtd->ecc_stats.corrected += stat; + oob += eccbytes; + +if (chip->ecc.postpad) { + chip->read_buf (mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + +/* Calculate remaining oob bytes */ + n = mtd->oobsize - (oob - chip->oob_poi); +if (n) + chip->read_buf (mtd, oob, n); + +/* Then switch ECC off and read the OOB area to get the ECC code */ +_mxc_nand_enable_hwecc (mtd,0 ); + chip->cmdfunc (mtd,NAND_CMD_READOOB , mtd->writesize, host->page_addr); + eccsteps = chip->ecc.steps; + oob = chip->oob_poi + chip->ecc.prepad; +for (n =0 ; eccsteps; n++, eccsteps--, p += eccsize) { + host->col_addr = mtd->writesize + + n * eccpitch + + chip->ecc.prepad; + chip->read_buf (mtd, oob, eccbytes); + oob += eccbytes + chip->ecc.postpad; + } +_mxc_nand_enable_hwecc (mtd,1 ); +return 0 ; +} + +static int mxc_nand_write_oob_syndrome (struct mtd_info *mtd, +struct nand_chip *chip,int page) +{ +struct mxc_nand_host *host = chip->priv; +int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; +int length = mtd->oobsize; +int i, len, status, steps = chip->ecc.steps; +const uint8_t *bufpoi = chip->oob_poi; + + chip->cmdfunc (mtd,NAND_CMD_SEQIN , mtd->writesize, page); +for (i =0 ; i < steps; i++) { + len =min_t (int, length, eccpitch); + + chip->write_buf (mtd, bufpoi, len); + bufpoi += len; + length -= len; + host->col_addr += chip->ecc.prepad + chip->ecc.postpad; + } +if (length >0 ) + chip->write_buf (mtd, bufpoi, length); + + chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); + status = chip->waitfunc (mtd, chip); +return status &NAND_STATUS_FAIL ? -EIO :0 ; +} + +static void mxc_nand_write_page_raw_syndrome (struct mtd_info *mtd, +struct nand_chip *chip, +const uint8_t *buf) +{ +struct mxc_nand_host *host = chip->priv; +int eccsize = chip->ecc.size; +int eccbytes = chip->ecc.bytes; +int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; +uint8_t *oob = chip->oob_poi; +int steps, size; +int n; + +for (n =0 , steps = chip->ecc.steps; steps >0 ; n++, steps--) { + host->col_addr = n * eccsize; + chip->write_buf (mtd, buf, eccsize); + buf += eccsize; + + host->col_addr = mtd->writesize + n * eccpitch; + +if (chip->ecc.prepad) { + chip->write_buf (mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + host->col_addr += eccbytes; + oob += eccbytes; + +if (chip->ecc.postpad) { + chip->write_buf (mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); +if (size) + chip->write_buf (mtd, oob, size); +} + +static void mxc_nand_write_page_syndrome (struct mtd_info *mtd, +struct nand_chip *chip, +const uint8_t *buf) +{ +struct mxc_nand_host *host = chip->priv; +int i, n, eccsize = chip->ecc.size; +int eccbytes = chip->ecc.bytes; +int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; +int eccsteps = chip->ecc.steps; +const uint8_t *p = buf; +uint8_t *oob = chip->oob_poi; + + chip->ecc.hwctl (mtd,NAND_ECC_WRITE ); + +for (i = n =0 ; + eccsteps; + n++, eccsteps--, i += eccbytes, p += eccsize) { + host->col_addr = n * eccsize; + + chip->write_buf (mtd, p, eccsize); + + host->col_addr = mtd->writesize + n * eccpitch; + +if (chip->ecc.prepad) { + chip->write_buf (mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->write_buf (mtd, oob, eccbytes); + oob += eccbytes; + +if (chip->ecc.postpad) { + chip->write_buf (mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + +/* Calculate remaining oob bytes */ + i = mtd->oobsize - (oob - chip->oob_poi); +if (i) + chip->write_buf (mtd, oob, i); +} + +static int mxc_nand_correct_data (struct mtd_info *mtd,u_char *dat, +u_char *read_ecc,u_char *calc_ecc) +{ +struct nand_chip *nand_chip = mtd->priv; +struct mxc_nand_host *host = nand_chip->priv; +uint16_t ecc_status =readw (&host->regs->nfc_ecc_status_result); +int subpages = mtd->writesize / nand_chip->subpagesize; +int pg2blk_shift = nand_chip->phys_erase_shift - + nand_chip->page_shift; + +do { +if ((ecc_status &0xf ) >4 ) { +static int last_bad =-1 ; + +if (last_bad != host->page_addr >> pg2blk_shift) { + last_bad = host->page_addr >> pg2blk_shift; +printk (KERN_DEBUG +"MXC_NAND: HWECC uncorrectable ECC error" +" in block %u page %u subpage %d\n" , + last_bad, host->page_addr, + mtd->writesize / nand_chip->subpagesize + - subpages); + } +return -1 ; + } + ecc_status >>=4 ; + subpages--; + }while (subpages >0 ); + +return 0 ; +} +#else +#define mxc_nand_read_page_syndrome NULL +#define mxc_nand_read_page_raw_syndrome NULL +#define mxc_nand_read_oob_syndrome NULL +#define mxc_nand_write_page_syndrome NULL +#define mxc_nand_write_page_raw_syndrome NULL +#define mxc_nand_write_oob_syndrome NULL +#define mxc_nfc_11_nand_correct_data NULL +static int mxc_nand_correct_data (struct mtd_info *mtd,u_char *dat,u_char *read_ecc,u_char *calc_ecc) {
@@ -400,6 +855,9 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, return 0; } +#endif + +static int mxc_nand_calculate_ecc (struct mtd_info *mtd,const u_char *dat,u_char *ecc_code)
@@ -415,9 +873,9 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)uint8_t ret =0 ;uint16_t col;uint16_t __iomem *main_buf = - (uint16_t __iomem *)host->regs->main_area0; + (uint16_t __iomem *)host->regs->main_area[0 ];uint16_t __iomem *spare_buf = - (uint16_t __iomem *)host->regs->spare_area0; + (uint16_t __iomem *)host->regs->spare_area[0 ];union {uint16_t word;uint8_t bytes[2 ];
@@ -464,9 +922,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd) col += mtd->writesize;if (col < mtd->writesize) { - p = (uint16_t __iomem *)(host->regs->main_area0 + (col >>1 )); + p = (uint16_t __iomem *)(host->regs->main_area[0 ] + + (col >>1 )); }else { - p = (uint16_t __iomem *)(host->regs->spare_area0 + + p = (uint16_t __iomem *)(host->regs->spare_area[0 ] + ((col - mtd->writesize) >>1 )); }
@@ -525,9 +984,9 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,void __iomem *p;if (col < mtd->writesize) { - p = host->regs->main_area0 + (col & ~3 ); + p = host->regs->main_area[0 ] + (col & ~3 ); }else { - p = host->regs->spare_area0 - + p = host->regs->spare_area[0 ] - mtd->writesize + (col & ~3 ); }
@@ -595,9 +1054,9 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)void __iomem *p;if (col < mtd->writesize) { - p = host->regs->main_area0 + (col & ~3 ); + p = host->regs->main_area[0 ] + (col & ~3 ); }else { - p = host->regs->spare_area0 - + p = host->regs->spare_area[0 ] - mtd->writesize + (col & ~3 ); }
@@ -683,7 +1142,7 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)* Used by the upper layer to write command to NAND Flash for * different operations to be carried out on NAND Flash */ -static void mxc_nand_command (struct mtd_info *mtd,unsigned command, +void mxc_nand_command (struct mtd_info *mtd,unsigned command,int column,int page_addr) {struct nand_chip *nand_chip = mtd->priv;
@@ -705,6 +1164,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,break ;case NAND_CMD_READ0 : + host->page_addr = page_addr; host->col_addr = column; host->spare_only = false;break ;
@@ -750,7 +1210,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,case NAND_CMD_PAGEPROG :send_prog_page (host,0 , host->spare_only); -if (host->pagesize_2k) { +if (host->pagesize_2k && !is_mxc_nfc_11 ()) {/* data in 4 areas datas */ send_prog_page (host,1 , host->spare_only);send_prog_page (host,2 , host->spare_only);
@@ -780,30 +1240,12 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,/* Write out page address, if necessary */ if (page_addr !=-1 ) { -/* paddr_0 - p_addr_7 */ -send_addr (host, (page_addr &0xff )); - -if (host->pagesize_2k) { -send_addr (host, (page_addr >>8 ) &0xFF ); -if (mtd->size >=0x10000000 ) { -/* paddr_8 - paddr_15 */ -send_addr (host, (page_addr >>8 ) &0xff ); -send_addr (host, (page_addr >>16 ) &0xff ); - }else { -/* paddr_8 - paddr_15 */ -send_addr (host, (page_addr >>8 ) &0xff ); - } - }else { -/* One more address cycle for higher density devices */ -if (mtd->size >=0x4000000 ) { -/* paddr_8 - paddr_15 */ -send_addr (host, (page_addr >>8 ) &0xff ); -send_addr (host, (page_addr >>16 ) &0xff ); - }else { -/* paddr_8 - paddr_15 */ -send_addr (host, (page_addr >>8 ) &0xff ); - } - } +u32 page_mask = nand_chip->pagemask; +do { +send_addr (host, page_addr &0xFF ); + page_addr >>=8 ; + page_mask >>=8 ; + }while (page_mask); }/* Command post-processing step */
@@ -819,9 +1261,11 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,send_cmd (host,NAND_CMD_READSTART );/* read for each AREA */ send_read_page (host,0 , host->spare_only); -send_read_page (host,1 , host->spare_only); -send_read_page (host,2 , host->spare_only); -send_read_page (host,3 , host->spare_only); +if (!is_mxc_nfc_11 ()) { +send_read_page (host,1 , host->spare_only); +send_read_page (host,2 , host->spare_only); +send_read_page (host,3 , host->spare_only); + } }else {send_read_page (host,0 , host->spare_only); }
@@ -843,6 +1287,24 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, } } +#ifdef MXC_NFC_V1_1 +static void mxc_setup_config1 (void ) +{ +uint16_t tmp; + + tmp =readw (&host->regs->nfc_config1); + tmp |=NFC_ONE_CYCLE ; + tmp |=NFC_4_8N_ECC ; +writew (tmp, &host->regs->nfc_config1); +if (host->pagesize_2k) +writew (64 /2 , &host->regs->nfc_spare_area_size); +else +writew (16 /2 , &host->regs->nfc_spare_area_size); +} +#else +#define mxc_setup_config1 () +#endif +int board_nand_init (struct nand_chip *this) {struct mtd_info *mtd;
@@ -874,10 +1336,23 @@ int board_nand_init(struct nand_chip *this) this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; this->ecc.correct = mxc_nand_correct_data; - this->ecc.mode =NAND_ECC_HW ; +if (is_mxc_nfc_11 ()) { + this->ecc.mode =NAND_ECC_HW_SYNDROME ; + this->ecc.read_page = mxc_nand_read_page_syndrome; + this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; + this->ecc.read_oob = mxc_nand_read_oob_syndrome; + this->ecc.write_page = mxc_nand_write_page_syndrome; + this->ecc.write_page_raw = mxc_nand_write_page_raw_syndrome; + this->ecc.write_oob = mxc_nand_write_oob_syndrome; + this->ecc.bytes =9 ; + this->ecc.prepad =7 ; + }else { + this->ecc.mode =NAND_ECC_HW ; + } + + host->pagesize_2k =0 ; + this->ecc.size =512 ; - this->ecc.bytes =3 ; - this->ecc.layout = &nand_hw_eccoob; tmp =readw (&host->regs->nfc_config1); tmp |=NFC_ECC_EN ;writew (tmp, &host->regs->nfc_config1);
@@ -888,7 +1363,6 @@ int board_nand_init(struct nand_chip *this) tmp &= ~NFC_ECC_EN ;writew (tmp, &host->regs->nfc_config1);#endif -/* Reset NAND */ this->cmdfunc (mtd,NAND_CMD_RESET ,-1 ,-1 );
@@ -911,10 +1385,11 @@ int board_nand_init(struct nand_chip *this)#ifdef CONFIG_SYS_NAND_LARGEPAGE host->pagesize_2k =1 ; - this->ecc.layout = &nand_hw_eccoob_largepage; + this->ecc.layout = &nand_hw_eccoob2k;#else host->pagesize_2k =0 ; + this->ecc.layout = &nand_hw_eccoob;#endif - +mxc_setup_config1 ();return err; }
Signature · 1 line
1.6.4.2.236.gf324c