|
@@ -2818,6 +2818,72 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
|
|
|
return crc;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise
|
|
|
+ */
|
|
|
+static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
+ int busw)
|
|
|
+{
|
|
|
+ struct nand_onfi_params *p = &chip->onfi_params;
|
|
|
+ int i;
|
|
|
+ int val;
|
|
|
+
|
|
|
+ /* try ONFI for unknow chip or LP */
|
|
|
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
|
|
+ if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
|
|
+ chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ printk(KERN_INFO "ONFI flash detected\n");
|
|
|
+ chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
+ chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
|
|
+ if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
|
|
|
+ le16_to_cpu(p->crc)) {
|
|
|
+ printk(KERN_INFO "ONFI param page %d valid\n", i);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == 3)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* check version */
|
|
|
+ val = le16_to_cpu(p->revision);
|
|
|
+ if (val == 1 || val > (1 << 4)) {
|
|
|
+ printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
|
|
|
+ __func__, val);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (val & (1 << 4))
|
|
|
+ chip->onfi_version = 22;
|
|
|
+ else if (val & (1 << 3))
|
|
|
+ chip->onfi_version = 21;
|
|
|
+ else if (val & (1 << 2))
|
|
|
+ chip->onfi_version = 20;
|
|
|
+ else
|
|
|
+ chip->onfi_version = 10;
|
|
|
+
|
|
|
+ sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
|
|
+ sanitize_string(p->model, sizeof(p->model));
|
|
|
+ if (!mtd->name)
|
|
|
+ mtd->name = p->model;
|
|
|
+ mtd->writesize = le32_to_cpu(p->byte_per_page);
|
|
|
+ mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
|
|
+ mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
|
|
+ chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
|
|
|
+ busw = 0;
|
|
|
+ if (le16_to_cpu(p->features) & 1)
|
|
|
+ busw = NAND_BUSWIDTH_16;
|
|
|
+
|
|
|
+ chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
|
|
+ chip->options |= (NAND_NO_READRDY |
|
|
|
+ NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Get the flash and manufacturer id and lookup if the type is supported
|
|
|
*/
|
|
@@ -2828,6 +2894,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
|
|
{
|
|
|
int i, maf_idx;
|
|
|
u8 id_data[8];
|
|
|
+ int ret;
|
|
|
|
|
|
/* Select the device */
|
|
|
chip->select_chip(mtd, 0);
|
|
@@ -2872,67 +2939,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
|
|
|
|
|
chip->onfi_version = 0;
|
|
|
if (!type->name || !type->pagesize) {
|
|
|
- /* try ONFI for unknow chip or LP */
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
|
|
- if (chip->read_byte(mtd) == 'O' &&
|
|
|
- chip->read_byte(mtd) == 'N' &&
|
|
|
- chip->read_byte(mtd) == 'F' &&
|
|
|
- chip->read_byte(mtd) == 'I') {
|
|
|
-
|
|
|
- struct nand_onfi_params *p = &chip->onfi_params;
|
|
|
- int i;
|
|
|
-
|
|
|
- printk(KERN_INFO "ONFI flash detected\n");
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
|
|
- for (i = 0; i < 3; i++) {
|
|
|
- chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
|
|
- if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
|
|
|
- le16_to_cpu(p->crc))
|
|
|
- {
|
|
|
- printk(KERN_INFO "ONFI param page %d valid\n", i);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (i < 3) {
|
|
|
- /* check version */
|
|
|
- int val = le16_to_cpu(p->revision);
|
|
|
- if (val == 1 || val > (1 << 4))
|
|
|
- printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
|
|
|
- __func__, val);
|
|
|
- else {
|
|
|
- if (val & (1 << 4))
|
|
|
- chip->onfi_version = 22;
|
|
|
- else if (val & (1 << 3))
|
|
|
- chip->onfi_version = 21;
|
|
|
- else if (val & (1 << 2))
|
|
|
- chip->onfi_version = 20;
|
|
|
- else
|
|
|
- chip->onfi_version = 10;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (chip->onfi_version) {
|
|
|
- sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
|
|
- sanitize_string(p->model, sizeof(p->model));
|
|
|
- if (!mtd->name)
|
|
|
- mtd->name = p->model;
|
|
|
- mtd->writesize = le32_to_cpu(p->byte_per_page);
|
|
|
- mtd->erasesize = le32_to_cpu(p->pages_per_block)*mtd->writesize;
|
|
|
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
|
|
- chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
|
|
|
- busw = 0;
|
|
|
- if (le16_to_cpu(p->features) & 1)
|
|
|
- busw = NAND_BUSWIDTH_16;
|
|
|
-
|
|
|
- chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
|
|
- chip->options |= (NAND_NO_READRDY |
|
|
|
- NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
|
|
|
-
|
|
|
- goto ident_done;
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
+ /* Check is chip is ONFI compliant */
|
|
|
+ ret = nand_flash_detect_onfi(mtd, chip, busw);
|
|
|
+ if (ret)
|
|
|
+ goto ident_done;
|
|
|
}
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|