diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index c6bea32..1cde3e9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2318,15 +2318,25 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } +static u16 onfi_crc(u16 crc, unsigned char const *p, size_t len) +{ + int i; + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + return crc; +} /* * Get the flash and manufacturer id and lookup if the type is supported */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, - int busw, int *maf_id) + int busw, int *maf_id, int *dev_id) { struct nand_flash_dev *type = NULL; - int i, dev_id, maf_idx; + int i, maf_idx; int tmp_id, tmp_manf; /* Select the device */ @@ -2343,7 +2353,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Read manufacturer and device IDs */ *maf_id = chip->read_byte(mtd); - dev_id = chip->read_byte(mtd); + *dev_id = chip->read_byte(mtd); /* Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a @@ -2358,20 +2368,67 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, tmp_manf = chip->read_byte(mtd); tmp_id = chip->read_byte(mtd); - if (tmp_manf != *maf_id || tmp_id != dev_id) { + if (tmp_manf != *maf_id || tmp_id != *dev_id) { printk(KERN_INFO "%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, dev_id, tmp_manf, tmp_id); + *maf_id, *dev_id, tmp_manf, tmp_id); return ERR_PTR(-ENODEV); } /* Lookup the flash id */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (dev_id == nand_flash_ids[i].id) { + if (*dev_id == nand_flash_ids[i].id) { type = &nand_flash_ids[i]; break; } } +#if 1 + if (!type || !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') { + + int param[256/4]; + char *paramb = param; + int i; + + printk(KERN_INFO "ONFI flash detected\n"); + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + for (i = 0; i < 3; i++) { + /* XXX this that ok to use read_buf at this stage ? */ + chip->read_buf(mtd, paramb, 256); + if (onfi_crc(0x4F4E, paramb, 254) == le16_to_cpup(paramb+254)) + { + printk(KERN_INFO "ONFI param page %d valid\n", i); + } + } + if (i < 3) { + /* TODO */ + if (!mtd->name) + mtd->name = "onfi flash"; + mtd->writesize = le32_to_cpup(paramb+80); + mtd->erasesize = le32_to_cpup(paramb+92)*mtd->writesize; + mtd->oobsize = le16_to_cpup(paramb+84); + chip->chipsize = le32_to_cpup(paramb+96) * mtd->erasesize; + busw = 0; + if (le16_to_cpup(paramb+6) & 1) + busw = NAND_BUSWIDTH_16; + + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= (NAND_NO_READRDY | NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; + goto ident_done; + + } + } + } +#endif + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + /* Read manufacturer and device IDs */ + tmp_manf = chip->read_byte(mtd); + tmp_id = chip->read_byte(mtd); if (!type) return ERR_PTR(-ENODEV); @@ -2409,6 +2466,21 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, mtd->oobsize = mtd->writesize / 32; busw = type->options & NAND_BUSWIDTH_16; } + /* Get chip options, preserve non chip based options */ + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + + /* Check if chip is a not a samsung device. Do not clear the + * options for chips which are not having an extended id. + */ + if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; +ident_done: + + /* + * Set chip as a default. Board drivers can override it, if necessary + */ + chip->options |= NAND_NO_AUTOINCR; /* Try to identify manufacturer */ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { @@ -2423,7 +2495,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (busw != (chip->options & NAND_BUSWIDTH_16)) { printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); printk(KERN_WARNING "NAND bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); @@ -2443,21 +2515,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->badblockpos = mtd->writesize > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; - /* Get chip options, preserve non chip based options */ - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - - /* - * Set chip as a default. Board drivers can override it, if necessary - */ - chip->options |= NAND_NO_AUTOINCR; - - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; - /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) chip->erase_cmd = multi_erase_cmd; @@ -2468,9 +2525,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; + /* TODO onfi flash name */ printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, - nand_manuf_ids[maf_idx].name, type->name); + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, + nand_manuf_ids[maf_idx].name, type?type->name:mtd->name); return type; } @@ -2487,7 +2545,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, */ int nand_scan_ident(struct mtd_info *mtd, int maxchips) { - int i, busw, nand_maf_id; + int i, busw, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; @@ -2497,7 +2555,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) nand_set_defaults(chip, busw); /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); + type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, &nand_dev_id); if (IS_ERR(type)) { printk(KERN_WARNING "No NAND device found!!!\n"); @@ -2514,7 +2572,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || - type->id != chip->read_byte(mtd)) + nand_dev_id != chip->read_byte(mtd)) break; } if (i > 1) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 81774e5..edf3d27 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -78,6 +78,7 @@ extern void nand_wait_ready(struct mtd_info *mtd); #define NAND_CMD_RNDIN 0x85 #define NAND_CMD_READID 0x90 #define NAND_CMD_ERASE2 0xd0 +#define NAND_CMD_PARAM 0xec #define NAND_CMD_RESET 0xff /* Extended commands for large page devices */