]> git.sur5r.net Git - u-boot/blobdiff - drivers/mtd/nand/fsl_ifc_nand.c
Merge branch 'u-boot/master' into 'u-boot-arm/master'
[u-boot] / drivers / mtd / nand / fsl_ifc_nand.c
index b3f3c3c05a58bc23c2ae7b68fdd5ec00a6421027..b13d8a9303a9bea0410c0d9e039926366d5ab7c4 100644 (file)
@@ -1,6 +1,6 @@
 /* Integrated Flash Controller NAND Machine Driver
  *
- * Copyright (c) 2011 Freescale Semiconductor, Inc
+ * Copyright (c) 2012 Freescale Semiconductor, Inc
  *
  * Authors: Dipen Dudhat <Dipen.Dudhat@freescale.com>
  *
@@ -30,6 +30,7 @@
 #include <asm/errno.h>
 #include <asm/fsl_ifc.h>
 
+#define FSL_IFC_V1_1_0 0x01010000
 #define MAX_BANKS      4
 #define ERR_BYTE       0xFF /* Value returned for read bytes
                                when read failed */
@@ -221,24 +222,11 @@ static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
                          u32 *eccstat, unsigned int bufnum)
 {
        u32 reg = eccstat[bufnum / 4];
-       int errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+       int errors;
 
-       if (errors == 15) { /* uncorrectable */
-               /* Blank pages fail hw ECC checks */
-               if (is_blank(mtd, ctrl, bufnum))
-                       return 1;
+       errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
 
-               /*
-                * We disable ECCER reporting in hardware due to
-                * erratum IFC-A002770 -- so report it now if we
-                * see an uncorrectable error in ECCSTAT.
-                */
-               ctrl->status |= IFC_NAND_EVTER_STAT_ECCER;
-       } else if (errors > 0) {
-               mtd->ecc_stats.corrected += errors;
-       }
-
-       return 0;
+       return errors;
 }
 
 /*
@@ -279,16 +267,33 @@ static int fsl_ifc_run_command(struct mtd_info *mtd)
                printf("%s: Write Protect Error\n", __func__);
 
        if (ctrl->eccread) {
-               int bufperpage = mtd->writesize / 512;
-               int bufnum = (ctrl->page & priv->bufnum_mask) * bufperpage;
-               int bufnum_end = bufnum + bufperpage - 1;
+               int errors;
+               int bufnum = ctrl->page & priv->bufnum_mask;
+               int sector = bufnum * chip->ecc.steps;
+               int sector_end = sector + chip->ecc.steps - 1;
 
-               for (i = bufnum / 4; i <= bufnum_end / 4; i++)
+               for (i = sector / 4; i <= sector_end / 4; i++)
                        eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
 
-               for (i = bufnum; i <= bufnum_end; i++) {
-                       if (check_read_ecc(mtd, ctrl, eccstat, i))
+               for (i = sector; i <= sector_end; i++) {
+                       errors = check_read_ecc(mtd, ctrl, eccstat, i);
+
+                       if (errors == 15) {
+                               /*
+                                * Uncorrectable error.
+                                * OK only if the whole page is blank.
+                                *
+                                * We disable ECCER reporting due to erratum
+                                * IFC-A002770 -- so report it now if we
+                                * see an uncorrectable error in ECCSTAT.
+                                */
+                               if (!is_blank(mtd, ctrl, bufnum))
+                                       ctrl->status |=
+                                               IFC_NAND_EVTER_STAT_ECCER;
                                break;
+                       }
+
+                       mtd->ecc_stats.corrected += errors;
                }
 
                ctrl->eccread = 0;
@@ -380,19 +385,30 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
        /* READID must read all possible bytes while CEB is active */
        case NAND_CMD_READID:
