summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStefan Agner <stefan@agner.ch>2015-04-03 17:26:13 +0200
committerStefan Agner <stefan@agner.ch>2015-04-14 09:08:08 +0200
commit7831b68f12dc3acf9abd25624f742d638d5f522f (patch)
tree48a5d7baa13a588d085743540492742f5cacced2 /drivers
parent4c8c050fd83fafe7677bb44babd89f264cb7850d (diff)
mtd: vf610_nfc: enable ONFI detection
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.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/vf610_nfc.c65
1 files changed, 47 insertions, 18 deletions
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 2c02ff5996..99457d4ad1 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -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 */