1ba0501acSDingqiang Lin /* 2ba0501acSDingqiang Lin * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd 3ba0501acSDingqiang Lin * 4ba0501acSDingqiang Lin * SPDX-License-Identifier: GPL-2.0 5ba0501acSDingqiang Lin */ 6ba0501acSDingqiang Lin 7ba0501acSDingqiang Lin #include <common.h> 8ba0501acSDingqiang Lin #include <linux/bug.h> 9ba0501acSDingqiang Lin #include <linux/delay.h> 10ba0501acSDingqiang Lin 11ba0501acSDingqiang Lin #include "flash.h" 12ba0501acSDingqiang Lin #include "flash_com.h" 13ba0501acSDingqiang Lin #include "sfc.h" 14ba0501acSDingqiang Lin #include "sfc_nand.h" 15ba0501acSDingqiang Lin #include "rkflash_debug.h" 16ba0501acSDingqiang Lin 17ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 18ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 19*6281205aSDingqiang Lin {0x98C2, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 18, 8, 0xB0, 0XFF, 4, 8, NULL}, 20ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 21*6281205aSDingqiang Lin {0x98CB, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 19, 8, 0xB0, 0XFF, 4, 8, NULL}, 22ba0501acSDingqiang Lin /* MX35LF1GE4AB */ 23*6281205aSDingqiang Lin {0xC212, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp1}, 24ba0501acSDingqiang Lin /* MX35LF2GE4AB */ 25*6281205aSDingqiang Lin {0xC222, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 4, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp1}, 26ba0501acSDingqiang Lin /* GD5F1GQ4UAYIG */ 27*6281205aSDingqiang Lin {0xC8F1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0, 4, 8, NULL}, 28ba0501acSDingqiang Lin /* MT29F1G01ZAC */ 29*6281205aSDingqiang Lin {0x2C12, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x00, 18, 1, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp1}, 30*6281205aSDingqiang Lin /* GD5F2GQ40BY2GR */ 31*6281205aSDingqiang Lin {0xC8D2, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 8, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp3}, 32ba0501acSDingqiang Lin /* GD5F1GQ4U */ 33*6281205aSDingqiang Lin {0xC8D1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp3}, 34ba0501acSDingqiang Lin /* IS37SML01G1 */ 35*6281205aSDingqiang Lin {0xC821, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x00, 18, 1, 0xB0, 0XFF, 8, 12, &sfc_nand_ecc_status_sp1}, 36ba0501acSDingqiang Lin /* W25N01GV */ 37*6281205aSDingqiang Lin {0xEFAA, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 1, 0xFF, 0XFF, 4, 20, &sfc_nand_ecc_status_sp1}, 38*6281205aSDingqiang Lin /* HYF2GQ4UAACAE */ 39*6281205aSDingqiang Lin {0xC952, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 14, 0xB0, 0, 4, 36, NULL}, 40*6281205aSDingqiang Lin /* HYF2GQ4UDACAE */ 41*6281205aSDingqiang Lin {0xC922, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 4, 0xB0, 0, 4, 20, NULL}, 42*6281205aSDingqiang Lin /* HYF1GQ4UDACAE */ 43*6281205aSDingqiang Lin {0xC921, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0, 4, 20, NULL}, 44ba0501acSDingqiang Lin }; 45ba0501acSDingqiang Lin 46ba0501acSDingqiang Lin static u8 id_byte[8]; 47ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 48ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 49ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 50ba0501acSDingqiang Lin 51ba0501acSDingqiang Lin static struct nand_info *spi_nand_get_info(u8 *nand_id) 52ba0501acSDingqiang Lin { 53ba0501acSDingqiang Lin u32 i; 54ba0501acSDingqiang Lin u32 id = (nand_id[0] << 8) | (nand_id[1] << 0); 55ba0501acSDingqiang Lin 56ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 57ba0501acSDingqiang Lin if (spi_nand_tbl[i].id == id) 58ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 59ba0501acSDingqiang Lin } 60ba0501acSDingqiang Lin return NULL; 61ba0501acSDingqiang Lin } 62ba0501acSDingqiang Lin 63ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 64ba0501acSDingqiang Lin { 65ba0501acSDingqiang Lin int ret; 66ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 67ba0501acSDingqiang Lin 68ba0501acSDingqiang Lin sfcmd.d32 = 0; 69ba0501acSDingqiang Lin sfcmd.b.cmd = CMD_WRITE_EN; 70ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0, 0, NULL); 71ba0501acSDingqiang Lin return ret; 72ba0501acSDingqiang Lin } 73ba0501acSDingqiang Lin 74ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 75ba0501acSDingqiang Lin { 76ba0501acSDingqiang Lin int ret; 77ba0501acSDingqiang Lin union SFCCTRL_DATA sfctrl; 78ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 79ba0501acSDingqiang Lin u8 status = 0xFF; 80ba0501acSDingqiang Lin 81ba0501acSDingqiang Lin sfcmd.d32 = 0; 82ba0501acSDingqiang Lin sfcmd.b.cmd = 0; 83ba0501acSDingqiang Lin sfcmd.b.datasize = 1; 84ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 85ba0501acSDingqiang Lin 86ba0501acSDingqiang Lin sfctrl.b.datalines = 2; 87ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, sfctrl.d32, 0, &status); 88ba0501acSDingqiang Lin return ret; 89ba0501acSDingqiang Lin } 90ba0501acSDingqiang Lin 91ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 92ba0501acSDingqiang Lin { 93ba0501acSDingqiang Lin int ret; 94ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 95ba0501acSDingqiang Lin 96ba0501acSDingqiang Lin sfcmd.d32 = 0; 97ba0501acSDingqiang Lin sfcmd.b.cmd = 0x0F; 98ba0501acSDingqiang Lin sfcmd.b.datasize = 1; 99ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 100ba0501acSDingqiang Lin *data = 0; 101ba0501acSDingqiang Lin 102ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, data); 103ba0501acSDingqiang Lin if (ret != SFC_OK) 104ba0501acSDingqiang Lin return ret; 105ba0501acSDingqiang Lin return SFC_OK; 106ba0501acSDingqiang Lin } 107ba0501acSDingqiang Lin 108ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 109ba0501acSDingqiang Lin { 110ba0501acSDingqiang Lin int ret; 111ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 112ba0501acSDingqiang Lin 113ba0501acSDingqiang Lin sfc_nand_write_en(); 114ba0501acSDingqiang Lin 115ba0501acSDingqiang Lin sfcmd.d32 = 0; 116ba0501acSDingqiang Lin sfcmd.b.cmd = 0x1F; 117ba0501acSDingqiang Lin sfcmd.b.datasize = 1; 118ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 119ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 120ba0501acSDingqiang Lin 121ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, &status); 122ba0501acSDingqiang Lin if (ret != SFC_OK) 123ba0501acSDingqiang Lin return ret; 124ba0501acSDingqiang Lin return ret; 125ba0501acSDingqiang Lin } 126ba0501acSDingqiang Lin 127ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 128ba0501acSDingqiang Lin { 129ba0501acSDingqiang Lin int ret; 130ba0501acSDingqiang Lin int i; 131ba0501acSDingqiang Lin u8 status; 132ba0501acSDingqiang Lin 133ba0501acSDingqiang Lin *data = 0; 134ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 135ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 136ba0501acSDingqiang Lin if (ret != SFC_OK) 137ba0501acSDingqiang Lin return ret; 138ba0501acSDingqiang Lin *data = status; 139ba0501acSDingqiang Lin if (!(status & (1 << 0))) 140ba0501acSDingqiang Lin return SFC_OK; 141ba0501acSDingqiang Lin sfc_delay(1); 142ba0501acSDingqiang Lin } 143ba0501acSDingqiang Lin return -1; 144ba0501acSDingqiang Lin } 145ba0501acSDingqiang Lin 146*6281205aSDingqiang Lin /* 147*6281205aSDingqiang Lin * ecc default: 148*6281205aSDingqiang Lin * 0, No bit errors were detected 149*6281205aSDingqiang Lin * 1, Bit errors were detected and corrected. 150*6281205aSDingqiang Lin * 2, Multiple bit errors were detected and not corrected. 151*6281205aSDingqiang Lin * 3, Bits errors were detected and corrected, bit error count 152*6281205aSDingqiang Lin * exceed the bit flip detection threshold 153*6281205aSDingqiang Lin */ 154*6281205aSDingqiang Lin static u32 sfc_nand_ecc_status(void) 155*6281205aSDingqiang Lin { 156*6281205aSDingqiang Lin int ret; 157*6281205aSDingqiang Lin u32 i; 158*6281205aSDingqiang Lin u8 ecc; 159*6281205aSDingqiang Lin u8 status; 160*6281205aSDingqiang Lin u32 timeout = 1000 * 1000; 161*6281205aSDingqiang Lin 162*6281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 163*6281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 164*6281205aSDingqiang Lin if (ret != SFC_OK) 165*6281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 166*6281205aSDingqiang Lin if (!(status & (1 << 0))) 167*6281205aSDingqiang Lin break; 168*6281205aSDingqiang Lin sfc_delay(1); 169*6281205aSDingqiang Lin } 170*6281205aSDingqiang Lin 171*6281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 172*6281205aSDingqiang Lin 173*6281205aSDingqiang Lin if (ecc <= 1) 174*6281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 175*6281205aSDingqiang Lin else if (ecc == 2) 176*6281205aSDingqiang Lin ret = SFC_NAND_ECC_ERROR; 177*6281205aSDingqiang Lin else 178*6281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 179*6281205aSDingqiang Lin 180*6281205aSDingqiang Lin return ret; 181*6281205aSDingqiang Lin } 182*6281205aSDingqiang Lin 183*6281205aSDingqiang Lin /* 184*6281205aSDingqiang Lin * ecc spectial type1: 185*6281205aSDingqiang Lin * 0x00, No bit errors were detected; 186*6281205aSDingqiang Lin * 0x01, Bits errors were detected and corrected, bit error count 187*6281205aSDingqiang Lin * may reach the bit flip detection threshold; 188*6281205aSDingqiang Lin * 0x10, Multiple bit errors were detected and not corrected; 189*6281205aSDingqiang Lin * 0x11, Reserved. 190*6281205aSDingqiang Lin */ 191*6281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp1(void) 192*6281205aSDingqiang Lin { 193*6281205aSDingqiang Lin int ret; 194*6281205aSDingqiang Lin u32 i; 195*6281205aSDingqiang Lin u8 ecc; 196*6281205aSDingqiang Lin u8 status; 197*6281205aSDingqiang Lin u32 timeout = 1000 * 1000; 198*6281205aSDingqiang Lin 199*6281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 200*6281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 201*6281205aSDingqiang Lin if (ret != SFC_OK) 202*6281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 203*6281205aSDingqiang Lin if (!(status & (1 << 0))) 204*6281205aSDingqiang Lin break; 205*6281205aSDingqiang Lin sfc_delay(1); 206*6281205aSDingqiang Lin } 207*6281205aSDingqiang Lin 208*6281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 209*6281205aSDingqiang Lin 210*6281205aSDingqiang Lin if (ecc == 0) 211*6281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 212*6281205aSDingqiang Lin else if (ecc == 1) 213*6281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 214*6281205aSDingqiang Lin else 215*6281205aSDingqiang Lin ret = SFC_NAND_ECC_ERROR; 216*6281205aSDingqiang Lin 217*6281205aSDingqiang Lin return ret; 218*6281205aSDingqiang Lin } 219*6281205aSDingqiang Lin 220*6281205aSDingqiang Lin /* 221*6281205aSDingqiang Lin * ecc spectial type3: 222*6281205aSDingqiang Lin * [0x0000, 0x0011], No bit errors were detected; 223*6281205aSDingqiang Lin * [0x0100, 0x0111], Bit errors were detected and corrected. Not 224*6281205aSDingqiang Lin * reach Flipping Bits; 225*6281205aSDingqiang Lin * [0x1000, 0x1011], Multiple bit errors were detected and 226*6281205aSDingqiang Lin * not corrected. 227*6281205aSDingqiang Lin * [0x1100, 0x1111], Bit error count equals the bit flip 228*6281205aSDingqiang Lin * detectionthreshold 229*6281205aSDingqiang Lin */ 230*6281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp3(void) 231*6281205aSDingqiang Lin { 232*6281205aSDingqiang Lin int ret; 233*6281205aSDingqiang Lin u32 i; 234*6281205aSDingqiang Lin u8 ecc; 235*6281205aSDingqiang Lin u8 status, status1; 236*6281205aSDingqiang Lin u32 timeout = 1000 * 1000; 237*6281205aSDingqiang Lin 238*6281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 239*6281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 240*6281205aSDingqiang Lin if (ret != SFC_OK) 241*6281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 242*6281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 243*6281205aSDingqiang Lin if (ret != SFC_OK) 244*6281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 245*6281205aSDingqiang Lin if (!(status & (1 << 0))) 246*6281205aSDingqiang Lin break; 247*6281205aSDingqiang Lin sfc_delay(1); 248*6281205aSDingqiang Lin } 249*6281205aSDingqiang Lin 250*6281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 251*6281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 252*6281205aSDingqiang Lin if (ecc < 7) 253*6281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 254*6281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 255*6281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 256*6281205aSDingqiang Lin else 257*6281205aSDingqiang Lin ret = SFC_NAND_ECC_ERROR; 258*6281205aSDingqiang Lin 259*6281205aSDingqiang Lin return ret; 260*6281205aSDingqiang Lin } 261*6281205aSDingqiang Lin 262ba0501acSDingqiang Lin static u32 sfc_nand_erase_block(u8 cs, u32 addr) 263ba0501acSDingqiang Lin { 264ba0501acSDingqiang Lin int ret; 265ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 266ba0501acSDingqiang Lin u8 status; 267ba0501acSDingqiang Lin 268ba0501acSDingqiang Lin sfcmd.d32 = 0; 269ba0501acSDingqiang Lin sfcmd.b.cmd = p_nand_info->block_erase_cmd; 270ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 271ba0501acSDingqiang Lin sfc_nand_write_en(); 272ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0, addr, NULL); 273ba0501acSDingqiang Lin if (ret != SFC_OK) 274ba0501acSDingqiang Lin return ret; 275ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 276ba0501acSDingqiang Lin if (status & (1 << 2)) 277ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 278ba0501acSDingqiang Lin return ret; 279ba0501acSDingqiang Lin } 280ba0501acSDingqiang Lin 281ba0501acSDingqiang Lin static u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 282ba0501acSDingqiang Lin { 283ba0501acSDingqiang Lin int ret; 284ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 285ba0501acSDingqiang Lin union SFCCTRL_DATA sfctrl; 286ba0501acSDingqiang Lin u8 status; 287ba0501acSDingqiang Lin u32 data_sz = 2048; 288ba0501acSDingqiang Lin u32 spare_offs_1 = p_nand_info->spare_offs_1; 289ba0501acSDingqiang Lin u32 spare_offs_2 = p_nand_info->spare_offs_2; 290ba0501acSDingqiang Lin 291ba0501acSDingqiang Lin memcpy(gp_page_buf, p_data, data_sz); 292ba0501acSDingqiang Lin gp_page_buf[(data_sz + spare_offs_1) / 4] = p_spare[0]; 293ba0501acSDingqiang Lin gp_page_buf[(data_sz + spare_offs_2) / 4] = p_spare[1]; 294ba0501acSDingqiang Lin 295ba0501acSDingqiang Lin sfc_nand_write_en(); 296ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 297ba0501acSDingqiang Lin p_nand_info->QE_address == 0xFF && 298ba0501acSDingqiang Lin sfc_get_version() != SFC_VER_3) 299ba0501acSDingqiang Lin sfc_nand_rw_preset(); 300ba0501acSDingqiang Lin 301ba0501acSDingqiang Lin sfcmd.d32 = 0; 302ba0501acSDingqiang Lin sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 303ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 304ba0501acSDingqiang Lin sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE; 305ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 306ba0501acSDingqiang Lin 307ba0501acSDingqiang Lin sfctrl.d32 = 0; 308ba0501acSDingqiang Lin sfctrl.b.datalines = sfc_nand_dev.prog_lines; 309ba0501acSDingqiang Lin sfctrl.b.addrbits = 16; 310ba0501acSDingqiang Lin sfc_request(sfcmd.d32, sfctrl.d32, 0, gp_page_buf); 311ba0501acSDingqiang Lin 312ba0501acSDingqiang Lin sfcmd.d32 = 0; 313ba0501acSDingqiang Lin sfcmd.b.cmd = p_nand_info->page_prog_cmd; 314ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 315ba0501acSDingqiang Lin sfcmd.b.datasize = 0; 316ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 317ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0, addr, p_data); 318ba0501acSDingqiang Lin if (ret != SFC_OK) 319ba0501acSDingqiang Lin return ret; 320ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 321ba0501acSDingqiang Lin if (status & (1 << 3)) 322ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 323ba0501acSDingqiang Lin return ret; 324ba0501acSDingqiang Lin } 325ba0501acSDingqiang Lin 326ba0501acSDingqiang Lin static u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 327ba0501acSDingqiang Lin { 328ba0501acSDingqiang Lin int ret; 329ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 330ba0501acSDingqiang Lin union SFCCTRL_DATA sfctrl; 331*6281205aSDingqiang Lin u32 ecc_result; 332ba0501acSDingqiang Lin u32 data_sz = 2048; 333ba0501acSDingqiang Lin u32 spare_offs_1 = p_nand_info->spare_offs_1; 334ba0501acSDingqiang Lin u32 spare_offs_2 = p_nand_info->spare_offs_2; 335ba0501acSDingqiang Lin 336ba0501acSDingqiang Lin sfcmd.d32 = 0; 337ba0501acSDingqiang Lin sfcmd.b.cmd = p_nand_info->page_read_cmd; 338ba0501acSDingqiang Lin sfcmd.b.datasize = 0; 339ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 340ba0501acSDingqiang Lin sfc_request(sfcmd.d32, 0, addr, p_data); 341ba0501acSDingqiang Lin 342*6281205aSDingqiang Lin if (p_nand_info->ecc_status) 343*6281205aSDingqiang Lin ecc_result = p_nand_info->ecc_status(); 344*6281205aSDingqiang Lin else 345*6281205aSDingqiang Lin ecc_result = sfc_nand_ecc_status(); 346*6281205aSDingqiang Lin 347ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 348ba0501acSDingqiang Lin p_nand_info->QE_address == 0xFF && 349ba0501acSDingqiang Lin sfc_get_version() != SFC_VER_3) 350ba0501acSDingqiang Lin sfc_nand_rw_preset(); 351ba0501acSDingqiang Lin 352ba0501acSDingqiang Lin sfcmd.d32 = 0; 353ba0501acSDingqiang Lin sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 354ba0501acSDingqiang Lin sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE; 355ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 356ba0501acSDingqiang Lin sfctrl.d32 = 0; 357ba0501acSDingqiang Lin sfctrl.b.datalines = sfc_nand_dev.read_lines; 358ba0501acSDingqiang Lin 359ba0501acSDingqiang Lin memset(gp_page_buf, 0, SFC_NAND_PAGE_MAX_SIZE); 360ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, sfctrl.d32, 0, gp_page_buf); 361ba0501acSDingqiang Lin 362ba0501acSDingqiang Lin memcpy(p_data, gp_page_buf, data_sz); 363ba0501acSDingqiang Lin p_spare[0] = gp_page_buf[(data_sz + spare_offs_1) / 4]; 364ba0501acSDingqiang Lin p_spare[1] = gp_page_buf[(data_sz + spare_offs_2) / 4]; 365ba0501acSDingqiang Lin if (ret != SFC_OK) 366ba0501acSDingqiang Lin return SFC_NAND_ECC_ERROR; 367ba0501acSDingqiang Lin 368*6281205aSDingqiang Lin if (ecc_result != SFC_NAND_ECC_OK) { 369*6281205aSDingqiang Lin PRINT_SFC_E("%s[0x%x], ret=0x%x\n", __func__, addr, ecc_result); 370ba0501acSDingqiang Lin if (p_data) 371ba0501acSDingqiang Lin PRINT_SFC_HEX("data:", p_data, 4, 8); 372ba0501acSDingqiang Lin if (p_spare) 373ba0501acSDingqiang Lin PRINT_SFC_HEX("spare:", p_spare, 4, 2); 374ba0501acSDingqiang Lin } 375*6281205aSDingqiang Lin return ecc_result; 376ba0501acSDingqiang Lin } 377ba0501acSDingqiang Lin 378ba0501acSDingqiang Lin static int sfc_nand_read_id_raw(u8 *data) 379ba0501acSDingqiang Lin { 380ba0501acSDingqiang Lin int ret; 381ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 382ba0501acSDingqiang Lin 383ba0501acSDingqiang Lin sfcmd.d32 = 0; 384ba0501acSDingqiang Lin sfcmd.b.cmd = CMD_READ_JEDECID; 385ba0501acSDingqiang Lin sfcmd.b.datasize = 3; 386ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 387ba0501acSDingqiang Lin 388ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0x8 << 16, 0, data); 389ba0501acSDingqiang Lin 390ba0501acSDingqiang Lin return ret; 391ba0501acSDingqiang Lin } 392ba0501acSDingqiang Lin 393ba0501acSDingqiang Lin /* 394ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 395ba0501acSDingqiang Lin * If not FF, it's bad blk 396ba0501acSDingqiang Lin */ 397ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 398ba0501acSDingqiang Lin { 399ba0501acSDingqiang Lin u16 blk; 400ba0501acSDingqiang Lin u32 bad_cnt, page; 401ba0501acSDingqiang Lin u32 blk_per_die; 402ba0501acSDingqiang Lin u32 *pread; 403ba0501acSDingqiang Lin u32 *pspare_read; 404ba0501acSDingqiang Lin 405ba0501acSDingqiang Lin PRINT_SFC_E("%s\n", __func__); 406ba0501acSDingqiang Lin pread = ftl_malloc(2048); 407ba0501acSDingqiang Lin pspare_read = ftl_malloc(8); 408ba0501acSDingqiang Lin bad_cnt = 0; 409ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 410ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 411ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 412ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 413ba0501acSDingqiang Lin p_nand_info->page_per_blk; 414ba0501acSDingqiang Lin sfc_nand_read_page(0, page, pread, pspare_read); 415ba0501acSDingqiang Lin 416ba0501acSDingqiang Lin if (pread[0] != 0xFFFFFFFF || 417ba0501acSDingqiang Lin pspare_read[0] != 0xFFFFFFFF) { 418ba0501acSDingqiang Lin table[bad_cnt++] = blk; 419ba0501acSDingqiang Lin PRINT_SFC_E("die[%d], bad_blk[%d]\n", die, blk); 420ba0501acSDingqiang Lin } 421ba0501acSDingqiang Lin } 422ba0501acSDingqiang Lin ftl_free(pread); 423ba0501acSDingqiang Lin ftl_free(pspare_read); 424ba0501acSDingqiang Lin return (int)bad_cnt; 425ba0501acSDingqiang Lin } 426ba0501acSDingqiang Lin 427ba0501acSDingqiang Lin #if SFC_NAND_STRESS_TEST_EN 428ba0501acSDingqiang Lin 429ba0501acSDingqiang Lin #define SFC_NAND_PAGE_SIZE 2048 430ba0501acSDingqiang Lin #define SFC_NAND_SPARE_SIZE 8 431ba0501acSDingqiang Lin 432ba0501acSDingqiang Lin static u16 bad_blk_list[1024]; 433ba0501acSDingqiang Lin static u32 pwrite[SFC_NAND_PAGE_SIZE / 4]; 434ba0501acSDingqiang Lin static u32 pread[SFC_NAND_PAGE_SIZE / 4]; 435ba0501acSDingqiang Lin static u32 pspare_write[SFC_NAND_SPARE_SIZE / 4]; 436ba0501acSDingqiang Lin static u32 pspare_read[SFC_NAND_SPARE_SIZE / 4]; 437ba0501acSDingqiang Lin static u32 bad_blk_num; 438ba0501acSDingqiang Lin static u32 bad_page_num; 439ba0501acSDingqiang Lin 440ba0501acSDingqiang Lin static void sfc_nand_test(void) 441ba0501acSDingqiang Lin { 442ba0501acSDingqiang Lin u32 i, blk, page, bad_cnt, page_addr; 443ba0501acSDingqiang Lin int ret; 444ba0501acSDingqiang Lin u32 pages_num = 64; 445ba0501acSDingqiang Lin u32 blk_addr = 64; 446ba0501acSDingqiang Lin u32 is_bad_blk = 0; 447ba0501acSDingqiang Lin 448ba0501acSDingqiang Lin PRINT_SFC_E("%s\n", __func__); 449ba0501acSDingqiang Lin 450ba0501acSDingqiang Lin bad_blk_num = 0; 451ba0501acSDingqiang Lin bad_page_num = 0; 452ba0501acSDingqiang Lin bad_cnt = sfc_nand_get_bad_block_list(bad_blk_list, 0); 453ba0501acSDingqiang Lin 454ba0501acSDingqiang Lin for (blk = 0; blk < 1024; blk++) { 455ba0501acSDingqiang Lin for (i = 0; i < bad_cnt; i++) { 456ba0501acSDingqiang Lin if (bad_blk_list[i] == blk) 457ba0501acSDingqiang Lin break; 458ba0501acSDingqiang Lin } 459ba0501acSDingqiang Lin if (i < bad_cnt) 460ba0501acSDingqiang Lin continue; 461ba0501acSDingqiang Lin is_bad_blk = 0; 462ba0501acSDingqiang Lin PRINT_SFC_E("Flash prog block: %x\n", blk); 463ba0501acSDingqiang Lin sfc_nand_erase_block(0, blk * blk_addr); 464ba0501acSDingqiang Lin for (page = 0; page < pages_num; page++) { 465ba0501acSDingqiang Lin page_addr = blk * blk_addr + page; 466ba0501acSDingqiang Lin for (i = 0; i < 512; i++) 467ba0501acSDingqiang Lin pwrite[i] = (page_addr << 16) + i; 468ba0501acSDingqiang Lin pspare_write[0] = pwrite[0] + 0x5AF0; 469ba0501acSDingqiang Lin pspare_write[1] = pspare_write[0] + 1; 470ba0501acSDingqiang Lin sfc_nand_prog_page(0, page_addr, pwrite, pspare_write); 471ba0501acSDingqiang Lin memset(pread, 0, 2048); 472ba0501acSDingqiang Lin memset(pspare_read, 0, 8); 473ba0501acSDingqiang Lin ret = sfc_nand_read_page(0, page_addr, pread, 474ba0501acSDingqiang Lin pspare_read); 475ba0501acSDingqiang Lin if (ret != SFC_NAND_ECC_OK) 476ba0501acSDingqiang Lin is_bad_blk = 1; 477ba0501acSDingqiang Lin for (i = 0; i < 512; i++) { 478ba0501acSDingqiang Lin if (pwrite[i] != pread[i]) { 479ba0501acSDingqiang Lin is_bad_blk = 1; 480ba0501acSDingqiang Lin break; 481ba0501acSDingqiang Lin } 482ba0501acSDingqiang Lin } 483ba0501acSDingqiang Lin for (i = 0; i < 2; i++) { 484ba0501acSDingqiang Lin if (pspare_write[i] != pspare_read[i]) { 485ba0501acSDingqiang Lin is_bad_blk = 1; 486ba0501acSDingqiang Lin break; 487ba0501acSDingqiang Lin } 488ba0501acSDingqiang Lin } 489ba0501acSDingqiang Lin if (is_bad_blk) { 490ba0501acSDingqiang Lin bad_page_num++; 491ba0501acSDingqiang Lin PRINT_SFC_E("ERR:page%x, ret=%x\n", 492ba0501acSDingqiang Lin page_addr, ret); 493ba0501acSDingqiang Lin PRINT_SFC_HEX("data:", pread, 4, 8); 494ba0501acSDingqiang Lin PRINT_SFC_HEX("spare:", pspare_read, 4, 2); 495ba0501acSDingqiang Lin } 496ba0501acSDingqiang Lin } 497ba0501acSDingqiang Lin sfc_nand_erase_block(0, blk * blk_addr); 498ba0501acSDingqiang Lin if (is_bad_blk) 499ba0501acSDingqiang Lin bad_blk_num++; 500ba0501acSDingqiang Lin } 501ba0501acSDingqiang Lin PRINT_SFC_E("bad_blk_num = %d, bad_page_num = %d\n", 502ba0501acSDingqiang Lin bad_blk_num, bad_page_num); 503ba0501acSDingqiang Lin 504ba0501acSDingqiang Lin PRINT_SFC_E("Flash Test Finish!!!\n"); 505ba0501acSDingqiang Lin while (1) 506ba0501acSDingqiang Lin ; 507ba0501acSDingqiang Lin } 508ba0501acSDingqiang Lin #endif 509ba0501acSDingqiang Lin 510ba0501acSDingqiang Lin static void ftl_flash_init(void) 511ba0501acSDingqiang Lin { 512ba0501acSDingqiang Lin /* para init */ 513ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 514ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 515ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 516ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 517ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 518ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 519ba0501acSDingqiang Lin g_nand_phy_info.byte_per_sec = 512; 520ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 521ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 522ba0501acSDingqiang Lin p_nand_info->page_per_blk; 523ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 524ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 525ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 526ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 527ba0501acSDingqiang Lin 528ba0501acSDingqiang Lin /* driver register */ 529ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 530ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 531ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 532ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 533ba0501acSDingqiang Lin } 534ba0501acSDingqiang Lin 535ba0501acSDingqiang Lin static int spi_nand_enable_QE(void) 536ba0501acSDingqiang Lin { 537ba0501acSDingqiang Lin int ret = SFC_OK; 538ba0501acSDingqiang Lin u8 status; 539ba0501acSDingqiang Lin int bit_offset = p_nand_info->QE_bits; 540ba0501acSDingqiang Lin 541ba0501acSDingqiang Lin if (bit_offset == 0xFF) 542ba0501acSDingqiang Lin return SFC_OK; 543ba0501acSDingqiang Lin 544ba0501acSDingqiang Lin ret = sfc_nand_read_feature(p_nand_info->QE_address, &status); 545ba0501acSDingqiang Lin if (ret != SFC_OK) 546ba0501acSDingqiang Lin return ret; 547ba0501acSDingqiang Lin 548ba0501acSDingqiang Lin if (status & (1 << bit_offset)) /* is QE bit set */ 549ba0501acSDingqiang Lin return SFC_OK; 550ba0501acSDingqiang Lin 551ba0501acSDingqiang Lin status |= (1 << bit_offset); 552ba0501acSDingqiang Lin return sfc_nand_write_feature(p_nand_info->QE_address, status); 553ba0501acSDingqiang Lin 554ba0501acSDingqiang Lin return ret; 555ba0501acSDingqiang Lin } 556ba0501acSDingqiang Lin 557ba0501acSDingqiang Lin u32 sfc_nand_init(void) 558ba0501acSDingqiang Lin { 559ba0501acSDingqiang Lin PRINT_SFC_I("...%s enter...\n", __func__); 560ba0501acSDingqiang Lin 561ba0501acSDingqiang Lin sfc_nand_read_id_raw(id_byte); 562ba0501acSDingqiang Lin PRINT_SFC_E("sfc_nand id: %x %x %x\n", 563ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 564ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 565ba0501acSDingqiang Lin return FTL_NO_FLASH; 566ba0501acSDingqiang Lin 567ba0501acSDingqiang Lin p_nand_info = spi_nand_get_info(id_byte); 568ba0501acSDingqiang Lin if (!p_nand_info) 569ba0501acSDingqiang Lin return FTL_UNSUPPORTED_FLASH; 570ba0501acSDingqiang Lin 571ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 572ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 573ba0501acSDingqiang Lin 574ba0501acSDingqiang Lin /* disable block lock */ 575ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 576ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 577ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 578ba0501acSDingqiang Lin sfc_nand_dev.page_read_cmd = p_nand_info->read_cache_cmd_1; 579ba0501acSDingqiang Lin sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_1; 580ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 581ba0501acSDingqiang Lin if (spi_nand_enable_QE() == SFC_OK) { 582ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 583ba0501acSDingqiang Lin sfc_nand_dev.page_read_cmd = 584ba0501acSDingqiang Lin p_nand_info->read_cache_cmd_4; 585ba0501acSDingqiang Lin } 586ba0501acSDingqiang Lin } 587ba0501acSDingqiang Lin 588ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 589ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 590ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 591ba0501acSDingqiang Lin sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_4; 592ba0501acSDingqiang Lin } 593ba0501acSDingqiang Lin 594ba0501acSDingqiang Lin if (1) { 595ba0501acSDingqiang Lin u8 status; 596ba0501acSDingqiang Lin 597ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 598ba0501acSDingqiang Lin PRINT_SFC_I("sfc_nand A0 = 0x%x\n", status); 599ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 600ba0501acSDingqiang Lin PRINT_SFC_I("sfc_nand B0 = 0x%x\n", status); 601ba0501acSDingqiang Lin sfc_nand_read_feature(0xC0, &status); 602ba0501acSDingqiang Lin PRINT_SFC_I("sfc_nand C0 = 0x%x\n", status); 603ba0501acSDingqiang Lin PRINT_SFC_I("read_lines = %x\n", sfc_nand_dev.read_lines); 604ba0501acSDingqiang Lin PRINT_SFC_I("prog_lines = %x\n", sfc_nand_dev.prog_lines); 605ba0501acSDingqiang Lin PRINT_SFC_I("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 606ba0501acSDingqiang Lin PRINT_SFC_I("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 607ba0501acSDingqiang Lin } 608ba0501acSDingqiang Lin ftl_flash_init(); 609ba0501acSDingqiang Lin 610ba0501acSDingqiang Lin #if SFC_NAND_STRESS_TEST_EN 611ba0501acSDingqiang Lin sfc_nand_test(); 612ba0501acSDingqiang Lin #endif 613ba0501acSDingqiang Lin 614ba0501acSDingqiang Lin return SFC_OK; 615ba0501acSDingqiang Lin } 616ba0501acSDingqiang Lin 617ba0501acSDingqiang Lin int sfc_nand_read_id(u8 *data) 618ba0501acSDingqiang Lin { 619ba0501acSDingqiang Lin memcpy(data, id_byte, 3); 620ba0501acSDingqiang Lin return 0; 621ba0501acSDingqiang Lin } 622