xref: /rk3399_ARM-atf/drivers/nxp/ifc/nand/ifc_nand.c (revision 4bd8c929b4bc6e1731c2892b38d4a8c43e8e89dc)
128279cf2SJiafei Pan /*
228279cf2SJiafei Pan  * Copyright 2022 NXP
328279cf2SJiafei Pan  *
428279cf2SJiafei Pan  * SPDX-License-Identifier: BSD-3-Clause
528279cf2SJiafei Pan  */
628279cf2SJiafei Pan 
728279cf2SJiafei Pan #include <string.h>
828279cf2SJiafei Pan 
928279cf2SJiafei Pan #include <common/debug.h>
1028279cf2SJiafei Pan #include <drivers/io/io_block.h>
1128279cf2SJiafei Pan #include "ifc.h"
1228279cf2SJiafei Pan #include <lib/xlat_tables/xlat_tables_v2.h>
1328279cf2SJiafei Pan #include <nxp_timer.h>
1428279cf2SJiafei Pan 
1528279cf2SJiafei Pan /* Private structure for NAND driver data */
1628279cf2SJiafei Pan static struct nand_info nand_drv_data;
1728279cf2SJiafei Pan 
1828279cf2SJiafei Pan static int update_bbt(uint32_t idx, uint32_t blk, uint32_t *updated,
1928279cf2SJiafei Pan 		struct nand_info *nand);
2028279cf2SJiafei Pan 
nand_wait(struct nand_info * nand)2128279cf2SJiafei Pan static int nand_wait(struct nand_info *nand)
2228279cf2SJiafei Pan {
2328279cf2SJiafei Pan 	int timeout = 1;
2428279cf2SJiafei Pan 	uint32_t  neesr;
2528279cf2SJiafei Pan 	unsigned long start_time;
2628279cf2SJiafei Pan 
2728279cf2SJiafei Pan 	start_time = get_timer_val(0);
2828279cf2SJiafei Pan 
2928279cf2SJiafei Pan 	while (get_timer_val(start_time) < NAND_TIMEOUT_MS) {
3028279cf2SJiafei Pan 		/* clear the OPC event */
3128279cf2SJiafei Pan 		neesr = read_reg(nand, NAND_EVTER_STAT);
3228279cf2SJiafei Pan 		if (neesr & NAND_EVTER_STAT_OPC_DN) {
3328279cf2SJiafei Pan 			write_reg(nand, NAND_EVTER_STAT, neesr);
3428279cf2SJiafei Pan 			timeout = 0;
3528279cf2SJiafei Pan 
3628279cf2SJiafei Pan 			/* check for other errors */
3728279cf2SJiafei Pan 			if (neesr & NAND_EVTER_STAT_FTOER) {
3828279cf2SJiafei Pan 				ERROR("%s NAND_EVTER_STAT_FTOER occurs\n",
3928279cf2SJiafei Pan 						__func__);
4028279cf2SJiafei Pan 				return -1;
4128279cf2SJiafei Pan 			} else if (neesr & NAND_EVTER_STAT_ECCER) {
4228279cf2SJiafei Pan 				ERROR("%s NAND_EVTER_STAT_ECCER occurs\n",
4328279cf2SJiafei Pan 						__func__);
4428279cf2SJiafei Pan 				return -1;
4528279cf2SJiafei Pan 			} else if (neesr & NAND_EVTER_STAT_DQSER) {
4628279cf2SJiafei Pan 				ERROR("%s NAND_EVTER_STAT_DQSER occurs\n",
4728279cf2SJiafei Pan 						__func__);
4828279cf2SJiafei Pan 				return -1;
4928279cf2SJiafei Pan 			}
5028279cf2SJiafei Pan 
5128279cf2SJiafei Pan 			break;
5228279cf2SJiafei Pan 		}
5328279cf2SJiafei Pan 	}
5428279cf2SJiafei Pan 
5528279cf2SJiafei Pan 	if (timeout) {
5628279cf2SJiafei Pan 		ERROR("%s ERROR_NAND_TIMEOUT occurs\n", __func__);
5728279cf2SJiafei Pan 		return -1;
5828279cf2SJiafei Pan 	}
5928279cf2SJiafei Pan 
6028279cf2SJiafei Pan 	return 0;
6128279cf2SJiafei Pan }
6228279cf2SJiafei Pan 
nand_get_port_size(struct nand_info * nand)6328279cf2SJiafei Pan static uint32_t nand_get_port_size(struct nand_info *nand)
6428279cf2SJiafei Pan {
6528279cf2SJiafei Pan 	uint32_t port_size = U(0);
6628279cf2SJiafei Pan 	uint32_t cs_reg;
6728279cf2SJiafei Pan 	uint32_t cur_cs;
6828279cf2SJiafei Pan 
6928279cf2SJiafei Pan 	cur_cs = U(0);
7028279cf2SJiafei Pan 	cs_reg = CSPR(cur_cs);
7128279cf2SJiafei Pan 	port_size = (read_reg(nand, cs_reg) & CSPR_PS) >> CSPR_PS_SHIFT;
7228279cf2SJiafei Pan 	switch (port_size) {
7328279cf2SJiafei Pan 	case CSPR_PS_8:
7428279cf2SJiafei Pan 		port_size = U(8);
7528279cf2SJiafei Pan 		break;
7628279cf2SJiafei Pan 	case CSPR_PS_16:
7728279cf2SJiafei Pan 		port_size = U(16);
7828279cf2SJiafei Pan 		break;
7928279cf2SJiafei Pan 	case CSPR_PS_32:
8028279cf2SJiafei Pan 		port_size = U(32);
8128279cf2SJiafei Pan 		break;
8228279cf2SJiafei Pan 	default:
8328279cf2SJiafei Pan 		port_size = U(8);
8428279cf2SJiafei Pan 	}
8528279cf2SJiafei Pan 
8628279cf2SJiafei Pan 	return port_size;
8728279cf2SJiafei Pan }
8828279cf2SJiafei Pan 
nand_get_page_size(struct nand_info * nand)8928279cf2SJiafei Pan static uint32_t nand_get_page_size(struct nand_info *nand)
9028279cf2SJiafei Pan {
9128279cf2SJiafei Pan 	uint32_t pg_size;
9228279cf2SJiafei Pan 	uint32_t cs_reg;
9328279cf2SJiafei Pan 	uint32_t cur_cs;
9428279cf2SJiafei Pan 
9528279cf2SJiafei Pan 	cur_cs = 0;
9628279cf2SJiafei Pan 	cs_reg = CSOR(cur_cs);
9728279cf2SJiafei Pan 	pg_size = read_reg(nand, cs_reg) & CSOR_NAND_PGS;
9828279cf2SJiafei Pan 	switch (pg_size) {
9928279cf2SJiafei Pan 	case CSOR_NAND_PGS_2K:
10028279cf2SJiafei Pan 		pg_size = U(2048);
10128279cf2SJiafei Pan 		break;
10228279cf2SJiafei Pan 	case CSOR_NAND_PGS_4K:
10328279cf2SJiafei Pan 		pg_size = U(4096);
10428279cf2SJiafei Pan 		break;
10528279cf2SJiafei Pan 	case CSOR_NAND_PGS_8K:
10628279cf2SJiafei Pan 		pg_size = U(8192);
10728279cf2SJiafei Pan 		break;
10828279cf2SJiafei Pan 	case CSOR_NAND_PGS_16K:
10928279cf2SJiafei Pan 		pg_size = U(16384);
11028279cf2SJiafei Pan 		break;
11128279cf2SJiafei Pan 	default:
11228279cf2SJiafei Pan 		pg_size = U(512);
11328279cf2SJiafei Pan 	}
11428279cf2SJiafei Pan 
11528279cf2SJiafei Pan 	return pg_size;
11628279cf2SJiafei Pan }
11728279cf2SJiafei Pan 
nand_get_pages_per_blk(struct nand_info * nand)11828279cf2SJiafei Pan static uint32_t nand_get_pages_per_blk(struct nand_info *nand)
11928279cf2SJiafei Pan {
12028279cf2SJiafei Pan 	uint32_t pages_per_blk;
12128279cf2SJiafei Pan 	uint32_t cs_reg;
12228279cf2SJiafei Pan 	uint32_t cur_cs;
12328279cf2SJiafei Pan 
12428279cf2SJiafei Pan 	cur_cs = 0;
12528279cf2SJiafei Pan 	cs_reg = CSOR(cur_cs);
12628279cf2SJiafei Pan 	pages_per_blk = (read_reg(nand, cs_reg) & CSOR_NAND_PB);
12728279cf2SJiafei Pan 	switch (pages_per_blk) {
12828279cf2SJiafei Pan 	case CSOR_NAND_PB_32:
12928279cf2SJiafei Pan 		pages_per_blk = U(32);
13028279cf2SJiafei Pan 		break;
13128279cf2SJiafei Pan 	case CSOR_NAND_PB_64:
13228279cf2SJiafei Pan 		pages_per_blk = U(64);
13328279cf2SJiafei Pan 		break;
13428279cf2SJiafei Pan 	case CSOR_NAND_PB_128:
13528279cf2SJiafei Pan 		pages_per_blk = U(128);
13628279cf2SJiafei Pan 		break;
13728279cf2SJiafei Pan 	case CSOR_NAND_PB_256:
13828279cf2SJiafei Pan 		pages_per_blk = U(256);
13928279cf2SJiafei Pan 		break;
14028279cf2SJiafei Pan 	case CSOR_NAND_PB_512:
14128279cf2SJiafei Pan 		pages_per_blk = U(512);
14228279cf2SJiafei Pan 		break;
14328279cf2SJiafei Pan 	case CSOR_NAND_PB_1024:
14428279cf2SJiafei Pan 		pages_per_blk = U(1024);
14528279cf2SJiafei Pan 		break;
14628279cf2SJiafei Pan 	case CSOR_NAND_PB_2048:
14728279cf2SJiafei Pan 		pages_per_blk = U(2048);
14828279cf2SJiafei Pan 		break;
14928279cf2SJiafei Pan 	default:
15028279cf2SJiafei Pan 		pages_per_blk = U(0);
15128279cf2SJiafei Pan 	}
15228279cf2SJiafei Pan 
15328279cf2SJiafei Pan 	return pages_per_blk;
15428279cf2SJiafei Pan }
15528279cf2SJiafei Pan 
get_page_index_width(uint32_t ppb)15628279cf2SJiafei Pan static uint32_t get_page_index_width(uint32_t ppb)
15728279cf2SJiafei Pan {
15828279cf2SJiafei Pan 	switch (ppb) {
15928279cf2SJiafei Pan 	case CSOR_NAND_PPB_32:
16028279cf2SJiafei Pan 		return U(5);
16128279cf2SJiafei Pan 	case CSOR_NAND_PPB_64:
16228279cf2SJiafei Pan 		return U(6);
16328279cf2SJiafei Pan 	case CSOR_NAND_PPB_128:
16428279cf2SJiafei Pan 		return U(7);
16528279cf2SJiafei Pan 	case CSOR_NAND_PPB_256:
16628279cf2SJiafei Pan 		return U(8);
16728279cf2SJiafei Pan 	case CSOR_NAND_PPB_512:
16828279cf2SJiafei Pan 		return U(9);
16928279cf2SJiafei Pan 	case CSOR_NAND_PPB_1024:
17028279cf2SJiafei Pan 		return U(10);
17128279cf2SJiafei Pan 	case CSOR_NAND_PPB_2048:
17228279cf2SJiafei Pan 		return U(11);
17328279cf2SJiafei Pan 	default:
17428279cf2SJiafei Pan 		return U(5);
17528279cf2SJiafei Pan 	}
17628279cf2SJiafei Pan }
17728279cf2SJiafei Pan 
nand_get_params(struct nand_info * nand)17828279cf2SJiafei Pan static void nand_get_params(struct nand_info *nand)
17928279cf2SJiafei Pan {
18028279cf2SJiafei Pan 	nand->port_size = nand_get_port_size(nand);
18128279cf2SJiafei Pan 
18228279cf2SJiafei Pan 	nand->page_size = nand_get_page_size(nand);
18328279cf2SJiafei Pan 
18428279cf2SJiafei Pan 	/*
18528279cf2SJiafei Pan 	 * Set Bad marker Location for LP / SP
18628279cf2SJiafei Pan 	 * Small Page : 8 Bit	 : 0x5
18728279cf2SJiafei Pan 	 * Small Page : 16 Bit	: 0xa
18828279cf2SJiafei Pan 	 * Large Page : 8 /16 Bit : 0x0
18928279cf2SJiafei Pan 	 */
19028279cf2SJiafei Pan 	nand->bad_marker_loc = (nand->page_size == 512) ?
19128279cf2SJiafei Pan 				((nand->port_size == 8) ? 0x5 : 0xa) : 0;
19228279cf2SJiafei Pan 
19328279cf2SJiafei Pan 	/* check for the device is ONFI compliant or not */
19428279cf2SJiafei Pan 	nand->onfi_dev_flag =
19528279cf2SJiafei Pan 	   (read_reg(nand, NAND_EVTER_STAT) & NAND_EVTER_STAT_BBI_SRCH_SEL)
19628279cf2SJiafei Pan 	   ? 1 : 0;
19728279cf2SJiafei Pan 
19828279cf2SJiafei Pan 	/* NAND Blk serached count for incremental Bad block search cnt */
19928279cf2SJiafei Pan 	nand->bbs = 0;
20028279cf2SJiafei Pan 
20128279cf2SJiafei Pan 	/* pages per Block */
20228279cf2SJiafei Pan 	nand->ppb = nand_get_pages_per_blk(nand);
20328279cf2SJiafei Pan 
20428279cf2SJiafei Pan 	/* Blk size */
20528279cf2SJiafei Pan 	nand->blk_size = nand->page_size * nand->ppb;
20628279cf2SJiafei Pan 
20728279cf2SJiafei Pan 	/* get_page_index_width */
20828279cf2SJiafei Pan 	nand->pi_width = get_page_index_width(nand->ppb);
20928279cf2SJiafei Pan 
21028279cf2SJiafei Pan 	/* bad block table init */
21128279cf2SJiafei Pan 	nand->lgb = 0;
21228279cf2SJiafei Pan 	nand->bbt_max = 0;
21328279cf2SJiafei Pan 	nand->bzero_good = 0;
21428279cf2SJiafei Pan 	memset(nand->bbt, EMPTY_VAL, BBT_SIZE * sizeof(nand->bbt[0]));
21528279cf2SJiafei Pan }
21628279cf2SJiafei Pan 
nand_init(struct nand_info * nand)21728279cf2SJiafei Pan static int nand_init(struct nand_info *nand)
21828279cf2SJiafei Pan {
21928279cf2SJiafei Pan 	uint32_t ncfgr = 0;
22028279cf2SJiafei Pan 
22128279cf2SJiafei Pan 	/* Get nand Parameters from IFC */
22228279cf2SJiafei Pan 	nand_get_params(nand);
22328279cf2SJiafei Pan 
22428279cf2SJiafei Pan 	/* Clear all errors */
22528279cf2SJiafei Pan 	write_reg(nand, NAND_EVTER_STAT, U(0xffffffff));
22628279cf2SJiafei Pan 
22728279cf2SJiafei Pan 	/*
22828279cf2SJiafei Pan 	 * Disable autoboot in NCFGR. Mapping will change from
22928279cf2SJiafei Pan 	 * physical to logical for SRAM buffer
23028279cf2SJiafei Pan 	 */
23128279cf2SJiafei Pan 	ncfgr = read_reg(nand, NCFGR);
23228279cf2SJiafei Pan 	write_reg(nand, NCFGR, (ncfgr & ~NCFGR_BOOT));
23328279cf2SJiafei Pan 
23428279cf2SJiafei Pan 	return 0;
23528279cf2SJiafei Pan }
23628279cf2SJiafei Pan 
nand_read_data(uintptr_t ifc_region_addr,uint32_t row_add,uint32_t col_add,uint32_t byte_cnt,uint8_t * data,uint32_t main_spare,struct nand_info * nand)23728279cf2SJiafei Pan static int nand_read_data(
23828279cf2SJiafei Pan 		uintptr_t ifc_region_addr,
23928279cf2SJiafei Pan 		uint32_t row_add,
24028279cf2SJiafei Pan 		uint32_t col_add,
24128279cf2SJiafei Pan 		uint32_t byte_cnt,
24228279cf2SJiafei Pan 		uint8_t *data,
24328279cf2SJiafei Pan 		uint32_t main_spare,
24428279cf2SJiafei Pan 		struct nand_info *nand)
24528279cf2SJiafei Pan {
24628279cf2SJiafei Pan 	uint32_t page_size_add_bits = U(0);
24728279cf2SJiafei Pan 	uint32_t page_add_in_actual, page_add;
24828279cf2SJiafei Pan 	uintptr_t sram_addr_calc;
24928279cf2SJiafei Pan 	int ret;
25028279cf2SJiafei Pan 	uint32_t col_val;
25128279cf2SJiafei Pan 
25228279cf2SJiafei Pan 	/* Programming MS bit to read from spare area.*/
25328279cf2SJiafei Pan 	col_val = (main_spare << NAND_COL_MS_SHIFT) | col_add;
25428279cf2SJiafei Pan 
25528279cf2SJiafei Pan 	write_reg(nand, NAND_BC, byte_cnt);
25628279cf2SJiafei Pan 
25728279cf2SJiafei Pan 	write_reg(nand, ROW0, row_add);
25828279cf2SJiafei Pan 	write_reg(nand, COL0, col_val);
25928279cf2SJiafei Pan 
26028279cf2SJiafei Pan 	/* Program FCR for small Page */
26128279cf2SJiafei Pan 	if (nand->page_size == U(512)) {
26228279cf2SJiafei Pan 		if (byte_cnt == 0 ||
26328279cf2SJiafei Pan 			(byte_cnt != 0  && main_spare == 0 && col_add <= 255)) {
26428279cf2SJiafei Pan 			write_reg(nand, NAND_FCR0,
26528279cf2SJiafei Pan 				  (NAND_CMD_READ0 << FCR_CMD0_SHIFT));
26628279cf2SJiafei Pan 		} else if (main_spare == 0) {
26728279cf2SJiafei Pan 			write_reg(nand, NAND_FCR0,
26828279cf2SJiafei Pan 				  (NAND_CMD_READ1 << FCR_CMD0_SHIFT));
26928279cf2SJiafei Pan 		} else {
27028279cf2SJiafei Pan 			write_reg(nand, NAND_FCR0,
27128279cf2SJiafei Pan 				  (NAND_CMD_READOOB << FCR_CMD0_SHIFT));
27228279cf2SJiafei Pan 		}
27328279cf2SJiafei Pan 
27428279cf2SJiafei Pan 	} else {
27528279cf2SJiafei Pan 		/* Program FCR for Large Page */
27628279cf2SJiafei Pan 		write_reg(nand, NAND_FCR0, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
27728279cf2SJiafei Pan 			  (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
27828279cf2SJiafei Pan 	}
27928279cf2SJiafei Pan 	if (nand->page_size == U(512)) {
28028279cf2SJiafei Pan 		write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) |
28128279cf2SJiafei Pan 					  (FIR_OP_CA0 << FIR_OP1_SHIFT) |
28228279cf2SJiafei Pan 					  (FIR_OP_RA0 << FIR_OP2_SHIFT) |
28328279cf2SJiafei Pan 					  (FIR_OP_BTRD << FIR_OP3_SHIFT) |
28428279cf2SJiafei Pan 					  (FIR_OP_NOP << FIR_OP4_SHIFT)));
28528279cf2SJiafei Pan 		write_reg(nand, NAND_FIR1, U(0x00000000));
28628279cf2SJiafei Pan 	} else {
28728279cf2SJiafei Pan 		write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) |
28828279cf2SJiafei Pan 					 (FIR_OP_CA0 << FIR_OP1_SHIFT) |
28928279cf2SJiafei Pan 					 (FIR_OP_RA0 << FIR_OP2_SHIFT) |
29028279cf2SJiafei Pan 					 (FIR_OP_CMD1 << FIR_OP3_SHIFT) |
29128279cf2SJiafei Pan 					 (FIR_OP_BTRD << FIR_OP4_SHIFT)));
29228279cf2SJiafei Pan 
29328279cf2SJiafei Pan 		write_reg(nand, NAND_FIR1, (FIR_OP_NOP << FIR_OP5_SHIFT));
29428279cf2SJiafei Pan 	}
29528279cf2SJiafei Pan 	write_reg(nand, NANDSEQ_STRT, NAND_SEQ_STRT_FIR_STRT);
29628279cf2SJiafei Pan 
29728279cf2SJiafei Pan 	ret = nand_wait(nand);
29828279cf2SJiafei Pan 	if (ret != 0)
29928279cf2SJiafei Pan 		return ret;
30028279cf2SJiafei Pan 
30128279cf2SJiafei Pan 	/* calculate page_size_add_bits i.e bits
30228279cf2SJiafei Pan 	 * in sram address corresponding to area
30328279cf2SJiafei Pan 	 * within a page for sram
30428279cf2SJiafei Pan 	 */
30528279cf2SJiafei Pan 	if (nand->page_size == U(512))
30628279cf2SJiafei Pan 		page_size_add_bits = U(10);
30728279cf2SJiafei Pan 	else if (nand->page_size == U(2048))
30828279cf2SJiafei Pan 		page_size_add_bits = U(12);
30928279cf2SJiafei Pan 	else if (nand->page_size == U(4096))
31028279cf2SJiafei Pan 		page_size_add_bits = U(13);
31128279cf2SJiafei Pan 	else if (nand->page_size == U(8192))
31228279cf2SJiafei Pan 		page_size_add_bits = U(14);
31328279cf2SJiafei Pan 	else if (nand->page_size == U(16384))
31428279cf2SJiafei Pan 		page_size_add_bits = U(15);
31528279cf2SJiafei Pan 
31628279cf2SJiafei Pan 	page_add = row_add;
31728279cf2SJiafei Pan 
31828279cf2SJiafei Pan 	page_add_in_actual = (page_add << page_size_add_bits) & U(0x0000FFFF);
31928279cf2SJiafei Pan 
32028279cf2SJiafei Pan 	if (byte_cnt == 0)
32128279cf2SJiafei Pan 		col_add = U(0);
32228279cf2SJiafei Pan 
32328279cf2SJiafei Pan 	/* Calculate SRAM address for main and spare area */
32428279cf2SJiafei Pan 	if (main_spare == 0)
32528279cf2SJiafei Pan 		sram_addr_calc = ifc_region_addr | page_add_in_actual | col_add;
32628279cf2SJiafei Pan 	else
32728279cf2SJiafei Pan 		sram_addr_calc = ifc_region_addr | page_add_in_actual |
32828279cf2SJiafei Pan 				 (col_add + nand->page_size);
32928279cf2SJiafei Pan 
33028279cf2SJiafei Pan 	/* Depending Byte_count copy full page or partial page from SRAM */
33128279cf2SJiafei Pan 	if (byte_cnt == 0)
33228279cf2SJiafei Pan 		memcpy(data, (void *)sram_addr_calc,
33328279cf2SJiafei Pan 			nand->page_size);
33428279cf2SJiafei Pan 	else
33528279cf2SJiafei Pan 		memcpy(data, (void *)sram_addr_calc, byte_cnt);
33628279cf2SJiafei Pan 
33728279cf2SJiafei Pan 	return 0;
33828279cf2SJiafei Pan }
33928279cf2SJiafei Pan 
nand_read(struct nand_info * nand,int32_t src_addr,uintptr_t dst,uint32_t size)34028279cf2SJiafei Pan static int nand_read(struct nand_info *nand, int32_t src_addr,
34128279cf2SJiafei Pan 		uintptr_t dst, uint32_t size)
34228279cf2SJiafei Pan {
34328279cf2SJiafei Pan 	uint32_t log_blk = U(0);
34428279cf2SJiafei Pan 	uint32_t pg_no = U(0);
34528279cf2SJiafei Pan 	uint32_t col_off = U(0);
34628279cf2SJiafei Pan 	uint32_t row_off = U(0);
34728279cf2SJiafei Pan 	uint32_t byte_cnt = U(0);
34828279cf2SJiafei Pan 	uint32_t read_cnt = U(0);
34928279cf2SJiafei Pan 	uint32_t i = U(0);
35028279cf2SJiafei Pan 	uint32_t updated = U(0);
35128279cf2SJiafei Pan 
35228279cf2SJiafei Pan 	int ret = 0;
35328279cf2SJiafei Pan 	uint8_t *out = (uint8_t *)dst;
35428279cf2SJiafei Pan 
35528279cf2SJiafei Pan 	uint32_t pblk;
35628279cf2SJiafei Pan 
35728279cf2SJiafei Pan 	/* loop till size */
35828279cf2SJiafei Pan 	while (size) {
35928279cf2SJiafei Pan 		log_blk = (src_addr / nand->blk_size);
36028279cf2SJiafei Pan 		pg_no = ((src_addr - (log_blk * nand->blk_size)) /
36128279cf2SJiafei Pan 					 nand->page_size);
36228279cf2SJiafei Pan 		pblk = log_blk;
36328279cf2SJiafei Pan 
36428279cf2SJiafei Pan 		 // iterate the bbt to find the block
36528279cf2SJiafei Pan 		for (i = 0; i <= nand->bbt_max; i++) {
36628279cf2SJiafei Pan 			if (nand->bbt[i] == EMPTY_VAL_CHECK) {
36728279cf2SJiafei Pan 				ret = update_bbt(i, pblk, &updated, nand);
36828279cf2SJiafei Pan 
36928279cf2SJiafei Pan 				if (ret != 0)
37028279cf2SJiafei Pan 					return ret;
37128279cf2SJiafei Pan 				 /*
37228279cf2SJiafei Pan 				  * if table not updated and we reached
37328279cf2SJiafei Pan 				  * end of table
37428279cf2SJiafei Pan 				  */
37528279cf2SJiafei Pan 				if (!updated)
37628279cf2SJiafei Pan 					break;
37728279cf2SJiafei Pan 			}
37828279cf2SJiafei Pan 
37928279cf2SJiafei Pan 			if (pblk < nand->bbt[i])
38028279cf2SJiafei Pan 				break;
38128279cf2SJiafei Pan 			else if (pblk >= nand->bbt[i])
38228279cf2SJiafei Pan 				pblk++;
38328279cf2SJiafei Pan 		}
38428279cf2SJiafei Pan 
38528279cf2SJiafei Pan 		col_off = (src_addr % nand->page_size);
38628279cf2SJiafei Pan 		if (col_off) {
38728279cf2SJiafei Pan 			if ((col_off + size) < nand->page_size)
38828279cf2SJiafei Pan 				byte_cnt = size;
38928279cf2SJiafei Pan 			else
39028279cf2SJiafei Pan 				byte_cnt = nand->page_size - col_off;
39128279cf2SJiafei Pan 
39228279cf2SJiafei Pan 			row_off = (pblk << nand->pi_width) | pg_no;
39328279cf2SJiafei Pan 
39428279cf2SJiafei Pan 			ret = nand_read_data(
39528279cf2SJiafei Pan 					nand->ifc_region_addr,
39628279cf2SJiafei Pan 					row_off,
39728279cf2SJiafei Pan 					col_off,
39828279cf2SJiafei Pan 					byte_cnt, out, MAIN, nand);
39928279cf2SJiafei Pan 
40028279cf2SJiafei Pan 			if (ret != 0)
40128279cf2SJiafei Pan 				return ret;
40228279cf2SJiafei Pan 		} else {
40328279cf2SJiafei Pan 			 /*
40428279cf2SJiafei Pan 			  * fullpage/Partial Page
40528279cf2SJiafei Pan 			  * if byte_cnt = 0 full page
40628279cf2SJiafei Pan 			  * else partial page
40728279cf2SJiafei Pan 			  */
40828279cf2SJiafei Pan 			if (size < nand->page_size) {
40928279cf2SJiafei Pan 				byte_cnt = size;
41028279cf2SJiafei Pan 				read_cnt = size;
41128279cf2SJiafei Pan 			} else	{
41228279cf2SJiafei Pan 				byte_cnt = nand->page_size;
41328279cf2SJiafei Pan 				read_cnt = 0;
41428279cf2SJiafei Pan 			}
41528279cf2SJiafei Pan 			row_off = (pblk << nand->pi_width) | pg_no;
41628279cf2SJiafei Pan 
41728279cf2SJiafei Pan 			ret = nand_read_data(
41828279cf2SJiafei Pan 					nand->ifc_region_addr,
41928279cf2SJiafei Pan 					row_off,
42028279cf2SJiafei Pan 					0,
42128279cf2SJiafei Pan 					read_cnt, out, MAIN, nand);
42228279cf2SJiafei Pan 
42328279cf2SJiafei Pan 			if (ret != 0) {
42428279cf2SJiafei Pan 				ERROR("Error from nand-read_data %d\n", ret);
42528279cf2SJiafei Pan 				return ret;
42628279cf2SJiafei Pan 			}
42728279cf2SJiafei Pan 		}
42828279cf2SJiafei Pan 		src_addr += byte_cnt;
42928279cf2SJiafei Pan 		out += byte_cnt;
43028279cf2SJiafei Pan 		size -= byte_cnt;
43128279cf2SJiafei Pan 	}
43228279cf2SJiafei Pan 	return 0;
43328279cf2SJiafei Pan }
43428279cf2SJiafei Pan 
isgoodblock(uint32_t blk,uint32_t * gb,struct nand_info * nand)43528279cf2SJiafei Pan static int isgoodblock(uint32_t blk, uint32_t *gb, struct nand_info *nand)
43628279cf2SJiafei Pan {
43728279cf2SJiafei Pan 	uint8_t buf[2];
43828279cf2SJiafei Pan 	int ret;
43928279cf2SJiafei Pan 	uint32_t row_add;
44028279cf2SJiafei Pan 
44128279cf2SJiafei Pan 	*gb = 0;
44228279cf2SJiafei Pan 
44328279cf2SJiafei Pan 	/* read Page 0 of blk */
44428279cf2SJiafei Pan 	ret = nand_read_data(
44528279cf2SJiafei Pan 			nand->ifc_region_addr,
44628279cf2SJiafei Pan 			blk << nand->pi_width,
44728279cf2SJiafei Pan 			nand->bad_marker_loc,
44828279cf2SJiafei Pan 			0x2, buf, 1, nand);
44928279cf2SJiafei Pan 
45028279cf2SJiafei Pan 	if (ret != 0)
45128279cf2SJiafei Pan 		return ret;
45228279cf2SJiafei Pan 
45328279cf2SJiafei Pan 	/* For ONFI devices check Page 0 and Last page of block for
45428279cf2SJiafei Pan 	 * Bad Marker and for NON-ONFI Page 0 and 1 for Bad Marker
45528279cf2SJiafei Pan 	 */
45628279cf2SJiafei Pan 	row_add = (blk << nand->pi_width);
45728279cf2SJiafei Pan 	if (nand->port_size == 8) {
45828279cf2SJiafei Pan 		/* port size is 8 Bit */
45928279cf2SJiafei Pan 		/* check if page 0 has 0xff */
46028279cf2SJiafei Pan 		if (buf[0] == 0xff) {
46128279cf2SJiafei Pan 			/* check page 1 */
46228279cf2SJiafei Pan 			if (nand->onfi_dev_flag)
46328279cf2SJiafei Pan 				ret =  nand_read_data(
46428279cf2SJiafei Pan 						nand->ifc_region_addr,
46528279cf2SJiafei Pan 						row_add | (nand->ppb - 1),
46628279cf2SJiafei Pan 						nand->bad_marker_loc,
46728279cf2SJiafei Pan 						0x2, buf, SPARE, nand);
46828279cf2SJiafei Pan 			else
46928279cf2SJiafei Pan 				ret =  nand_read_data(
47028279cf2SJiafei Pan 						nand->ifc_region_addr,
47128279cf2SJiafei Pan 						row_add | 1,
47228279cf2SJiafei Pan 						nand->bad_marker_loc,
47328279cf2SJiafei Pan 						0x2, buf, SPARE, nand);
47428279cf2SJiafei Pan 
47528279cf2SJiafei Pan 			if (ret != 0)
47628279cf2SJiafei Pan 				return ret;
47728279cf2SJiafei Pan 
47828279cf2SJiafei Pan 			if (buf[0] == 0xff)
47928279cf2SJiafei Pan 				*gb = GOOD_BLK;
48028279cf2SJiafei Pan 			else
48128279cf2SJiafei Pan 				*gb = BAD_BLK;
48228279cf2SJiafei Pan 		} else {
48328279cf2SJiafei Pan 			/* no, so it is bad blk */
48428279cf2SJiafei Pan 			*gb = BAD_BLK;
48528279cf2SJiafei Pan 		}
48628279cf2SJiafei Pan 	} else {
48728279cf2SJiafei Pan 		/* Port size 16-Bit */
48828279cf2SJiafei Pan 		/* check if page 0 has 0xffff */
48928279cf2SJiafei Pan 		if ((buf[0] == 0xff) &&
49028279cf2SJiafei Pan 			(buf[1] == 0xff)) {
49128279cf2SJiafei Pan 			/* check page 1 for 0xffff */
49228279cf2SJiafei Pan 			if (nand->onfi_dev_flag) {
49328279cf2SJiafei Pan 				ret =  nand_read_data(
49428279cf2SJiafei Pan 						nand->ifc_region_addr,
49528279cf2SJiafei Pan 						row_add | (nand->ppb - 1),
49628279cf2SJiafei Pan 						nand->bad_marker_loc,
49728279cf2SJiafei Pan 						0x2, buf, SPARE, nand);
49828279cf2SJiafei Pan 			} else {
49928279cf2SJiafei Pan 				ret =  nand_read_data(
50028279cf2SJiafei Pan 						nand->ifc_region_addr,
50128279cf2SJiafei Pan 						row_add | 1,
50228279cf2SJiafei Pan 						nand->bad_marker_loc,
50328279cf2SJiafei Pan 						0x2, buf, SPARE, nand);
50428279cf2SJiafei Pan 			}
50528279cf2SJiafei Pan 
50628279cf2SJiafei Pan 			if (ret != 0)
50728279cf2SJiafei Pan 				return ret;
50828279cf2SJiafei Pan 
50928279cf2SJiafei Pan 			if ((buf[0] == 0xff) &&
51028279cf2SJiafei Pan 				(buf[1] == 0xff)) {
51128279cf2SJiafei Pan 				*gb = GOOD_BLK;
51228279cf2SJiafei Pan 			} else {
51328279cf2SJiafei Pan 				*gb = BAD_BLK;
51428279cf2SJiafei Pan 			}
51528279cf2SJiafei Pan 		} else {
51628279cf2SJiafei Pan 			/* no, so it is bad blk */
51728279cf2SJiafei Pan 			*gb = BAD_BLK;
51828279cf2SJiafei Pan 		}
51928279cf2SJiafei Pan 	}
52028279cf2SJiafei Pan 	return 0;
52128279cf2SJiafei Pan }
52228279cf2SJiafei Pan 
update_bbt(uint32_t idx,uint32_t blk,uint32_t * updated,struct nand_info * nand)52328279cf2SJiafei Pan static int update_bbt(uint32_t idx, uint32_t blk,
52428279cf2SJiafei Pan 			   uint32_t *updated,  struct nand_info *nand)
52528279cf2SJiafei Pan {
52628279cf2SJiafei Pan 	uint32_t sblk;
52728279cf2SJiafei Pan 	uint32_t lgb;
52828279cf2SJiafei Pan 	int ret;
52928279cf2SJiafei Pan 
53028279cf2SJiafei Pan 	if (nand->bzero_good && blk == 0)
53128279cf2SJiafei Pan 		return 0;
53228279cf2SJiafei Pan 
53328279cf2SJiafei Pan 	/* special case for lgb == 0 */
534*1b491eeaSElyes Haouas 	/* if blk <= lgb return */
53528279cf2SJiafei Pan 	if (nand->lgb != 0 && blk <= nand->lgb)
53628279cf2SJiafei Pan 		return 0;
53728279cf2SJiafei Pan 
53828279cf2SJiafei Pan 	*updated = 0;
53928279cf2SJiafei Pan 
54028279cf2SJiafei Pan 	/* if blk is more than lgb, iterate from lgb till a good block
54128279cf2SJiafei Pan 	 * is found for blk
54228279cf2SJiafei Pan 	 */
54328279cf2SJiafei Pan 
54428279cf2SJiafei Pan 	if (nand->lgb < blk)
54528279cf2SJiafei Pan 		sblk = nand->lgb;
54628279cf2SJiafei Pan 	else
54728279cf2SJiafei Pan 		/* this is when lgb = 0 */
54828279cf2SJiafei Pan 		sblk = blk;
54928279cf2SJiafei Pan 
55028279cf2SJiafei Pan 
55128279cf2SJiafei Pan 	lgb = nand->lgb;
55228279cf2SJiafei Pan 
55328279cf2SJiafei Pan 	/* loop from blk to find a good block */
55428279cf2SJiafei Pan 	while (1) {
55528279cf2SJiafei Pan 		while (lgb <= sblk) {
55628279cf2SJiafei Pan 			uint32_t gb = 0;
55728279cf2SJiafei Pan 
55828279cf2SJiafei Pan 			ret =  isgoodblock(lgb, &gb, nand);
55928279cf2SJiafei Pan 			if (ret != 0)
56028279cf2SJiafei Pan 				return ret;
56128279cf2SJiafei Pan 
56228279cf2SJiafei Pan 			/* special case block 0 is good then set this flag */
56328279cf2SJiafei Pan 			if (lgb == 0 && gb == GOOD_BLK)
56428279cf2SJiafei Pan 				nand->bzero_good = 1;
56528279cf2SJiafei Pan 
56628279cf2SJiafei Pan 			if (gb == BAD_BLK) {
56728279cf2SJiafei Pan 				if (idx >= BBT_SIZE) {
56828279cf2SJiafei Pan 					ERROR("NAND BBT Table full\n");
56928279cf2SJiafei Pan 					return -1;
57028279cf2SJiafei Pan 				}
57128279cf2SJiafei Pan 				*updated = 1;
57228279cf2SJiafei Pan 				nand->bbt[idx] = lgb;
57328279cf2SJiafei Pan 				idx++;
57428279cf2SJiafei Pan 				blk++;
57528279cf2SJiafei Pan 				sblk++;
57628279cf2SJiafei Pan 				if (idx > nand->bbt_max)
57728279cf2SJiafei Pan 					nand->bbt_max = idx;
57828279cf2SJiafei Pan 			}
57928279cf2SJiafei Pan 			lgb++;
58028279cf2SJiafei Pan 		}
58128279cf2SJiafei Pan 		/* the access block found */
58228279cf2SJiafei Pan 		if (sblk == blk) {
58328279cf2SJiafei Pan 			/* when good block found update lgb */
58428279cf2SJiafei Pan 			nand->lgb =  blk;
58528279cf2SJiafei Pan 			break;
58628279cf2SJiafei Pan 		}
58728279cf2SJiafei Pan 		sblk++;
58828279cf2SJiafei Pan 	}
58928279cf2SJiafei Pan 
59028279cf2SJiafei Pan 	return 0;
59128279cf2SJiafei Pan }
59228279cf2SJiafei Pan 
ifc_nand_read(int lba,uintptr_t buf,size_t size)59328279cf2SJiafei Pan static size_t ifc_nand_read(int lba, uintptr_t buf, size_t size)
59428279cf2SJiafei Pan {
59528279cf2SJiafei Pan 	int ret;
59628279cf2SJiafei Pan 	uint32_t page_size;
59728279cf2SJiafei Pan 	uint32_t src_addr;
59828279cf2SJiafei Pan 	struct nand_info *nand = &nand_drv_data;
59928279cf2SJiafei Pan 
60028279cf2SJiafei Pan 	page_size = nand_get_page_size(nand);
60128279cf2SJiafei Pan 	src_addr = lba * page_size;
60228279cf2SJiafei Pan 	ret = nand_read(nand, src_addr, buf, size);
60328279cf2SJiafei Pan 	return ret ? 0 : size;
60428279cf2SJiafei Pan }
60528279cf2SJiafei Pan 
60628279cf2SJiafei Pan static struct io_block_dev_spec ifc_nand_spec = {
60728279cf2SJiafei Pan 	.buffer = {
60828279cf2SJiafei Pan 		.offset = 0,
60928279cf2SJiafei Pan 		.length = 0,
61028279cf2SJiafei Pan 	},
61128279cf2SJiafei Pan 	.ops = {
61228279cf2SJiafei Pan 		.read = ifc_nand_read,
61328279cf2SJiafei Pan 	},
61428279cf2SJiafei Pan 	/*
61528279cf2SJiafei Pan 	 * Default block size assumed as 2K
61628279cf2SJiafei Pan 	 * Would be updated based on actual size
61728279cf2SJiafei Pan 	 */
61828279cf2SJiafei Pan 	.block_size = UL(2048),
61928279cf2SJiafei Pan };
62028279cf2SJiafei Pan 
ifc_nand_init(uintptr_t * block_dev_spec,uintptr_t ifc_region_addr,uintptr_t ifc_register_addr,size_t ifc_sram_size,uintptr_t ifc_nand_blk_offset,size_t ifc_nand_blk_size)62128279cf2SJiafei Pan int ifc_nand_init(uintptr_t *block_dev_spec,
62228279cf2SJiafei Pan 			uintptr_t ifc_region_addr,
62328279cf2SJiafei Pan 			uintptr_t ifc_register_addr,
62428279cf2SJiafei Pan 			size_t ifc_sram_size,
62528279cf2SJiafei Pan 			uintptr_t ifc_nand_blk_offset,
62628279cf2SJiafei Pan 			size_t ifc_nand_blk_size)
62728279cf2SJiafei Pan {
62828279cf2SJiafei Pan 	struct nand_info *nand = NULL;
62928279cf2SJiafei Pan 	int ret;
63028279cf2SJiafei Pan 
63128279cf2SJiafei Pan 	nand = &nand_drv_data;
63228279cf2SJiafei Pan 	memset(nand, 0, sizeof(struct nand_info));
63328279cf2SJiafei Pan 
63428279cf2SJiafei Pan 	nand->ifc_region_addr = ifc_region_addr;
63528279cf2SJiafei Pan 	nand->ifc_register_addr = ifc_register_addr;
63628279cf2SJiafei Pan 
63728279cf2SJiafei Pan 	VERBOSE("nand_init\n");
63828279cf2SJiafei Pan 	ret = nand_init(nand);
63928279cf2SJiafei Pan 	if (ret) {
64028279cf2SJiafei Pan 		ERROR("nand init failed\n");
64128279cf2SJiafei Pan 		return ret;
64228279cf2SJiafei Pan 	}
64328279cf2SJiafei Pan 
64428279cf2SJiafei Pan 	ifc_nand_spec.buffer.offset = ifc_nand_blk_offset;
64528279cf2SJiafei Pan 	ifc_nand_spec.buffer.length = ifc_nand_blk_size;
64628279cf2SJiafei Pan 
64728279cf2SJiafei Pan 	ifc_nand_spec.block_size = nand_get_page_size(nand);
64828279cf2SJiafei Pan 
64928279cf2SJiafei Pan 	VERBOSE("Page size is %ld\n", ifc_nand_spec.block_size);
65028279cf2SJiafei Pan 
65128279cf2SJiafei Pan 	*block_dev_spec = (uintptr_t)&ifc_nand_spec;
65228279cf2SJiafei Pan 
65328279cf2SJiafei Pan 	/* Adding NAND SRAM< Buffer in XLAT Table */
65428279cf2SJiafei Pan 	mmap_add_region(ifc_region_addr, ifc_region_addr,
65528279cf2SJiafei Pan 			ifc_sram_size, MT_DEVICE | MT_RW);
65628279cf2SJiafei Pan 
65728279cf2SJiafei Pan 	return 0;
65828279cf2SJiafei Pan }
659