diff options
| author | Florian Fainelli <florian@openwrt.org> | 2010-08-30 12:32:24 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-10-24 18:46:34 -0400 |
| commit | d1e1f4e42b5df063712ca2926e50c07b95c96b96 (patch) | |
| tree | 6dc4ab018397d5029690957b27d376e25d1c1f85 | |
| parent | 42af8b58fb5ec97214e85780db71bb9d60541fcc (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.c | 164 | ||||
| -rw-r--r-- | include/linux/mtd/nand.h | 68 |
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 | */ | ||
| 2792 | static 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 | |||
| 2809 | static 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 | */ |
| 2792 | static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | 2824 | static 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 | |||
