mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	mtd: spinand: Instantiate a SPI-NAND on-die ECC engine
Make use of the existing functions taken from the SPI-NAND core to instantiate an on-die ECC engine specific to the SPI-NAND core. The next step will be to tweak the core to use this object instead of calling the helpers directly. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20200930154109.3922-4-miquel.raynal@bootlin.com
This commit is contained in:
		
							parent
							
								
									55a1a71a7f
								
							
						
					
					
						commit
						945845b54c
					
				| @ -246,6 +246,73 @@ static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = { | |||||||
| 	.free = spinand_noecc_ooblayout_free, | 	.free = spinand_noecc_ooblayout_free, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static int spinand_ondie_ecc_init_ctx(struct nand_device *nand) | ||||||
|  | { | ||||||
|  | 	struct spinand_device *spinand = nand_to_spinand(nand); | ||||||
|  | 	struct mtd_info *mtd = nanddev_to_mtd(nand); | ||||||
|  | 	struct spinand_ondie_ecc_conf *engine_conf; | ||||||
|  | 
 | ||||||
|  | 	nand->ecc.ctx.conf.engine_type = NAND_ECC_ENGINE_TYPE_ON_DIE; | ||||||
|  | 	nand->ecc.ctx.conf.step_size = nand->ecc.requirements.step_size; | ||||||
|  | 	nand->ecc.ctx.conf.strength = nand->ecc.requirements.strength; | ||||||
|  | 
 | ||||||
|  | 	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL); | ||||||
|  | 	if (!engine_conf) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	nand->ecc.ctx.priv = engine_conf; | ||||||
|  | 
 | ||||||
|  | 	if (spinand->eccinfo.ooblayout) | ||||||
|  | 		mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); | ||||||
|  | 	else | ||||||
|  | 		mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void spinand_ondie_ecc_cleanup_ctx(struct nand_device *nand) | ||||||
|  | { | ||||||
|  | 	kfree(nand->ecc.ctx.priv); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand, | ||||||
|  | 					    struct nand_page_io_req *req) | ||||||
|  | { | ||||||
|  | 	struct spinand_device *spinand = nand_to_spinand(nand); | ||||||
|  | 	bool enable = (req->mode != MTD_OPS_RAW); | ||||||
|  | 
 | ||||||
|  | 	/* Only enable or disable the engine */ | ||||||
|  | 	return spinand_ecc_enable(spinand, enable); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, | ||||||
|  | 					   struct nand_page_io_req *req) | ||||||
|  | { | ||||||
|  | 	struct spinand_ondie_ecc_conf *engine_conf = nand->ecc.ctx.priv; | ||||||
|  | 	struct spinand_device *spinand = nand_to_spinand(nand); | ||||||
|  | 
 | ||||||
|  | 	if (req->mode == MTD_OPS_RAW) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	/* Nothing to do when finishing a page write */ | ||||||
|  | 	if (req->type == NAND_PAGE_WRITE) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	/* Finish a page write: check the status, report errors/bitflips */ | ||||||
|  | 	return spinand_check_ecc_status(spinand, engine_conf->status); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct nand_ecc_engine_ops spinand_ondie_ecc_engine_ops = { | ||||||
|  | 	.init_ctx = spinand_ondie_ecc_init_ctx, | ||||||
|  | 	.cleanup_ctx = spinand_ondie_ecc_cleanup_ctx, | ||||||
|  | 	.prepare_io_req = spinand_ondie_ecc_prepare_io_req, | ||||||
|  | 	.finish_io_req = spinand_ondie_ecc_finish_io_req, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static __maybe_unused struct nand_ecc_engine spinand_ondie_ecc_engine = { | ||||||
|  | 	.ops = &spinand_ondie_ecc_engine_ops, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static int spinand_write_enable_op(struct spinand_device *spinand) | static int spinand_write_enable_op(struct spinand_device *spinand) | ||||||
| { | { | ||||||
| 	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true); | 	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true); | ||||||
|  | |||||||
| @ -286,6 +286,15 @@ struct spinand_ecc_info { | |||||||
| #define SPINAND_HAS_QE_BIT		BIT(0) | #define SPINAND_HAS_QE_BIT		BIT(0) | ||||||
| #define SPINAND_HAS_CR_FEAT_BIT		BIT(1) | #define SPINAND_HAS_CR_FEAT_BIT		BIT(1) | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure | ||||||
|  |  * @status: status of the last wait operation that will be used in case | ||||||
|  |  *          ->get_status() is not populated by the spinand device. | ||||||
|  |  */ | ||||||
|  | struct spinand_ondie_ecc_conf { | ||||||
|  | 	u8 status; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct spinand_info - Structure used to describe SPI NAND chips |  * struct spinand_info - Structure used to describe SPI NAND chips | ||||||
|  * @model: model name |  * @model: model name | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Miquel Raynal
						Miquel Raynal