aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2010-08-30 12:32:24 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-10-24 18:46:34 -0400
commitd1e1f4e42b5df063712ca2926e50c07b95c96b96 (patch)
tree6dc4ab018397d5029690957b27d376e25d1c1f85
parent42af8b58fb5ec97214e85780db71bb9d60541fcc (diff)
mtd: nand: add support for reading ONFI parameters from NAND device
This patch adds support for reading NAND device ONFI parameters and use the ONFI informations to define its geometry. In case the device supports ONFI, the onfi_version field in struct nand_chip contains the version (BCD) and the onfi_params structure can be used by drivers to set up timings and such. We currently only support ONFI 1.0 parameters. Signed-off-by: Brian Norris <norris@broadcom.com> Signed-off-by: Matthieu Castet <matthieu.castet@parrot.com> Signed-off-by: Maxime Bizon <mbizon@freebox.fr> Signed-off-by: Florian Fainelli <ffainelli@freebox.fr> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/nand/nand_base.c164
-rw-r--r--include/linux/mtd/nand.h68
2 files changed, 202 insertions, 30 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 596ac848b46d..5b26fffc3534 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2787,14 +2787,46 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
2787} 2787}
2788 2788
2789/* 2789/*
2790 * sanitize ONFI strings so we can safely print them
2791 */
2792static void sanitize_string(uint8_t *s, size_t len)
2793{
2794 ssize_t i;
2795
2796 /* null terminate */
2797 s[len - 1] = 0;
2798
2799 /* remove non printable chars */
2800 for (i = 0; i < len - 1; i++) {
2801 if (s[i] < ' ' || s[i] > 127)
2802 s[i] = '?';
2803 }
2804
2805 /* remove trailing spaces */
2806 strim(s);
2807}
2808
2809static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
2810{
2811 int i;
2812 while (len--) {
2813 crc ^= *p++ << 8;
2814 for (i = 0; i < 8; i++)
2815 crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
2816 }
2817
2818 return crc;
2819}
2820
2821/*
2790 * Get the flash and manufacturer id and lookup if the type is supported 2822 * Get the flash and manufacturer id and lookup if the type is supported
2791 */ 2823 */
2792static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, 2824static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2793 struct nand_chip *chip, 2825 struct nand_chip *chip,
2794 int busw, int *maf_id, 2826 int busw, int *maf_id, int *dev_id,
2795 struct nand_flash_dev *type) 2827 struct nand_flash_dev *type)
2796{ 2828{
2797 int i, dev_id, maf_idx; 2829 int i, maf_idx;
2798 u8 id_data[8]; 2830 u8 id_data[8];
2799 2831
2800 /* Select the device */ 2832 /* Select the device */
@@ -2811,7 +2843,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2811 2843
2812 /* Read manufacturer and device IDs */ 2844 /* Read manufacturer and device IDs */
2813 *maf_id = chip->read_byte(mtd); 2845 *maf_id = chip->read_byte(mtd);
2814 dev_id = chip->read_byte(mtd); 2846 *dev_id = chip->read_byte(mtd);
2815 2847
2816 /* Try again to make sure, as some systems the bus-hold or other 2848 /* Try again to make sure, as some systems the bus-hold or other
2817 * interface concerns can cause random data which looks like a 2849 * interface concerns can cause random data which looks like a
@@ -2821,15 +2853,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2821 2853
2822 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); 2854 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
2823 2855
2824 /* Read entire ID string */ 2856 for (i = 0; i < 2; i++)
2825
2826 for (i = 0; i < 8; i++)
2827 id_data[i] = chip->read_byte(mtd); 2857 id_data[i] = chip->read_byte(mtd);
2828 2858
2829 if (id_data[0] != *maf_id || id_data[1] != dev_id) { 2859 if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
2830 printk(KERN_INFO "%s: second ID read did not match " 2860 printk(KERN_INFO "%s: second ID read did not match "
2831 "%02x,%02x against %02x,%02x\n", __func__, 2861 "%02x,%02x against %02x,%02x\n", __func__,
2832 *maf_id, dev_id, id_data[0], id_data[1]); 2862 *maf_id, *dev_id, id_data[0], id_data[1]);
2833 return ERR_PTR(-ENODEV); 2863 return ERR_PTR(-ENODEV);
2834 } 2864 }
2835 2865
@@ -2837,9 +2867,81 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2837 type = nand_flash_ids; 2867 type = nand_flash_ids;
2838 2868
2839 for (; type->name != NULL; type++) 2869 for (; type->name != NULL; type++)
2840 if (dev_id == type->id) 2870 if (*dev_id == type->id)
2841 break; 2871 break;
2842 2872
2873 chip->onfi_version = 0;
2874 if (!type->name || !type->pagesize) {
2875 /* try ONFI for unknow chip or LP */
2876 chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
2877 if (chip->read_byte(mtd) == 'O' &&
2878 chip->read_byte(mtd) == 'N' &&
2879 chip->read_byte(mtd) == 'F' &&
2880 chip->read_byte(mtd) == 'I') {
2881
2882 struct nand_onfi_params *p = &chip->onfi_params;
2883 int i;
2884
2885 printk(KERN_INFO "ONFI flash detected\n");
2886 chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
2887 for (i = 0; i < 3; i++) {
2888 chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
2889 if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
2890 le16_to_cpu(p->crc))
2891 {
2892 printk(KERN_INFO "ONFI param page %d valid\n", i);
2893 break;
2894 }
2895 }
2896
2897 if (i < 3) {
2898 /* check version */
2899 int val = le16_to_cpu(p->revision);
2900 if (val == 1 || val > (1 << 4))
2901 printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
2902 __func__, val);
2903 else {
2904 if (val & (1 << 4))
2905 chip->onfi_version = 22;
2906 else if (val & (1 << 3))
2907 chip->onfi_version = 21;
2908 else if (val & (1 << 2))
2909 chip->onfi_version = 20;
2910 else
2911 chip->onfi_version = 10;
2912 }
2913 }
2914
2915 if (chip->onfi_version) {
2916 sanitize_string(p->manufacturer, sizeof(p->manufacturer));
2917 sanitize_string(p->model, sizeof(p->model));
2918 if (!mtd->name)
2919 mtd->name = p->model;
2920 mtd->writesize = le32_to_cpu(p->byte_per_page);
2921 mtd->erasesize = le32_to_cpu(p->pages_per_block)*mtd->writesize;
2922 mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
2923 chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
2924 busw = 0;
2925 if (le16_to_cpu(p->features) & 1)
2926 busw = NAND_BUSWIDTH_16;
2927
2928 chip->options &= ~NAND_CHIPOPTIONS_MSK;
2929 chip->options |= (NAND_NO_READRDY |
2930 NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
2931
2932 goto ident_done;
2933
2934 }
2935 }
2936 }
2937
2938 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
2939
2940 /* Read entire ID string */
2941
2942 for (i = 0; i < 8; i++)
2943 id_data[i] = chip->read_byte(mtd);
2944
2843 if (!type->name) 2945 if (!type->name)
2844 return ERR_PTR(-ENODEV); 2946 return ERR_PTR(-ENODEV);
2845 2947
@@ -2927,6 +3029,21 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2927 mtd->erasesize <<= ((id_data[3] & 0x03) << 1); 3029 mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
2928 } 3030 }
2929 } 3031 }
3032 /* Get chip options, preserve non chip based options */
3033 chip->options &= ~NAND_CHIPOPTIONS_MSK;
3034 chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
3035