mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	mtd: nand: Add manufacturer specific initialization/detection steps
Upstream linux commit abbe26d144ec22. A lot of NANDs are implementing generic features in a non-generic way, or are providing advanced auto-detection logic where the NAND ID bytes meaning changes with the NAND generation. Providing this vendor specific initialization step will allow us to get rid of full-id entries in the nand_ids table or all the vendor specific cases added over the time in the generic NAND ID decoding logic. Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com> Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
This commit is contained in:
		| @@ -4286,6 +4286,39 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC | ||||||
|  |  * compliant and does not have a full-id or legacy-id entry in the nand_ids | ||||||
|  |  * table. | ||||||
|  |  */ | ||||||
|  | static void nand_manufacturer_detect(struct mtd_info *mtd, struct nand_chip *chip) | ||||||
|  | { | ||||||
|  | 	/* | ||||||
|  | 	 * Try manufacturer detection if available and use | ||||||
|  | 	 * nand_decode_ext_id() otherwise. | ||||||
|  | 	 */ | ||||||
|  | 	if (chip->manufacturer.desc && chip->manufacturer.desc->ops && | ||||||
|  | 	    chip->manufacturer.desc->ops->detect) | ||||||
|  | 		chip->manufacturer.desc->ops->detect(chip); | ||||||
|  | 	else | ||||||
|  | 		nand_decode_ext_id(mtd, chip); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Manufacturer initialization. This function is called for all NANDs including | ||||||
|  |  * ONFI and JEDEC compliant ones. | ||||||
|  |  * Manufacturer drivers should put all their specific initialization code in | ||||||
|  |  * their ->init() hook. | ||||||
|  |  */ | ||||||
|  | static int nand_manufacturer_init(struct nand_chip *chip) | ||||||
|  | { | ||||||
|  | 	if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops || | ||||||
|  | 	    !chip->manufacturer.desc->ops->init) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	return chip->manufacturer.desc->ops->init(chip); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Old devices have chip data hardcoded in the device ID table. nand_decode_id |  * Old devices have chip data hardcoded in the device ID table. nand_decode_id | ||||||
|  * decodes a matching ID table entry and assigns the MTD size parameters for |  * decodes a matching ID table entry and assigns the MTD size parameters for | ||||||
| @@ -4383,6 +4416,26 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * nand_get_manufacturer_desc - Get manufacturer information from the | ||||||
|  |  *                              manufacturer ID | ||||||
|  |  * @id: manufacturer ID | ||||||
|  |  * | ||||||
|  |  * Returns a nand_manufacturer_desc object if the manufacturer is defined | ||||||
|  |  * in the NAND manufacturers database, NULL otherwise. | ||||||
|  |  */ | ||||||
|  | static const struct nand_manufacturers *nand_get_manufacturer_desc(u8 id) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; nand_manuf_ids[i].id != 0x0; i++) { | ||||||
|  | 		if (nand_manuf_ids[i].id == id) | ||||||
|  | 			return &nand_manuf_ids[i]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Get the flash and manufacturer id and lookup if the type is supported. |  * Get the flash and manufacturer id and lookup if the type is supported. | ||||||
|  */ |  */ | ||||||
| @@ -4391,8 +4444,8 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||||||
| 						  int *maf_id, int *dev_id, | 						  int *maf_id, int *dev_id, | ||||||
| 						  struct nand_flash_dev *type) | 						  struct nand_flash_dev *type) | ||||||
| { | { | ||||||
|  | 	const struct nand_manufacturers *manufacturer_desc; | ||||||
| 	int busw, ret; | 	int busw, ret; | ||||||
| 	int maf_idx; |  | ||||||
| 	u8 *id_data = chip->id.data; | 	u8 *id_data = chip->id.data; | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| @@ -4433,6 +4486,12 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||||||
| 		return ERR_PTR(-ENODEV); | 		return ERR_PTR(-ENODEV); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data)); | ||||||
|  |  | ||||||
|  | 	/* Try to identify manufacturer */ | ||||||
|  | 	manufacturer_desc = nand_get_manufacturer_desc(*maf_id); | ||||||
|  | 	chip->manufacturer.desc = manufacturer_desc; | ||||||
|  |  | ||||||
| 	if (!type) | 	if (!type) | ||||||
| 		type = nand_flash_ids; | 		type = nand_flash_ids; | ||||||
|  |  | ||||||
| @@ -4451,8 +4510,6 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||||||
| 	 */ | 	 */ | ||||||
| 	chip->options &= ~NAND_BUSWIDTH_16; | 	chip->options &= ~NAND_BUSWIDTH_16; | ||||||
|  |  | ||||||
| 	chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data)); |  | ||||||
|  |  | ||||||
| 	for (; type->name != NULL; type++) { | 	for (; type->name != NULL; type++) { | ||||||
| 		if (is_full_id_nand(type)) { | 		if (is_full_id_nand(type)) { | ||||||
| 			if (find_full_id_nand(mtd, chip, type)) | 			if (find_full_id_nand(mtd, chip, type)) | ||||||
| @@ -4482,8 +4539,7 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||||||
| 	chip->chipsize = (uint64_t)type->chipsize << 20; | 	chip->chipsize = (uint64_t)type->chipsize << 20; | ||||||
|  |  | ||||||
| 	if (!type->pagesize) { | 	if (!type->pagesize) { | ||||||
| 		/* Decode parameters from extended ID */ | 		nand_manufacturer_detect(mtd, chip); | ||||||
| 		nand_decode_ext_id(mtd, chip); |  | ||||||
| 	} else { | 	} else { | ||||||
| 		nand_decode_id(mtd, chip, type); | 		nand_decode_id(mtd, chip, type); | ||||||
| 	} | 	} | ||||||
| @@ -4499,12 +4555,6 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||||||
| 		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | 		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | ||||||
| ident_done: | ident_done: | ||||||
|  |  | ||||||
| 	/* Try to identify manufacturer */ |  | ||||||
| 	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { |  | ||||||
| 		if (nand_manuf_ids[maf_idx].id == *maf_id) |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (chip->options & NAND_BUSWIDTH_AUTO) { | 	if (chip->options & NAND_BUSWIDTH_AUTO) { | ||||||
| 		WARN_ON(chip->options & NAND_BUSWIDTH_16); | 		WARN_ON(chip->options & NAND_BUSWIDTH_16); | ||||||
| 		chip->options |= busw; | 		chip->options |= busw; | ||||||
| @@ -4516,7 +4566,7 @@ ident_done: | |||||||
| 		 */ | 		 */ | ||||||
| 		pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", | 		pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", | ||||||
| 			*maf_id, *dev_id); | 			*maf_id, *dev_id); | ||||||
| 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name); | 		pr_info("%s %s\n", manufacturer_desc->name, mtd->name); | ||||||
| 		pr_warn("bus width %d instead %d bit\n", | 		pr_warn("bus width %d instead %d bit\n", | ||||||
| 			   (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, | 			   (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, | ||||||
| 			   busw ? 16 : 8); | 			   busw ? 16 : 8); | ||||||
| @@ -4549,28 +4599,30 @@ ident_done: | |||||||
| 	if (mtd->writesize > 512 && chip->cmdfunc == nand_command) | 	if (mtd->writesize > 512 && chip->cmdfunc == nand_command) | ||||||
| 		chip->cmdfunc = nand_command_lp; | 		chip->cmdfunc = nand_command_lp; | ||||||
|  |  | ||||||
|  | 	ret = nand_manufacturer_init(chip); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ERR_PTR(ret); | ||||||
|  |  | ||||||
| 	pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", | 	pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", | ||||||
| 		*maf_id, *dev_id); | 		*maf_id, *dev_id); | ||||||
|  |  | ||||||
| #ifdef CONFIG_SYS_NAND_ONFI_DETECTION | #ifdef CONFIG_SYS_NAND_ONFI_DETECTION | ||||||
| 	if (chip->onfi_version) | 	if (chip->onfi_version) | ||||||
| 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, | 		pr_info("%s %s\n", manufacturer_desc->name, | ||||||
| 				chip->onfi_params.model); | 			chip->onfi_params.model); | ||||||
| 	else if (chip->jedec_version) | 	else if (chip->jedec_version) | ||||||
| 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, | 		pr_info("%s %s\n", manufacturer_desc->name, | ||||||
| 				chip->jedec_params.model); | 			chip->jedec_params.model); | ||||||
| 	else | 	else | ||||||
| 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, | 		pr_info("%s %s\n", manufacturer_desc->name, type->name); | ||||||
| 				type->name); |  | ||||||
| #else | #else | ||||||
| 	if (chip->jedec_version) | 	if (chip->jedec_version) | ||||||
| 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, | 		pr_info("%s %s\n", manufacturer_desc->name, | ||||||
| 				chip->jedec_params.model); | 			chip->jedec_params.model); | ||||||
| 	else | 	else | ||||||
| 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, | 		pr_info("%s %s\n", manufacturer_desc->name, type->name); | ||||||
| 				type->name); |  | ||||||
|  |  | ||||||
| 	pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, | 	pr_info("%s %s\n", manufacturer_desc->name, | ||||||
| 		type->name); | 		type->name); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -796,6 +796,17 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) | |||||||
| 	return &conf->timings.sdr; | 	return &conf->timings.sdr; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * struct nand_manufacturer_ops - NAND Manufacturer operations | ||||||
|  |  * @detect: detect the NAND memory organization and capabilities | ||||||
|  |  * @init: initialize all vendor specific fields (like the ->read_retry() | ||||||
|  |  *	  implementation) if any. | ||||||
|  |  */ | ||||||
|  | struct nand_manufacturer_ops { | ||||||
|  | 	void (*detect)(struct nand_chip *chip); | ||||||
|  | 	int (*init)(struct nand_chip *chip); | ||||||
|  | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * struct nand_chip - NAND Private Flash Chip Data |  * struct nand_chip - NAND Private Flash Chip Data | ||||||
|  * @mtd:		MTD device registered to the MTD framework |  * @mtd:		MTD device registered to the MTD framework | ||||||
| @@ -897,6 +908,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) | |||||||
|  *			devices. |  *			devices. | ||||||
|  * @priv:		[OPTIONAL] pointer to private chip data |  * @priv:		[OPTIONAL] pointer to private chip data | ||||||
|  * @write_page:		[REPLACEABLE] High-level page write function |  * @write_page:		[REPLACEABLE] High-level page write function | ||||||
|  |  * @manufacturer:	[INTERN] Contains manufacturer information | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| struct nand_chip { | struct nand_chip { | ||||||
| @@ -983,6 +995,11 @@ struct nand_chip { | |||||||
| 	struct nand_bbt_descr *badblock_pattern; | 	struct nand_bbt_descr *badblock_pattern; | ||||||
|  |  | ||||||
| 	void *priv; | 	void *priv; | ||||||
|  |  | ||||||
|  | 	struct { | ||||||
|  | 		const struct nand_manufacturers *desc; | ||||||
|  | 		void *priv; | ||||||
|  | 	} manufacturer; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static inline void nand_set_flash_node(struct nand_chip *chip, | static inline void nand_set_flash_node(struct nand_chip *chip, | ||||||
| @@ -1016,6 +1033,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) | |||||||
| 	chip->priv = priv; | 	chip->priv = priv; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static inline void nand_set_manufacturer_data(struct nand_chip *chip, | ||||||
|  | 					      void *priv) | ||||||
|  | { | ||||||
|  | 	chip->manufacturer.priv = priv; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline void *nand_get_manufacturer_data(struct nand_chip *chip) | ||||||
|  | { | ||||||
|  | 	return chip->manufacturer.priv; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * NAND Flash Manufacturer ID Codes |  * NAND Flash Manufacturer ID Codes | ||||||
|  */ |  */ | ||||||
| @@ -1120,10 +1148,12 @@ struct nand_flash_dev { | |||||||
|  * struct nand_manufacturers - NAND Flash Manufacturer ID Structure |  * struct nand_manufacturers - NAND Flash Manufacturer ID Structure | ||||||
|  * @name:	Manufacturer name |  * @name:	Manufacturer name | ||||||
|  * @id:		manufacturer ID code of device. |  * @id:		manufacturer ID code of device. | ||||||
|  |  * @ops:	manufacturer operations | ||||||
| */ | */ | ||||||
| struct nand_manufacturers { | struct nand_manufacturers { | ||||||
| 	int id; | 	int id; | ||||||
| 	char *name; | 	char *name; | ||||||
|  | 	const struct nand_manufacturer_ops *ops; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| extern struct nand_flash_dev nand_flash_ids[]; | extern struct nand_flash_dev nand_flash_ids[]; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user