mtd: nand: pxa3xx: add raw read support
Raw read support is added by editing a few code sections:
    ->handle_data_pio() includes the ECC bytes that are not consumed
    anymore by the ECC engine.
    ->prepare_set_command() is changed so that the ECC bytes are
    requested as part of the data I/O length.
    ->drain_fifo() shall also avoid checking the R/B pin too often
    when in raw mode.
    ->read_page_raw()/->read_oob_raw() are written from scratch.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
			
			
This commit is contained in:
		
							parent
							
								
									a3e1653dde
								
							
						
					
					
						commit
						6293b0361d
					
				|  | @ -195,6 +195,7 @@ struct pxa3xx_nand_info { | ||||||
| 
 | 
 | ||||||
| 	int			cs; | 	int			cs; | ||||||
| 	int			use_ecc;	/* use HW ECC ? */ | 	int			use_ecc;	/* use HW ECC ? */ | ||||||
|  | 	int			force_raw;	/* prevent use_ecc to be set */ | ||||||
| 	int			ecc_bch;	/* using BCH ECC? */ | 	int			ecc_bch;	/* using BCH ECC? */ | ||||||
| 	int			use_spare;	/* use spare ? */ | 	int			use_spare;	/* use spare ? */ | ||||||
| 	int			need_wait; | 	int			need_wait; | ||||||
|  | @ -579,7 +580,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) | ||||||
| 
 | 
 | ||||||
