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 17f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void); 18f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void); 19f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void); 20f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void); 21f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void); 22f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void); 23f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void); 24362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void); 25629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void); 26*d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void); 27f28847a8SJon Lin 28ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 29ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 30b833c879SJon Lin { 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 31ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 32b833c879SJon Lin { 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 33a6fcac41SJon Lin /* TC58CVG2S0HRAIJ */ 34b833c879SJon Lin { 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 }, 35a6fcac41SJon Lin /* TC58CVG1S3HRAIJ */ 36b833c879SJon Lin { 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 37a6fcac41SJon Lin /* TC58CVG0S3HRAIJ */ 38b833c879SJon Lin { 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 39f28847a8SJon Lin 40f28847a8SJon Lin /* MX35LF1GE4AB */ 41b833c879SJon Lin { 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 42f28847a8SJon Lin /* MX35LF2GE4AB */ 43b833c879SJon Lin { 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 44f28847a8SJon Lin /* MX35LF2GE4AD */ 45b833c879SJon Lin { 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 46f28847a8SJon Lin /* MX35LF4GE4AD */ 47362b1be1SJon Lin { 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 48362b1be1SJon Lin /* MX35UF1GE4AC */ 49362b1be1SJon Lin { 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 50362b1be1SJon Lin /* MX35UF2GE4AC */ 51362b1be1SJon Lin { 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 52f28847a8SJon Lin 53f28847a8SJon Lin /* GD5F1GQ4UAYIG */ 54b833c879SJon Lin { 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 55f28847a8SJon Lin /* GD5F1GQ4RB9IGR */ 56b833c879SJon Lin { 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 57f28847a8SJon Lin /* GD5F2GQ40BY2GR */ 58b833c879SJon Lin { 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 59f28847a8SJon Lin /* GD5F1GQ5UEYIG */ 60b833c879SJon Lin { 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 61f28847a8SJon Lin /* GD5F2GQ5UEYIG */ 62b833c879SJon Lin { 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 63f28847a8SJon Lin /* GD5F1GQ4R */ 64b833c879SJon Lin { 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 65362b1be1SJon Lin /* GD5F4GQ6RExxG 1*4096 */ 66*d4db0b8dSJon Lin { 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 }, 67362b1be1SJon Lin /* GD5F4GQ6UExxG 1*4096 */ 68*d4db0b8dSJon Lin { 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 }, 698a654f32SJon Lin /* GD5F1GQ4UExxH */ 708a654f32SJon Lin { 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 71bf620bf6SJon Lin /* GD5F1GQ5REYIG */ 72bf620bf6SJon Lin { 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 73bf620bf6SJon Lin /* GD5F2GQ5REYIG */ 74bf620bf6SJon Lin { 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 75bf620bf6SJon Lin /* GD5F2GM7RxG */ 76bf620bf6SJon Lin { 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 77bf620bf6SJon Lin /* GD5F2GM7UxG */ 78bf620bf6SJon Lin { 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 7945292245SJon Lin /* GD5F1GM7UxG */ 8045292245SJon Lin { 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 81*d4db0b8dSJon Lin /* GD5F4GQ4UAYIG 1*4096 */ 82*d4db0b8dSJon Lin { 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 83f28847a8SJon Lin 84f28847a8SJon Lin /* W25N01GV */ 85b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 86b833c879SJon Lin /* W25N02KVZEIR */ 87b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 88629111d3SJon Lin /* W25N04KVZEIR */ 89629111d3SJon Lin { 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 }, 90f28847a8SJon Lin /* W25N01GW */ 917bdae1e3SJon Lin { 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 927bdae1e3SJon Lin /* W25N02KW */ 937bdae1e3SJon Lin { 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 948a654f32SJon Lin /* W25N512GVEIG */ 958a654f32SJon Lin { 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 96f28847a8SJon Lin 97f28847a8SJon Lin /* HYF2GQ4UAACAE */ 98b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 99f28847a8SJon Lin /* HYF1GQ4UDACAE */ 100b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 101f28847a8SJon Lin /* HYF1GQ4UPACAE */ 102b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 103f28847a8SJon Lin /* HYF2GQ4UDACAE */ 104b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 105f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 106b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 107f28847a8SJon Lin /* HYF4GQ4UAACBE */ 108b833c879SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 109f28847a8SJon Lin 110f28847a8SJon Lin /* FS35ND01G-S1 */ 111b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 112f28847a8SJon Lin /* FS35ND02G-S2 */ 113b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 11458463f4dSJon Lin /* FS35ND01G-S1Y2 */ 115b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 116f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 117b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 118f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 119b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 120bf620bf6SJon Lin /* F35SQA001G */ 121bf620bf6SJon Lin { 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 12245292245SJon Lin /* F35SQA002G */ 12345292245SJon Lin { 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 124*d4db0b8dSJon Lin /* F35SQA512M */ 125*d4db0b8dSJon Lin { 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 126*d4db0b8dSJon Lin /* F35UQA512M */ 127*d4db0b8dSJon Lin { 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 128f28847a8SJon Lin 129f28847a8SJon Lin /* DS35Q1GA-IB */ 130b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 131f28847a8SJon Lin /* DS35Q2GA-IB */ 132b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 133f28847a8SJon Lin /* DS35M1GA-1B */ 134b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 135bf620bf6SJon Lin /* DS35M2GA-IB */ 136bf620bf6SJon Lin { 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 137*d4db0b8dSJon Lin /* DS35Q1GB-IB */ 138*d4db0b8dSJon Lin { 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 139629111d3SJon Lin /* DS35Q2GB-IB */ 140629111d3SJon Lin { 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 141*d4db0b8dSJon Lin /* DS35Q4GM */ 142*d4db0b8dSJon Lin { 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 143bf620bf6SJon Lin /* DS35M1GB-IB */ 144bf620bf6SJon Lin { 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 145f28847a8SJon Lin 146f28847a8SJon Lin /* EM73C044VCC-H */ 147b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 148f28847a8SJon Lin /* EM73D044VCE-H */ 149b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 150f28847a8SJon Lin /* EM73E044SNA-G */ 151b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 152629111d3SJon Lin /* EM73C044VCF-H */ 153629111d3SJon Lin { 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 154f28847a8SJon Lin 155f28847a8SJon Lin /* XT26G02A */ 156362b1be1SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 157f28847a8SJon Lin /* XT26G01A */ 158362b1be1SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 159f28847a8SJon Lin /* XT26G04A */ 160362b1be1SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 161f28847a8SJon Lin /* XT26G01B */ 162362b1be1SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 163f28847a8SJon Lin /* XT26G02B */ 164362b1be1SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 165362b1be1SJon Lin /* XT26G01C */ 166362b1be1SJon Lin { 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 167362b1be1SJon Lin /* XT26G02C */ 168362b1be1SJon Lin { 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 169362b1be1SJon Lin /* XT26G04C */ 170362b1be1SJon Lin { 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 }, 171629111d3SJon Lin /* XT26G11C */ 172629111d3SJon Lin { 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 173a80fd396SJon Lin 174362b1be1SJon Lin /* MT29F2G01ABA, XT26G02E, F50L2G41XA */ 175629111d3SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 176629111d3SJon Lin /* MT29F1G01ABA, F50L1G41XA */ 177629111d3SJon Lin { 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 178a80fd396SJon Lin 179a80fd396SJon Lin /* FM25S01 */ 180b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 181a80fd396SJon Lin /* FM25S01A */ 182b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 183a80fd396SJon Lin /* FM25S02A */ 184b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 1857bdae1e3SJon Lin /* FM25LS01 */ 1867bdae1e3SJon Lin { 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 187f28847a8SJon Lin 188f28847a8SJon Lin /* IS37SML01G1 */ 189b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 190f28847a8SJon Lin /* F50L1G41LB */ 191b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 192f28847a8SJon Lin /* ATO25D1GA */ 193b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 194362b1be1SJon Lin /* BWJX08K-2Gb */ 195362b1be1SJon Lin { 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 196629111d3SJon Lin /* JS28U1GQSCAHG-83 */ 197629111d3SJon Lin { 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 1988a654f32SJon Lin /* SGM7000I-S24W1GH */ 1998a654f32SJon Lin { 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 200bf620bf6SJon Lin /* TX25G01 */ 201bf620bf6SJon Lin { 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 202*d4db0b8dSJon Lin /* S35ML04G3 */ 203*d4db0b8dSJon Lin { 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 }, 204ba0501acSDingqiang Lin }; 205ba0501acSDingqiang Lin 206ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 207ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 208ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 209ba0501acSDingqiang Lin 210a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 211ba0501acSDingqiang Lin { 212ba0501acSDingqiang Lin u32 i; 213ba0501acSDingqiang Lin 214ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 215b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 216b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 217b833c879SJon Lin if (spi_nand_tbl[i].id2 && 218b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 219b833c879SJon Lin continue; 220b833c879SJon Lin 221ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 222ba0501acSDingqiang Lin } 223b833c879SJon Lin } 224f28847a8SJon Lin 225ba0501acSDingqiang Lin return NULL; 226ba0501acSDingqiang Lin } 227ba0501acSDingqiang Lin 228ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 229ba0501acSDingqiang Lin { 230ba0501acSDingqiang Lin int ret; 23158463f4dSJon Lin struct rk_sfc_op op; 232ba0501acSDingqiang Lin 23358463f4dSJon Lin op.sfcmd.d32 = 0; 23458463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 23558463f4dSJon Lin 23658463f4dSJon Lin op.sfctrl.d32 = 0; 23758463f4dSJon Lin 23858463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 239ba0501acSDingqiang Lin return ret; 240ba0501acSDingqiang Lin } 241ba0501acSDingqiang Lin 242ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 243ba0501acSDingqiang Lin { 244ba0501acSDingqiang Lin int ret; 24558463f4dSJon Lin struct rk_sfc_op op; 246ba0501acSDingqiang Lin 24758463f4dSJon Lin op.sfcmd.d32 = 0; 248f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 249f28847a8SJon Lin op.sfcmd.b.cs = 2; 250ba0501acSDingqiang Lin 25158463f4dSJon Lin op.sfctrl.d32 = 0; 25258463f4dSJon Lin op.sfctrl.b.datalines = 2; 253f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 254f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 25558463f4dSJon Lin 256f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 257ba0501acSDingqiang Lin return ret; 258ba0501acSDingqiang Lin } 259ba0501acSDingqiang Lin 260ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 261ba0501acSDingqiang Lin { 262ba0501acSDingqiang Lin int ret; 26358463f4dSJon Lin struct rk_sfc_op op; 264ba0501acSDingqiang Lin 26558463f4dSJon Lin op.sfcmd.d32 = 0; 26658463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 26758463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 26858463f4dSJon Lin 26958463f4dSJon Lin op.sfctrl.d32 = 0; 27058463f4dSJon Lin op.sfctrl.b.addrbits = 8; 27158463f4dSJon Lin 272ba0501acSDingqiang Lin *data = 0; 273ba0501acSDingqiang Lin 27458463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 275f28847a8SJon Lin 276ba0501acSDingqiang Lin if (ret != SFC_OK) 277ba0501acSDingqiang Lin return ret; 278f28847a8SJon Lin 279ba0501acSDingqiang Lin return SFC_OK; 280ba0501acSDingqiang Lin } 281ba0501acSDingqiang Lin 282ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 283ba0501acSDingqiang Lin { 284ba0501acSDingqiang Lin int ret; 28558463f4dSJon Lin struct rk_sfc_op op; 286ba0501acSDingqiang Lin 287ba0501acSDingqiang Lin sfc_nand_write_en(); 288ba0501acSDingqiang Lin 28958463f4dSJon Lin op.sfcmd.d32 = 0; 29058463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 29158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 29258463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 293ba0501acSDingqiang Lin 29458463f4dSJon Lin op.sfctrl.d32 = 0; 29558463f4dSJon Lin op.sfctrl.b.addrbits = 8; 29658463f4dSJon Lin 29758463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 298f28847a8SJon Lin 299ba0501acSDingqiang Lin if (ret != SFC_OK) 300ba0501acSDingqiang Lin return ret; 301f28847a8SJon Lin 302ba0501acSDingqiang Lin return ret; 303ba0501acSDingqiang Lin } 304ba0501acSDingqiang Lin 305ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 306ba0501acSDingqiang Lin { 307ba0501acSDingqiang Lin int ret; 308ba0501acSDingqiang Lin int i; 309ba0501acSDingqiang Lin u8 status; 310ba0501acSDingqiang Lin 311ba0501acSDingqiang Lin *data = 0; 312f28847a8SJon Lin 313ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 314ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 315f28847a8SJon Lin 316ba0501acSDingqiang Lin if (ret != SFC_OK) 317ba0501acSDingqiang Lin return ret; 318f28847a8SJon Lin 319ba0501acSDingqiang Lin *data = status; 320f28847a8SJon Lin 321ba0501acSDingqiang Lin if (!(status & (1 << 0))) 322ba0501acSDingqiang Lin return SFC_OK; 323f28847a8SJon Lin 324ba0501acSDingqiang Lin sfc_delay(1); 325ba0501acSDingqiang Lin } 326f28847a8SJon Lin 327f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 328ba0501acSDingqiang Lin } 329ba0501acSDingqiang Lin 3306281205aSDingqiang Lin /* 3316281205aSDingqiang Lin * ecc default: 332a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 333f28847a8SJon Lin * 0b00, No bit errors were detected 334f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 335f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 336f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 337362b1be1SJon Lin * reach the bit flip detection threshold 3386281205aSDingqiang Lin */ 339f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 3406281205aSDingqiang Lin { 34158463f4dSJon Lin u32 ret; 3426281205aSDingqiang Lin u32 i; 3436281205aSDingqiang Lin u8 ecc; 3446281205aSDingqiang Lin u8 status; 3456281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3466281205aSDingqiang Lin 3476281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3486281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 349f28847a8SJon Lin 3506281205aSDingqiang Lin if (ret != SFC_OK) 3516281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 352f28847a8SJon Lin 3536281205aSDingqiang Lin if (!(status & (1 << 0))) 3546281205aSDingqiang Lin break; 355f28847a8SJon Lin 3566281205aSDingqiang Lin sfc_delay(1); 3576281205aSDingqiang Lin } 3586281205aSDingqiang Lin 3596281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3606281205aSDingqiang Lin 3616281205aSDingqiang Lin if (ecc <= 1) 3626281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3636281205aSDingqiang Lin else if (ecc == 2) 36458463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3656281205aSDingqiang Lin else 3666281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3676281205aSDingqiang Lin 3686281205aSDingqiang Lin return ret; 3696281205aSDingqiang Lin } 3706281205aSDingqiang Lin 3716281205aSDingqiang Lin /* 3726281205aSDingqiang Lin * ecc spectial type1: 373a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 374f28847a8SJon Lin * 0b00, No bit errors were detected; 375f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 3766281205aSDingqiang Lin * may reach the bit flip detection threshold; 377f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 378f28847a8SJon Lin * 0b11, Reserved. 3796281205aSDingqiang Lin */ 380f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 3816281205aSDingqiang Lin { 38258463f4dSJon Lin u32 ret; 3836281205aSDingqiang Lin u32 i; 3846281205aSDingqiang Lin u8 ecc; 3856281205aSDingqiang Lin u8 status; 3866281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3876281205aSDingqiang Lin 3886281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3896281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 390f28847a8SJon Lin 3916281205aSDingqiang Lin if (ret != SFC_OK) 3926281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 393f28847a8SJon Lin 3946281205aSDingqiang Lin if (!(status & (1 << 0))) 3956281205aSDingqiang Lin break; 396f28847a8SJon Lin 3976281205aSDingqiang Lin sfc_delay(1); 3986281205aSDingqiang Lin } 3996281205aSDingqiang Lin 4006281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4016281205aSDingqiang Lin 4026281205aSDingqiang Lin if (ecc == 0) 4036281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4046281205aSDingqiang Lin else if (ecc == 1) 4056281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4066281205aSDingqiang Lin else 40758463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4086281205aSDingqiang Lin 4096281205aSDingqiang Lin return ret; 4106281205aSDingqiang Lin } 4116281205aSDingqiang Lin 4126281205aSDingqiang Lin /* 413d9cdd318SJon Lin * ecc spectial type2: 414a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 415f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 416f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 417d9cdd318SJon Lin * reach Flipping Bits; 418f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 419c84f0ed8SJon Lin * not corrected. 420f28847a8SJon Lin * [0b1100, 0b1111], reserved. 421d9cdd318SJon Lin */ 422f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 423d9cdd318SJon Lin { 42458463f4dSJon Lin u32 ret; 425d9cdd318SJon Lin u32 i; 426d9cdd318SJon Lin u8 ecc; 427d9cdd318SJon Lin u8 status, status1; 428d9cdd318SJon Lin u32 timeout = 1000 * 1000; 429d9cdd318SJon Lin 430d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 431d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 432f28847a8SJon Lin 433d9cdd318SJon Lin if (ret != SFC_OK) 434d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 435f28847a8SJon Lin 436d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 437f28847a8SJon Lin 438d9cdd318SJon Lin if (ret != SFC_OK) 439d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 440f28847a8SJon Lin 441d9cdd318SJon Lin if (!(status & (1 << 0))) 442d9cdd318SJon Lin break; 443f28847a8SJon Lin 444d9cdd318SJon Lin sfc_delay(1); 445d9cdd318SJon Lin } 446d9cdd318SJon Lin 447d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 448d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 449f28847a8SJon Lin 450d9cdd318SJon Lin if (ecc < 7) 451d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 452d9cdd318SJon Lin else if (ecc == 7) 453d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 454d9cdd318SJon Lin else 45558463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 456d9cdd318SJon Lin 457d9cdd318SJon Lin return ret; 458d9cdd318SJon Lin } 459d9cdd318SJon Lin 460d9cdd318SJon Lin /* 4616281205aSDingqiang Lin * ecc spectial type3: 462a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 463f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 464f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 4656281205aSDingqiang Lin * reach Flipping Bits; 466f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 4676281205aSDingqiang Lin * not corrected. 468f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 4696281205aSDingqiang Lin * detectio nthreshold 4706281205aSDingqiang Lin */ 471f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 4726281205aSDingqiang Lin { 47358463f4dSJon Lin u32 ret; 4746281205aSDingqiang Lin u32 i; 4756281205aSDingqiang Lin u8 ecc; 4766281205aSDingqiang Lin u8 status, status1; 4776281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4786281205aSDingqiang Lin 4796281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4806281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 481f28847a8SJon Lin 4826281205aSDingqiang Lin if (ret != SFC_OK) 4836281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 484f28847a8SJon Lin 4856281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 486f28847a8SJon Lin 4876281205aSDingqiang Lin if (ret != SFC_OK) 4886281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 489f28847a8SJon Lin 4906281205aSDingqiang Lin if (!(status & (1 << 0))) 4916281205aSDingqiang Lin break; 492f28847a8SJon Lin 4936281205aSDingqiang Lin sfc_delay(1); 4946281205aSDingqiang Lin } 4956281205aSDingqiang Lin 4966281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4976281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 498f28847a8SJon Lin 4996281205aSDingqiang Lin if (ecc < 7) 5006281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 5016281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 5026281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 5036281205aSDingqiang Lin else 50458463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 5056281205aSDingqiang Lin 5066281205aSDingqiang Lin return ret; 5076281205aSDingqiang Lin } 5086281205aSDingqiang Lin 50925098c06SDingqiang Lin /* 51025098c06SDingqiang Lin * ecc spectial type4: 511a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 512f28847a8SJon Lin * [0b0000], No bit errors were detected; 513f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 51425098c06SDingqiang Lin * reach Flipping Bits; 515f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 51625098c06SDingqiang Lin * not corrected. 517f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 51825098c06SDingqiang Lin * detection threshold 51925098c06SDingqiang Lin * else, reserved 52025098c06SDingqiang Lin */ 521f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 52225098c06SDingqiang Lin { 52358463f4dSJon Lin u32 ret; 52425098c06SDingqiang Lin u32 i; 52525098c06SDingqiang Lin u8 ecc; 52625098c06SDingqiang Lin u8 status; 52725098c06SDingqiang Lin u32 timeout = 1000 * 1000; 52825098c06SDingqiang Lin 52925098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 53025098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 531f28847a8SJon Lin 53225098c06SDingqiang Lin if (ret != SFC_OK) 53325098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 534f28847a8SJon Lin 53525098c06SDingqiang Lin if (!(status & (1 << 0))) 53625098c06SDingqiang Lin break; 537f28847a8SJon Lin 53825098c06SDingqiang Lin sfc_delay(1); 53925098c06SDingqiang Lin } 54025098c06SDingqiang Lin 54125098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 542f28847a8SJon Lin 54325098c06SDingqiang Lin if (ecc < 7) 54425098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 54525098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 54625098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 54725098c06SDingqiang Lin else 54858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 54925098c06SDingqiang Lin 55025098c06SDingqiang Lin return ret; 55125098c06SDingqiang Lin } 55225098c06SDingqiang Lin 55325098c06SDingqiang Lin /* 55425098c06SDingqiang Lin * ecc spectial type5: 555a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 556f28847a8SJon Lin * [0b000], No bit errors were detected; 557f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 55825098c06SDingqiang Lin * reach Flipping Bits; 559f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 56025098c06SDingqiang Lin * detection threshold 561f28847a8SJon Lin * [0b101, 0b110], Reserved; 562f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 56325098c06SDingqiang Lin * not corrected. 56425098c06SDingqiang Lin */ 565f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 56625098c06SDingqiang Lin { 56758463f4dSJon Lin u32 ret; 56825098c06SDingqiang Lin u32 i; 56925098c06SDingqiang Lin u8 ecc; 57025098c06SDingqiang Lin u8 status; 57125098c06SDingqiang Lin u32 timeout = 1000 * 1000; 57225098c06SDingqiang Lin 57325098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 57425098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 575f28847a8SJon Lin 57625098c06SDingqiang Lin if (ret != SFC_OK) 57725098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 578f28847a8SJon Lin 57925098c06SDingqiang Lin if (!(status & (1 << 0))) 58025098c06SDingqiang Lin break; 581f28847a8SJon Lin 58225098c06SDingqiang Lin sfc_delay(1); 58325098c06SDingqiang Lin } 58425098c06SDingqiang Lin 58525098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 586f28847a8SJon Lin 58725098c06SDingqiang Lin if (ecc < 4) 58825098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 58925098c06SDingqiang Lin else if (ecc == 4) 59025098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 59125098c06SDingqiang Lin else 59258463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 59325098c06SDingqiang Lin 59425098c06SDingqiang Lin return ret; 59525098c06SDingqiang Lin } 59625098c06SDingqiang Lin 597f28847a8SJon Lin /* 598f28847a8SJon Lin * ecc spectial type6: 599f28847a8SJon Lin * ecc bits: 0xC0[4,6] 600f28847a8SJon Lin * [0b000], No bit errors were detected; 601f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 602f28847a8SJon Lin * reach Flipping Bits; 603f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 604f28847a8SJon Lin * not corrected. 605f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 606f28847a8SJon Lin * reach Flipping Bits; 607f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 608f28847a8SJon Lin * detectionthreshold 609f28847a8SJon Lin * others, Reserved. 610f28847a8SJon Lin */ 611f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 612f28847a8SJon Lin { 613f28847a8SJon Lin u32 ret; 614f28847a8SJon Lin u32 i; 615f28847a8SJon Lin u8 ecc; 616f28847a8SJon Lin u8 status; 617f28847a8SJon Lin u32 timeout = 1000 * 1000; 618f28847a8SJon Lin 619f28847a8SJon Lin for (i = 0; i < timeout; i++) { 620f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 621f28847a8SJon Lin 622f28847a8SJon Lin if (ret != SFC_OK) 623f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 624f28847a8SJon Lin 625f28847a8SJon Lin if (!(status & (1 << 0))) 626f28847a8SJon Lin break; 627f28847a8SJon Lin 628f28847a8SJon Lin sfc_delay(1); 629f28847a8SJon Lin } 630f28847a8SJon Lin 631f28847a8SJon Lin ecc = (status >> 4) & 0x07; 632f28847a8SJon Lin 633f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 634f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 635f28847a8SJon Lin else if (ecc == 5) 636f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 637f28847a8SJon Lin else 638f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 639f28847a8SJon Lin 640f28847a8SJon Lin return ret; 641f28847a8SJon Lin } 642f28847a8SJon Lin 643362b1be1SJon Lin /* 644362b1be1SJon Lin * ecc spectial type7: 645362b1be1SJon Lin * ecc bits: 0xC0[4,7] 646362b1be1SJon Lin * [0b0000], No bit errors were detected; 647362b1be1SJon Lin * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 648362b1be1SJon Lin * reach Flipping Bits; 649362b1be1SJon Lin * [0b1000], 8 Bit errors were detected and corrected. Bit error count 650362b1be1SJon Lin * equals the bit flip detectionthreshold; 651362b1be1SJon Lin * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 652362b1be1SJon Lin * others, Reserved. 653362b1be1SJon Lin */ 654362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void) 655362b1be1SJon Lin { 656362b1be1SJon Lin u32 ret; 657362b1be1SJon Lin u32 i; 658362b1be1SJon Lin u8 ecc; 659362b1be1SJon Lin u8 status; 660362b1be1SJon Lin u32 timeout = 1000 * 1000; 661362b1be1SJon Lin 662362b1be1SJon Lin for (i = 0; i < timeout; i++) { 663362b1be1SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 664362b1be1SJon Lin 665362b1be1SJon Lin if (ret != SFC_OK) 666362b1be1SJon Lin return SFC_NAND_ECC_ERROR; 667362b1be1SJon Lin 668362b1be1SJon Lin if (!(status & (1 << 0))) 669362b1be1SJon Lin break; 670362b1be1SJon Lin 671362b1be1SJon Lin sfc_delay(1); 672362b1be1SJon Lin } 673362b1be1SJon Lin 674362b1be1SJon Lin ecc = (status >> 4) & 0xf; 675362b1be1SJon Lin 676362b1be1SJon Lin if (ecc < 7) 677362b1be1SJon Lin ret = SFC_NAND_ECC_OK; 678362b1be1SJon Lin else if (ecc == 7 || ecc == 8) 679362b1be1SJon Lin ret = SFC_NAND_ECC_REFRESH; 680362b1be1SJon Lin else 681362b1be1SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 682362b1be1SJon Lin 683362b1be1SJon Lin return ret; 684362b1be1SJon Lin } 685362b1be1SJon Lin 686629111d3SJon Lin /* 687629111d3SJon Lin * ecc spectial type8: 688629111d3SJon Lin * ecc bits: 0xC0[4,6] 689629111d3SJon Lin * [0b000], No bit errors were detected; 690629111d3SJon Lin * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not 691629111d3SJon Lin * reach Flipping Bits; 692629111d3SJon Lin * [0b100], Bit error count equals the bit flip 693629111d3SJon Lin * detection threshold 694629111d3SJon Lin * others, Reserved. 695629111d3SJon Lin */ 696629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void) 697629111d3SJon Lin { 698629111d3SJon Lin u32 ret; 699629111d3SJon Lin u32 i; 700629111d3SJon Lin u8 ecc; 701629111d3SJon Lin u8 status; 702629111d3SJon Lin u32 timeout = 1000 * 1000; 703629111d3SJon Lin 704629111d3SJon Lin for (i = 0; i < timeout; i++) { 705629111d3SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 706629111d3SJon Lin 707629111d3SJon Lin if (ret != SFC_OK) 708629111d3SJon Lin return SFC_NAND_ECC_ERROR; 709629111d3SJon Lin 710629111d3SJon Lin if (!(status & (1 << 0))) 711629111d3SJon Lin break; 712629111d3SJon Lin 713629111d3SJon Lin sfc_delay(1); 714629111d3SJon Lin } 715629111d3SJon Lin 716629111d3SJon Lin ecc = (status >> 4) & 0x07; 717629111d3SJon Lin 718629111d3SJon Lin if (ecc < 4) 719629111d3SJon Lin ret = SFC_NAND_ECC_OK; 720629111d3SJon Lin else if (ecc == 4) 721629111d3SJon Lin ret = SFC_NAND_ECC_REFRESH; 722629111d3SJon Lin else 723629111d3SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 724629111d3SJon Lin 725629111d3SJon Lin return ret; 726629111d3SJon Lin } 727629111d3SJon Lin 728*d4db0b8dSJon Lin /* 729*d4db0b8dSJon Lin * ecc spectial type9: 730*d4db0b8dSJon Lin * ecc bits: 0xC0[4,5] 731*d4db0b8dSJon Lin * 0b00, No bit errors were detected 732*d4db0b8dSJon Lin * 0b01, 1-2Bit errors were detected and corrected. 733*d4db0b8dSJon Lin * 0b10, 3-4Bit errors were detected and corrected. 734*d4db0b8dSJon Lin * 0b11, 11 can be used as uncorrectable 735*d4db0b8dSJon Lin */ 736*d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void) 737*d4db0b8dSJon Lin { 738*d4db0b8dSJon Lin u32 ret; 739*d4db0b8dSJon Lin u32 i; 740*d4db0b8dSJon Lin u8 ecc; 741*d4db0b8dSJon Lin u8 status; 742*d4db0b8dSJon Lin u32 timeout = 1000 * 1000; 743*d4db0b8dSJon Lin 744*d4db0b8dSJon Lin for (i = 0; i < timeout; i++) { 745*d4db0b8dSJon Lin ret = sfc_nand_read_feature(0xC0, &status); 746*d4db0b8dSJon Lin 747*d4db0b8dSJon Lin if (ret != SFC_OK) 748*d4db0b8dSJon Lin return SFC_NAND_ECC_ERROR; 749*d4db0b8dSJon Lin 750*d4db0b8dSJon Lin if (!(status & (1 << 0))) 751*d4db0b8dSJon Lin break; 752*d4db0b8dSJon Lin 753*d4db0b8dSJon Lin sfc_delay(1); 754*d4db0b8dSJon Lin } 755*d4db0b8dSJon Lin 756*d4db0b8dSJon Lin ecc = (status >> 4) & 0x03; 757*d4db0b8dSJon Lin 758*d4db0b8dSJon Lin if (ecc <= 1) 759*d4db0b8dSJon Lin ret = SFC_NAND_ECC_OK; 760*d4db0b8dSJon Lin else if (ecc == 2) 761*d4db0b8dSJon Lin ret = SFC_NAND_ECC_REFRESH; 762*d4db0b8dSJon Lin else 763*d4db0b8dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 764*d4db0b8dSJon Lin 765*d4db0b8dSJon Lin return ret; 766*d4db0b8dSJon Lin } 767*d4db0b8dSJon Lin 768c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 769ba0501acSDingqiang Lin { 770ba0501acSDingqiang Lin int ret; 77158463f4dSJon Lin struct rk_sfc_op op; 772ba0501acSDingqiang Lin u8 status; 773ba0501acSDingqiang Lin 774c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 77558463f4dSJon Lin op.sfcmd.d32 = 0; 776f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 77758463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 77858463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 77958463f4dSJon Lin 78058463f4dSJon Lin op.sfctrl.d32 = 0; 78158463f4dSJon Lin 782ba0501acSDingqiang Lin sfc_nand_write_en(); 78358463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 784f28847a8SJon Lin 785ba0501acSDingqiang Lin if (ret != SFC_OK) 786ba0501acSDingqiang Lin return ret; 787f28847a8SJon Lin 788ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 789f28847a8SJon Lin 790ba0501acSDingqiang Lin if (status & (1 << 2)) 791ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 792c84f0ed8SJon Lin 793ba0501acSDingqiang Lin return ret; 794ba0501acSDingqiang Lin } 795ba0501acSDingqiang Lin 796629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len) 797629111d3SJon Lin { 798629111d3SJon Lin int ret; 799629111d3SJon Lin u32 plane; 800629111d3SJon Lin struct rk_sfc_op op; 801629111d3SJon Lin 802629111d3SJon Lin op.sfcmd.d32 = 0; 803629111d3SJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 804629111d3SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 805629111d3SJon Lin op.sfcmd.b.dummybits = 8; 806629111d3SJon Lin 807629111d3SJon Lin op.sfctrl.d32 = 0; 808629111d3SJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 809629111d3SJon Lin op.sfctrl.b.addrbits = 16; 810629111d3SJon Lin 811629111d3SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 812629111d3SJon Lin 813629111d3SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 814629111d3SJon Lin if (ret != SFC_OK) 815629111d3SJon Lin return SFC_NAND_HW_ERROR; 816629111d3SJon Lin 817629111d3SJon Lin return ret; 818629111d3SJon Lin } 819629111d3SJon Lin 820f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 821ba0501acSDingqiang Lin { 822ba0501acSDingqiang Lin int ret; 823415cf080Sjon.lin u32 plane; 82458463f4dSJon Lin struct rk_sfc_op op; 825ba0501acSDingqiang Lin u8 status; 82658463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 827629111d3SJon Lin u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page; 828ba0501acSDingqiang Lin 829c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 830ba0501acSDingqiang Lin sfc_nand_write_en(); 831f28847a8SJon Lin 832ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 83325098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 83425098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 835ba0501acSDingqiang Lin sfc_nand_rw_preset(); 836ba0501acSDingqiang Lin 83758463f4dSJon Lin op.sfcmd.d32 = 0; 83858463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 83958463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 84058463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 841ba0501acSDingqiang Lin 84258463f4dSJon Lin op.sfctrl.d32 = 0; 84358463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 84458463f4dSJon Lin op.sfctrl.b.addrbits = 16; 845415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 84658463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 847ba0501acSDingqiang Lin 848629111d3SJon Lin /* 849c797b43aSJon Lin * At the moment of power lost or dev running in harsh environment, flash 850c797b43aSJon Lin * maybe work in a unkonw state and result in bit flip, when this situation 851c797b43aSJon Lin * is detected by cache recheck, it's better to wait a second for a reliable 852c797b43aSJon Lin * hardware environment to avoid abnormal data written to flash array. 853629111d3SJon Lin */ 854361684bfSJon Lin if (p_nand_info->id0 == MID_GIGADEV) { 855629111d3SJon Lin sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size); 856c797b43aSJon Lin if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) { 857c797b43aSJon Lin rkflash_print_error("%s %x cache bitflip\n", __func__, addr); 858c797b43aSJon Lin mdelay(1000); 859c797b43aSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 860c797b43aSJon Lin } 861c797b43aSJon Lin } 862629111d3SJon Lin 86358463f4dSJon Lin op.sfcmd.d32 = 0; 864f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 86558463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 86658463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 86758463f4dSJon Lin 86858463f4dSJon Lin op.sfctrl.d32 = 0; 86958463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 870f28847a8SJon Lin 871ba0501acSDingqiang Lin if (ret != SFC_OK) 872ba0501acSDingqiang Lin return ret; 873f28847a8SJon Lin 874ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 875ba0501acSDingqiang Lin if (status & (1 << 3)) 876ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 877c84f0ed8SJon Lin 878ba0501acSDingqiang Lin return ret; 879ba0501acSDingqiang Lin } 880ba0501acSDingqiang Lin 881c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 882c84f0ed8SJon Lin { 883c84f0ed8SJon Lin int ret; 884c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 885c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 886a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 887c84f0ed8SJon Lin 888c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 889c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 890a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 891a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 892f28847a8SJon Lin 893c84f0ed8SJon Lin if (sec_per_page == 8) { 894a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 895a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 896c84f0ed8SJon Lin } 897f28847a8SJon Lin 898c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 899c84f0ed8SJon Lin 900c84f0ed8SJon Lin return ret; 901c84f0ed8SJon Lin } 902c84f0ed8SJon Lin 903a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 904ba0501acSDingqiang Lin { 905ba0501acSDingqiang Lin int ret; 906415cf080Sjon.lin u32 plane; 90758463f4dSJon Lin struct rk_sfc_op op; 9086281205aSDingqiang Lin u32 ecc_result; 909a6fcac41SJon Lin u8 status; 910ba0501acSDingqiang Lin 91158463f4dSJon Lin op.sfcmd.d32 = 0; 912f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 91358463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 91458463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 91558463f4dSJon Lin 91658463f4dSJon Lin op.sfctrl.d32 = 0; 91758463f4dSJon Lin 918a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 919f28847a8SJon Lin 920ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 92125098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 92225098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 923ba0501acSDingqiang Lin sfc_nand_rw_preset(); 924ba0501acSDingqiang Lin 925a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 926a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 927a6fcac41SJon Lin 92858463f4dSJon Lin op.sfcmd.d32 = 0; 92958463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 930a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 931a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 93258463f4dSJon Lin 93358463f4dSJon Lin op.sfctrl.d32 = 0; 93458463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 935a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 936ba0501acSDingqiang Lin 937a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 938a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 939a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 940c84f0ed8SJon Lin 941c84f0ed8SJon Lin if (ret != SFC_OK) 942f28847a8SJon Lin return SFC_NAND_HW_ERROR; 943c84f0ed8SJon Lin 944c84f0ed8SJon Lin return ecc_result; 945c84f0ed8SJon Lin } 946c84f0ed8SJon Lin 947a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 948a80fd396SJon Lin { 949a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 950a80fd396SJon Lin 951a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 952a80fd396SJon Lin } 953a80fd396SJon Lin 954c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 955c84f0ed8SJon Lin { 95658463f4dSJon Lin u32 ret; 957c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 958c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 959a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 960c84f0ed8SJon Lin 961c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 962f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 963a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 964a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 965f28847a8SJon Lin 966f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 967a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 968a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 969f25e3cafSJon Lin } 970ba0501acSDingqiang Lin 971f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 972f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 973f28847a8SJon Lin 974c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 975c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 976f28847a8SJon Lin 977ba0501acSDingqiang Lin if (p_data) 978c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 979f28847a8SJon Lin 980ba0501acSDingqiang Lin if (p_spare) 981c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 982ba0501acSDingqiang Lin } 983f25e3cafSJon Lin 984c84f0ed8SJon Lin return ret; 985ba0501acSDingqiang Lin } 986ba0501acSDingqiang Lin 987c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 988c84f0ed8SJon Lin { 989c84f0ed8SJon Lin u32 ret; 990c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 991a80fd396SJon Lin u32 marker = 0; 992c84f0ed8SJon Lin 993a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 994f28847a8SJon Lin 995f28847a8SJon Lin /* unify with mtd framework */ 996629111d3SJon Lin if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff) 997a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 998a80fd396SJon Lin __func__, addr, ret, marker); 999f28847a8SJon Lin 1000c84f0ed8SJon Lin /* Original bad block */ 1001a80fd396SJon Lin if ((u16)marker != 0xffff) 1002c84f0ed8SJon Lin return true; 1003c84f0ed8SJon Lin 1004c84f0ed8SJon Lin return false; 1005c84f0ed8SJon Lin } 1006c84f0ed8SJon Lin 1007c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 1008c84f0ed8SJon Lin { 1009c84f0ed8SJon Lin u32 ret; 1010c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 1011c84f0ed8SJon Lin 1012c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 1013f28847a8SJon Lin 1014c84f0ed8SJon Lin if (ret) 1015c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 1016f28847a8SJon Lin 1017c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 1018c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 1019f28847a8SJon Lin 1020c84f0ed8SJon Lin if (ret) 1021c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 1022c84f0ed8SJon Lin 1023c84f0ed8SJon Lin return ret; 1024c84f0ed8SJon Lin } 1025c84f0ed8SJon Lin 1026c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 1027ba0501acSDingqiang Lin { 1028ba0501acSDingqiang Lin int ret; 102958463f4dSJon Lin struct rk_sfc_op op; 1030ba0501acSDingqiang Lin 103158463f4dSJon Lin op.sfcmd.d32 = 0; 103258463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 103358463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 1034ba0501acSDingqiang Lin 103558463f4dSJon Lin op.sfctrl.d32 = 0; 103658463f4dSJon Lin op.sfctrl.b.addrbits = 8; 103758463f4dSJon Lin 103858463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 1039ba0501acSDingqiang Lin 1040ba0501acSDingqiang Lin return ret; 1041ba0501acSDingqiang Lin } 1042ba0501acSDingqiang Lin 1043ba0501acSDingqiang Lin /* 1044ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 1045ba0501acSDingqiang Lin * If not FF, it's bad blk 1046ba0501acSDingqiang Lin */ 1047ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 1048ba0501acSDingqiang Lin { 1049ba0501acSDingqiang Lin u32 bad_cnt, page; 1050ba0501acSDingqiang Lin u32 blk_per_die; 10512ac88c1bSJon Lin u16 blk; 1052ba0501acSDingqiang Lin 1053c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 1054c84f0ed8SJon Lin 1055ba0501acSDingqiang Lin bad_cnt = 0; 1056ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 1057ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1058f28847a8SJon Lin 1059ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 1060ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 1061ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1062ba0501acSDingqiang Lin 10632ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 1064ba0501acSDingqiang Lin table[bad_cnt++] = blk; 1065c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 1066ba0501acSDingqiang Lin } 1067ba0501acSDingqiang Lin } 1068f28847a8SJon Lin 1069ba0501acSDingqiang Lin return (int)bad_cnt; 1070ba0501acSDingqiang Lin } 1071ba0501acSDingqiang Lin 1072c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 1073ba0501acSDingqiang Lin { 1074ba0501acSDingqiang Lin /* para init */ 1075ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 1076ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 1077ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 1078ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 1079ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 1080ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 1081c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 1082ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 1083ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 1084ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1085ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 1086ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 1087ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1088ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 1089ba0501acSDingqiang Lin 1090ba0501acSDingqiang Lin /* driver register */ 1091ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 1092ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 1093ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 1094ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 109557d18453Sjon.lin g_nand_ops.bch_sel = NULL; 1096ba0501acSDingqiang Lin } 1097ba0501acSDingqiang Lin 1098a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 1099ba0501acSDingqiang Lin { 1100ba0501acSDingqiang Lin int ret = SFC_OK; 1101ba0501acSDingqiang Lin u8 status; 1102ba0501acSDingqiang Lin 1103f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 1104ba0501acSDingqiang Lin 1105ba0501acSDingqiang Lin if (ret != SFC_OK) 1106ba0501acSDingqiang Lin return ret; 1107ba0501acSDingqiang Lin 1108f28847a8SJon Lin if (status & 1) /* is QE bit set */ 1109ba0501acSDingqiang Lin return SFC_OK; 1110ba0501acSDingqiang Lin 1111f28847a8SJon Lin status |= 1; 1112ba0501acSDingqiang Lin 1113f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 1114ba0501acSDingqiang Lin } 1115ba0501acSDingqiang Lin 1116ba0501acSDingqiang Lin u32 sfc_nand_init(void) 1117ba0501acSDingqiang Lin { 1118c84f0ed8SJon Lin u8 status, id_byte[8]; 1119ba0501acSDingqiang Lin 1120c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 1121c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 1122ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 1123f28847a8SJon Lin 1124ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 112558463f4dSJon Lin return (u32)FTL_NO_FLASH; 1126ba0501acSDingqiang Lin 1127a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 1128f28847a8SJon Lin 112945292245SJon Lin if (!p_nand_info) { 113045292245SJon Lin pr_err("The device not support yet!\n"); 113145292245SJon Lin 113258463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 113345292245SJon Lin } 1134ba0501acSDingqiang Lin 1135ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 1136ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 1137c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 1138c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 1139c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 1140ba0501acSDingqiang Lin 1141ba0501acSDingqiang Lin /* disable block lock */ 1142ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 1143ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 1144ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 1145f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 1146f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 1147629111d3SJon Lin sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE); 1148629111d3SJon Lin if (!sfc_nand_dev.recheck_buffer) { 1149629111d3SJon Lin rkflash_print_error("%s recheck_buffer alloc failed\n", __func__); 1150629111d3SJon Lin return -1; 1151629111d3SJon Lin } 1152f28847a8SJon Lin 1153ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 1154f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 1155f28847a8SJon Lin !p_nand_info->has_qe_bits) { 1156ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 1157f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 1158ba0501acSDingqiang Lin } 1159ba0501acSDingqiang Lin } 1160ba0501acSDingqiang Lin 1161ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 1162ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 1163ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 1164f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 1165ba0501acSDingqiang Lin } 1166ba0501acSDingqiang Lin 1167ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 1168c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 1169ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 1170c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 1171c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 1172c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 1173c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 1174c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 1175ba0501acSDingqiang Lin 1176ba0501acSDingqiang Lin return SFC_OK; 1177ba0501acSDingqiang Lin } 1178ba0501acSDingqiang Lin 1179c84f0ed8SJon Lin void sfc_nand_deinit(void) 1180ba0501acSDingqiang Lin { 1181c84f0ed8SJon Lin /* to-do */ 1182629111d3SJon Lin kfree(sfc_nand_dev.recheck_buffer); 1183ba0501acSDingqiang Lin } 1184c84f0ed8SJon Lin 1185c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 1186c84f0ed8SJon Lin { 1187c84f0ed8SJon Lin return &sfc_nand_dev; 1188c84f0ed8SJon Lin } 1189c84f0ed8SJon Lin 1190