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_com.h" 12cd67f373SDingqiang Lin #include "rkflash_debug.h" 13cd67f373SDingqiang Lin #include "rk_sftl.h" 14ba0501acSDingqiang Lin #include "sfc.h" 15ba0501acSDingqiang Lin #include "sfc_nand.h" 16ba0501acSDingqiang Lin 17ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 18ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 19*415cf080Sjon.lin {0x98C2, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 18, 8, 0xFF, 0xFF, 4, 8, NULL}, 20ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 21*415cf080Sjon.lin {0x98CB, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 19, 8, 0xFF, 0xFF, 4, 8, NULL}, 22ba0501acSDingqiang Lin /* MX35LF1GE4AB */ 236281205aSDingqiang 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 */ 256281205aSDingqiang 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 */ 276281205aSDingqiang Lin {0xC8F1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0, 4, 8, NULL}, 28ba0501acSDingqiang Lin /* MT29F1G01ZAC */ 296281205aSDingqiang 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}, 306281205aSDingqiang Lin /* GD5F2GQ40BY2GR */ 316281205aSDingqiang 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 */ 336281205aSDingqiang 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*415cf080Sjon.lin {0xC821, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x00, 18, 1, 0xFF, 0xFF, 8, 12, &sfc_nand_ecc_status_sp1}, 36ba0501acSDingqiang Lin /* W25N01GV */ 37*415cf080Sjon.lin {0xEFAA, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 1, 0xFF, 0xFF, 4, 20, &sfc_nand_ecc_status_sp1}, 3840425644SDingqiang Lin /* HYF2GQ4UAACAE */ 3925098c06SDingqiang Lin {0xC952, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 14, 0xB0, 0, 4, 36, NULL}, 406281205aSDingqiang Lin /* HYF2GQ4UDACAE */ 4125098c06SDingqiang Lin {0xC922, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 4, 0xB0, 0, 4, 20, NULL}, 4240425644SDingqiang Lin /* HYF2GQ4UHCCAE */ 4325098c06SDingqiang Lin {0xC95A, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 14, 0xB0, 0, 4, 36, NULL}, 446281205aSDingqiang Lin /* HYF1GQ4UDACAE */ 4525098c06SDingqiang Lin {0xC921, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 4, 0xB0, 0, 4, 20, NULL}, 4640425644SDingqiang Lin /* F50L1G41LB */ 47*415cf080Sjon.lin {0xC801, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 1, 0xFF, 0xFF, 20, 36, &sfc_nand_ecc_status_sp1}, 4840425644SDingqiang Lin /* XT26G02A */ 49*415cf080Sjon.lin {0x0BE2, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 1, 0xB0, 0x0, 8, 12, &sfc_nand_ecc_status_sp4}, 5040425644SDingqiang Lin /* XT26G01A */ 51*415cf080Sjon.lin {0x0BE1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 1, 0xB0, 0x0, 8, 12, &sfc_nand_ecc_status_sp4}, 5225098c06SDingqiang Lin /* FS35ND01G-S1 */ 5325098c06SDingqiang Lin {0xCDB1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0x0, 16, 20, &sfc_nand_ecc_status_sp5}, 5425098c06SDingqiang Lin /* FS35ND02G-S2 */ 5525098c06SDingqiang Lin {0xCDA2, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x03, 0x02, 0xD8, 0x00, 19, 4, 0xFF, 0xFF, 16, 20, &sfc_nand_ecc_status_sp5}, 56*415cf080Sjon.lin /* DS35Q1GA-1B */ 57*415cf080Sjon.lin {0xE571, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0x0, 4, 20, &sfc_nand_ecc_status_sp1}, 58*415cf080Sjon.lin /* DS35Q2GA-1B */ 59*415cf080Sjon.lin {0xE572, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 4, 0xB0, 0x0, 4, 20, &sfc_nand_ecc_status_sp1}, 60*415cf080Sjon.lin /* EM73C044SNC-G */ 61*415cf080Sjon.lin {0xD522, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0x0, 4, 20, NULL}, 62*415cf080Sjon.lin /* EM73D044SNB-G */ 63*415cf080Sjon.lin {0xD520, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 8, 0xB0, 0x0, 4, 20, NULL} 64ba0501acSDingqiang Lin }; 65ba0501acSDingqiang Lin 66ba0501acSDingqiang Lin static u8 id_byte[8]; 67ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 68ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 69ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 70ba0501acSDingqiang Lin 71ba0501acSDingqiang Lin static struct nand_info *spi_nand_get_info(u8 *nand_id) 72ba0501acSDingqiang Lin { 73ba0501acSDingqiang Lin u32 i; 74ba0501acSDingqiang Lin u32 id = (nand_id[0] << 8) | (nand_id[1] << 0); 75ba0501acSDingqiang Lin 76ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 77ba0501acSDingqiang Lin if (spi_nand_tbl[i].id == id) 78ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 79ba0501acSDingqiang Lin } 80ba0501acSDingqiang Lin return NULL; 81ba0501acSDingqiang Lin } 82ba0501acSDingqiang Lin 83ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 84ba0501acSDingqiang Lin { 85ba0501acSDingqiang Lin int ret; 86ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 87ba0501acSDingqiang Lin 88ba0501acSDingqiang Lin sfcmd.d32 = 0; 89ba0501acSDingqiang Lin sfcmd.b.cmd = CMD_WRITE_EN; 90ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0, 0, NULL); 91ba0501acSDingqiang Lin return ret; 92ba0501acSDingqiang Lin } 93ba0501acSDingqiang Lin 94ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 95ba0501acSDingqiang Lin { 96ba0501acSDingqiang Lin int ret; 97ba0501acSDingqiang Lin union SFCCTRL_DATA sfctrl; 98ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 99ba0501acSDingqiang Lin u8 status = 0xFF; 100ba0501acSDingqiang Lin 101ba0501acSDingqiang Lin sfcmd.d32 = 0; 102ba0501acSDingqiang Lin sfcmd.b.cmd = 0; 103ba0501acSDingqiang Lin sfcmd.b.datasize = 1; 104ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 105ba0501acSDingqiang Lin 106ba0501acSDingqiang Lin sfctrl.b.datalines = 2; 107ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, sfctrl.d32, 0, &status); 108ba0501acSDingqiang Lin return ret; 109ba0501acSDingqiang Lin } 110ba0501acSDingqiang Lin 111ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 112ba0501acSDingqiang Lin { 113ba0501acSDingqiang Lin int ret; 114ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 115ba0501acSDingqiang Lin 116ba0501acSDingqiang Lin sfcmd.d32 = 0; 117ba0501acSDingqiang Lin sfcmd.b.cmd = 0x0F; 118ba0501acSDingqiang Lin sfcmd.b.datasize = 1; 119ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 120ba0501acSDingqiang Lin *data = 0; 121ba0501acSDingqiang Lin 122ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, data); 123ba0501acSDingqiang Lin if (ret != SFC_OK) 124ba0501acSDingqiang Lin return ret; 125ba0501acSDingqiang Lin return SFC_OK; 126ba0501acSDingqiang Lin } 127ba0501acSDingqiang Lin 128ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 129ba0501acSDingqiang Lin { 130ba0501acSDingqiang Lin int ret; 131ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 132ba0501acSDingqiang Lin 133ba0501acSDingqiang Lin sfc_nand_write_en(); 134ba0501acSDingqiang Lin 135ba0501acSDingqiang Lin sfcmd.d32 = 0; 136ba0501acSDingqiang Lin sfcmd.b.cmd = 0x1F; 137ba0501acSDingqiang Lin sfcmd.b.datasize = 1; 138ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 139ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 140ba0501acSDingqiang Lin 141ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, &status); 142ba0501acSDingqiang Lin if (ret != SFC_OK) 143ba0501acSDingqiang Lin return ret; 144ba0501acSDingqiang Lin return ret; 145ba0501acSDingqiang Lin } 146ba0501acSDingqiang Lin 147ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 148ba0501acSDingqiang Lin { 149ba0501acSDingqiang Lin int ret; 150ba0501acSDingqiang Lin int i; 151ba0501acSDingqiang Lin u8 status; 152ba0501acSDingqiang Lin 153ba0501acSDingqiang Lin *data = 0; 154ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 155ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 156ba0501acSDingqiang Lin if (ret != SFC_OK) 157ba0501acSDingqiang Lin return ret; 158ba0501acSDingqiang Lin *data = status; 159ba0501acSDingqiang Lin if (!(status & (1 << 0))) 160ba0501acSDingqiang Lin return SFC_OK; 161ba0501acSDingqiang Lin sfc_delay(1); 162ba0501acSDingqiang Lin } 163ba0501acSDingqiang Lin return -1; 164ba0501acSDingqiang Lin } 165ba0501acSDingqiang Lin 1666281205aSDingqiang Lin /* 1676281205aSDingqiang Lin * ecc default: 1686281205aSDingqiang Lin * 0, No bit errors were detected 1696281205aSDingqiang Lin * 1, Bit errors were detected and corrected. 1706281205aSDingqiang Lin * 2, Multiple bit errors were detected and not corrected. 1716281205aSDingqiang Lin * 3, Bits errors were detected and corrected, bit error count 1726281205aSDingqiang Lin * exceed the bit flip detection threshold 1736281205aSDingqiang Lin */ 1746281205aSDingqiang Lin static u32 sfc_nand_ecc_status(void) 1756281205aSDingqiang Lin { 1766281205aSDingqiang Lin int ret; 1776281205aSDingqiang Lin u32 i; 1786281205aSDingqiang Lin u8 ecc; 1796281205aSDingqiang Lin u8 status; 1806281205aSDingqiang Lin u32 timeout = 1000 * 1000; 1816281205aSDingqiang Lin 1826281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 1836281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 1846281205aSDingqiang Lin if (ret != SFC_OK) 1856281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 1866281205aSDingqiang Lin if (!(status & (1 << 0))) 1876281205aSDingqiang Lin break; 1886281205aSDingqiang Lin sfc_delay(1); 1896281205aSDingqiang Lin } 1906281205aSDingqiang Lin 1916281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 1926281205aSDingqiang Lin 1936281205aSDingqiang Lin if (ecc <= 1) 1946281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 1956281205aSDingqiang Lin else if (ecc == 2) 1966281205aSDingqiang Lin ret = SFC_NAND_ECC_ERROR; 1976281205aSDingqiang Lin else 1986281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 1996281205aSDingqiang Lin 2006281205aSDingqiang Lin return ret; 2016281205aSDingqiang Lin } 2026281205aSDingqiang Lin 2036281205aSDingqiang Lin /* 2046281205aSDingqiang Lin * ecc spectial type1: 2056281205aSDingqiang Lin * 0x00, No bit errors were detected; 2066281205aSDingqiang Lin * 0x01, Bits errors were detected and corrected, bit error count 2076281205aSDingqiang Lin * may reach the bit flip detection threshold; 2086281205aSDingqiang Lin * 0x10, Multiple bit errors were detected and not corrected; 2096281205aSDingqiang Lin * 0x11, Reserved. 2106281205aSDingqiang Lin */ 2116281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp1(void) 2126281205aSDingqiang Lin { 2136281205aSDingqiang Lin int ret; 2146281205aSDingqiang Lin u32 i; 2156281205aSDingqiang Lin u8 ecc; 2166281205aSDingqiang Lin u8 status; 2176281205aSDingqiang Lin u32 timeout = 1000 * 1000; 2186281205aSDingqiang Lin 2196281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 2206281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 2216281205aSDingqiang Lin if (ret != SFC_OK) 2226281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 2236281205aSDingqiang Lin if (!(status & (1 << 0))) 2246281205aSDingqiang Lin break; 2256281205aSDingqiang Lin sfc_delay(1); 2266281205aSDingqiang Lin } 2276281205aSDingqiang Lin 2286281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 2296281205aSDingqiang Lin 2306281205aSDingqiang Lin if (ecc == 0) 2316281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 2326281205aSDingqiang Lin else if (ecc == 1) 2336281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 2346281205aSDingqiang Lin else 2356281205aSDingqiang Lin ret = SFC_NAND_ECC_ERROR; 2366281205aSDingqiang Lin 2376281205aSDingqiang Lin return ret; 2386281205aSDingqiang Lin } 2396281205aSDingqiang Lin 2406281205aSDingqiang Lin /* 2416281205aSDingqiang Lin * ecc spectial type3: 2426281205aSDingqiang Lin * [0x0000, 0x0011], No bit errors were detected; 2436281205aSDingqiang Lin * [0x0100, 0x0111], Bit errors were detected and corrected. Not 2446281205aSDingqiang Lin * reach Flipping Bits; 2456281205aSDingqiang Lin * [0x1000, 0x1011], Multiple bit errors were detected and 2466281205aSDingqiang Lin * not corrected. 2476281205aSDingqiang Lin * [0x1100, 0x1111], Bit error count equals the bit flip 2486281205aSDingqiang Lin * detectionthreshold 2496281205aSDingqiang Lin */ 2506281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp3(void) 2516281205aSDingqiang Lin { 2526281205aSDingqiang Lin int ret; 2536281205aSDingqiang Lin u32 i; 2546281205aSDingqiang Lin u8 ecc; 2556281205aSDingqiang Lin u8 status, status1; 2566281205aSDingqiang Lin u32 timeout = 1000 * 1000; 2576281205aSDingqiang Lin 2586281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 2596281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 2606281205aSDingqiang Lin if (ret != SFC_OK) 2616281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 2626281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 2636281205aSDingqiang Lin if (ret != SFC_OK) 2646281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 2656281205aSDingqiang Lin if (!(status & (1 << 0))) 2666281205aSDingqiang Lin break; 2676281205aSDingqiang Lin sfc_delay(1); 2686281205aSDingqiang Lin } 2696281205aSDingqiang Lin 2706281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 2716281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 2726281205aSDingqiang Lin if (ecc < 7) 2736281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 2746281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 2756281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 2766281205aSDingqiang Lin else 2776281205aSDingqiang Lin ret = SFC_NAND_ECC_ERROR; 2786281205aSDingqiang Lin 2796281205aSDingqiang Lin return ret; 2806281205aSDingqiang Lin } 2816281205aSDingqiang Lin 28225098c06SDingqiang Lin /* 28325098c06SDingqiang Lin * ecc spectial type4: 28425098c06SDingqiang Lin * [0x0000], No bit errors were detected; 28525098c06SDingqiang Lin * [0x0001, 0x0111], Bit errors were detected and corrected. Not 28625098c06SDingqiang Lin * reach Flipping Bits; 28725098c06SDingqiang Lin * [0x1000], Multiple bit errors were detected and 28825098c06SDingqiang Lin * not corrected. 28925098c06SDingqiang Lin * [0x1100], Bit error count equals the bit flip 29025098c06SDingqiang Lin * detectionthreshold 29125098c06SDingqiang Lin * else, reserved 29225098c06SDingqiang Lin */ 29325098c06SDingqiang Lin u32 sfc_nand_ecc_status_sp4(void) 29425098c06SDingqiang Lin { 29525098c06SDingqiang Lin int ret; 29625098c06SDingqiang Lin u32 i; 29725098c06SDingqiang Lin u8 ecc; 29825098c06SDingqiang Lin u8 status; 29925098c06SDingqiang Lin u32 timeout = 1000 * 1000; 30025098c06SDingqiang Lin 30125098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 30225098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 30325098c06SDingqiang Lin if (ret != SFC_OK) 30425098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 30525098c06SDingqiang Lin if (!(status & (1 << 0))) 30625098c06SDingqiang Lin break; 30725098c06SDingqiang Lin sfc_delay(1); 30825098c06SDingqiang Lin } 30925098c06SDingqiang Lin 31025098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 31125098c06SDingqiang Lin if (ecc < 7) 31225098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 31325098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 31425098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 31525098c06SDingqiang Lin else 31625098c06SDingqiang Lin ret = SFC_NAND_ECC_ERROR; 31725098c06SDingqiang Lin 31825098c06SDingqiang Lin return ret; 31925098c06SDingqiang Lin } 32025098c06SDingqiang Lin 32125098c06SDingqiang Lin /* 32225098c06SDingqiang Lin * ecc spectial type5: 32325098c06SDingqiang Lin * [0x0], No bit errors were detected; 32425098c06SDingqiang Lin * [0x001, 0x011], Bit errors were detected and corrected. Not 32525098c06SDingqiang Lin * reach Flipping Bits; 32625098c06SDingqiang Lin * [0x100], Bit error count equals the bit flip 32725098c06SDingqiang Lin * detectionthreshold 32825098c06SDingqiang Lin * [0x101, 0x110], Reserved; 32925098c06SDingqiang Lin * [0x111], Multiple bit errors were detected and 33025098c06SDingqiang Lin * not corrected. 33125098c06SDingqiang Lin */ 33225098c06SDingqiang Lin u32 sfc_nand_ecc_status_sp5(void) 33325098c06SDingqiang Lin { 33425098c06SDingqiang Lin int ret; 33525098c06SDingqiang Lin u32 i; 33625098c06SDingqiang Lin u8 ecc; 33725098c06SDingqiang Lin u8 status; 33825098c06SDingqiang Lin u32 timeout = 1000 * 1000; 33925098c06SDingqiang Lin 34025098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 34125098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 34225098c06SDingqiang Lin if (ret != SFC_OK) 34325098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 34425098c06SDingqiang Lin if (!(status & (1 << 0))) 34525098c06SDingqiang Lin break; 34625098c06SDingqiang Lin sfc_delay(1); 34725098c06SDingqiang Lin } 34825098c06SDingqiang Lin 34925098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 35025098c06SDingqiang Lin if (ecc < 4) 35125098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 35225098c06SDingqiang Lin else if (ecc == 4) 35325098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 35425098c06SDingqiang Lin else 35525098c06SDingqiang Lin ret = SFC_NAND_ECC_ERROR; 35625098c06SDingqiang Lin 35725098c06SDingqiang Lin return ret; 35825098c06SDingqiang Lin } 35925098c06SDingqiang Lin 360ba0501acSDingqiang Lin static u32 sfc_nand_erase_block(u8 cs, u32 addr) 361ba0501acSDingqiang Lin { 362ba0501acSDingqiang Lin int ret; 363ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 364ba0501acSDingqiang Lin u8 status; 365ba0501acSDingqiang Lin 366ba0501acSDingqiang Lin sfcmd.d32 = 0; 367ba0501acSDingqiang Lin sfcmd.b.cmd = p_nand_info->block_erase_cmd; 368ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 369ba0501acSDingqiang Lin sfc_nand_write_en(); 370ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0, addr, NULL); 371ba0501acSDingqiang Lin if (ret != SFC_OK) 372ba0501acSDingqiang Lin return ret; 373ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 374ba0501acSDingqiang Lin if (status & (1 << 2)) 375ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 376ba0501acSDingqiang Lin return ret; 377ba0501acSDingqiang Lin } 378ba0501acSDingqiang Lin 379ba0501acSDingqiang Lin static u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 380ba0501acSDingqiang Lin { 381ba0501acSDingqiang Lin int ret; 382*415cf080Sjon.lin u32 plane; 383ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 384ba0501acSDingqiang Lin union SFCCTRL_DATA sfctrl; 385ba0501acSDingqiang Lin u8 status; 386ba0501acSDingqiang Lin u32 data_sz = 2048; 387ba0501acSDingqiang Lin u32 spare_offs_1 = p_nand_info->spare_offs_1; 388ba0501acSDingqiang Lin u32 spare_offs_2 = p_nand_info->spare_offs_2; 389ba0501acSDingqiang Lin 390ba0501acSDingqiang Lin memcpy(gp_page_buf, p_data, data_sz); 391*415cf080Sjon.lin ftl_memset(&gp_page_buf[data_sz / 4], 0xff, 64); 392ba0501acSDingqiang Lin gp_page_buf[(data_sz + spare_offs_1) / 4] = p_spare[0]; 393ba0501acSDingqiang Lin gp_page_buf[(data_sz + spare_offs_2) / 4] = p_spare[1]; 394ba0501acSDingqiang Lin 395ba0501acSDingqiang Lin sfc_nand_write_en(); 396ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 39725098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 39825098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 399ba0501acSDingqiang Lin sfc_nand_rw_preset(); 400ba0501acSDingqiang Lin 401ba0501acSDingqiang Lin sfcmd.d32 = 0; 402ba0501acSDingqiang Lin sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 403ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 404ba0501acSDingqiang Lin sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE; 405ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 406ba0501acSDingqiang Lin 407ba0501acSDingqiang Lin sfctrl.d32 = 0; 408ba0501acSDingqiang Lin sfctrl.b.datalines = sfc_nand_dev.prog_lines; 409ba0501acSDingqiang Lin sfctrl.b.addrbits = 16; 410*415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 411*415cf080Sjon.lin sfc_request(sfcmd.d32, sfctrl.d32, plane, gp_page_buf); 412ba0501acSDingqiang Lin 413ba0501acSDingqiang Lin sfcmd.d32 = 0; 414ba0501acSDingqiang Lin sfcmd.b.cmd = p_nand_info->page_prog_cmd; 415ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 416ba0501acSDingqiang Lin sfcmd.b.datasize = 0; 417ba0501acSDingqiang Lin sfcmd.b.rw = SFC_WRITE; 418ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0, addr, p_data); 419ba0501acSDingqiang Lin if (ret != SFC_OK) 420ba0501acSDingqiang Lin return ret; 421ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 422ba0501acSDingqiang Lin if (status & (1 << 3)) 423ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 424ba0501acSDingqiang Lin return ret; 425ba0501acSDingqiang Lin } 426ba0501acSDingqiang Lin 427ba0501acSDingqiang Lin static u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 428ba0501acSDingqiang Lin { 429ba0501acSDingqiang Lin int ret; 430*415cf080Sjon.lin u32 plane; 431ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 432ba0501acSDingqiang Lin union SFCCTRL_DATA sfctrl; 4336281205aSDingqiang Lin u32 ecc_result; 434ba0501acSDingqiang Lin u32 data_sz = 2048; 435ba0501acSDingqiang Lin u32 spare_offs_1 = p_nand_info->spare_offs_1; 436ba0501acSDingqiang Lin u32 spare_offs_2 = p_nand_info->spare_offs_2; 437ba0501acSDingqiang Lin 438ba0501acSDingqiang Lin sfcmd.d32 = 0; 439ba0501acSDingqiang Lin sfcmd.b.cmd = p_nand_info->page_read_cmd; 440ba0501acSDingqiang Lin sfcmd.b.datasize = 0; 441ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 442ba0501acSDingqiang Lin sfc_request(sfcmd.d32, 0, addr, p_data); 443ba0501acSDingqiang Lin 4446281205aSDingqiang Lin if (p_nand_info->ecc_status) 4456281205aSDingqiang Lin ecc_result = p_nand_info->ecc_status(); 4466281205aSDingqiang Lin else 4476281205aSDingqiang Lin ecc_result = sfc_nand_ecc_status(); 4486281205aSDingqiang Lin 449ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 45025098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 45125098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 452ba0501acSDingqiang Lin sfc_nand_rw_preset(); 453ba0501acSDingqiang Lin 454ba0501acSDingqiang Lin sfcmd.d32 = 0; 455ba0501acSDingqiang Lin sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 456ba0501acSDingqiang Lin sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE; 457ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_24BITS; 458ba0501acSDingqiang Lin sfctrl.d32 = 0; 459ba0501acSDingqiang Lin sfctrl.b.datalines = sfc_nand_dev.read_lines; 460ba0501acSDingqiang Lin 461*415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 462ba0501acSDingqiang Lin memset(gp_page_buf, 0, SFC_NAND_PAGE_MAX_SIZE); 463*415cf080Sjon.lin ret = sfc_request(sfcmd.d32, sfctrl.d32, plane << 8, gp_page_buf); 464ba0501acSDingqiang Lin 465ba0501acSDingqiang Lin memcpy(p_data, gp_page_buf, data_sz); 466ba0501acSDingqiang Lin p_spare[0] = gp_page_buf[(data_sz + spare_offs_1) / 4]; 467ba0501acSDingqiang Lin p_spare[1] = gp_page_buf[(data_sz + spare_offs_2) / 4]; 468ba0501acSDingqiang Lin if (ret != SFC_OK) 469ba0501acSDingqiang Lin return SFC_NAND_ECC_ERROR; 470ba0501acSDingqiang Lin 4716281205aSDingqiang Lin if (ecc_result != SFC_NAND_ECC_OK) { 4726281205aSDingqiang Lin PRINT_SFC_E("%s[0x%x], ret=0x%x\n", __func__, addr, ecc_result); 473ba0501acSDingqiang Lin if (p_data) 474ba0501acSDingqiang Lin PRINT_SFC_HEX("data:", p_data, 4, 8); 475ba0501acSDingqiang Lin if (p_spare) 476ba0501acSDingqiang Lin PRINT_SFC_HEX("spare:", p_spare, 4, 2); 477ba0501acSDingqiang Lin } 4786281205aSDingqiang Lin return ecc_result; 479ba0501acSDingqiang Lin } 480ba0501acSDingqiang Lin 481ba0501acSDingqiang Lin static int sfc_nand_read_id_raw(u8 *data) 482ba0501acSDingqiang Lin { 483ba0501acSDingqiang Lin int ret; 484ba0501acSDingqiang Lin union SFCCMD_DATA sfcmd; 485ba0501acSDingqiang Lin 486ba0501acSDingqiang Lin sfcmd.d32 = 0; 487ba0501acSDingqiang Lin sfcmd.b.cmd = CMD_READ_JEDECID; 488ba0501acSDingqiang Lin sfcmd.b.datasize = 3; 489ba0501acSDingqiang Lin sfcmd.b.addrbits = SFC_ADDR_XBITS; 490ba0501acSDingqiang Lin 491ba0501acSDingqiang Lin ret = sfc_request(sfcmd.d32, 0x8 << 16, 0, data); 492ba0501acSDingqiang Lin 493ba0501acSDingqiang Lin return ret; 494ba0501acSDingqiang Lin } 495ba0501acSDingqiang Lin 496ba0501acSDingqiang Lin /* 497ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 498ba0501acSDingqiang Lin * If not FF, it's bad blk 499ba0501acSDingqiang Lin */ 500ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 501ba0501acSDingqiang Lin { 502ba0501acSDingqiang Lin u16 blk; 503ba0501acSDingqiang Lin u32 bad_cnt, page; 504ba0501acSDingqiang Lin u32 blk_per_die; 505ba0501acSDingqiang Lin u32 *pread; 506ba0501acSDingqiang Lin u32 *pspare_read; 507ba0501acSDingqiang Lin 508ba0501acSDingqiang Lin PRINT_SFC_E("%s\n", __func__); 509ba0501acSDingqiang Lin pread = ftl_malloc(2048); 510ba0501acSDingqiang Lin pspare_read = ftl_malloc(8); 511ba0501acSDingqiang Lin bad_cnt = 0; 512ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 513ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 514ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 515ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 516ba0501acSDingqiang Lin p_nand_info->page_per_blk; 517ba0501acSDingqiang Lin sfc_nand_read_page(0, page, pread, pspare_read); 518ba0501acSDingqiang Lin 519ba0501acSDingqiang Lin if (pread[0] != 0xFFFFFFFF || 520ba0501acSDingqiang Lin pspare_read[0] != 0xFFFFFFFF) { 521ba0501acSDingqiang Lin table[bad_cnt++] = blk; 522ba0501acSDingqiang Lin PRINT_SFC_E("die[%d], bad_blk[%d]\n", die, blk); 523ba0501acSDingqiang Lin } 524ba0501acSDingqiang Lin } 525ba0501acSDingqiang Lin ftl_free(pread); 526ba0501acSDingqiang Lin ftl_free(pspare_read); 527ba0501acSDingqiang Lin return (int)bad_cnt; 528ba0501acSDingqiang Lin } 529ba0501acSDingqiang Lin 530ba0501acSDingqiang Lin #if SFC_NAND_STRESS_TEST_EN 531ba0501acSDingqiang Lin 532ba0501acSDingqiang Lin #define SFC_NAND_PAGE_SIZE 2048 533ba0501acSDingqiang Lin #define SFC_NAND_SPARE_SIZE 8 534ba0501acSDingqiang Lin 535ba0501acSDingqiang Lin static u16 bad_blk_list[1024]; 536ba0501acSDingqiang Lin static u32 pwrite[SFC_NAND_PAGE_SIZE / 4]; 537ba0501acSDingqiang Lin static u32 pread[SFC_NAND_PAGE_SIZE / 4]; 538ba0501acSDingqiang Lin static u32 pspare_write[SFC_NAND_SPARE_SIZE / 4]; 539ba0501acSDingqiang Lin static u32 pspare_read[SFC_NAND_SPARE_SIZE / 4]; 540ba0501acSDingqiang Lin static u32 bad_blk_num; 541ba0501acSDingqiang Lin static u32 bad_page_num; 542ba0501acSDingqiang Lin 543ba0501acSDingqiang Lin static void sfc_nand_test(void) 544ba0501acSDingqiang Lin { 545ba0501acSDingqiang Lin u32 i, blk, page, bad_cnt, page_addr; 546ba0501acSDingqiang Lin int ret; 547ba0501acSDingqiang Lin u32 pages_num = 64; 548ba0501acSDingqiang Lin u32 blk_addr = 64; 549ba0501acSDingqiang Lin u32 is_bad_blk = 0; 550ba0501acSDingqiang Lin 551ba0501acSDingqiang Lin PRINT_SFC_E("%s\n", __func__); 552ba0501acSDingqiang Lin 553ba0501acSDingqiang Lin bad_blk_num = 0; 554ba0501acSDingqiang Lin bad_page_num = 0; 555ba0501acSDingqiang Lin bad_cnt = sfc_nand_get_bad_block_list(bad_blk_list, 0); 556ba0501acSDingqiang Lin 557ba0501acSDingqiang Lin for (blk = 0; blk < 1024; blk++) { 558ba0501acSDingqiang Lin for (i = 0; i < bad_cnt; i++) { 559ba0501acSDingqiang Lin if (bad_blk_list[i] == blk) 560ba0501acSDingqiang Lin break; 561ba0501acSDingqiang Lin } 562ba0501acSDingqiang Lin if (i < bad_cnt) 563ba0501acSDingqiang Lin continue; 564ba0501acSDingqiang Lin is_bad_blk = 0; 565ba0501acSDingqiang Lin PRINT_SFC_E("Flash prog block: %x\n", blk); 566ba0501acSDingqiang Lin sfc_nand_erase_block(0, blk * blk_addr); 567ba0501acSDingqiang Lin for (page = 0; page < pages_num; page++) { 568ba0501acSDingqiang Lin page_addr = blk * blk_addr + page; 569ba0501acSDingqiang Lin for (i = 0; i < 512; i++) 570ba0501acSDingqiang Lin pwrite[i] = (page_addr << 16) + i; 571ba0501acSDingqiang Lin pspare_write[0] = pwrite[0] + 0x5AF0; 572ba0501acSDingqiang Lin pspare_write[1] = pspare_write[0] + 1; 573ba0501acSDingqiang Lin sfc_nand_prog_page(0, page_addr, pwrite, pspare_write); 574ba0501acSDingqiang Lin memset(pread, 0, 2048); 575ba0501acSDingqiang Lin memset(pspare_read, 0, 8); 576ba0501acSDingqiang Lin ret = sfc_nand_read_page(0, page_addr, pread, 577ba0501acSDingqiang Lin pspare_read); 578ba0501acSDingqiang Lin if (ret != SFC_NAND_ECC_OK) 579ba0501acSDingqiang Lin is_bad_blk = 1; 580ba0501acSDingqiang Lin for (i = 0; i < 512; i++) { 581ba0501acSDingqiang Lin if (pwrite[i] != pread[i]) { 582ba0501acSDingqiang Lin is_bad_blk = 1; 583ba0501acSDingqiang Lin break; 584ba0501acSDingqiang Lin } 585ba0501acSDingqiang Lin } 586ba0501acSDingqiang Lin for (i = 0; i < 2; i++) { 587ba0501acSDingqiang Lin if (pspare_write[i] != pspare_read[i]) { 588ba0501acSDingqiang Lin is_bad_blk = 1; 589ba0501acSDingqiang Lin break; 590ba0501acSDingqiang Lin } 591ba0501acSDingqiang Lin } 592ba0501acSDingqiang Lin if (is_bad_blk) { 593ba0501acSDingqiang Lin bad_page_num++; 594ba0501acSDingqiang Lin PRINT_SFC_E("ERR:page%x, ret=%x\n", 595ba0501acSDingqiang Lin page_addr, ret); 596ba0501acSDingqiang Lin PRINT_SFC_HEX("data:", pread, 4, 8); 597ba0501acSDingqiang Lin PRINT_SFC_HEX("spare:", pspare_read, 4, 2); 598ba0501acSDingqiang Lin } 599ba0501acSDingqiang Lin } 600ba0501acSDingqiang Lin sfc_nand_erase_block(0, blk * blk_addr); 601ba0501acSDingqiang Lin if (is_bad_blk) 602ba0501acSDingqiang Lin bad_blk_num++; 603ba0501acSDingqiang Lin } 604ba0501acSDingqiang Lin PRINT_SFC_E("bad_blk_num = %d, bad_page_num = %d\n", 605ba0501acSDingqiang Lin bad_blk_num, bad_page_num); 606ba0501acSDingqiang Lin 607ba0501acSDingqiang Lin PRINT_SFC_E("Flash Test Finish!!!\n"); 608ba0501acSDingqiang Lin while (1) 609ba0501acSDingqiang Lin ; 610ba0501acSDingqiang Lin } 611ba0501acSDingqiang Lin #endif 612ba0501acSDingqiang Lin 613ba0501acSDingqiang Lin static void ftl_flash_init(void) 614ba0501acSDingqiang Lin { 615ba0501acSDingqiang Lin /* para init */ 616ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 617ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 618ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 619ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 620ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 621ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 622ba0501acSDingqiang Lin g_nand_phy_info.byte_per_sec = 512; 623ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 624ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 625ba0501acSDingqiang Lin p_nand_info->page_per_blk; 626ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 627ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 628ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 629ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 630ba0501acSDingqiang Lin 631ba0501acSDingqiang Lin /* driver register */ 632ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 633ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 634ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 635ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 63657d18453Sjon.lin g_nand_ops.bch_sel = NULL; 637ba0501acSDingqiang Lin } 638ba0501acSDingqiang Lin 639ba0501acSDingqiang Lin static int spi_nand_enable_QE(void) 640ba0501acSDingqiang Lin { 641ba0501acSDingqiang Lin int ret = SFC_OK; 642ba0501acSDingqiang Lin u8 status; 643ba0501acSDingqiang Lin int bit_offset = p_nand_info->QE_bits; 644ba0501acSDingqiang Lin 645ba0501acSDingqiang Lin if (bit_offset == 0xFF) 646ba0501acSDingqiang Lin return SFC_OK; 647ba0501acSDingqiang Lin 648ba0501acSDingqiang Lin ret = sfc_nand_read_feature(p_nand_info->QE_address, &status); 649ba0501acSDingqiang Lin if (ret != SFC_OK) 650ba0501acSDingqiang Lin return ret; 651ba0501acSDingqiang Lin 652ba0501acSDingqiang Lin if (status & (1 << bit_offset)) /* is QE bit set */ 653ba0501acSDingqiang Lin return SFC_OK; 654ba0501acSDingqiang Lin 655ba0501acSDingqiang Lin status |= (1 << bit_offset); 656ba0501acSDingqiang Lin return sfc_nand_write_feature(p_nand_info->QE_address, status); 657ba0501acSDingqiang Lin 658ba0501acSDingqiang Lin return ret; 659ba0501acSDingqiang Lin } 660ba0501acSDingqiang Lin 661ba0501acSDingqiang Lin u32 sfc_nand_init(void) 662ba0501acSDingqiang Lin { 663ba0501acSDingqiang Lin PRINT_SFC_I("...%s enter...\n", __func__); 664ba0501acSDingqiang Lin 665ba0501acSDingqiang Lin sfc_nand_read_id_raw(id_byte); 6665727ee42Sjon.lin PRINT_SFC_E("sfc_nand id: %x %x %x\n", 667ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 668ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 669ba0501acSDingqiang Lin return FTL_NO_FLASH; 670ba0501acSDingqiang Lin 671ba0501acSDingqiang Lin p_nand_info = spi_nand_get_info(id_byte); 672ba0501acSDingqiang Lin if (!p_nand_info) 673ba0501acSDingqiang Lin return FTL_UNSUPPORTED_FLASH; 674ba0501acSDingqiang Lin 675ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 676ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 677ba0501acSDingqiang Lin 678ba0501acSDingqiang Lin /* disable block lock */ 679ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 680ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 681ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 682ba0501acSDingqiang Lin sfc_nand_dev.page_read_cmd = p_nand_info->read_cache_cmd_1; 683ba0501acSDingqiang Lin sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_1; 684ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 685ba0501acSDingqiang Lin if (spi_nand_enable_QE() == SFC_OK) { 686ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 687ba0501acSDingqiang Lin sfc_nand_dev.page_read_cmd = 688ba0501acSDingqiang Lin p_nand_info->read_cache_cmd_4; 689ba0501acSDingqiang Lin } 690ba0501acSDingqiang Lin } 691ba0501acSDingqiang Lin 692ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 693ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 694ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 695ba0501acSDingqiang Lin sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_4; 696ba0501acSDingqiang Lin } 697ba0501acSDingqiang Lin 698ba0501acSDingqiang Lin if (1) { 699ba0501acSDingqiang Lin u8 status; 700ba0501acSDingqiang Lin 701ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 702ba0501acSDingqiang Lin PRINT_SFC_I("sfc_nand A0 = 0x%x\n", status); 703ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 704ba0501acSDingqiang Lin PRINT_SFC_I("sfc_nand B0 = 0x%x\n", status); 705ba0501acSDingqiang Lin sfc_nand_read_feature(0xC0, &status); 706ba0501acSDingqiang Lin PRINT_SFC_I("sfc_nand C0 = 0x%x\n", status); 707ba0501acSDingqiang Lin PRINT_SFC_I("read_lines = %x\n", sfc_nand_dev.read_lines); 708ba0501acSDingqiang Lin PRINT_SFC_I("prog_lines = %x\n", sfc_nand_dev.prog_lines); 709ba0501acSDingqiang Lin PRINT_SFC_I("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 710ba0501acSDingqiang Lin PRINT_SFC_I("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 711ba0501acSDingqiang Lin } 712ba0501acSDingqiang Lin ftl_flash_init(); 713ba0501acSDingqiang Lin 714ba0501acSDingqiang Lin #if SFC_NAND_STRESS_TEST_EN 715ba0501acSDingqiang Lin sfc_nand_test(); 716ba0501acSDingqiang Lin #endif 717ba0501acSDingqiang Lin 718ba0501acSDingqiang Lin return SFC_OK; 719ba0501acSDingqiang Lin } 720ba0501acSDingqiang Lin 721ba0501acSDingqiang Lin int sfc_nand_read_id(u8 *data) 722ba0501acSDingqiang Lin { 723ba0501acSDingqiang Lin memcpy(data, id_byte, 3); 724ba0501acSDingqiang Lin return 0; 725ba0501acSDingqiang Lin } 726