+       case NAND_CMD_PARAM: {
+               int timing = IFC_FIR_OP_RB;
+               if (command == NAND_CMD_PARAM)
+                       timing = IFC_FIR_OP_RBCD;
+
                out_be32(&ifc->ifc_nand.nand_fir0,
-                               (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
                                (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
-                               (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+                               (timing << IFC_NAND_FIR0_OP2_SHIFT));
                out_be32(&ifc->ifc_nand.nand_fcr0,
-                               NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
-               /* 4 bytes for manuf, device and exts */
-               out_be32(&ifc->ifc_nand.nand_fbcr, 4);
-               ctrl->read_bytes = 4;
+                               command << IFC_NAND_FCR0_CMD0_SHIFT);
+               out_be32(&ifc->ifc_nand.row3, column);
+
+               /*
+                * although currently it's 8 bytes for READID, we always read
+                * the maximum 256 bytes(for PARAM)
+                */
+               out_be32(&ifc->ifc_nand.nand_fbcr, 256);
+               ctrl->read_bytes = 256;
 
                set_addr(mtd, 0, 0, 0);
                fsl_ifc_run_command(mtd);
                return;
+       }
 
        /* ERASE1 stores the block and page address */
        case NAND_CMD_ERASE1:
@@ -448,21 +464,19 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                        out_be32(&ifc->ifc_nand.nand_fir1,
                                 (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
 
-                       if (column >= mtd->writesize) {
-                               /* OOB area --> READOOB */
-                               column -= mtd->writesize;
-                               nand_fcr0 |= NAND_CMD_READOOB <<
-                                               IFC_NAND_FCR0_CMD0_SHIFT;
-                               ctrl->oob = 1;
-                       } else if (column < 256) {
-                               /* First 256 bytes --> READ0 */
-                               nand_fcr0 |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
-                       } else {
-                               /* Second 256 bytes --> READ1 */
-                               nand_fcr0 |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
-                       }
+                       if (column >= mtd->writesize)
+                               nand_fcr0 |=
+                               NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+                       else
+                               nand_fcr0 |=
+                               NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
                }
 
+               if (column >= mtd->writesize) {
+                       /* OOB area --> READOOB */
+                       column -= mtd->writesize;
+                       ctrl->oob = 1;
+               }
                out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
                set_addr(mtd, column, page_addr, ctrl->oob);
                return;
@@ -471,7 +485,8 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
        /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
        case NAND_CMD_PAGEPROG:
                if (ctrl->oob)
-                       out_be32(&ifc->ifc_nand.nand_fbcr, ctrl->index);
+                       out_be32(&ifc->ifc_nand.nand_fbcr,
+                                       ctrl->index - ctrl->column);
                else
                        out_be32(&ifc->ifc_nand.nand_fbcr, 0);
 
@@ -724,11 +739,66 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
 {
 }
 
+static void fsl_ifc_sram_init(void)
+{
+       struct fsl_ifc *ifc = ifc_ctrl->regs;
+       uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
+       long long end_tick;
+
+       cs = ifc_ctrl->cs_nand >> IFC_NAND_CSEL_SHIFT;
+
+       /* Save CSOR and CSOR_ext */
+       csor = in_be32(&ifc_ctrl->regs->csor_cs[cs].csor);
+       csor_ext = in_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext);
+
+       /* chage PageSize 8K and SpareSize 1K*/
+       csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
+       out_be32(&ifc_ctrl->regs->csor_cs[cs].csor, csor_8k);
+       out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, 0x0000400);
+
+       /* READID */
+       out_be32(&ifc->ifc_nand.nand_fir0,
+                       (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                       (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+                       (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+       out_be32(&ifc->ifc_nand.nand_fcr0,
+                       NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
+       out_be32(&ifc->ifc_nand.row3, 0x0);
+
+       out_be32(&ifc->ifc_nand.nand_fbcr, 0x0);
+
+       /* Program ROW0/COL0 */
+       out_be32(&ifc->ifc_nand.row0, 0x0);
+       out_be32(&ifc->ifc_nand.col0, 0x0);
+
+       /* set the chip select for NAND Transaction */
+       out_be32(&ifc->ifc_nand.nand_csel, ifc_ctrl->cs_nand);
+
+       /* start read seq */
+       out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+
+       /* wait for NAND Machine complete flag or timeout */
+       end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
+
+       while (end_tick > get_ticks()) {
+               ifc_ctrl->status = in_be32(&ifc->ifc_nand.nand_evter_stat);
+
+               if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC)
+                       break;
+       }
+
+       out_be32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status);
+
+       /* Restore CSOR and CSOR_ext */
+       out_be32(&ifc_ctrl->regs->csor_cs[cs].csor, csor);
+       out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext);
+}
+
 int board_nand_init(struct nand_chip *nand)
 {
        struct fsl_ifc_mtd *priv;
        struct nand_ecclayout *layout;
-       uint32_t cspr = 0, csor = 0;
+       uint32_t cspr = 0, csor = 0, ver = 0;
 
        if (!ifc_ctrl) {
                fsl_ifc_ctrl_init();
@@ -761,6 +831,7 @@ int board_nand_init(struct nand_chip *nand)
        if (priv->bank >= MAX_BANKS) {
                printf("%s: address did not match any "
                       "chip selects\n", __func__);
+               kfree(priv);
                return -ENODEV;
        }
 
@@ -782,7 +853,7 @@ int board_nand_init(struct nand_chip *nand)
 
        /* set up nand options */
        nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
-                       NAND_USE_FLASH_BBT;
+                       NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
 
        if (cspr & CSPR_PORT_SIZE_16) {
                nand->read_byte = fsl_ifc_read_byte16;
@@ -846,5 +917,9 @@ int board_nand_init(struct nand_chip *nand)
                nand->ecc.mode = NAND_ECC_SOFT;
        }
 
+       ver = in_be32(&ifc_ctrl->regs->ifc_rev);
+       if (ver == FSL_IFC_V1_1_0)
+               fsl_ifc_sram_init();
+
        return 0;
 }