diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2010-05-04 23:58:03 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-05-13 20:54:44 -0400 |
commit | 426c457a3216fac74e3d44dd39729b0689f4c7ab (patch) | |
tree | cb250bba8d202484a44c9302caf3717eec5538d2 /drivers/mtd/nand/nand_base.c | |
parent | 9ea5973883bbe26372f45d99eb3a500f08d966f9 (diff) |
mtd: nand: extend NAND flash detection to new MLC chips
Some of the newer MLC devices have a 6-byte ID sequence in which
several field definitions differ from older chips in a manner that is
not backward compatible. For instance:
Samsung K9GAG08U0M (5-byte sequence): ec d5 14 b6 74
4th byte, bits 1:0 encode the page size: 0=1KiB, 1=2KiB, 2=4KiB, 3=8KiB
4th byte, bits 5:4 encode the block size: 0=64KiB, 1=128KiB, ...
4th byte, bit 6 encodes the OOB size: 0=8B/512B, 1=16B/512B
Samsung K9GAG08U0D (6-byte sequence): ec d5 94 29 34 41
4th byte, bits 1:0 encode the page size: 0=2KiB, 1=4KiB, 3=8KiB, 4=rsvd
4th byte, bits 7;5:4 encode the block size: 0=128KiB, 1=256KiB, ...
4th byte, bits 6;3:2 encode the OOB size: 1=128B/page, 2=218B/page
This patch uses the new 6-byte scheme if the following conditions are
all true:
1) The ID code wraps around after exactly 6 bytes
2) Manufacturer is Samsung
3) 6th byte is zero
The patch also extends the maximum OOB size from 128B to 256B.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b9dc65c7253c..85891dcc27ad 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -2774,8 +2774,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2774 | int busw, int *maf_id, | 2774 | int busw, int *maf_id, |
2775 | struct nand_flash_dev *type) | 2775 | struct nand_flash_dev *type) |
2776 | { | 2776 | { |
2777 | int dev_id, maf_idx; | 2777 | int i, dev_id, maf_idx; |
2778 | int tmp_id, tmp_manf; | 2778 | u8 id_data[8]; |
2779 | 2779 | ||
2780 | /* Select the device */ | 2780 | /* Select the device */ |
2781 | chip->select_chip(mtd, 0); | 2781 | chip->select_chip(mtd, 0); |
@@ -2801,15 +2801,15 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2801 | 2801 | ||
2802 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 2802 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
2803 | 2803 | ||
2804 | /* Read manufacturer and device IDs */ | 2804 | /* Read entire ID string */ |
2805 | 2805 | ||
2806 | tmp_manf = chip->read_byte(mtd); | 2806 | for (i = 0; i < 8; i++) |
2807 | tmp_id = chip->read_byte(mtd); | 2807 | id_data[i] = chip->read_byte(mtd); |
2808 | 2808 | ||
2809 | if (tmp_manf != *maf_id || tmp_id != dev_id) { | 2809 | if (id_data[0] != *maf_id || id_data[1] != dev_id) { |
2810 | printk(KERN_INFO "%s: second ID read did not match " | 2810 | printk(KERN_INFO "%s: second ID read did not match " |
2811 | "%02x,%02x against %02x,%02x\n", __func__, | 2811 | "%02x,%02x against %02x,%02x\n", __func__, |
2812 | *maf_id, dev_id, tmp_manf, tmp_id); | 2812 | *maf_id, dev_id, id_data[0], id_data[1]); |
2813 | return ERR_PTR(-ENODEV); | 2813 | return ERR_PTR(-ENODEV); |
2814 | } | 2814 | } |
2815 | 2815 | ||
@@ -2832,21 +2832,45 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2832 | if (!type->pagesize) { | 2832 | if (!type->pagesize) { |
2833 | int extid; | 2833 | int extid; |
2834 | /* The 3rd id byte holds MLC / multichip data */ | 2834 | /* The 3rd id byte holds MLC / multichip data */ |
2835 | chip->cellinfo = chip->read_byte(mtd); | 2835 | chip->cellinfo = id_data[2]; |
2836 | /* The 4th id byte is the important one */ | 2836 | /* The 4th id byte is the important one */ |
2837 | extid = chip->read_byte(mtd); | 2837 | extid = id_data[3]; |
2838 | /* Calc pagesize */ | ||
2839 | mtd->writesize = 1024 << (extid & 0x3); | ||
2840 | extid >>= 2; | ||
2841 | /* Calc oobsize */ | ||
2842 | mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); | ||
2843 | extid >>= 2; | ||
2844 | /* Calc blocksize. Blocksize is multiples of 64KiB */ | ||
2845 | mtd->erasesize = (64 * 1024) << (extid & 0x03); | ||
2846 | extid >>= 2; | ||
2847 | /* Get buswidth information */ | ||
2848 | busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; | ||
2849 | 2838 | ||
2839 | /* | ||
2840 | * Field definitions are in the following datasheets: | ||
2841 | * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) | ||
2842 | * New style (6 byte ID): Samsung K9GAG08U0D (p.40) | ||
2843 | * | ||
2844 | * Check for wraparound + Samsung ID + nonzero 6th byte | ||
2845 | * to decide what to do. | ||
2846 | */ | ||
2847 | if (id_data[0] == id_data[6] && id_data[1] == id_data[7] && | ||
2848 | id_data[0] == NAND_MFR_SAMSUNG && | ||
2849 | id_data[5] != 0x00) { | ||
2850 | /* Calc pagesize */ | ||
2851 | mtd->writesize = 2048 << (extid & 0x03); | ||
2852 | extid >>= 2; | ||
2853 | /* Calc oobsize */ | ||
2854 | mtd->oobsize = (extid & 0x03) == 0x01 ? 128 : 218; | ||
2855 | extid >>= 2; | ||
2856 | /* Calc blocksize */ | ||
2857 | mtd->erasesize = (128 * 1024) << | ||
2858 | (((extid >> 1) & 0x04) | (extid & 0x03)); | ||
2859 | busw = 0; | ||
2860 | } else { | ||
2861 | /* Calc pagesize */ | ||
2862 | mtd->writesize = 1024 << (extid & 0x03); | ||
2863 | extid >>= 2; | ||
2864 | /* Calc oobsize */ | ||
2865 | mtd->oobsize = (8 << (extid & 0x01)) * | ||
2866 | (mtd->writesize >> 9); | ||
2867 | extid >>= 2; | ||
2868 | /* Calc blocksize. Blocksize is multiples of 64KiB */ | ||
2869 | mtd->erasesize = (64 * 1024) << (extid & 0x03); | ||
2870 | extid >>= 2; | ||
2871 | /* Get buswidth information */ | ||
2872 | busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; | ||
2873 | } | ||
2850 | } else { | 2874 | } else { |
2851 | /* | 2875 | /* |
2852 | * Old devices have chip data hardcoded in the device id table | 2876 | * Old devices have chip data hardcoded in the device id table |