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 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 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 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 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 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 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 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 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 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 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 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 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 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