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); 26d4db0b8dSJon 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 }, 52*f5e7a59fSJon Lin /* MX35UF1GE4AD */ 53*f5e7a59fSJon Lin { 0xC2, 0x96, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 54*f5e7a59fSJon Lin /* MX35UF2GE4AD */ 55*f5e7a59fSJon Lin { 0xC2, 0xA6, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 56*f5e7a59fSJon Lin /* MX35UF4GE4AD */ 57*f5e7a59fSJon Lin { 0xC2, 0xB7, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 58f28847a8SJon Lin 59f28847a8SJon Lin /* GD5F1GQ4UAYIG */ 60b833c879SJon Lin { 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 61f28847a8SJon Lin /* GD5F1GQ4RB9IGR */ 62b833c879SJon Lin { 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 63f28847a8SJon Lin /* GD5F2GQ40BY2GR */ 64b833c879SJon Lin { 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 65f28847a8SJon Lin /* GD5F1GQ5UEYIG */ 66b833c879SJon Lin { 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 67f28847a8SJon Lin /* GD5F2GQ5UEYIG */ 68b833c879SJon Lin { 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 69f28847a8SJon Lin /* GD5F1GQ4R */ 70b833c879SJon Lin { 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 71362b1be1SJon Lin /* GD5F4GQ6RExxG 1*4096 */ 72d4db0b8dSJon Lin { 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 }, 73362b1be1SJon Lin /* GD5F4GQ6UExxG 1*4096 */ 74d4db0b8dSJon Lin { 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 }, 758a654f32SJon Lin /* GD5F1GQ4UExxH */ 768a654f32SJon Lin { 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 77bf620bf6SJon Lin /* GD5F1GQ5REYIG */ 78bf620bf6SJon Lin { 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 79bf620bf6SJon Lin /* GD5F2GQ5REYIG */ 80bf620bf6SJon Lin { 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 81bf620bf6SJon Lin /* GD5F2GM7RxG */ 82bf620bf6SJon Lin { 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 83bf620bf6SJon Lin /* GD5F2GM7UxG */ 84bf620bf6SJon Lin { 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 8545292245SJon Lin /* GD5F1GM7UxG */ 8645292245SJon Lin { 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 87d4db0b8dSJon Lin /* GD5F4GQ4UAYIG 1*4096 */ 88d4db0b8dSJon Lin { 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 89f28847a8SJon Lin 90f28847a8SJon Lin /* W25N01GV */ 91b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 92b833c879SJon Lin /* W25N02KVZEIR */ 93b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 94629111d3SJon Lin /* W25N04KVZEIR */ 95629111d3SJon Lin { 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 }, 96f28847a8SJon Lin /* W25N01GW */ 977bdae1e3SJon Lin { 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 987bdae1e3SJon Lin /* W25N02KW */ 997bdae1e3SJon Lin { 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 1008a654f32SJon Lin /* W25N512GVEIG */ 1018a654f32SJon Lin { 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 102*f5e7a59fSJon Lin /* W25N01KV */ 103*f5e7a59fSJon Lin { 0xEF, 0xAE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 104f28847a8SJon Lin 105f28847a8SJon Lin /* HYF2GQ4UAACAE */ 106b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 107f28847a8SJon Lin /* HYF1GQ4UDACAE */ 108b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 109f28847a8SJon Lin /* HYF1GQ4UPACAE */ 110b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 111f28847a8SJon Lin /* HYF2GQ4UDACAE */ 112b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 113f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 114b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 115f28847a8SJon Lin /* HYF4GQ4UAACBE */ 116b833c879SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 117f28847a8SJon Lin 118f28847a8SJon Lin /* FS35ND01G-S1 */ 119b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 120f28847a8SJon Lin /* FS35ND02G-S2 */ 121b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 12258463f4dSJon Lin /* FS35ND01G-S1Y2 */ 123b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 124f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 125b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 126f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 127b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 128bf620bf6SJon Lin /* F35SQA001G */ 129bf620bf6SJon Lin { 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 13045292245SJon Lin /* F35SQA002G */ 13145292245SJon Lin { 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 132d4db0b8dSJon Lin /* F35SQA512M */ 133d4db0b8dSJon Lin { 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 134d4db0b8dSJon Lin /* F35UQA512M */ 135*f5e7a59fSJon Lin { 0xCD, 0x60, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 136f28847a8SJon Lin 137f28847a8SJon Lin /* DS35Q1GA-IB */ 138b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 139f28847a8SJon Lin /* DS35Q2GA-IB */ 140b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 141f28847a8SJon Lin /* DS35M1GA-1B */ 142b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 143bf620bf6SJon Lin /* DS35M2GA-IB */ 144bf620bf6SJon Lin { 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 145d4db0b8dSJon Lin /* DS35Q1GB-IB */ 146d4db0b8dSJon Lin { 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 147629111d3SJon Lin /* DS35Q2GB-IB */ 148629111d3SJon Lin { 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 149d4db0b8dSJon Lin /* DS35Q4GM */ 150d4db0b8dSJon Lin { 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 151bf620bf6SJon Lin /* DS35M1GB-IB */ 152bf620bf6SJon Lin { 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 153*f5e7a59fSJon Lin /* DS35Q12B-IB */ 154*f5e7a59fSJon Lin { 0xE5, 0xF5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 155*f5e7a59fSJon Lin /* DS35M12B-IB */ 156*f5e7a59fSJon Lin { 0xE5, 0xA5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 157f28847a8SJon Lin 158f28847a8SJon Lin /* EM73C044VCC-H */ 159b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 160f28847a8SJon Lin /* EM73D044VCE-H */ 161b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 162f28847a8SJon Lin /* EM73E044SNA-G */ 163b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 164629111d3SJon Lin /* EM73C044VCF-H */ 165629111d3SJon Lin { 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 166f28847a8SJon Lin 167f28847a8SJon Lin /* XT26G02A */ 168362b1be1SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 169f28847a8SJon Lin /* XT26G01A */ 170362b1be1SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 171f28847a8SJon Lin /* XT26G04A */ 172362b1be1SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 173f28847a8SJon Lin /* XT26G01B */ 174362b1be1SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 175f28847a8SJon Lin /* XT26G02B */ 176362b1be1SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 177362b1be1SJon Lin /* XT26G01C */ 178362b1be1SJon Lin { 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 179362b1be1SJon Lin /* XT26G02C */ 180362b1be1SJon Lin { 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 181362b1be1SJon Lin /* XT26G04C */ 182362b1be1SJon Lin { 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 }, 183629111d3SJon Lin /* XT26G11C */ 184629111d3SJon Lin { 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 185a80fd396SJon Lin 186362b1be1SJon Lin /* MT29F2G01ABA, XT26G02E, F50L2G41XA */ 187629111d3SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 188629111d3SJon Lin /* MT29F1G01ABA, F50L1G41XA */ 189629111d3SJon Lin { 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 190a80fd396SJon Lin 191a80fd396SJon Lin /* FM25S01 */ 192b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 193a80fd396SJon Lin /* FM25S01A */ 194b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 195a80fd396SJon Lin /* FM25S02A */ 196b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 1977bdae1e3SJon Lin /* FM25LS01 */ 1987bdae1e3SJon Lin { 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 199f28847a8SJon Lin 200f28847a8SJon Lin /* IS37SML01G1 */ 201b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 202f28847a8SJon Lin /* F50L1G41LB */ 203b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 204f28847a8SJon Lin /* ATO25D1GA */ 205b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 206362b1be1SJon Lin /* BWJX08K-2Gb */ 207362b1be1SJon Lin { 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 208629111d3SJon Lin /* JS28U1GQSCAHG-83 */ 209629111d3SJon Lin { 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 2108a654f32SJon Lin /* SGM7000I-S24W1GH */ 2118a654f32SJon Lin { 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 212bf620bf6SJon Lin /* TX25G01 */ 213bf620bf6SJon Lin { 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 214*f5e7a59fSJon Lin /* ANV1GCP0CLG */ 215*f5e7a59fSJon Lin { 0x01, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status9 }, 216*f5e7a59fSJon Lin /* S35ML02G3, ANV1GCP0CLG */ 217*f5e7a59fSJon Lin { 0x01, 0x25, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 }, 218d4db0b8dSJon Lin /* S35ML04G3 */ 219*f5e7a59fSJon Lin { 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 }, 220ba0501acSDingqiang Lin }; 221ba0501acSDingqiang Lin 222ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 223ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 224ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 225ba0501acSDingqiang Lin 226a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 227ba0501acSDingqiang Lin { 228ba0501acSDingqiang Lin u32 i; 229ba0501acSDingqiang Lin 230ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 231b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 232b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 233b833c879SJon Lin if (spi_nand_tbl[i].id2 && 234b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 235b833c879SJon Lin continue; 236b833c879SJon Lin 237ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 238ba0501acSDingqiang Lin } 239b833c879SJon Lin } 240f28847a8SJon Lin 241ba0501acSDingqiang Lin return NULL; 242ba0501acSDingqiang Lin } 243ba0501acSDingqiang Lin 244ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 245ba0501acSDingqiang Lin { 246ba0501acSDingqiang Lin int ret; 24758463f4dSJon Lin struct rk_sfc_op op; 248ba0501acSDingqiang Lin 24958463f4dSJon Lin op.sfcmd.d32 = 0; 25058463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 25158463f4dSJon Lin 25258463f4dSJon Lin op.sfctrl.d32 = 0; 25358463f4dSJon Lin 25458463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 255ba0501acSDingqiang Lin return ret; 256ba0501acSDingqiang Lin } 257ba0501acSDingqiang Lin 258ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 259ba0501acSDingqiang Lin { 260ba0501acSDingqiang Lin int ret; 26158463f4dSJon Lin struct rk_sfc_op op; 262ba0501acSDingqiang Lin 26358463f4dSJon Lin op.sfcmd.d32 = 0; 264f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 265f28847a8SJon Lin op.sfcmd.b.cs = 2; 266ba0501acSDingqiang Lin 26758463f4dSJon Lin op.sfctrl.d32 = 0; 26858463f4dSJon Lin op.sfctrl.b.datalines = 2; 269f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 270f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 27158463f4dSJon Lin 272f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 273ba0501acSDingqiang Lin return ret; 274ba0501acSDingqiang Lin } 275ba0501acSDingqiang Lin 276ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 277ba0501acSDingqiang Lin { 278ba0501acSDingqiang Lin int ret; 27958463f4dSJon Lin struct rk_sfc_op op; 280ba0501acSDingqiang Lin 28158463f4dSJon Lin op.sfcmd.d32 = 0; 28258463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 28358463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 28458463f4dSJon Lin 28558463f4dSJon Lin op.sfctrl.d32 = 0; 28658463f4dSJon Lin op.sfctrl.b.addrbits = 8; 28758463f4dSJon Lin 288ba0501acSDingqiang Lin *data = 0; 289ba0501acSDingqiang Lin 29058463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 291f28847a8SJon Lin 292ba0501acSDingqiang Lin if (ret != SFC_OK) 293ba0501acSDingqiang Lin return ret; 294f28847a8SJon Lin 295ba0501acSDingqiang Lin return SFC_OK; 296ba0501acSDingqiang Lin } 297ba0501acSDingqiang Lin 298ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 299ba0501acSDingqiang Lin { 300ba0501acSDingqiang Lin int ret; 30158463f4dSJon Lin struct rk_sfc_op op; 302ba0501acSDingqiang Lin 303ba0501acSDingqiang Lin sfc_nand_write_en(); 304ba0501acSDingqiang Lin 30558463f4dSJon Lin op.sfcmd.d32 = 0; 30658463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 30758463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 30858463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 309ba0501acSDingqiang Lin 31058463f4dSJon Lin op.sfctrl.d32 = 0; 31158463f4dSJon Lin op.sfctrl.b.addrbits = 8; 31258463f4dSJon Lin 31358463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 314f28847a8SJon Lin 315ba0501acSDingqiang Lin if (ret != SFC_OK) 316ba0501acSDingqiang Lin return ret; 317f28847a8SJon Lin 318ba0501acSDingqiang Lin return ret; 319ba0501acSDingqiang Lin } 320ba0501acSDingqiang Lin 321ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 322ba0501acSDingqiang Lin { 323ba0501acSDingqiang Lin int ret; 324ba0501acSDingqiang Lin int i; 325ba0501acSDingqiang Lin u8 status; 326ba0501acSDingqiang Lin 327ba0501acSDingqiang Lin *data = 0; 328f28847a8SJon Lin 329ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 330ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 331f28847a8SJon Lin 332ba0501acSDingqiang Lin if (ret != SFC_OK) 333ba0501acSDingqiang Lin return ret; 334f28847a8SJon Lin 335ba0501acSDingqiang Lin *data = status; 336f28847a8SJon Lin 337ba0501acSDingqiang Lin if (!(status & (1 << 0))) 338ba0501acSDingqiang Lin return SFC_OK; 339f28847a8SJon Lin 340ba0501acSDingqiang Lin sfc_delay(1); 341ba0501acSDingqiang Lin } 342f28847a8SJon Lin 343f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 344ba0501acSDingqiang Lin } 345ba0501acSDingqiang Lin 3466281205aSDingqiang Lin /* 3476281205aSDingqiang Lin * ecc default: 348a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 349f28847a8SJon Lin * 0b00, No bit errors were detected 350f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 351f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 352f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 353362b1be1SJon Lin * reach the bit flip detection threshold 3546281205aSDingqiang Lin */ 355f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 3566281205aSDingqiang Lin { 35758463f4dSJon Lin u32 ret; 3586281205aSDingqiang Lin u32 i; 3596281205aSDingqiang Lin u8 ecc; 3606281205aSDingqiang Lin u8 status; 3616281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3626281205aSDingqiang Lin 3636281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3646281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 365f28847a8SJon Lin 3666281205aSDingqiang Lin if (ret != SFC_OK) 3676281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 368f28847a8SJon Lin 3696281205aSDingqiang Lin if (!(status & (1 << 0))) 3706281205aSDingqiang Lin break; 371f28847a8SJon Lin 3726281205aSDingqiang Lin sfc_delay(1); 3736281205aSDingqiang Lin } 3746281205aSDingqiang Lin 3756281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3766281205aSDingqiang Lin 3776281205aSDingqiang Lin if (ecc <= 1) 3786281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3796281205aSDingqiang Lin else if (ecc == 2) 38058463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3816281205aSDingqiang Lin else 3826281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3836281205aSDingqiang Lin 3846281205aSDingqiang Lin return ret; 3856281205aSDingqiang Lin } 3866281205aSDingqiang Lin 3876281205aSDingqiang Lin /* 3886281205aSDingqiang Lin * ecc spectial type1: 389a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 390f28847a8SJon Lin * 0b00, No bit errors were detected; 391f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 3926281205aSDingqiang Lin * may reach the bit flip detection threshold; 393f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 394f28847a8SJon Lin * 0b11, Reserved. 3956281205aSDingqiang Lin */ 396f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 3976281205aSDingqiang Lin { 39858463f4dSJon Lin u32 ret; 3996281205aSDingqiang Lin u32 i; 4006281205aSDingqiang Lin u8 ecc; 4016281205aSDingqiang Lin u8 status; 4026281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4036281205aSDingqiang Lin 4046281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4056281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 406f28847a8SJon Lin 4076281205aSDingqiang Lin if (ret != SFC_OK) 4086281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 409f28847a8SJon Lin 4106281205aSDingqiang Lin if (!(status & (1 << 0))) 4116281205aSDingqiang Lin break; 412f28847a8SJon Lin 4136281205aSDingqiang Lin sfc_delay(1); 4146281205aSDingqiang Lin } 4156281205aSDingqiang Lin 4166281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4176281205aSDingqiang Lin 4186281205aSDingqiang Lin if (ecc == 0) 4196281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4206281205aSDingqiang Lin else if (ecc == 1) 4216281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4226281205aSDingqiang Lin else 42358463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4246281205aSDingqiang Lin 4256281205aSDingqiang Lin return ret; 4266281205aSDingqiang Lin } 4276281205aSDingqiang Lin 4286281205aSDingqiang Lin /* 429d9cdd318SJon Lin * ecc spectial type2: 430a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 431f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 432f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 433d9cdd318SJon Lin * reach Flipping Bits; 434f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 435c84f0ed8SJon Lin * not corrected. 436f28847a8SJon Lin * [0b1100, 0b1111], reserved. 437d9cdd318SJon Lin */ 438f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 439d9cdd318SJon Lin { 44058463f4dSJon Lin u32 ret; 441d9cdd318SJon Lin u32 i; 442d9cdd318SJon Lin u8 ecc; 443d9cdd318SJon Lin u8 status, status1; 444d9cdd318SJon Lin u32 timeout = 1000 * 1000; 445d9cdd318SJon Lin 446d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 447d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 448f28847a8SJon Lin 449d9cdd318SJon Lin if (ret != SFC_OK) 450d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 451f28847a8SJon Lin 452d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 453f28847a8SJon Lin 454d9cdd318SJon Lin if (ret != SFC_OK) 455d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 456f28847a8SJon Lin 457d9cdd318SJon Lin if (!(status & (1 << 0))) 458d9cdd318SJon Lin break; 459f28847a8SJon Lin 460d9cdd318SJon Lin sfc_delay(1); 461d9cdd318SJon Lin } 462d9cdd318SJon Lin 463d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 464d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 465f28847a8SJon Lin 466d9cdd318SJon Lin if (ecc < 7) 467d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 468d9cdd318SJon Lin else if (ecc == 7) 469d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 470d9cdd318SJon Lin else 47158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 472d9cdd318SJon Lin 473d9cdd318SJon Lin return ret; 474d9cdd318SJon Lin } 475d9cdd318SJon Lin 476d9cdd318SJon Lin /* 4776281205aSDingqiang Lin * ecc spectial type3: 478a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 479f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 480f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 4816281205aSDingqiang Lin * reach Flipping Bits; 482f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 4836281205aSDingqiang Lin * not corrected. 484f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 4856281205aSDingqiang Lin * detectio nthreshold 4866281205aSDingqiang Lin */ 487f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 4886281205aSDingqiang Lin { 48958463f4dSJon Lin u32 ret; 4906281205aSDingqiang Lin u32 i; 4916281205aSDingqiang Lin u8 ecc; 4926281205aSDingqiang Lin u8 status, status1; 4936281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4946281205aSDingqiang Lin 4956281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4966281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 497f28847a8SJon Lin 4986281205aSDingqiang Lin if (ret != SFC_OK) 4996281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 500f28847a8SJon Lin 5016281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 502f28847a8SJon Lin 5036281205aSDingqiang Lin if (ret != SFC_OK) 5046281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 505f28847a8SJon Lin 5066281205aSDingqiang Lin if (!(status & (1 << 0))) 5076281205aSDingqiang Lin break; 508f28847a8SJon Lin 5096281205aSDingqiang Lin sfc_delay(1); 5106281205aSDingqiang Lin } 5116281205aSDingqiang Lin 5126281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 5136281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 514f28847a8SJon Lin 5156281205aSDingqiang Lin if (ecc < 7) 5166281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 5176281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 5186281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 5196281205aSDingqiang Lin else 52058463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 5216281205aSDingqiang Lin 5226281205aSDingqiang Lin return ret; 5236281205aSDingqiang Lin } 5246281205aSDingqiang Lin 52525098c06SDingqiang Lin /* 52625098c06SDingqiang Lin * ecc spectial type4: 527a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 528f28847a8SJon Lin * [0b0000], No bit errors were detected; 529f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 53025098c06SDingqiang Lin * reach Flipping Bits; 531f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 53225098c06SDingqiang Lin * not corrected. 533f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 53425098c06SDingqiang Lin * detection threshold 53525098c06SDingqiang Lin * else, reserved 53625098c06SDingqiang Lin */ 537f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 53825098c06SDingqiang Lin { 53958463f4dSJon Lin u32 ret; 54025098c06SDingqiang Lin u32 i; 54125098c06SDingqiang Lin u8 ecc; 54225098c06SDingqiang Lin u8 status; 54325098c06SDingqiang Lin u32 timeout = 1000 * 1000; 54425098c06SDingqiang Lin 54525098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 54625098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 547f28847a8SJon Lin 54825098c06SDingqiang Lin if (ret != SFC_OK) 54925098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 550f28847a8SJon Lin 55125098c06SDingqiang Lin if (!(status & (1 << 0))) 55225098c06SDingqiang Lin break; 553f28847a8SJon Lin 55425098c06SDingqiang Lin sfc_delay(1); 55525098c06SDingqiang Lin } 55625098c06SDingqiang Lin 55725098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 558f28847a8SJon Lin 55925098c06SDingqiang Lin if (ecc < 7) 56025098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 56125098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 56225098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 56325098c06SDingqiang Lin else 56458463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 56525098c06SDingqiang Lin 56625098c06SDingqiang Lin return ret; 56725098c06SDingqiang Lin } 56825098c06SDingqiang Lin 56925098c06SDingqiang Lin /* 57025098c06SDingqiang Lin * ecc spectial type5: 571a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 572f28847a8SJon Lin * [0b000], No bit errors were detected; 573f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 57425098c06SDingqiang Lin * reach Flipping Bits; 575f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 57625098c06SDingqiang Lin * detection threshold 577f28847a8SJon Lin * [0b101, 0b110], Reserved; 578f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 57925098c06SDingqiang Lin * not corrected. 58025098c06SDingqiang Lin */ 581f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 58225098c06SDingqiang Lin { 58358463f4dSJon Lin u32 ret; 58425098c06SDingqiang Lin u32 i; 58525098c06SDingqiang Lin u8 ecc; 58625098c06SDingqiang Lin u8 status; 58725098c06SDingqiang Lin u32 timeout = 1000 * 1000; 58825098c06SDingqiang Lin 58925098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 59025098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 591f28847a8SJon Lin 59225098c06SDingqiang Lin if (ret != SFC_OK) 59325098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 594f28847a8SJon Lin 59525098c06SDingqiang Lin if (!(status & (1 << 0))) 59625098c06SDingqiang Lin break; 597f28847a8SJon Lin 59825098c06SDingqiang Lin sfc_delay(1); 59925098c06SDingqiang Lin } 60025098c06SDingqiang Lin 60125098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 602f28847a8SJon Lin 60325098c06SDingqiang Lin if (ecc < 4) 60425098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 60525098c06SDingqiang Lin else if (ecc == 4) 60625098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 60725098c06SDingqiang Lin else 60858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 60925098c06SDingqiang Lin 61025098c06SDingqiang Lin return ret; 61125098c06SDingqiang Lin } 61225098c06SDingqiang Lin 613f28847a8SJon Lin /* 614f28847a8SJon Lin * ecc spectial type6: 615f28847a8SJon Lin * ecc bits: 0xC0[4,6] 616f28847a8SJon Lin * [0b000], No bit errors were detected; 617f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 618f28847a8SJon Lin * reach Flipping Bits; 619f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 620f28847a8SJon Lin * not corrected. 621f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 622f28847a8SJon Lin * reach Flipping Bits; 623f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 624f28847a8SJon Lin * detectionthreshold 625f28847a8SJon Lin * others, Reserved. 626f28847a8SJon Lin */ 627f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 628f28847a8SJon Lin { 629f28847a8SJon Lin u32 ret; 630f28847a8SJon Lin u32 i; 631f28847a8SJon Lin u8 ecc; 632f28847a8SJon Lin u8 status; 633f28847a8SJon Lin u32 timeout = 1000 * 1000; 634f28847a8SJon Lin 635f28847a8SJon Lin for (i = 0; i < timeout; i++) { 636f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 637f28847a8SJon Lin 638f28847a8SJon Lin if (ret != SFC_OK) 639f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 640f28847a8SJon Lin 641f28847a8SJon Lin if (!(status & (1 << 0))) 642f28847a8SJon Lin break; 643f28847a8SJon Lin 644f28847a8SJon Lin sfc_delay(1); 645f28847a8SJon Lin } 646f28847a8SJon Lin 647f28847a8SJon Lin ecc = (status >> 4) & 0x07; 648f28847a8SJon Lin 649f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 650f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 651f28847a8SJon Lin else if (ecc == 5) 652f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 653f28847a8SJon Lin else 654f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 655f28847a8SJon Lin 656f28847a8SJon Lin return ret; 657f28847a8SJon Lin } 658f28847a8SJon Lin 659362b1be1SJon Lin /* 660362b1be1SJon Lin * ecc spectial type7: 661362b1be1SJon Lin * ecc bits: 0xC0[4,7] 662362b1be1SJon Lin * [0b0000], No bit errors were detected; 663362b1be1SJon Lin * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 664362b1be1SJon Lin * reach Flipping Bits; 665362b1be1SJon Lin * [0b1000], 8 Bit errors were detected and corrected. Bit error count 666362b1be1SJon Lin * equals the bit flip detectionthreshold; 667362b1be1SJon Lin * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 668362b1be1SJon Lin * others, Reserved. 669362b1be1SJon Lin */ 670362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void) 671362b1be1SJon Lin { 672362b1be1SJon Lin u32 ret; 673362b1be1SJon Lin u32 i; 674362b1be1SJon Lin u8 ecc; 675362b1be1SJon Lin u8 status; 676362b1be1SJon Lin u32 timeout = 1000 * 1000; 677362b1be1SJon Lin 678362b1be1SJon Lin for (i = 0; i < timeout; i++) { 679362b1be1SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 680362b1be1SJon Lin 681362b1be1SJon Lin if (ret != SFC_OK) 682362b1be1SJon Lin return SFC_NAND_ECC_ERROR; 683362b1be1SJon Lin 684362b1be1SJon Lin if (!(status & (1 << 0))) 685362b1be1SJon Lin break; 686362b1be1SJon Lin 687362b1be1SJon Lin sfc_delay(1); 688362b1be1SJon Lin } 689362b1be1SJon Lin 690362b1be1SJon Lin ecc = (status >> 4) & 0xf; 691362b1be1SJon Lin 692362b1be1SJon Lin if (ecc < 7) 693362b1be1SJon Lin ret = SFC_NAND_ECC_OK; 694362b1be1SJon Lin else if (ecc == 7 || ecc == 8) 695362b1be1SJon Lin ret = SFC_NAND_ECC_REFRESH; 696362b1be1SJon Lin else 697362b1be1SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 698362b1be1SJon Lin 699362b1be1SJon Lin return ret; 700362b1be1SJon Lin } 701362b1be1SJon Lin 702629111d3SJon Lin /* 703629111d3SJon Lin * ecc spectial type8: 704629111d3SJon Lin * ecc bits: 0xC0[4,6] 705629111d3SJon Lin * [0b000], No bit errors were detected; 706629111d3SJon Lin * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not 707629111d3SJon Lin * reach Flipping Bits; 708629111d3SJon Lin * [0b100], Bit error count equals the bit flip 709629111d3SJon Lin * detection threshold 710629111d3SJon Lin * others, Reserved. 711629111d3SJon Lin */ 712629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void) 713629111d3SJon Lin { 714629111d3SJon Lin u32 ret; 715629111d3SJon Lin u32 i; 716629111d3SJon Lin u8 ecc; 717629111d3SJon Lin u8 status; 718629111d3SJon Lin u32 timeout = 1000 * 1000; 719629111d3SJon Lin 720629111d3SJon Lin for (i = 0; i < timeout; i++) { 721629111d3SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 722629111d3SJon Lin 723629111d3SJon Lin if (ret != SFC_OK) 724629111d3SJon Lin return SFC_NAND_ECC_ERROR; 725629111d3SJon Lin 726629111d3SJon Lin if (!(status & (1 << 0))) 727629111d3SJon Lin break; 728629111d3SJon Lin 729629111d3SJon Lin sfc_delay(1); 730629111d3SJon Lin } 731629111d3SJon Lin 732629111d3SJon Lin ecc = (status >> 4) & 0x07; 733629111d3SJon Lin 734629111d3SJon Lin if (ecc < 4) 735629111d3SJon Lin ret = SFC_NAND_ECC_OK; 736629111d3SJon Lin else if (ecc == 4) 737629111d3SJon Lin ret = SFC_NAND_ECC_REFRESH; 738629111d3SJon Lin else 739629111d3SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 740629111d3SJon Lin 741629111d3SJon Lin return ret; 742629111d3SJon Lin } 743629111d3SJon Lin 744d4db0b8dSJon Lin /* 745d4db0b8dSJon Lin * ecc spectial type9: 746d4db0b8dSJon Lin * ecc bits: 0xC0[4,5] 747d4db0b8dSJon Lin * 0b00, No bit errors were detected 748d4db0b8dSJon Lin * 0b01, 1-2Bit errors were detected and corrected. 749d4db0b8dSJon Lin * 0b10, 3-4Bit errors were detected and corrected. 750d4db0b8dSJon Lin * 0b11, 11 can be used as uncorrectable 751d4db0b8dSJon Lin */ 752d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void) 753d4db0b8dSJon Lin { 754d4db0b8dSJon Lin u32 ret; 755d4db0b8dSJon Lin u32 i; 756d4db0b8dSJon Lin u8 ecc; 757d4db0b8dSJon Lin u8 status; 758d4db0b8dSJon Lin u32 timeout = 1000 * 1000; 759d4db0b8dSJon Lin 760d4db0b8dSJon Lin for (i = 0; i < timeout; i++) { 761d4db0b8dSJon Lin ret = sfc_nand_read_feature(0xC0, &status); 762d4db0b8dSJon Lin 763d4db0b8dSJon Lin if (ret != SFC_OK) 764d4db0b8dSJon Lin return SFC_NAND_ECC_ERROR; 765d4db0b8dSJon Lin 766d4db0b8dSJon Lin if (!(status & (1 << 0))) 767d4db0b8dSJon Lin break; 768d4db0b8dSJon Lin 769d4db0b8dSJon Lin sfc_delay(1); 770d4db0b8dSJon Lin } 771d4db0b8dSJon Lin 772d4db0b8dSJon Lin ecc = (status >> 4) & 0x03; 773d4db0b8dSJon Lin 774d4db0b8dSJon Lin if (ecc <= 1) 775d4db0b8dSJon Lin ret = SFC_NAND_ECC_OK; 776d4db0b8dSJon Lin else if (ecc == 2) 777d4db0b8dSJon Lin ret = SFC_NAND_ECC_REFRESH; 778d4db0b8dSJon Lin else 779d4db0b8dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 780d4db0b8dSJon Lin 781d4db0b8dSJon Lin return ret; 782d4db0b8dSJon Lin } 783d4db0b8dSJon Lin 784c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 785ba0501acSDingqiang Lin { 786ba0501acSDingqiang Lin int ret; 78758463f4dSJon Lin struct rk_sfc_op op; 788ba0501acSDingqiang Lin u8 status; 789ba0501acSDingqiang Lin 790c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 79158463f4dSJon Lin op.sfcmd.d32 = 0; 792f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 79358463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 79458463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 79558463f4dSJon Lin 79658463f4dSJon Lin op.sfctrl.d32 = 0; 79758463f4dSJon Lin 798ba0501acSDingqiang Lin sfc_nand_write_en(); 79958463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 800f28847a8SJon Lin 801ba0501acSDingqiang Lin if (ret != SFC_OK) 802ba0501acSDingqiang Lin return ret; 803f28847a8SJon Lin 804ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 805f28847a8SJon Lin 806ba0501acSDingqiang Lin if (status & (1 << 2)) 807ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 808c84f0ed8SJon Lin 809ba0501acSDingqiang Lin return ret; 810ba0501acSDingqiang Lin } 811ba0501acSDingqiang Lin 812629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len) 813629111d3SJon Lin { 814629111d3SJon Lin int ret; 815629111d3SJon Lin u32 plane; 816629111d3SJon Lin struct rk_sfc_op op; 817629111d3SJon Lin 818629111d3SJon Lin op.sfcmd.d32 = 0; 819629111d3SJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 820629111d3SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 821629111d3SJon Lin op.sfcmd.b.dummybits = 8; 822629111d3SJon Lin 823629111d3SJon Lin op.sfctrl.d32 = 0; 824629111d3SJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 825629111d3SJon Lin op.sfctrl.b.addrbits = 16; 826629111d3SJon Lin 827629111d3SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 828629111d3SJon Lin 829629111d3SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 830629111d3SJon Lin if (ret != SFC_OK) 831629111d3SJon Lin return SFC_NAND_HW_ERROR; 832629111d3SJon Lin 833629111d3SJon Lin return ret; 834629111d3SJon Lin } 835629111d3SJon Lin 836f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 837ba0501acSDingqiang Lin { 838ba0501acSDingqiang Lin int ret; 839415cf080Sjon.lin u32 plane; 84058463f4dSJon Lin struct rk_sfc_op op; 841ba0501acSDingqiang Lin u8 status; 84258463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 843629111d3SJon Lin u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page; 844ba0501acSDingqiang Lin 845c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 846ba0501acSDingqiang Lin sfc_nand_write_en(); 847f28847a8SJon Lin 848ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 84925098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 85025098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 851ba0501acSDingqiang Lin sfc_nand_rw_preset(); 852ba0501acSDingqiang Lin 85358463f4dSJon Lin op.sfcmd.d32 = 0; 85458463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 85558463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 85658463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 857ba0501acSDingqiang Lin 85858463f4dSJon Lin op.sfctrl.d32 = 0; 85958463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 86058463f4dSJon Lin op.sfctrl.b.addrbits = 16; 861415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 86258463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 863ba0501acSDingqiang Lin 864629111d3SJon Lin /* 865c797b43aSJon Lin * At the moment of power lost or dev running in harsh environment, flash 866c797b43aSJon Lin * maybe work in a unkonw state and result in bit flip, when this situation 867c797b43aSJon Lin * is detected by cache recheck, it's better to wait a second for a reliable 868c797b43aSJon Lin * hardware environment to avoid abnormal data written to flash array. 869629111d3SJon Lin */ 870361684bfSJon Lin if (p_nand_info->id0 == MID_GIGADEV) { 871629111d3SJon Lin sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size); 872c797b43aSJon Lin if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) { 873c797b43aSJon Lin rkflash_print_error("%s %x cache bitflip\n", __func__, addr); 874c797b43aSJon Lin mdelay(1000); 875c797b43aSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 876c797b43aSJon Lin } 877c797b43aSJon Lin } 878629111d3SJon Lin 87958463f4dSJon Lin op.sfcmd.d32 = 0; 880f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 88158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 88258463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 88358463f4dSJon Lin 88458463f4dSJon Lin op.sfctrl.d32 = 0; 88558463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 886f28847a8SJon Lin 887ba0501acSDingqiang Lin if (ret != SFC_OK) 888ba0501acSDingqiang Lin return ret; 889f28847a8SJon Lin 890ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 891ba0501acSDingqiang Lin if (status & (1 << 3)) 892ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 893c84f0ed8SJon Lin 894ba0501acSDingqiang Lin return ret; 895ba0501acSDingqiang Lin } 896ba0501acSDingqiang Lin 897c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 898c84f0ed8SJon Lin { 899c84f0ed8SJon Lin int ret; 900c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 901c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 902a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 903c84f0ed8SJon Lin 904c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 905c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 906a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 907a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 908f28847a8SJon Lin 909c84f0ed8SJon Lin if (sec_per_page == 8) { 910a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 911a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 912c84f0ed8SJon Lin } 913f28847a8SJon Lin 914c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 915c84f0ed8SJon Lin 916c84f0ed8SJon Lin return ret; 917c84f0ed8SJon Lin } 918c84f0ed8SJon Lin 919a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 920ba0501acSDingqiang Lin { 921ba0501acSDingqiang Lin int ret; 922415cf080Sjon.lin u32 plane; 92358463f4dSJon Lin struct rk_sfc_op op; 9246281205aSDingqiang Lin u32 ecc_result; 925a6fcac41SJon Lin u8 status; 926ba0501acSDingqiang Lin 92758463f4dSJon Lin op.sfcmd.d32 = 0; 928f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 92958463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 93058463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 93158463f4dSJon Lin 93258463f4dSJon Lin op.sfctrl.d32 = 0; 93358463f4dSJon Lin 934a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 935f28847a8SJon Lin 936ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 93725098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 93825098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 939ba0501acSDingqiang Lin sfc_nand_rw_preset(); 940ba0501acSDingqiang Lin 941a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 942a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 943a6fcac41SJon Lin 94458463f4dSJon Lin op.sfcmd.d32 = 0; 94558463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 946a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 947a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 94858463f4dSJon Lin 94958463f4dSJon Lin op.sfctrl.d32 = 0; 95058463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 951a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 952ba0501acSDingqiang Lin 953a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 954a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 955a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 956c84f0ed8SJon Lin 957c84f0ed8SJon Lin if (ret != SFC_OK) 958f28847a8SJon Lin return SFC_NAND_HW_ERROR; 959c84f0ed8SJon Lin 960c84f0ed8SJon Lin return ecc_result; 961c84f0ed8SJon Lin } 962c84f0ed8SJon Lin 963a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 964a80fd396SJon Lin { 965a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 966a80fd396SJon Lin 967a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 968a80fd396SJon Lin } 969a80fd396SJon Lin 970c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 971c84f0ed8SJon Lin { 97258463f4dSJon Lin u32 ret; 973c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 974c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 975a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 976c84f0ed8SJon Lin 977c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 978f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 979a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 980a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 981f28847a8SJon Lin 982f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 983a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 984a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 985f25e3cafSJon Lin } 986ba0501acSDingqiang Lin 987f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 988f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 989f28847a8SJon Lin 990c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 991c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 992f28847a8SJon Lin 993ba0501acSDingqiang Lin if (p_data) 994c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 995f28847a8SJon Lin 996ba0501acSDingqiang Lin if (p_spare) 997c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 998ba0501acSDingqiang Lin } 999f25e3cafSJon Lin 1000c84f0ed8SJon Lin return ret; 1001ba0501acSDingqiang Lin } 1002ba0501acSDingqiang Lin 1003c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 1004c84f0ed8SJon Lin { 1005c84f0ed8SJon Lin u32 ret; 1006c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 1007a80fd396SJon Lin u32 marker = 0; 1008c84f0ed8SJon Lin 1009a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 1010f28847a8SJon Lin 1011f28847a8SJon Lin /* unify with mtd framework */ 1012629111d3SJon Lin if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff) 1013a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 1014a80fd396SJon Lin __func__, addr, ret, marker); 1015f28847a8SJon Lin 1016c84f0ed8SJon Lin /* Original bad block */ 1017a80fd396SJon Lin if ((u16)marker != 0xffff) 1018c84f0ed8SJon Lin return true; 1019c84f0ed8SJon Lin 1020c84f0ed8SJon Lin return false; 1021c84f0ed8SJon Lin } 1022c84f0ed8SJon Lin 1023c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 1024c84f0ed8SJon Lin { 1025c84f0ed8SJon Lin u32 ret; 1026c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 1027c84f0ed8SJon Lin 1028c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 1029f28847a8SJon Lin 1030c84f0ed8SJon Lin if (ret) 1031c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 1032f28847a8SJon Lin 1033c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 1034c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 1035f28847a8SJon Lin 1036c84f0ed8SJon Lin if (ret) 1037c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 1038c84f0ed8SJon Lin 1039c84f0ed8SJon Lin return ret; 1040c84f0ed8SJon Lin } 1041c84f0ed8SJon Lin 1042c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 1043ba0501acSDingqiang Lin { 1044ba0501acSDingqiang Lin int ret; 104558463f4dSJon Lin struct rk_sfc_op op; 1046ba0501acSDingqiang Lin 104758463f4dSJon Lin op.sfcmd.d32 = 0; 104858463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 104958463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 1050ba0501acSDingqiang Lin 105158463f4dSJon Lin op.sfctrl.d32 = 0; 105258463f4dSJon Lin op.sfctrl.b.addrbits = 8; 105358463f4dSJon Lin 105458463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 1055ba0501acSDingqiang Lin 1056ba0501acSDingqiang Lin return ret; 1057ba0501acSDingqiang Lin } 1058ba0501acSDingqiang Lin 1059ba0501acSDingqiang Lin /* 1060ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 1061ba0501acSDingqiang Lin * If not FF, it's bad blk 1062ba0501acSDingqiang Lin */ 1063ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 1064ba0501acSDingqiang Lin { 1065ba0501acSDingqiang Lin u32 bad_cnt, page; 1066ba0501acSDingqiang Lin u32 blk_per_die; 10672ac88c1bSJon Lin u16 blk; 1068ba0501acSDingqiang Lin 1069c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 1070c84f0ed8SJon Lin 1071ba0501acSDingqiang Lin bad_cnt = 0; 1072ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 1073ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1074f28847a8SJon Lin 1075ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 1076ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 1077ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1078ba0501acSDingqiang Lin 10792ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 1080ba0501acSDingqiang Lin table[bad_cnt++] = blk; 1081c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 1082ba0501acSDingqiang Lin } 1083ba0501acSDingqiang Lin } 1084f28847a8SJon Lin 1085ba0501acSDingqiang Lin return (int)bad_cnt; 1086ba0501acSDingqiang Lin } 1087ba0501acSDingqiang Lin 1088c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 1089ba0501acSDingqiang Lin { 1090ba0501acSDingqiang Lin /* para init */ 1091ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 1092ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 1093ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 1094ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 1095ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 1096ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 1097c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 1098ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 1099ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 1100ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1101ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 1102ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 1103ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1104ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 1105ba0501acSDingqiang Lin 1106ba0501acSDingqiang Lin /* driver register */ 1107ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 1108ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 1109ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 1110ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 111157d18453Sjon.lin g_nand_ops.bch_sel = NULL; 1112ba0501acSDingqiang Lin } 1113ba0501acSDingqiang Lin 1114a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 1115ba0501acSDingqiang Lin { 1116ba0501acSDingqiang Lin int ret = SFC_OK; 1117ba0501acSDingqiang Lin u8 status; 1118ba0501acSDingqiang Lin 1119f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 1120ba0501acSDingqiang Lin 1121ba0501acSDingqiang Lin if (ret != SFC_OK) 1122ba0501acSDingqiang Lin return ret; 1123ba0501acSDingqiang Lin 1124f28847a8SJon Lin if (status & 1) /* is QE bit set */ 1125ba0501acSDingqiang Lin return SFC_OK; 1126ba0501acSDingqiang Lin 1127f28847a8SJon Lin status |= 1; 1128ba0501acSDingqiang Lin 1129f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 1130ba0501acSDingqiang Lin } 1131ba0501acSDingqiang Lin 1132ba0501acSDingqiang Lin u32 sfc_nand_init(void) 1133ba0501acSDingqiang Lin { 1134c84f0ed8SJon Lin u8 status, id_byte[8]; 1135ba0501acSDingqiang Lin 1136c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 1137c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 1138ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 1139f28847a8SJon Lin 1140ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 114158463f4dSJon Lin return (u32)FTL_NO_FLASH; 1142ba0501acSDingqiang Lin 1143a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 1144f28847a8SJon Lin 114545292245SJon Lin if (!p_nand_info) { 114645292245SJon Lin pr_err("The device not support yet!\n"); 114745292245SJon Lin 114858463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 114945292245SJon Lin } 1150ba0501acSDingqiang Lin 1151ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 1152ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 1153c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 1154c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 1155c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 1156ba0501acSDingqiang Lin 1157ba0501acSDingqiang Lin /* disable block lock */ 1158ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 1159ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 1160ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 1161f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 1162f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 1163629111d3SJon Lin sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE); 1164629111d3SJon Lin if (!sfc_nand_dev.recheck_buffer) { 1165629111d3SJon Lin rkflash_print_error("%s recheck_buffer alloc failed\n", __func__); 1166629111d3SJon Lin return -1; 1167629111d3SJon Lin } 1168f28847a8SJon Lin 1169ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 1170f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 1171f28847a8SJon Lin !p_nand_info->has_qe_bits) { 1172ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 1173f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 1174ba0501acSDingqiang Lin } 1175ba0501acSDingqiang Lin } 1176ba0501acSDingqiang Lin 1177ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 1178ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 1179ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 1180f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 1181ba0501acSDingqiang Lin } 1182ba0501acSDingqiang Lin 1183ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 1184c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 1185ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 1186c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 1187c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 1188c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 1189c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 1190c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 1191ba0501acSDingqiang Lin 1192ba0501acSDingqiang Lin return SFC_OK; 1193ba0501acSDingqiang Lin } 1194ba0501acSDingqiang Lin 1195c84f0ed8SJon Lin void sfc_nand_deinit(void) 1196ba0501acSDingqiang Lin { 1197c84f0ed8SJon Lin /* to-do */ 1198629111d3SJon Lin kfree(sfc_nand_dev.recheck_buffer); 1199ba0501acSDingqiang Lin } 1200c84f0ed8SJon Lin 1201c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 1202c84f0ed8SJon Lin { 1203c84f0ed8SJon Lin return &sfc_nand_dev; 1204c84f0ed8SJon Lin } 1205c84f0ed8SJon Lin 1206