Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kevin Cernekee and committed by
David Woodhouse
426c457a 9ea59738

+45 -21
+44 -20
drivers/mtd/nand/nand_base.c
··· 2774 2774 int busw, int *maf_id, 2775 2775 struct nand_flash_dev *type) 2776 2776 { 2777 - int dev_id, maf_idx; 2778 - int tmp_id, tmp_manf; 2777 + int i, dev_id, maf_idx; 2778 + u8 id_data[8]; 2779 2779 2780 2780 /* Select the device */ 2781 2781 chip->select_chip(mtd, 0); ··· 2801 2801 2802 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); 2807 - tmp_id = chip->read_byte(mtd); 2806 + for (i = 0; i < 8; i++) 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 2810 printk(KERN_INFO "%s: second ID read did not match " 2811 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 2813 return ERR_PTR(-ENODEV); 2814 2814 } 2815 2815 ··· 2832 2832 if (!type->pagesize) { 2833 2833 int extid; 2834 2834 /* The 3rd id byte holds MLC / multichip data */ 2835 - chip->cellinfo = chip->read_byte(mtd); 2835 + chip->cellinfo = id_data[2]; 2836 2836 /* The 4th id byte is the important one */ 2837 - extid = chip->read_byte(mtd); 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; 2837 + extid = id_data[3]; 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 2874 } else { 2851 2875 /* 2852 2876 * Old devices have chip data hardcoded in the device id table
+1 -1
include/linux/mtd/nand.h
··· 53 53 * is supported now. If you add a chip with bigger oobsize/page 54 54 * adjust this accordingly. 55 55 */ 56 - #define NAND_MAX_OOBSIZE 128 56 + #define NAND_MAX_OOBSIZE 256 57 57 #define NAND_MAX_PAGESIZE 4096 58 58 59 59 /*