1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright 2022 NXP 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <string.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <common/debug.h> 10*91f16700Schasinglulu #include <drivers/io/io_block.h> 11*91f16700Schasinglulu #include "ifc.h" 12*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h> 13*91f16700Schasinglulu #include <nxp_timer.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu /* Private structure for NAND driver data */ 16*91f16700Schasinglulu static struct nand_info nand_drv_data; 17*91f16700Schasinglulu 18*91f16700Schasinglulu static int update_bbt(uint32_t idx, uint32_t blk, uint32_t *updated, 19*91f16700Schasinglulu struct nand_info *nand); 20*91f16700Schasinglulu 21*91f16700Schasinglulu static int nand_wait(struct nand_info *nand) 22*91f16700Schasinglulu { 23*91f16700Schasinglulu int timeout = 1; 24*91f16700Schasinglulu uint32_t neesr; 25*91f16700Schasinglulu unsigned long start_time; 26*91f16700Schasinglulu 27*91f16700Schasinglulu start_time = get_timer_val(0); 28*91f16700Schasinglulu 29*91f16700Schasinglulu while (get_timer_val(start_time) < NAND_TIMEOUT_MS) { 30*91f16700Schasinglulu /* clear the OPC event */ 31*91f16700Schasinglulu neesr = read_reg(nand, NAND_EVTER_STAT); 32*91f16700Schasinglulu if (neesr & NAND_EVTER_STAT_OPC_DN) { 33*91f16700Schasinglulu write_reg(nand, NAND_EVTER_STAT, neesr); 34*91f16700Schasinglulu timeout = 0; 35*91f16700Schasinglulu 36*91f16700Schasinglulu /* check for other errors */ 37*91f16700Schasinglulu if (neesr & NAND_EVTER_STAT_FTOER) { 38*91f16700Schasinglulu ERROR("%s NAND_EVTER_STAT_FTOER occurs\n", 39*91f16700Schasinglulu __func__); 40*91f16700Schasinglulu return -1; 41*91f16700Schasinglulu } else if (neesr & NAND_EVTER_STAT_ECCER) { 42*91f16700Schasinglulu ERROR("%s NAND_EVTER_STAT_ECCER occurs\n", 43*91f16700Schasinglulu __func__); 44*91f16700Schasinglulu return -1; 45*91f16700Schasinglulu } else if (neesr & NAND_EVTER_STAT_DQSER) { 46*91f16700Schasinglulu ERROR("%s NAND_EVTER_STAT_DQSER occurs\n", 47*91f16700Schasinglulu __func__); 48*91f16700Schasinglulu return -1; 49*91f16700Schasinglulu } 50*91f16700Schasinglulu 51*91f16700Schasinglulu break; 52*91f16700Schasinglulu } 53*91f16700Schasinglulu } 54*91f16700Schasinglulu 55*91f16700Schasinglulu if (timeout) { 56*91f16700Schasinglulu ERROR("%s ERROR_NAND_TIMEOUT occurs\n", __func__); 57*91f16700Schasinglulu return -1; 58*91f16700Schasinglulu } 59*91f16700Schasinglulu 60*91f16700Schasinglulu return 0; 61*91f16700Schasinglulu } 62*91f16700Schasinglulu 63*91f16700Schasinglulu static uint32_t nand_get_port_size(struct nand_info *nand) 64*91f16700Schasinglulu { 65*91f16700Schasinglulu uint32_t port_size = U(0); 66*91f16700Schasinglulu uint32_t cs_reg; 67*91f16700Schasinglulu uint32_t cur_cs; 68*91f16700Schasinglulu 69*91f16700Schasinglulu cur_cs = U(0); 70*91f16700Schasinglulu cs_reg = CSPR(cur_cs); 71*91f16700Schasinglulu port_size = (read_reg(nand, cs_reg) & CSPR_PS) >> CSPR_PS_SHIFT; 72*91f16700Schasinglulu switch (port_size) { 73*91f16700Schasinglulu case CSPR_PS_8: 74*91f16700Schasinglulu port_size = U(8); 75*91f16700Schasinglulu break; 76*91f16700Schasinglulu case CSPR_PS_16: 77*91f16700Schasinglulu port_size = U(16); 78*91f16700Schasinglulu break; 79*91f16700Schasinglulu case CSPR_PS_32: 80*91f16700Schasinglulu port_size = U(32); 81*91f16700Schasinglulu break; 82*91f16700Schasinglulu default: 83*91f16700Schasinglulu port_size = U(8); 84*91f16700Schasinglulu } 85*91f16700Schasinglulu 86*91f16700Schasinglulu return port_size; 87*91f16700Schasinglulu } 88*91f16700Schasinglulu 89*91f16700Schasinglulu static uint32_t nand_get_page_size(struct nand_info *nand) 90*91f16700Schasinglulu { 91*91f16700Schasinglulu uint32_t pg_size; 92*91f16700Schasinglulu uint32_t cs_reg; 93*91f16700Schasinglulu uint32_t cur_cs; 94*91f16700Schasinglulu 95*91f16700Schasinglulu cur_cs = 0; 96*91f16700Schasinglulu cs_reg = CSOR(cur_cs); 97*91f16700Schasinglulu pg_size = read_reg(nand, cs_reg) & CSOR_NAND_PGS; 98*91f16700Schasinglulu switch (pg_size) { 99*91f16700Schasinglulu case CSOR_NAND_PGS_2K: 100*91f16700Schasinglulu pg_size = U(2048); 101*91f16700Schasinglulu break; 102*91f16700Schasinglulu case CSOR_NAND_PGS_4K: 103*91f16700Schasinglulu pg_size = U(4096); 104*91f16700Schasinglulu break; 105*91f16700Schasinglulu case CSOR_NAND_PGS_8K: 106*91f16700Schasinglulu pg_size = U(8192); 107*91f16700Schasinglulu break; 108*91f16700Schasinglulu case CSOR_NAND_PGS_16K: 109*91f16700Schasinglulu pg_size = U(16384); 110*91f16700Schasinglulu break; 111*91f16700Schasinglulu default: 112*91f16700Schasinglulu pg_size = U(512); 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu return pg_size; 116*91f16700Schasinglulu } 117*91f16700Schasinglulu 118*91f16700Schasinglulu static uint32_t nand_get_pages_per_blk(struct nand_info *nand) 119*91f16700Schasinglulu { 120*91f16700Schasinglulu uint32_t pages_per_blk; 121*91f16700Schasinglulu uint32_t cs_reg; 122*91f16700Schasinglulu uint32_t cur_cs; 123*91f16700Schasinglulu 124*91f16700Schasinglulu cur_cs = 0; 125*91f16700Schasinglulu cs_reg = CSOR(cur_cs); 126*91f16700Schasinglulu pages_per_blk = (read_reg(nand, cs_reg) & CSOR_NAND_PB); 127*91f16700Schasinglulu switch (pages_per_blk) { 128*91f16700Schasinglulu case CSOR_NAND_PB_32: 129*91f16700Schasinglulu pages_per_blk = U(32); 130*91f16700Schasinglulu break; 131*91f16700Schasinglulu case CSOR_NAND_PB_64: 132*91f16700Schasinglulu pages_per_blk = U(64); 133*91f16700Schasinglulu break; 134*91f16700Schasinglulu case CSOR_NAND_PB_128: 135*91f16700Schasinglulu pages_per_blk = U(128); 136*91f16700Schasinglulu break; 137*91f16700Schasinglulu case CSOR_NAND_PB_256: 138*91f16700Schasinglulu pages_per_blk = U(256); 139*91f16700Schasinglulu break; 140*91f16700Schasinglulu case CSOR_NAND_PB_512: 141*91f16700Schasinglulu pages_per_blk = U(512); 142*91f16700Schasinglulu break; 143*91f16700Schasinglulu case CSOR_NAND_PB_1024: 144*91f16700Schasinglulu pages_per_blk = U(1024); 145*91f16700Schasinglulu break; 146*91f16700Schasinglulu case CSOR_NAND_PB_2048: 147*91f16700Schasinglulu pages_per_blk = U(2048); 148*91f16700Schasinglulu break; 149*91f16700Schasinglulu default: 150*91f16700Schasinglulu pages_per_blk = U(0); 151*91f16700Schasinglulu } 152*91f16700Schasinglulu 153*91f16700Schasinglulu return pages_per_blk; 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu static uint32_t get_page_index_width(uint32_t ppb) 157*91f16700Schasinglulu { 158*91f16700Schasinglulu switch (ppb) { 159*91f16700Schasinglulu case CSOR_NAND_PPB_32: 160*91f16700Schasinglulu return U(5); 161*91f16700Schasinglulu case CSOR_NAND_PPB_64: 162*91f16700Schasinglulu return U(6); 163*91f16700Schasinglulu case CSOR_NAND_PPB_128: 164*91f16700Schasinglulu return U(7); 165*91f16700Schasinglulu case CSOR_NAND_PPB_256: 166*91f16700Schasinglulu return U(8); 167*91f16700Schasinglulu case CSOR_NAND_PPB_512: 168*91f16700Schasinglulu return U(9); 169*91f16700Schasinglulu case CSOR_NAND_PPB_1024: 170*91f16700Schasinglulu return U(10); 171*91f16700Schasinglulu case CSOR_NAND_PPB_2048: 172*91f16700Schasinglulu return U(11); 173*91f16700Schasinglulu default: 174*91f16700Schasinglulu return U(5); 175*91f16700Schasinglulu } 176*91f16700Schasinglulu } 177*91f16700Schasinglulu 178*91f16700Schasinglulu static void nand_get_params(struct nand_info *nand) 179*91f16700Schasinglulu { 180*91f16700Schasinglulu nand->port_size = nand_get_port_size(nand); 181*91f16700Schasinglulu 182*91f16700Schasinglulu nand->page_size = nand_get_page_size(nand); 183*91f16700Schasinglulu 184*91f16700Schasinglulu /* 185*91f16700Schasinglulu * Set Bad marker Location for LP / SP 186*91f16700Schasinglulu * Small Page : 8 Bit : 0x5 187*91f16700Schasinglulu * Small Page : 16 Bit : 0xa 188*91f16700Schasinglulu * Large Page : 8 /16 Bit : 0x0 189*91f16700Schasinglulu */ 190*91f16700Schasinglulu nand->bad_marker_loc = (nand->page_size == 512) ? 191*91f16700Schasinglulu ((nand->port_size == 8) ? 0x5 : 0xa) : 0; 192*91f16700Schasinglulu 193*91f16700Schasinglulu /* check for the device is ONFI compliant or not */ 194*91f16700Schasinglulu nand->onfi_dev_flag = 195*91f16700Schasinglulu (read_reg(nand, NAND_EVTER_STAT) & NAND_EVTER_STAT_BBI_SRCH_SEL) 196*91f16700Schasinglulu ? 1 : 0; 197*91f16700Schasinglulu 198*91f16700Schasinglulu /* NAND Blk serached count for incremental Bad block search cnt */ 199*91f16700Schasinglulu nand->bbs = 0; 200*91f16700Schasinglulu 201*91f16700Schasinglulu /* pages per Block */ 202*91f16700Schasinglulu nand->ppb = nand_get_pages_per_blk(nand); 203*91f16700Schasinglulu 204*91f16700Schasinglulu /* Blk size */ 205*91f16700Schasinglulu nand->blk_size = nand->page_size * nand->ppb; 206*91f16700Schasinglulu 207*91f16700Schasinglulu /* get_page_index_width */ 208*91f16700Schasinglulu nand->pi_width = get_page_index_width(nand->ppb); 209*91f16700Schasinglulu 210*91f16700Schasinglulu /* bad block table init */ 211*91f16700Schasinglulu nand->lgb = 0; 212*91f16700Schasinglulu nand->bbt_max = 0; 213*91f16700Schasinglulu nand->bzero_good = 0; 214*91f16700Schasinglulu memset(nand->bbt, EMPTY_VAL, BBT_SIZE * sizeof(nand->bbt[0])); 215*91f16700Schasinglulu } 216*91f16700Schasinglulu 217*91f16700Schasinglulu static int nand_init(struct nand_info *nand) 218*91f16700Schasinglulu { 219*91f16700Schasinglulu uint32_t ncfgr = 0; 220*91f16700Schasinglulu 221*91f16700Schasinglulu /* Get nand Parameters from IFC */ 222*91f16700Schasinglulu nand_get_params(nand); 223*91f16700Schasinglulu 224*91f16700Schasinglulu /* Clear all errors */ 225*91f16700Schasinglulu write_reg(nand, NAND_EVTER_STAT, U(0xffffffff)); 226*91f16700Schasinglulu 227*91f16700Schasinglulu /* 228*91f16700Schasinglulu * Disable autoboot in NCFGR. Mapping will change from 229*91f16700Schasinglulu * physical to logical for SRAM buffer 230*91f16700Schasinglulu */ 231*91f16700Schasinglulu ncfgr = read_reg(nand, NCFGR); 232*91f16700Schasinglulu write_reg(nand, NCFGR, (ncfgr & ~NCFGR_BOOT)); 233*91f16700Schasinglulu 234*91f16700Schasinglulu return 0; 235*91f16700Schasinglulu } 236*91f16700Schasinglulu 237*91f16700Schasinglulu static int nand_read_data( 238*91f16700Schasinglulu uintptr_t ifc_region_addr, 239*91f16700Schasinglulu uint32_t row_add, 240*91f16700Schasinglulu uint32_t col_add, 241*91f16700Schasinglulu uint32_t byte_cnt, 242*91f16700Schasinglulu uint8_t *data, 243*91f16700Schasinglulu uint32_t main_spare, 244*91f16700Schasinglulu struct nand_info *nand) 245*91f16700Schasinglulu { 246*91f16700Schasinglulu uint32_t page_size_add_bits = U(0); 247*91f16700Schasinglulu uint32_t page_add_in_actual, page_add; 248*91f16700Schasinglulu uintptr_t sram_addr_calc; 249*91f16700Schasinglulu int ret; 250*91f16700Schasinglulu uint32_t col_val; 251*91f16700Schasinglulu 252*91f16700Schasinglulu /* Programming MS bit to read from spare area.*/ 253*91f16700Schasinglulu col_val = (main_spare << NAND_COL_MS_SHIFT) | col_add; 254*91f16700Schasinglulu 255*91f16700Schasinglulu write_reg(nand, NAND_BC, byte_cnt); 256*91f16700Schasinglulu 257*91f16700Schasinglulu write_reg(nand, ROW0, row_add); 258*91f16700Schasinglulu write_reg(nand, COL0, col_val); 259*91f16700Schasinglulu 260*91f16700Schasinglulu /* Program FCR for small Page */ 261*91f16700Schasinglulu if (nand->page_size == U(512)) { 262*91f16700Schasinglulu if (byte_cnt == 0 || 263*91f16700Schasinglulu (byte_cnt != 0 && main_spare == 0 && col_add <= 255)) { 264*91f16700Schasinglulu write_reg(nand, NAND_FCR0, 265*91f16700Schasinglulu (NAND_CMD_READ0 << FCR_CMD0_SHIFT)); 266*91f16700Schasinglulu } else if (main_spare == 0) { 267*91f16700Schasinglulu write_reg(nand, NAND_FCR0, 268*91f16700Schasinglulu (NAND_CMD_READ1 << FCR_CMD0_SHIFT)); 269*91f16700Schasinglulu } else { 270*91f16700Schasinglulu write_reg(nand, NAND_FCR0, 271*91f16700Schasinglulu (NAND_CMD_READOOB << FCR_CMD0_SHIFT)); 272*91f16700Schasinglulu } 273*91f16700Schasinglulu 274*91f16700Schasinglulu } else { 275*91f16700Schasinglulu /* Program FCR for Large Page */ 276*91f16700Schasinglulu write_reg(nand, NAND_FCR0, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | 277*91f16700Schasinglulu (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); 278*91f16700Schasinglulu } 279*91f16700Schasinglulu if (nand->page_size == U(512)) { 280*91f16700Schasinglulu write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) | 281*91f16700Schasinglulu (FIR_OP_CA0 << FIR_OP1_SHIFT) | 282*91f16700Schasinglulu (FIR_OP_RA0 << FIR_OP2_SHIFT) | 283*91f16700Schasinglulu (FIR_OP_BTRD << FIR_OP3_SHIFT) | 284*91f16700Schasinglulu (FIR_OP_NOP << FIR_OP4_SHIFT))); 285*91f16700Schasinglulu write_reg(nand, NAND_FIR1, U(0x00000000)); 286*91f16700Schasinglulu } else { 287*91f16700Schasinglulu write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) | 288*91f16700Schasinglulu (FIR_OP_CA0 << FIR_OP1_SHIFT) | 289*91f16700Schasinglulu (FIR_OP_RA0 << FIR_OP2_SHIFT) | 290*91f16700Schasinglulu (FIR_OP_CMD1 << FIR_OP3_SHIFT) | 291*91f16700Schasinglulu (FIR_OP_BTRD << FIR_OP4_SHIFT))); 292*91f16700Schasinglulu 293*91f16700Schasinglulu write_reg(nand, NAND_FIR1, (FIR_OP_NOP << FIR_OP5_SHIFT)); 294*91f16700Schasinglulu } 295*91f16700Schasinglulu write_reg(nand, NANDSEQ_STRT, NAND_SEQ_STRT_FIR_STRT); 296*91f16700Schasinglulu 297*91f16700Schasinglulu ret = nand_wait(nand); 298*91f16700Schasinglulu if (ret != 0) 299*91f16700Schasinglulu return ret; 300*91f16700Schasinglulu 301*91f16700Schasinglulu /* calculate page_size_add_bits i.e bits 302*91f16700Schasinglulu * in sram address corresponding to area 303*91f16700Schasinglulu * within a page for sram 304*91f16700Schasinglulu */ 305*91f16700Schasinglulu if (nand->page_size == U(512)) 306*91f16700Schasinglulu page_size_add_bits = U(10); 307*91f16700Schasinglulu else if (nand->page_size == U(2048)) 308*91f16700Schasinglulu page_size_add_bits = U(12); 309*91f16700Schasinglulu else if (nand->page_size == U(4096)) 310*91f16700Schasinglulu page_size_add_bits = U(13); 311*91f16700Schasinglulu else if (nand->page_size == U(8192)) 312*91f16700Schasinglulu page_size_add_bits = U(14); 313*91f16700Schasinglulu else if (nand->page_size == U(16384)) 314*91f16700Schasinglulu page_size_add_bits = U(15); 315*91f16700Schasinglulu 316*91f16700Schasinglulu page_add = row_add; 317*91f16700Schasinglulu 318*91f16700Schasinglulu page_add_in_actual = (page_add << page_size_add_bits) & U(0x0000FFFF); 319*91f16700Schasinglulu 320*91f16700Schasinglulu if (byte_cnt == 0) 321*91f16700Schasinglulu col_add = U(0); 322*91f16700Schasinglulu 323*91f16700Schasinglulu /* Calculate SRAM address for main and spare area */ 324*91f16700Schasinglulu if (main_spare == 0) 325*91f16700Schasinglulu sram_addr_calc = ifc_region_addr | page_add_in_actual | col_add; 326*91f16700Schasinglulu else 327*91f16700Schasinglulu sram_addr_calc = ifc_region_addr | page_add_in_actual | 328*91f16700Schasinglulu (col_add + nand->page_size); 329*91f16700Schasinglulu 330*91f16700Schasinglulu /* Depending Byte_count copy full page or partial page from SRAM */ 331*91f16700Schasinglulu if (byte_cnt == 0) 332*91f16700Schasinglulu memcpy(data, (void *)sram_addr_calc, 333*91f16700Schasinglulu nand->page_size); 334*91f16700Schasinglulu else 335*91f16700Schasinglulu memcpy(data, (void *)sram_addr_calc, byte_cnt); 336*91f16700Schasinglulu 337*91f16700Schasinglulu return 0; 338*91f16700Schasinglulu } 339*91f16700Schasinglulu 340*91f16700Schasinglulu static int nand_read(struct nand_info *nand, int32_t src_addr, 341*91f16700Schasinglulu uintptr_t dst, uint32_t size) 342*91f16700Schasinglulu { 343*91f16700Schasinglulu uint32_t log_blk = U(0); 344*91f16700Schasinglulu uint32_t pg_no = U(0); 345*91f16700Schasinglulu uint32_t col_off = U(0); 346*91f16700Schasinglulu uint32_t row_off = U(0); 347*91f16700Schasinglulu uint32_t byte_cnt = U(0); 348*91f16700Schasinglulu uint32_t read_cnt = U(0); 349*91f16700Schasinglulu uint32_t i = U(0); 350*91f16700Schasinglulu uint32_t updated = U(0); 351*91f16700Schasinglulu 352*91f16700Schasinglulu int ret = 0; 353*91f16700Schasinglulu uint8_t *out = (uint8_t *)dst; 354*91f16700Schasinglulu 355*91f16700Schasinglulu uint32_t pblk; 356*91f16700Schasinglulu 357*91f16700Schasinglulu /* loop till size */ 358*91f16700Schasinglulu while (size) { 359*91f16700Schasinglulu log_blk = (src_addr / nand->blk_size); 360*91f16700Schasinglulu pg_no = ((src_addr - (log_blk * nand->blk_size)) / 361*91f16700Schasinglulu nand->page_size); 362*91f16700Schasinglulu pblk = log_blk; 363*91f16700Schasinglulu 364*91f16700Schasinglulu // iterate the bbt to find the block 365*91f16700Schasinglulu for (i = 0; i <= nand->bbt_max; i++) { 366*91f16700Schasinglulu if (nand->bbt[i] == EMPTY_VAL_CHECK) { 367*91f16700Schasinglulu ret = update_bbt(i, pblk, &updated, nand); 368*91f16700Schasinglulu 369*91f16700Schasinglulu if (ret != 0) 370*91f16700Schasinglulu return ret; 371*91f16700Schasinglulu /* 372*91f16700Schasinglulu * if table not updated and we reached 373*91f16700Schasinglulu * end of table 374*91f16700Schasinglulu */ 375*91f16700Schasinglulu if (!updated) 376*91f16700Schasinglulu break; 377*91f16700Schasinglulu } 378*91f16700Schasinglulu 379*91f16700Schasinglulu if (pblk < nand->bbt[i]) 380*91f16700Schasinglulu break; 381*91f16700Schasinglulu else if (pblk >= nand->bbt[i]) 382*91f16700Schasinglulu pblk++; 383*91f16700Schasinglulu } 384*91f16700Schasinglulu 385*91f16700Schasinglulu col_off = (src_addr % nand->page_size); 386*91f16700Schasinglulu if (col_off) { 387*91f16700Schasinglulu if ((col_off + size) < nand->page_size) 388*91f16700Schasinglulu byte_cnt = size; 389*91f16700Schasinglulu else 390*91f16700Schasinglulu byte_cnt = nand->page_size - col_off; 391*91f16700Schasinglulu 392*91f16700Schasinglulu row_off = (pblk << nand->pi_width) | pg_no; 393*91f16700Schasinglulu 394*91f16700Schasinglulu ret = nand_read_data( 395*91f16700Schasinglulu nand->ifc_region_addr, 396*91f16700Schasinglulu row_off, 397*91f16700Schasinglulu col_off, 398*91f16700Schasinglulu byte_cnt, out, MAIN, nand); 399*91f16700Schasinglulu 400*91f16700Schasinglulu if (ret != 0) 401*91f16700Schasinglulu return ret; 402*91f16700Schasinglulu } else { 403*91f16700Schasinglulu /* 404*91f16700Schasinglulu * fullpage/Partial Page 405*91f16700Schasinglulu * if byte_cnt = 0 full page 406*91f16700Schasinglulu * else partial page 407*91f16700Schasinglulu */ 408*91f16700Schasinglulu if (size < nand->page_size) { 409*91f16700Schasinglulu byte_cnt = size; 410*91f16700Schasinglulu read_cnt = size; 411*91f16700Schasinglulu } else { 412*91f16700Schasinglulu byte_cnt = nand->page_size; 413*91f16700Schasinglulu read_cnt = 0; 414*91f16700Schasinglulu } 415*91f16700Schasinglulu row_off = (pblk << nand->pi_width) | pg_no; 416*91f16700Schasinglulu 417*91f16700Schasinglulu ret = nand_read_data( 418*91f16700Schasinglulu nand->ifc_region_addr, 419*91f16700Schasinglulu row_off, 420*91f16700Schasinglulu 0, 421*91f16700Schasinglulu read_cnt, out, MAIN, nand); 422*91f16700Schasinglulu 423*91f16700Schasinglulu if (ret != 0) { 424*91f16700Schasinglulu ERROR("Error from nand-read_data %d\n", ret); 425*91f16700Schasinglulu return ret; 426*91f16700Schasinglulu } 427*91f16700Schasinglulu } 428*91f16700Schasinglulu src_addr += byte_cnt; 429*91f16700Schasinglulu out += byte_cnt; 430*91f16700Schasinglulu size -= byte_cnt; 431*91f16700Schasinglulu } 432*91f16700Schasinglulu return 0; 433*91f16700Schasinglulu } 434*91f16700Schasinglulu 435*91f16700Schasinglulu static int isgoodblock(uint32_t blk, uint32_t *gb, struct nand_info *nand) 436*91f16700Schasinglulu { 437*91f16700Schasinglulu uint8_t buf[2]; 438*91f16700Schasinglulu int ret; 439*91f16700Schasinglulu uint32_t row_add; 440*91f16700Schasinglulu 441*91f16700Schasinglulu *gb = 0; 442*91f16700Schasinglulu 443*91f16700Schasinglulu /* read Page 0 of blk */ 444*91f16700Schasinglulu ret = nand_read_data( 445*91f16700Schasinglulu nand->ifc_region_addr, 446*91f16700Schasinglulu blk << nand->pi_width, 447*91f16700Schasinglulu nand->bad_marker_loc, 448*91f16700Schasinglulu 0x2, buf, 1, nand); 449*91f16700Schasinglulu 450*91f16700Schasinglulu if (ret != 0) 451*91f16700Schasinglulu return ret; 452*91f16700Schasinglulu 453*91f16700Schasinglulu /* For ONFI devices check Page 0 and Last page of block for 454*91f16700Schasinglulu * Bad Marker and for NON-ONFI Page 0 and 1 for Bad Marker 455*91f16700Schasinglulu */ 456*91f16700Schasinglulu row_add = (blk << nand->pi_width); 457*91f16700Schasinglulu if (nand->port_size == 8) { 458*91f16700Schasinglulu /* port size is 8 Bit */ 459*91f16700Schasinglulu /* check if page 0 has 0xff */ 460*91f16700Schasinglulu if (buf[0] == 0xff) { 461*91f16700Schasinglulu /* check page 1 */ 462*91f16700Schasinglulu if (nand->onfi_dev_flag) 463*91f16700Schasinglulu ret = nand_read_data( 464*91f16700Schasinglulu nand->ifc_region_addr, 465*91f16700Schasinglulu row_add | (nand->ppb - 1), 466*91f16700Schasinglulu nand->bad_marker_loc, 467*91f16700Schasinglulu 0x2, buf, SPARE, nand); 468*91f16700Schasinglulu else 469*91f16700Schasinglulu ret = nand_read_data( 470*91f16700Schasinglulu nand->ifc_region_addr, 471*91f16700Schasinglulu row_add | 1, 472*91f16700Schasinglulu nand->bad_marker_loc, 473*91f16700Schasinglulu 0x2, buf, SPARE, nand); 474*91f16700Schasinglulu 475*91f16700Schasinglulu if (ret != 0) 476*91f16700Schasinglulu return ret; 477*91f16700Schasinglulu 478*91f16700Schasinglulu if (buf[0] == 0xff) 479*91f16700Schasinglulu *gb = GOOD_BLK; 480*91f16700Schasinglulu else 481*91f16700Schasinglulu *gb = BAD_BLK; 482*91f16700Schasinglulu } else { 483*91f16700Schasinglulu /* no, so it is bad blk */ 484*91f16700Schasinglulu *gb = BAD_BLK; 485*91f16700Schasinglulu } 486*91f16700Schasinglulu } else { 487*91f16700Schasinglulu /* Port size 16-Bit */ 488*91f16700Schasinglulu /* check if page 0 has 0xffff */ 489*91f16700Schasinglulu if ((buf[0] == 0xff) && 490*91f16700Schasinglulu (buf[1] == 0xff)) { 491*91f16700Schasinglulu /* check page 1 for 0xffff */ 492*91f16700Schasinglulu if (nand->onfi_dev_flag) { 493*91f16700Schasinglulu ret = nand_read_data( 494*91f16700Schasinglulu nand->ifc_region_addr, 495*91f16700Schasinglulu row_add | (nand->ppb - 1), 496*91f16700Schasinglulu nand->bad_marker_loc, 497*91f16700Schasinglulu 0x2, buf, SPARE, nand); 498*91f16700Schasinglulu } else { 499*91f16700Schasinglulu ret = nand_read_data( 500*91f16700Schasinglulu nand->ifc_region_addr, 501*91f16700Schasinglulu row_add | 1, 502*91f16700Schasinglulu nand->bad_marker_loc, 503*91f16700Schasinglulu 0x2, buf, SPARE, nand); 504*91f16700Schasinglulu } 505*91f16700Schasinglulu 506*91f16700Schasinglulu if (ret != 0) 507*91f16700Schasinglulu return ret; 508*91f16700Schasinglulu 509*91f16700Schasinglulu if ((buf[0] == 0xff) && 510*91f16700Schasinglulu (buf[1] == 0xff)) { 511*91f16700Schasinglulu *gb = GOOD_BLK; 512*91f16700Schasinglulu } else { 513*91f16700Schasinglulu *gb = BAD_BLK; 514*91f16700Schasinglulu } 515*91f16700Schasinglulu } else { 516*91f16700Schasinglulu /* no, so it is bad blk */ 517*91f16700Schasinglulu *gb = BAD_BLK; 518*91f16700Schasinglulu } 519*91f16700Schasinglulu } 520*91f16700Schasinglulu return 0; 521*91f16700Schasinglulu } 522*91f16700Schasinglulu 523*91f16700Schasinglulu static int update_bbt(uint32_t idx, uint32_t blk, 524*91f16700Schasinglulu uint32_t *updated, struct nand_info *nand) 525*91f16700Schasinglulu { 526*91f16700Schasinglulu uint32_t sblk; 527*91f16700Schasinglulu uint32_t lgb; 528*91f16700Schasinglulu int ret; 529*91f16700Schasinglulu 530*91f16700Schasinglulu if (nand->bzero_good && blk == 0) 531*91f16700Schasinglulu return 0; 532*91f16700Schasinglulu 533*91f16700Schasinglulu /* special case for lgb == 0 */ 534*91f16700Schasinglulu /* if blk <= lgb return */ 535*91f16700Schasinglulu if (nand->lgb != 0 && blk <= nand->lgb) 536*91f16700Schasinglulu return 0; 537*91f16700Schasinglulu 538*91f16700Schasinglulu *updated = 0; 539*91f16700Schasinglulu 540*91f16700Schasinglulu /* if blk is more than lgb, iterate from lgb till a good block 541*91f16700Schasinglulu * is found for blk 542*91f16700Schasinglulu */ 543*91f16700Schasinglulu 544*91f16700Schasinglulu if (nand->lgb < blk) 545*91f16700Schasinglulu sblk = nand->lgb; 546*91f16700Schasinglulu else 547*91f16700Schasinglulu /* this is when lgb = 0 */ 548*91f16700Schasinglulu sblk = blk; 549*91f16700Schasinglulu 550*91f16700Schasinglulu 551*91f16700Schasinglulu lgb = nand->lgb; 552*91f16700Schasinglulu 553*91f16700Schasinglulu /* loop from blk to find a good block */ 554*91f16700Schasinglulu while (1) { 555*91f16700Schasinglulu while (lgb <= sblk) { 556*91f16700Schasinglulu uint32_t gb = 0; 557*91f16700Schasinglulu 558*91f16700Schasinglulu ret = isgoodblock(lgb, &gb, nand); 559*91f16700Schasinglulu if (ret != 0) 560*91f16700Schasinglulu return ret; 561*91f16700Schasinglulu 562*91f16700Schasinglulu /* special case block 0 is good then set this flag */ 563*91f16700Schasinglulu if (lgb == 0 && gb == GOOD_BLK) 564*91f16700Schasinglulu nand->bzero_good = 1; 565*91f16700Schasinglulu 566*91f16700Schasinglulu if (gb == BAD_BLK) { 567*91f16700Schasinglulu if (idx >= BBT_SIZE) { 568*91f16700Schasinglulu ERROR("NAND BBT Table full\n"); 569*91f16700Schasinglulu return -1; 570*91f16700Schasinglulu } 571*91f16700Schasinglulu *updated = 1; 572*91f16700Schasinglulu nand->bbt[idx] = lgb; 573*91f16700Schasinglulu idx++; 574*91f16700Schasinglulu blk++; 575*91f16700Schasinglulu sblk++; 576*91f16700Schasinglulu if (idx > nand->bbt_max) 577*91f16700Schasinglulu nand->bbt_max = idx; 578*91f16700Schasinglulu } 579*91f16700Schasinglulu lgb++; 580*91f16700Schasinglulu } 581*91f16700Schasinglulu /* the access block found */ 582*91f16700Schasinglulu if (sblk == blk) { 583*91f16700Schasinglulu /* when good block found update lgb */ 584*91f16700Schasinglulu nand->lgb = blk; 585*91f16700Schasinglulu break; 586*91f16700Schasinglulu } 587*91f16700Schasinglulu sblk++; 588*91f16700Schasinglulu } 589*91f16700Schasinglulu 590*91f16700Schasinglulu return 0; 591*91f16700Schasinglulu } 592*91f16700Schasinglulu 593*91f16700Schasinglulu static size_t ifc_nand_read(int lba, uintptr_t buf, size_t size) 594*91f16700Schasinglulu { 595*91f16700Schasinglulu int ret; 596*91f16700Schasinglulu uint32_t page_size; 597*91f16700Schasinglulu uint32_t src_addr; 598*91f16700Schasinglulu struct nand_info *nand = &nand_drv_data; 599*91f16700Schasinglulu 600*91f16700Schasinglulu page_size = nand_get_page_size(nand); 601*91f16700Schasinglulu src_addr = lba * page_size; 602*91f16700Schasinglulu ret = nand_read(nand, src_addr, buf, size); 603*91f16700Schasinglulu return ret ? 0 : size; 604*91f16700Schasinglulu } 605*91f16700Schasinglulu 606*91f16700Schasinglulu static struct io_block_dev_spec ifc_nand_spec = { 607*91f16700Schasinglulu .buffer = { 608*91f16700Schasinglulu .offset = 0, 609*91f16700Schasinglulu .length = 0, 610*91f16700Schasinglulu }, 611*91f16700Schasinglulu .ops = { 612*91f16700Schasinglulu .read = ifc_nand_read, 613*91f16700Schasinglulu }, 614*91f16700Schasinglulu /* 615*91f16700Schasinglulu * Default block size assumed as 2K 616*91f16700Schasinglulu * Would be updated based on actual size 617*91f16700Schasinglulu */ 618*91f16700Schasinglulu .block_size = UL(2048), 619*91f16700Schasinglulu }; 620*91f16700Schasinglulu 621*91f16700Schasinglulu int ifc_nand_init(uintptr_t *block_dev_spec, 622*91f16700Schasinglulu uintptr_t ifc_region_addr, 623*91f16700Schasinglulu uintptr_t ifc_register_addr, 624*91f16700Schasinglulu size_t ifc_sram_size, 625*91f16700Schasinglulu uintptr_t ifc_nand_blk_offset, 626*91f16700Schasinglulu size_t ifc_nand_blk_size) 627*91f16700Schasinglulu { 628*91f16700Schasinglulu struct nand_info *nand = NULL; 629*91f16700Schasinglulu int ret; 630*91f16700Schasinglulu 631*91f16700Schasinglulu nand = &nand_drv_data; 632*91f16700Schasinglulu memset(nand, 0, sizeof(struct nand_info)); 633*91f16700Schasinglulu 634*91f16700Schasinglulu nand->ifc_region_addr = ifc_region_addr; 635*91f16700Schasinglulu nand->ifc_register_addr = ifc_register_addr; 636*91f16700Schasinglulu 637*91f16700Schasinglulu VERBOSE("nand_init\n"); 638*91f16700Schasinglulu ret = nand_init(nand); 639*91f16700Schasinglulu if (ret) { 640*91f16700Schasinglulu ERROR("nand init failed\n"); 641*91f16700Schasinglulu return ret; 642*91f16700Schasinglulu } 643*91f16700Schasinglulu 644*91f16700Schasinglulu ifc_nand_spec.buffer.offset = ifc_nand_blk_offset; 645*91f16700Schasinglulu ifc_nand_spec.buffer.length = ifc_nand_blk_size; 646*91f16700Schasinglulu 647*91f16700Schasinglulu ifc_nand_spec.block_size = nand_get_page_size(nand); 648*91f16700Schasinglulu 649*91f16700Schasinglulu VERBOSE("Page size is %ld\n", ifc_nand_spec.block_size); 650*91f16700Schasinglulu 651*91f16700Schasinglulu *block_dev_spec = (uintptr_t)&ifc_nand_spec; 652*91f16700Schasinglulu 653*91f16700Schasinglulu /* Adding NAND SRAM< Buffer in XLAT Table */ 654*91f16700Schasinglulu mmap_add_region(ifc_region_addr, ifc_region_addr, 655*91f16700Schasinglulu ifc_sram_size, MT_DEVICE | MT_RW); 656*91f16700Schasinglulu 657*91f16700Schasinglulu return 0; 658*91f16700Schasinglulu } 659