mtd: vf610_nfc: enable ONFI detection
authorStefan Agner <stefan@agner.ch>
Fri, 3 Apr 2015 15:26:13 +0000 (17:26 +0200)
committerStefan Agner <stefan@agner.ch>
Tue, 14 Apr 2015 07:08:08 +0000 (09:08 +0200)
This changes enable ONFI detection. The Read ID command now allows
one address byte which is needed for ONFI detection. To read the
ONFI parameter page, the NAND_CMD_PARAM need to be supported. The
CMD code enables one command and one address byte along with reading
data from flash using R/B#, as specified by ONFI.

drivers/mtd/nand/vf610_nfc.c
include/configs/vf610twr.h

index 2c02ff5996d61a8766862447b399bcdd1d6d0bce..99457d4ad112b049a8802988c2099dd00f9f2fc3 100644 (file)
@@ -62,6 +62,7 @@
  * Briefly these are bitmasks of controller cycles.
  */
 #define READ_PAGE_CMD_CODE             0x7EE0
+#define READ_ONFI_PARAM_CMD_CODE       0x4860
 #define PROGRAM_PAGE_CMD_CODE          0x7FC0
 #define ERASE_CMD_CODE                 0x4EC0
 #define READ_ID_CMD_CODE               0x4804
@@ -150,6 +151,7 @@ struct vf610_nfc {
        int                alt_buf;
 #define ALT_BUF_ID   1
 #define ALT_BUF_STAT 2
+#define ALT_BUF_ONFI 3
        struct clk        *clk;
 };
 
@@ -390,6 +392,15 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
                vf610_nfc_ecc_mode(mtd, ECC_HW_MODE);
                break;
 
+       case NAND_CMD_PARAM:
+               nfc->alt_buf = ALT_BUF_ONFI;
+               vf610_nfc_transfer_size(nfc->regs, 768);
+               vf610_nfc_send_command(nfc->regs, NAND_CMD_PARAM, READ_ONFI_PARAM_CMD_CODE);
+               vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
+                                   ROW_ADDR_SHIFT, column);
+               vf610_nfc_ecc_mode(mtd, ECC_BYPASS);
+               break;
+
        case NAND_CMD_ERASE1:
                vf610_nfc_transfer_size(nfc->regs, 0);
                vf610_nfc_send_commands(nfc->regs, command,
@@ -399,8 +410,11 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
 
        case NAND_CMD_READID:
                nfc->alt_buf = ALT_BUF_ID;
+               nfc->column = 0;
                vf610_nfc_transfer_size(nfc->regs, 0);
                vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE);
+               vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
+                                   ROW_ADDR_SHIFT, column);
                break;
 
        case NAND_CMD_STATUS:
@@ -422,17 +436,11 @@ static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        uint c = nfc->column;
 
-       switch (nfc->alt_buf) {
-       case ALT_BUF_ID:
-               *buf = vf610_nfc_get_id(mtd, c);
-               break;
-       case ALT_BUF_STAT:
-               *buf = vf610_nfc_get_status(mtd);
-               break;
-       default:
-               vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
-               break;
-       }
+       /* Alternate buffers are only supported through read_byte */
+       if (nfc->alt_buf)
+               return;
+
+       vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
 
        nfc->column += len;
 }
@@ -453,8 +461,28 @@ static void vf610_nfc_write_buf(struct mtd_info *mtd, const u_char *buf,
 /* Read byte from NFC buffers */
 static u8 vf610_nfc_read_byte(struct mtd_info *mtd)
 {
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        u8 tmp;
-       vf610_nfc_read_buf(mtd, &tmp, sizeof(tmp));
+       uint c = nfc->column;
+
+       switch (nfc->alt_buf) {
+       case ALT_BUF_ID:
+               tmp = vf610_nfc_get_id(mtd, c);
+               break;
+       case ALT_BUF_STAT:
+               tmp = vf610_nfc_get_status(mtd);
+               break;
+       case ALT_BUF_ONFI:
+               /* Reverse byte since the controller uses big endianness */
+               c = nfc->column % 4;
+               c = nfc->column - c + (3 - c);
+               tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
+               break;
+       default:
+               tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
+               break;
+       }
+       nfc->column++;
        return tmp;
 }
 
@@ -602,13 +630,11 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
        mtd->priv = chip;
        chip->priv = nfc;
 
-       if (cfg.width == 16) {
+       if (cfg.width == 16)
                chip->options |= NAND_BUSWIDTH_16;
-               vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
-       } else {
-               chip->options &= ~NAND_BUSWIDTH_16;
-               vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
-       }
+
+       /* Use 8-bit mode during initialization */
+       vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
 
        /* Disable subpage writes as we do not provide ecc->hwctl */
        chip->options |= NAND_NO_SUBPAGE_WRITE;
@@ -651,6 +677,9 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
                goto error;
        }
 
+       if (cfg.width == 16)
+               vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
+
        chip->ecc.mode = NAND_ECC_SOFT; /* default */
 
        /* Single buffer only, max 256 OOB minus ECC status */
index 621aa134844d715bef2a0e3752b2c46806652a37..aa310411bf2ddb091cf9134f23c5cd1a80079373 100644 (file)
@@ -48,6 +48,7 @@
 /* NAND support */
 #define CONFIG_CMD_NAND
 #define CONFIG_CMD_NAND_TRIMFFS
+#define CONFIG_SYS_NAND_ONFI_DETECTION
 
 #ifdef CONFIG_CMD_NAND
 #define CONFIG_USE_ARCH_MEMCPY