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

mtd: spinand: rework detect procedure for different READ_ID operation

Currently there are 3 different variants of read_id implementation:
1. opcode only. Found in GD5FxGQ4xF.
2. opcode + 1 addr byte. Found in GD5GxGQ4xA/E
3. opcode + 1 dummy byte. Found in other currently supported chips.

Original implementation was for variant 1 and let detect function
of chips with variant 2 and 3 to ignore the first byte. This isn't
robust:

1. For chips of variant 2, if SPI master doesn't keep MOSI low
during read, chip will get a random id offset, and the entire id
buffer will shift by that offset, causing detect failure.

2. For chips of variant 1, if it happens to get a devid that equals
to manufacture id of variant 2 or 3 chips, it'll get incorrectly
detected.

This patch reworks detect procedure to address problems above. New
logic do detection for all variants separatedly, in 1-2-3 order.
Since all current detect methods do exactly the same id matching
procedure, unify them into core.c and remove detect method from
manufacture_ops.

Tested on GD5F1GQ4UAYIG and W25N01GVZEIG.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200208074439.146296-1-gch981213@gmail.com

authored by

Chuanhong Guo and committed by
Miquel Raynal
f1541773 a91f8170

+157 -203
+63 -23
drivers/mtd/nand/spi/core.c
··· 16 16 #include <linux/mtd/spinand.h> 17 17 #include <linux/of.h> 18 18 #include <linux/slab.h> 19 + #include <linux/string.h> 19 20 #include <linux/spi/spi.h> 20 21 #include <linux/spi/spi-mem.h> 21 22 ··· 371 370 return status & STATUS_BUSY ? -ETIMEDOUT : 0; 372 371 } 373 372 374 - static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf) 373 + static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr, 374 + u8 ndummy, u8 *buf) 375 375 { 376 - struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf, 377 - SPINAND_MAX_ID_LEN); 376 + struct spi_mem_op op = SPINAND_READID_OP( 377 + naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN); 378 378 int ret; 379 379 380 380 ret = spi_mem_exec_op(spinand->spimem, &op); ··· 764 762 &winbond_spinand_manufacturer, 765 763 }; 766 764 767 - static int spinand_manufacturer_detect(struct spinand_device *spinand) 765 + static int spinand_manufacturer_match(struct spinand_device *spinand, 766 + enum spinand_readid_method rdid_method) 768 767 { 768 + u8 *id = spinand->id.data; 769 769 unsigned int i; 770 770 int ret; 771 771 772 772 for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) { 773 - ret = spinand_manufacturers[i]->ops->detect(spinand); 774 - if (ret > 0) { 775 - spinand->manufacturer = spinand_manufacturers[i]; 776 - return 0; 777 - } else if (ret < 0) { 778 - return ret; 779 - } 780 - } 773 + const struct spinand_manufacturer *manufacturer = 774 + spinand_manufacturers[i]; 781 775 776 + if (id[0] != manufacturer->id) 777 + continue; 778 + 779 + ret = spinand_match_and_init(spinand, 780 + manufacturer->chips, 781 + manufacturer->nchips, 782 + rdid_method); 783 + if (ret < 0) 784 + continue; 785 + 786 + spinand->manufacturer = manufacturer; 787 + return 0; 788 + } 782 789 return -ENOTSUPP; 790 + } 791 + 792 + static int spinand_id_detect(struct spinand_device *spinand) 793 + { 794 + u8 *id = spinand->id.data; 795 + int ret; 796 + 797 + ret = spinand_read_id_op(spinand, 0, 0, id); 798 + if (ret) 799 + return ret; 800 + ret = spinand_manufacturer_match(spinand, SPINAND_READID_METHOD_OPCODE); 801 + if (!ret) 802 + return 0; 803 + 804 + ret = spinand_read_id_op(spinand, 1, 0, id); 805 + if (ret) 806 + return ret; 807 + ret = spinand_manufacturer_match(spinand, 808 + SPINAND_READID_METHOD_OPCODE_ADDR); 809 + if (!ret) 810 + return 0; 811 + 812 + ret = spinand_read_id_op(spinand, 0, 1, id); 813 + if (ret) 814 + return ret; 815 + ret = spinand_manufacturer_match(spinand, 816 + SPINAND_READID_METHOD_OPCODE_DUMMY); 817 + 818 + return ret; 783 819 } 784 820 785 821 static int spinand_manufacturer_init(struct spinand_device *spinand) ··· 875 835 * @spinand: SPI NAND object 876 836 * @table: SPI NAND device description table 877 837 * @table_size: size of the device description table 838 + * @rdid_method: read id method to match 878 839 * 879 - * Should be used by SPI NAND manufacturer drivers when they want to find a 880 - * match between a device ID retrieved through the READ_ID command and an 840 + * Match between a device ID retrieved through the READ_ID command and an 881 841 * entry in the SPI NAND description table. If a match is found, the spinand 882 842 * object will be initialized with information provided by the matching 883 843 * spinand_info entry. ··· 886 846 */ 887 847 int spinand_match_and_init(struct spinand_device *spinand, 888 848 const struct spinand_info *table, 889 - unsigned int table_size, u16 devid) 849 + unsigned int table_size, 850 + enum spinand_readid_method rdid_method) 890 851 { 852 + u8 *id = spinand->id.data; 891 853 struct nand_device *nand = spinand_to_nand(spinand); 892 854 unsigned int i; 893 855 ··· 897 855 const struct spinand_info *info = &table[i]; 898 856 const struct spi_mem_op *op; 899 857 900 - if (devid != info->devid) 858 + if (rdid_method != info->devid.method) 859 + continue; 860 + 861 + if (memcmp(id + 1, info->devid.id, info->devid.len)) 901 862 continue; 902 863 903 864 nand->memorg = table[i].memorg; 904 865 nand->eccreq = table[i].eccreq; 905 866 spinand->eccinfo = table[i].eccinfo; 906 867 spinand->flags = table[i].flags; 868 + spinand->id.len = 1 + table[i].devid.len; 907 869 spinand->select_target = table[i].select_target; 908 870 909 871 op = spinand_select_op_variant(spinand, ··· 944 898 if (ret) 945 899 return ret; 946 900 947 - ret = spinand_read_id_op(spinand, spinand->id.data); 948 - if (ret) 949 - return ret; 950 - 951 - spinand->id.len = SPINAND_MAX_ID_LEN; 952 - 953 - ret = spinand_manufacturer_detect(spinand); 901 + ret = spinand_id_detect(spinand); 954 902 if (ret) { 955 903 dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN, 956 904 spinand->id.data);
+12 -33
drivers/mtd/nand/spi/gigadevice.c
··· 195 195 } 196 196 197 197 static const struct spinand_info gigadevice_spinand_table[] = { 198 - SPINAND_INFO("GD5F1GQ4xA", 0xF1, 198 + SPINAND_INFO("GD5F1GQ4xA", 199 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1), 199 200 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), 200 201 NAND_ECCREQ(8, 512), 201 202 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 205 204 0, 206 205 SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, 207 206 gd5fxgq4xa_ecc_get_status)), 208 - SPINAND_INFO("GD5F2GQ4xA", 0xF2, 207 + SPINAND_INFO("GD5F2GQ4xA", 208 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2), 209 209 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), 210 210 NAND_ECCREQ(8, 512), 211 211 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 215 213 0, 216 214 SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, 217 215 gd5fxgq4xa_ecc_get_status)), 218 - SPINAND_INFO("GD5F4GQ4xA", 0xF4, 216 + SPINAND_INFO("GD5F4GQ4xA", 217 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4), 219 218 NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1), 220 219 NAND_ECCREQ(8, 512), 221 220 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 225 222 0, 226 223 SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, 227 224 gd5fxgq4xa_ecc_get_status)), 228 - SPINAND_INFO("GD5F1GQ4UExxG", 0xd1, 225 + SPINAND_INFO("GD5F1GQ4UExxG", 226 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1), 229 227 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 230 228 NAND_ECCREQ(8, 512), 231 229 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 235 231 0, 236 232 SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, 237 233 gd5fxgq4uexxg_ecc_get_status)), 238 - SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148, 234 + SPINAND_INFO("GD5F1GQ4UFxxG", 235 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48), 239 236 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 240 237 NAND_ECCREQ(8, 512), 241 238 SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f, ··· 247 242 gd5fxgq4ufxxg_ecc_get_status)), 248 243 }; 249 244 250 - static int gigadevice_spinand_detect(struct spinand_device *spinand) 251 - { 252 - u8 *id = spinand->id.data; 253 - u16 did; 254 - int ret; 255 - 256 - /* 257 - * Earlier GDF5-series devices (A,E) return [0][MID][DID] 258 - * Later (F) devices return [MID][DID1][DID2] 259 - */ 260 - 261 - if (id[0] == SPINAND_MFR_GIGADEVICE) 262 - did = (id[1] << 8) + id[2]; 263 - else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE) 264 - did = id[2]; 265 - else 266 - return 0; 267 - 268 - ret = spinand_match_and_init(spinand, gigadevice_spinand_table, 269 - ARRAY_SIZE(gigadevice_spinand_table), 270 - did); 271 - if (ret) 272 - return ret; 273 - 274 - return 1; 275 - } 276 - 277 245 static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { 278 - .detect = gigadevice_spinand_detect, 279 246 }; 280 247 281 248 const struct spinand_manufacturer gigadevice_spinand_manufacturer = { 282 249 .id = SPINAND_MFR_GIGADEVICE, 283 250 .name = "GigaDevice", 251 + .chips = gigadevice_spinand_table, 252 + .nchips = ARRAY_SIZE(gigadevice_spinand_table), 284 253 .ops = &gigadevice_spinand_manuf_ops, 285 254 };
+6 -24
drivers/mtd/nand/spi/macronix.c
··· 99 99 } 100 100 101 101 static const struct spinand_info macronix_spinand_table[] = { 102 - SPINAND_INFO("MX35LF1GE4AB", 0x12, 102 + SPINAND_INFO("MX35LF1GE4AB", 103 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12), 103 104 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), 104 105 NAND_ECCREQ(4, 512), 105 106 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 109 108 SPINAND_HAS_QE_BIT, 110 109 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, 111 110 mx35lf1ge4ab_ecc_get_status)), 112 - SPINAND_INFO("MX35LF2GE4AB", 0x22, 111 + SPINAND_INFO("MX35LF2GE4AB", 112 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22), 113 113 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1), 114 114 NAND_ECCREQ(4, 512), 115 115 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 120 118 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), 121 119 }; 122 120 123 - static int macronix_spinand_detect(struct spinand_device *spinand) 124 - { 125 - u8 *id = spinand->id.data; 126 - int ret; 127 - 128 - /* 129 - * Macronix SPI NAND read ID needs a dummy byte, so the first byte in 130 - * raw_id is garbage. 131 - */ 132 - if (id[1] != SPINAND_MFR_MACRONIX) 133 - return 0; 134 - 135 - ret = spinand_match_and_init(spinand, macronix_spinand_table, 136 - ARRAY_SIZE(macronix_spinand_table), 137 - id[2]); 138 - if (ret) 139 - return ret; 140 - 141 - return 1; 142 - } 143 - 144 121 static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = { 145 - .detect = macronix_spinand_detect, 146 122 }; 147 123 148 124 const struct spinand_manufacturer macronix_spinand_manufacturer = { 149 125 .id = SPINAND_MFR_MACRONIX, 150 126 .name = "Macronix", 127 + .chips = macronix_spinand_table, 128 + .nchips = ARRAY_SIZE(macronix_spinand_table), 151 129 .ops = &macronix_spinand_manuf_ops, 152 130 };
+4 -22
drivers/mtd/nand/spi/micron.c
··· 91 91 } 92 92 93 93 static const struct spinand_info micron_spinand_table[] = { 94 - SPINAND_INFO("MT29F2G01ABAGD", 0x24, 94 + SPINAND_INFO("MT29F2G01ABAGD", 95 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), 95 96 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), 96 97 NAND_ECCREQ(8, 512), 97 98 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 103 102 mt29f2g01abagd_ecc_get_status)), 104 103 }; 105 104 106 - static int micron_spinand_detect(struct spinand_device *spinand) 107 - { 108 - u8 *id = spinand->id.data; 109 - int ret; 110 - 111 - /* 112 - * Micron SPI NAND read ID need a dummy byte, 113 - * so the first byte in raw_id is dummy. 114 - */ 115 - if (id[1] != SPINAND_MFR_MICRON) 116 - return 0; 117 - 118 - ret = spinand_match_and_init(spinand, micron_spinand_table, 119 - ARRAY_SIZE(micron_spinand_table), id[2]); 120 - if (ret) 121 - return ret; 122 - 123 - return 1; 124 - } 125 - 126 105 static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = { 127 - .detect = micron_spinand_detect, 128 106 }; 129 107 130 108 const struct spinand_manufacturer micron_spinand_manufacturer = { 131 109 .id = SPINAND_MFR_MICRON, 132 110 .name = "Micron", 111 + .chips = micron_spinand_table, 112 + .nchips = ARRAY_SIZE(micron_spinand_table), 133 113 .ops = &micron_spinand_manuf_ops, 134 114 };
+6 -22
drivers/mtd/nand/spi/paragon.c
··· 97 97 98 98 99 99 static const struct spinand_info paragon_spinand_table[] = { 100 - SPINAND_INFO("PN26G01A", 0xe1, 100 + SPINAND_INFO("PN26G01A", 101 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe1), 101 102 NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1), 102 103 NAND_ECCREQ(8, 512), 103 104 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 107 106 0, 108 107 SPINAND_ECCINFO(&pn26g0xa_ooblayout, 109 108 pn26g0xa_ecc_get_status)), 110 - SPINAND_INFO("PN26G02A", 0xe2, 109 + SPINAND_INFO("PN26G02A", 110 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe2), 111 111 NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1), 112 112 NAND_ECCREQ(8, 512), 113 113 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 119 117 pn26g0xa_ecc_get_status)), 120 118 }; 121 119 122 - static int paragon_spinand_detect(struct spinand_device *spinand) 123 - { 124 - u8 *id = spinand->id.data; 125 - int ret; 126 - 127 - /* Read ID returns [0][MID][DID] */ 128 - 129 - if (id[1] != SPINAND_MFR_PARAGON) 130 - return 0; 131 - 132 - ret = spinand_match_and_init(spinand, paragon_spinand_table, 133 - ARRAY_SIZE(paragon_spinand_table), 134 - id[2]); 135 - if (ret) 136 - return ret; 137 - 138 - return 1; 139 - } 140 - 141 120 static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = { 142 - .detect = paragon_spinand_detect, 143 121 }; 144 122 145 123 const struct spinand_manufacturer paragon_spinand_manufacturer = { 146 124 .id = SPINAND_MFR_PARAGON, 147 125 .name = "Paragon", 126 + .chips = paragon_spinand_table, 127 + .nchips = ARRAY_SIZE(paragon_spinand_table), 148 128 .ops = &paragon_spinand_manuf_ops, 149 129 };
+16 -29
drivers/mtd/nand/spi/toshiba.c
··· 96 96 97 97 static const struct spinand_info toshiba_spinand_table[] = { 98 98 /* 3.3V 1Gb */ 99 - SPINAND_INFO("TC58CVG0S3", 0xC2, 99 + SPINAND_INFO("TC58CVG0S3", 100 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2), 100 101 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 101 102 NAND_ECCREQ(8, 512), 102 103 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 107 106 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 108 107 tc58cxgxsx_ecc_get_status)), 109 108 /* 3.3V 2Gb */ 110 - SPINAND_INFO("TC58CVG1S3", 0xCB, 109 + SPINAND_INFO("TC58CVG1S3", 110 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB), 111 111 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), 112 112 NAND_ECCREQ(8, 512), 113 113 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 118 116 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 119 117 tc58cxgxsx_ecc_get_status)), 120 118 /* 3.3V 4Gb */ 121 - SPINAND_INFO("TC58CVG2S0", 0xCD, 119 + SPINAND_INFO("TC58CVG2S0", 120 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD), 122 121 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 123 122 NAND_ECCREQ(8, 512), 124 123 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 129 126 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 130 127 tc58cxgxsx_ecc_get_status)), 131 128 /* 3.3V 4Gb */ 132 - SPINAND_INFO("TC58CVG2S0", 0xED, 129 + SPINAND_INFO("TC58CVG2S0", 130 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED), 133 131 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 134 132 NAND_ECCREQ(8, 512), 135 133 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 140 136 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 141 137 tc58cxgxsx_ecc_get_status)), 142 138 /* 1.8V 1Gb */ 143 - SPINAND_INFO("TC58CYG0S3", 0xB2, 139 + SPINAND_INFO("TC58CYG0S3", 140 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2), 144 141 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 145 142 NAND_ECCREQ(8, 512), 146 143 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 151 146 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 152 147 tc58cxgxsx_ecc_get_status)), 153 148 /* 1.8V 2Gb */ 154 - SPINAND_INFO("TC58CYG1S3", 0xBB, 149 + SPINAND_INFO("TC58CYG1S3", 150 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB), 155 151 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), 156 152 NAND_ECCREQ(8, 512), 157 153 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 162 156 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 163 157 tc58cxgxsx_ecc_get_status)), 164 158 /* 1.8V 4Gb */ 165 - SPINAND_INFO("TC58CYG2S0", 0xBD, 159 + SPINAND_INFO("TC58CYG2S0", 160 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD), 166 161 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 167 162 NAND_ECCREQ(8, 512), 168 163 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 174 167 tc58cxgxsx_ecc_get_status)), 175 168 }; 176 169 177 - static int toshiba_spinand_detect(struct spinand_device *spinand) 178 - { 179 - u8 *id = spinand->id.data; 180 - int ret; 181 - 182 - /* 183 - * Toshiba SPI NAND read ID needs a dummy byte, 184 - * so the first byte in id is garbage. 185 - */ 186 - if (id[1] != SPINAND_MFR_TOSHIBA) 187 - return 0; 188 - 189 - ret = spinand_match_and_init(spinand, toshiba_spinand_table, 190 - ARRAY_SIZE(toshiba_spinand_table), 191 - id[2]); 192 - if (ret) 193 - return ret; 194 - 195 - return 1; 196 - } 197 - 198 170 static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { 199 - .detect = toshiba_spinand_detect, 200 171 }; 201 172 202 173 const struct spinand_manufacturer toshiba_spinand_manufacturer = { 203 174 .id = SPINAND_MFR_TOSHIBA, 204 175 .name = "Toshiba", 176 + .chips = toshiba_spinand_table, 177 + .nchips = ARRAY_SIZE(toshiba_spinand_table), 205 178 .ops = &toshiba_spinand_manuf_ops, 206 179 };
+6 -28
drivers/mtd/nand/spi/winbond.c
··· 75 75 } 76 76 77 77 static const struct spinand_info winbond_spinand_table[] = { 78 - SPINAND_INFO("W25M02GV", 0xAB, 78 + SPINAND_INFO("W25M02GV", 79 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), 79 80 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), 80 81 NAND_ECCREQ(1, 512), 81 82 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 85 84 0, 86 85 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), 87 86 SPINAND_SELECT_TARGET(w25m02gv_select_target)), 88 - SPINAND_INFO("W25N01GV", 0xAA, 87 + SPINAND_INFO("W25N01GV", 88 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), 89 89 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), 90 90 NAND_ECCREQ(1, 512), 91 91 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ··· 95 93 0, 96 94 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), 97 95 }; 98 - 99 - /** 100 - * winbond_spinand_detect - initialize device related part in spinand_device 101 - * struct if it is a Winbond device. 102 - * @spinand: SPI NAND device structure 103 - */ 104 - static int winbond_spinand_detect(struct spinand_device *spinand) 105 - { 106 - u8 *id = spinand->id.data; 107 - int ret; 108 - 109 - /* 110 - * Winbond SPI NAND read ID need a dummy byte, 111 - * so the first byte in raw_id is dummy. 112 - */ 113 - if (id[1] != SPINAND_MFR_WINBOND) 114 - return 0; 115 - 116 - ret = spinand_match_and_init(spinand, winbond_spinand_table, 117 - ARRAY_SIZE(winbond_spinand_table), id[2]); 118 - if (ret) 119 - return ret; 120 - 121 - return 1; 122 - } 123 96 124 97 static int winbond_spinand_init(struct spinand_device *spinand) 125 98 { ··· 115 138 } 116 139 117 140 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = { 118 - .detect = winbond_spinand_detect, 119 141 .init = winbond_spinand_init, 120 142 }; 121 143 122 144 const struct spinand_manufacturer winbond_spinand_manufacturer = { 123 145 .id = SPINAND_MFR_WINBOND, 124 146 .name = "Winbond", 147 + .chips = winbond_spinand_table, 148 + .nchips = ARRAY_SIZE(winbond_spinand_table), 125 149 .ops = &winbond_spinand_manuf_ops, 126 150 };
+44 -22
include/linux/mtd/spinand.h
··· 32 32 SPI_MEM_OP_NO_DUMMY, \ 33 33 SPI_MEM_OP_NO_DATA) 34 34 35 - #define SPINAND_READID_OP(ndummy, buf, len) \ 35 + #define SPINAND_READID_OP(naddr, ndummy, buf, len) \ 36 36 SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \ 37 - SPI_MEM_OP_NO_ADDR, \ 37 + SPI_MEM_OP_ADDR(naddr, 0, 1), \ 38 38 SPI_MEM_OP_DUMMY(ndummy, 1), \ 39 39 SPI_MEM_OP_DATA_IN(len, buf, 1)) 40 40 ··· 176 176 * @data: buffer containing the id bytes. Currently 4 bytes large, but can 177 177 * be extended if required 178 178 * @len: ID length 179 - * 180 - * struct_spinand_id->data contains all bytes returned after a READ_ID command, 181 - * including dummy bytes if the chip does not emit ID bytes right after the 182 - * READ_ID command. The responsibility to extract real ID bytes is left to 183 - * struct_manufacurer_ops->detect(). 184 179 */ 185 180 struct spinand_id { 186 181 u8 data[SPINAND_MAX_ID_LEN]; 187 182 int len; 188 183 }; 189 184 185 + enum spinand_readid_method { 186 + SPINAND_READID_METHOD_OPCODE, 187 + SPINAND_READID_METHOD_OPCODE_ADDR, 188 + SPINAND_READID_METHOD_OPCODE_DUMMY, 189 + }; 190 + 191 + /** 192 + * struct spinand_devid - SPI NAND device id structure 193 + * @id: device id of current chip 194 + * @len: number of bytes in device id 195 + * @method: method to read chip id 196 + * There are 3 possible variants: 197 + * SPINAND_READID_METHOD_OPCODE: chip id is returned immediately 198 + * after read_id opcode. 199 + * SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after 200 + * read_id opcode + 1-byte address. 201 + * SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after 202 + * read_id opcode + 1 dummy byte. 203 + */ 204 + struct spinand_devid { 205 + const u8 *id; 206 + const u8 len; 207 + const enum spinand_readid_method method; 208 + }; 209 + 190 210 /** 191 211 * struct manufacurer_ops - SPI NAND manufacturer specific operations 192 - * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed 193 - * the core calls the struct_manufacurer_ops->detect() hook of each 194 - * registered manufacturer until one of them return 1. Note that 195 - * the first thing to check in this hook is that the manufacturer ID 196 - * in struct_spinand_device->id matches the manufacturer whose 197 - * ->detect() hook has been called. Should return 1 if there's a 198 - * match, 0 if the manufacturer ID does not match and a negative 199 - * error code otherwise. When true is returned, the core assumes 200 - * that properties of the NAND chip (spinand->base.memorg and 201 - * spinand->base.eccreq) have been filled 202 212 * @init: initialize a SPI NAND device 203 213 * @cleanup: cleanup a SPI NAND device 204 214 * 205 215 * Each SPI NAND manufacturer driver should implement this interface so that 206 - * NAND chips coming from this vendor can be detected and initialized properly. 216 + * NAND chips coming from this vendor can be initialized properly. 207 217 */ 208 218 struct spinand_manufacturer_ops { 209 - int (*detect)(struct spinand_device *spinand); 210 219 int (*init)(struct spinand_device *spinand); 211 220 void (*cleanup)(struct spinand_device *spinand); 212 221 }; ··· 224 215 * struct spinand_manufacturer - SPI NAND manufacturer instance 225 216 * @id: manufacturer ID 226 217 * @name: manufacturer name 218 + * @devid_len: number of bytes in device ID 219 + * @chips: supported SPI NANDs under current manufacturer 220 + * @nchips: number of SPI NANDs available in chips array 227 221 * @ops: manufacturer operations 228 222 */ 229 223 struct spinand_manufacturer { 230 224 u8 id; 231 225 char *name; 226 + const struct spinand_info *chips; 227 + const size_t nchips; 232 228 const struct spinand_manufacturer_ops *ops; 233 229 }; 234 230 ··· 305 291 */ 306 292 struct spinand_info { 307 293 const char *model; 308 - u16 devid; 294 + struct spinand_devid devid; 309 295 u32 flags; 310 296 struct nand_memory_organization memorg; 311 297 struct nand_ecc_req eccreq; ··· 318 304 int (*select_target)(struct spinand_device *spinand, 319 305 unsigned int target); 320 306 }; 307 + 308 + #define SPINAND_ID(__method, ...) \ 309 + { \ 310 + .id = (const u8[]){ __VA_ARGS__ }, \ 311 + .len = sizeof((u8[]){ __VA_ARGS__ }), \ 312 + .method = __method, \ 313 + } 321 314 322 315 #define SPINAND_INFO_OP_VARIANTS(__read, __write, __update) \ 323 316 { \ ··· 472 451 nanddev_set_of_node(&spinand->base, np); 473 452 } 474 453 475 - int spinand_match_and_init(struct spinand_device *dev, 454 + int spinand_match_and_init(struct spinand_device *spinand, 476 455 const struct spinand_info *table, 477 - unsigned int table_size, u16 devid); 456 + unsigned int table_size, 457 + enum spinand_readid_method rdid_method); 478 458 479 459 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val); 480 460 int spinand_select_target(struct spinand_device *spinand, unsigned int target);