| static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) | static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) | ||||||
| { | { | ||||||
| 	if (info->ecc_bch) { | 	if (info->ecc_bch && !info->force_raw) { | ||||||
| 		u32 ts; | 		u32 ts; | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
|  | @ -612,12 +613,22 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) | ||||||
| 
 | 
 | ||||||
| static void handle_data_pio(struct pxa3xx_nand_info *info) | static void handle_data_pio(struct pxa3xx_nand_info *info) | ||||||
| { | { | ||||||
|  | 	int data_len = info->step_chunk_size; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * In raw mode, include the spare area and the ECC bytes that are not | ||||||
|  | 	 * consumed by the controller in the data section. Do not reorganize | ||||||
|  | 	 * here, do it in the ->read_page_raw() handler instead. | ||||||
|  | 	 */ | ||||||
|  | 	if (info->force_raw) | ||||||
|  | 		data_len += info->step_spare_size + info->ecc_size; | ||||||
|  | 
 | ||||||
| 	switch (info->state) { | 	switch (info->state) { | ||||||
| 	case STATE_PIO_WRITING: | 	case STATE_PIO_WRITING: | ||||||
| 		if (info->step_chunk_size) | 		if (info->step_chunk_size) | ||||||
| 			writesl(info->mmio_base + NDDB, | 			writesl(info->mmio_base + NDDB, | ||||||
| 				info->data_buff + info->data_buff_pos, | 				info->data_buff + info->data_buff_pos, | ||||||
| 				DIV_ROUND_UP(info->step_chunk_size, 4)); | 				DIV_ROUND_UP(data_len, 4)); | ||||||
| 
 | 
 | ||||||
| 		if (info->step_spare_size) | 		if (info->step_spare_size) | ||||||
| 			writesl(info->mmio_base + NDDB, | 			writesl(info->mmio_base + NDDB, | ||||||
|  | @ -628,7 +639,10 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) | ||||||
| 		if (info->step_chunk_size) | 		if (info->step_chunk_size) | ||||||
| 			drain_fifo(info, | 			drain_fifo(info, | ||||||
| 				   info->data_buff + info->data_buff_pos, | 				   info->data_buff + info->data_buff_pos, | ||||||
| 				   DIV_ROUND_UP(info->step_chunk_size, 4)); | 				   DIV_ROUND_UP(data_len, 4)); | ||||||
|  | 
 | ||||||
|  | 		if (info->force_raw) | ||||||
|  | 			break; | ||||||
| 
 | 
 | ||||||
| 		if (info->step_spare_size) | 		if (info->step_spare_size) | ||||||
| 			drain_fifo(info, | 			drain_fifo(info, | ||||||
|  | @ -642,7 +656,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Update buffer pointers for multi-page read/write */ | 	/* Update buffer pointers for multi-page read/write */ | ||||||
| 	info->data_buff_pos += info->step_chunk_size; | 	info->data_buff_pos += data_len; | ||||||
| 	info->oob_buff_pos += info->step_spare_size; | 	info->oob_buff_pos += info->step_spare_size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -796,7 +810,8 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) | ||||||
| 	case NAND_CMD_READ0: | 	case NAND_CMD_READ0: | ||||||
| 	case NAND_CMD_READOOB: | 	case NAND_CMD_READOOB: | ||||||
| 	case NAND_CMD_PAGEPROG: | 	case NAND_CMD_PAGEPROG: | ||||||
| 		info->use_ecc = 1; | 		if (!info->force_raw) | ||||||
|  | 			info->use_ecc = 1; | ||||||
| 		break; | 		break; | ||||||
| 	case NAND_CMD_PARAM: | 	case NAND_CMD_PARAM: | ||||||
| 		info->use_spare = 0; | 		info->use_spare = 0; | ||||||
|  | @ -866,7 +881,13 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | ||||||
| 		 * which is either naked-read or last-read according to the | 		 * which is either naked-read or last-read according to the | ||||||
| 		 * state. | 		 * state. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (mtd->writesize == info->chunk_size) { | 		if (info->force_raw) { | ||||||
|  | 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | | ||||||
|  | 				       NDCB0_LEN_OVRD | | ||||||
|  | 				       NDCB0_EXT_CMD_TYPE(ext_cmd_type); | ||||||
|  | 			info->ndcb3 = info->step_chunk_size + | ||||||
|  | 				      info->step_spare_size + info->ecc_size; | ||||||
|  | 		} else if (mtd->writesize == info->chunk_size) { | ||||||
| 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); | 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); | ||||||
| 		} else if (mtd->writesize > info->chunk_size) { | 		} else if (mtd->writesize > info->chunk_size) { | ||||||
| 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) | ||||||
|  | @ -1238,6 +1259,69 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, | ||||||
| 	return info->max_bitflips; | 	return info->max_bitflips; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int pxa3xx_nand_read_page_raw(struct mtd_info *mtd, | ||||||
|  | 				     struct nand_chip *chip, uint8_t *buf, | ||||||
|  | 				     int oob_required, int page) | ||||||
|  | { | ||||||
|  | 	struct pxa3xx_nand_host *host = chip->priv; | ||||||
|  | 	struct pxa3xx_nand_info *info = host->info_data; | ||||||
|  | 	int chunk, ecc_off_buf; | ||||||
|  | 
 | ||||||
|  | 	if (!info->ecc_bch) | ||||||
|  | 		return -ENOTSUPP; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Set the force_raw boolean, then re-call ->cmdfunc() that will run | ||||||
|  | 	 * pxa3xx_nand_start(), which will actually disable the ECC engine. | ||||||
|  | 	 */ | ||||||
|  | 	info->force_raw = true; | ||||||
|  | 	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); | ||||||
|  | 
 | ||||||
|  | 	ecc_off_buf = (info->nfullchunks * info->spare_size) + | ||||||
|  | 		      info->last_spare_size; | ||||||
|  | 	for (chunk = 0; chunk < info->nfullchunks; chunk++) { | ||||||
|  | 		chip->read_buf(mtd, | ||||||
|  | 			       buf + (chunk * info->chunk_size), | ||||||
|  | 			       info->chunk_size); | ||||||
|  | 		chip->read_buf(mtd, | ||||||
|  | 			       chip->oob_poi + | ||||||
|  | 			       (chunk * (info->spare_size)), | ||||||
|  | 			       info->spare_size); | ||||||
|  | 		chip->read_buf(mtd, | ||||||
|  | 			       chip->oob_poi + ecc_off_buf + | ||||||
|  | 			       (chunk * (info->ecc_size)), | ||||||
|  | 			       info->ecc_size - 2); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (info->ntotalchunks > info->nfullchunks) { | ||||||
|  | 		chip->read_buf(mtd, | ||||||
|  | 			       buf + (info->nfullchunks * info->chunk_size), | ||||||
|  | 			       info->last_chunk_size); | ||||||
|  | 		chip->read_buf(mtd, | ||||||
|  | 			       chip->oob_poi + | ||||||
|  | 			       (info->nfullchunks * (info->spare_size)), | ||||||
|  | 			       info->last_spare_size); | ||||||
|  | 		chip->read_buf(mtd, | ||||||
|  | 			       chip->oob_poi + ecc_off_buf + | ||||||
|  | 			       (info->nfullchunks * (info->ecc_size)), | ||||||
|  | 			       info->ecc_size - 2); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	info->force_raw = false; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int pxa3xx_nand_read_oob_raw(struct mtd_info *mtd, | ||||||
|  | 				    struct nand_chip *chip, int page) | ||||||
|  | { | ||||||
|  | 	/* Invalidate page cache */ | ||||||
|  | 	chip->pagebuf = -1; | ||||||
|  | 
 | ||||||
|  | 	return chip->ecc.read_page_raw(mtd, chip, chip->buffers->databuf, true, | ||||||
|  | 				       page); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) | static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) | ||||||
| { | { | ||||||
| 	struct nand_chip *chip = mtd_to_nand(mtd); | 	struct nand_chip *chip = mtd_to_nand(mtd); | ||||||
|  | @ -1669,6 +1753,8 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) | ||||||
| 
 | 
 | ||||||
| 		nand_set_controller_data(chip, host); | 		nand_set_controller_data(chip, host); | ||||||
| 		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc; | 		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc; | ||||||
|  | 		chip->ecc.read_page_raw	= pxa3xx_nand_read_page_raw; | ||||||
|  | 		chip->ecc.read_oob_raw	= pxa3xx_nand_read_oob_raw; | ||||||
| 		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc; | 		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc; | ||||||
| 		chip->controller        = &info->controller; | 		chip->controller        = &info->controller; | ||||||
| 		chip->waitfunc		= pxa3xx_nand_waitfunc; | 		chip->waitfunc		= pxa3xx_nand_waitfunc; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue