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); 27*a4bd704eSJon Lin static u32 sfc_nand_get_ecc_status10(void); 28f28847a8SJon Lin 29ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 30ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 31b833c879SJon Lin { 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 32ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 33b833c879SJon Lin { 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 34a6fcac41SJon Lin /* TC58CVG2S0HRAIJ */ 35b833c879SJon Lin { 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 }, 36a6fcac41SJon Lin /* TC58CVG1S3HRAIJ */ 37b833c879SJon Lin { 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 38a6fcac41SJon Lin /* TC58CVG0S3HRAIJ */ 39b833c879SJon Lin { 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 40f28847a8SJon Lin 41f28847a8SJon Lin /* MX35LF1GE4AB */ 42b833c879SJon Lin { 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 43f28847a8SJon Lin /* MX35LF2GE4AB */ 44b833c879SJon Lin { 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 45f28847a8SJon Lin /* MX35LF2GE4AD */ 46b833c879SJon Lin { 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 47f28847a8SJon Lin /* MX35LF4GE4AD */ 48362b1be1SJon Lin { 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 49362b1be1SJon Lin /* MX35UF1GE4AC */ 50362b1be1SJon Lin { 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 51362b1be1SJon Lin /* MX35UF2GE4AC */ 52362b1be1SJon Lin { 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 53f5e7a59fSJon Lin /* MX35UF1GE4AD */ 54f5e7a59fSJon Lin { 0xC2, 0x96, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 55f5e7a59fSJon Lin /* MX35UF2GE4AD */ 56f5e7a59fSJon Lin { 0xC2, 0xA6, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 57f5e7a59fSJon Lin /* MX35UF4GE4AD */ 58f5e7a59fSJon Lin { 0xC2, 0xB7, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 59f28847a8SJon Lin 60f28847a8SJon Lin /* GD5F1GQ4UAYIG */ 61b833c879SJon Lin { 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 62f28847a8SJon Lin /* GD5F1GQ4RB9IGR */ 63b833c879SJon Lin { 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 64f28847a8SJon Lin /* GD5F2GQ40BY2GR */ 65b833c879SJon Lin { 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 66f28847a8SJon Lin /* GD5F1GQ5UEYIG */ 67b833c879SJon Lin { 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 68f28847a8SJon Lin /* GD5F2GQ5UEYIG */ 69b833c879SJon Lin { 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 70f28847a8SJon Lin /* GD5F1GQ4R */ 71b833c879SJon Lin { 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 72362b1be1SJon Lin /* GD5F4GQ6RExxG 1*4096 */ 73d4db0b8dSJon Lin { 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 }, 74362b1be1SJon Lin /* GD5F4GQ6UExxG 1*4096 */ 75d4db0b8dSJon Lin { 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 }, 768a654f32SJon Lin /* GD5F1GQ4UExxH */ 778a654f32SJon Lin { 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 78e5e85009SJon Lin /* GD5F1GQ5REYIG Add 3rd code to distingush with F50L2G41KA */ 79e5e85009SJon Lin { 0xC8, 0x41, 0xC8, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 80bf620bf6SJon Lin /* GD5F2GQ5REYIG */ 81bf620bf6SJon Lin { 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 82bf620bf6SJon Lin /* GD5F2GM7RxG */ 83e5e85009SJon Lin { 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 84bf620bf6SJon Lin /* GD5F2GM7UxG */ 85e5e85009SJon Lin { 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 8645292245SJon Lin /* GD5F1GM7UxG */ 87e5e85009SJon Lin { 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 88d4db0b8dSJon Lin /* GD5F4GQ4UAYIG 1*4096 */ 89d4db0b8dSJon Lin { 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 90e5e85009SJon Lin /* GD5F1GM7REYIGR */ 91e5e85009SJon Lin { 0xC8, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 92e5e85009SJon Lin /* GD5F4GM8UEYIGR */ 93e5e85009SJon Lin { 0xC8, 0x95, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 94f28847a8SJon Lin 95f28847a8SJon Lin /* W25N01GV */ 96b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 97b833c879SJon Lin /* W25N02KVZEIR */ 98b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 99629111d3SJon Lin /* W25N04KVZEIR */ 100629111d3SJon Lin { 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 }, 101f28847a8SJon Lin /* W25N01GW */ 1027bdae1e3SJon Lin { 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 1037bdae1e3SJon Lin /* W25N02KW */ 1047bdae1e3SJon Lin { 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 1058a654f32SJon Lin /* W25N512GVEIG */ 1068a654f32SJon Lin { 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 107f5e7a59fSJon Lin /* W25N01KV */ 108f5e7a59fSJon Lin { 0xEF, 0xAE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 109*a4bd704eSJon Lin /* W25N01JWZEIG */ 110*a4bd704eSJon Lin { 0xEF, 0xBC, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 111*a4bd704eSJon Lin /* W25N01KWZPIG */ 112*a4bd704eSJon Lin { 0xEF, 0xBE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 113f28847a8SJon Lin 114f28847a8SJon Lin /* HYF2GQ4UAACAE */ 115b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 116f28847a8SJon Lin /* HYF1GQ4UDACAE */ 117b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 118f28847a8SJon Lin /* HYF1GQ4UPACAE */ 119b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 120f28847a8SJon Lin /* HYF2GQ4UDACAE */ 121b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 122f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 123b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 124f28847a8SJon Lin /* HYF4GQ4UAACBE */ 12506efa4f9SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0xE, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 12606efa4f9SJon Lin /* HYF2GQ4IAACAE */ 12706efa4f9SJon Lin { 0xC9, 0x82, 0x00, 4, 0x40, 1, 2048, 0x4C, 20, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 12806efa4f9SJon Lin /* HYF1GQ4IDACAE */ 12906efa4f9SJon Lin { 0xC9, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 20, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 130f28847a8SJon Lin 131f28847a8SJon Lin /* FS35ND01G-S1 */ 132b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 133f28847a8SJon Lin /* FS35ND02G-S2 */ 134b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 13558463f4dSJon Lin /* FS35ND01G-S1Y2 */ 136b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 137f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 138b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 139f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 140b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 141bf620bf6SJon Lin /* F35SQA001G */ 142bf620bf6SJon Lin { 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 14345292245SJon Lin /* F35SQA002G */ 14445292245SJon Lin { 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 145d4db0b8dSJon Lin /* F35SQA512M */ 146d4db0b8dSJon Lin { 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 147d4db0b8dSJon Lin /* F35UQA512M */ 148f5e7a59fSJon Lin { 0xCD, 0x60, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 149e5e85009SJon Lin /* F35UQA002G-WWT */ 150e5e85009SJon Lin { 0xCD, 0x62, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 151*a4bd704eSJon Lin /* F35SQB004G-WWT */ 152e5e85009SJon Lin { 0xCD, 0x61, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 153*a4bd704eSJon Lin /* F35SQB004G */ 154*a4bd704eSJon Lin { 0xCD, 0x53, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status10 }, 155*a4bd704eSJon Lin /* F35SQB002G */ 156*a4bd704eSJon Lin { 0xCD, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status10 }, 157f28847a8SJon Lin 158f28847a8SJon Lin /* DS35Q1GA-IB */ 159b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 160f28847a8SJon Lin /* DS35Q2GA-IB */ 161b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 162f28847a8SJon Lin /* DS35M1GA-1B */ 163b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 164bf620bf6SJon Lin /* DS35M2GA-IB */ 165bf620bf6SJon Lin { 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 166d4db0b8dSJon Lin /* DS35Q1GB-IB */ 167d4db0b8dSJon Lin { 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 168629111d3SJon Lin /* DS35Q2GB-IB */ 169629111d3SJon Lin { 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 170d4db0b8dSJon Lin /* DS35Q4GM */ 171d4db0b8dSJon Lin { 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 172bf620bf6SJon Lin /* DS35M1GB-IB */ 173bf620bf6SJon Lin { 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 174f5e7a59fSJon Lin /* DS35Q12B-IB */ 175f5e7a59fSJon Lin { 0xE5, 0xF5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 176f5e7a59fSJon Lin /* DS35M12B-IB */ 177f5e7a59fSJon Lin { 0xE5, 0xA5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 178e5e85009SJon Lin /* DS35Q1GD-IB */ 179e5e85009SJon Lin { 0xE5, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 180*a4bd704eSJon Lin /* DS35M4GB-IB */ 181*a4bd704eSJon Lin { 0xE5, 0x64, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 182*a4bd704eSJon Lin /* DS35Q4GB-IB */ 183*a4bd704eSJon Lin { 0xE5, 0xB4, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 184*a4bd704eSJon Lin /* DS35M12C-IB */ 185*a4bd704eSJon Lin { 0xE5, 0x25, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 186*a4bd704eSJon Lin /* DS35Q12C-IB */ 187*a4bd704eSJon Lin { 0xE5, 0x75, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 188*a4bd704eSJon Lin /* DS35Q2GBS */ 189*a4bd704eSJon Lin { 0xE5, 0xB2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 190f28847a8SJon Lin 191f28847a8SJon Lin /* EM73C044VCC-H */ 192b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 193f28847a8SJon Lin /* EM73D044VCE-H */ 194b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 195f28847a8SJon Lin /* EM73E044SNA-G */ 196b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 197629111d3SJon Lin /* EM73C044VCF-H */ 198629111d3SJon Lin { 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 199f28847a8SJon Lin 200f28847a8SJon Lin /* XT26G02A */ 201362b1be1SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 202f28847a8SJon Lin /* XT26G01A */ 203362b1be1SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 204f28847a8SJon Lin /* XT26G04A */ 205362b1be1SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 206f28847a8SJon Lin /* XT26G01B */ 207362b1be1SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 208f28847a8SJon Lin /* XT26G02B */ 209362b1be1SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 210362b1be1SJon Lin /* XT26G01C */ 211362b1be1SJon Lin { 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 212362b1be1SJon Lin /* XT26G02C */ 213362b1be1SJon Lin { 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 214362b1be1SJon Lin /* XT26G04C */ 215362b1be1SJon Lin { 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 }, 216629111d3SJon Lin /* XT26G11C */ 217629111d3SJon Lin { 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 218e5e85009SJon Lin /* XT26Q02DWSIGA */ 219e5e85009SJon Lin { 0x0B, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 220e5e85009SJon Lin /* XT26Q01DWSIGA */ 221e5e85009SJon Lin { 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 222e5e85009SJon Lin /* XT26Q04DWSIGA */ 223e5e85009SJon Lin { 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 }, 224e5e85009SJon Lin /* XT26G01DWSIGA */ 225e5e85009SJon Lin { 0x0B, 0x31, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 226e5e85009SJon Lin /* XT26G02DWSIGA */ 227e5e85009SJon Lin { 0x0B, 0x32, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 228e5e85009SJon Lin /* XT26G04DWSIGA */ 229e5e85009SJon Lin { 0x0B, 0x33, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 }, 230*a4bd704eSJon Lin /* XT26Q04DWSIGT-B */ 231*a4bd704eSJon Lin { 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x14, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 }, 232*a4bd704eSJon Lin /* XT26Q01DWSIGA */ 233*a4bd704eSJon Lin { 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 234a80fd396SJon Lin 235362b1be1SJon Lin /* MT29F2G01ABA, XT26G02E, F50L2G41XA */ 236629111d3SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 237629111d3SJon Lin /* MT29F1G01ABA, F50L1G41XA */ 238629111d3SJon Lin { 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 239a80fd396SJon Lin 240a80fd396SJon Lin /* FM25S01 */ 241b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 242a80fd396SJon Lin /* FM25S01A */ 243b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 244a80fd396SJon Lin /* FM25S02A */ 245b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 2467bdae1e3SJon Lin /* FM25LS01 */ 2477bdae1e3SJon Lin { 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 248e5e85009SJon Lin /* FM25S01BI3 */ 249e5e85009SJon Lin { 0xA1, 0xD4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 250e5e85009SJon Lin /* FM25G02BI3 */ 251e5e85009SJon Lin { 0xA1, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 252*a4bd704eSJon Lin /* FM25S02BI3-DND-A-G3 */ 253*a4bd704eSJon Lin { 0xA1, 0xD6, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 254*a4bd704eSJon Lin /* FM25G02D */ 255*a4bd704eSJon Lin { 0xA1, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 256f28847a8SJon Lin 257f28847a8SJon Lin /* IS37SML01G1 */ 258b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 259f28847a8SJon Lin /* F50L1G41LB */ 260b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 261e5e85009SJon Lin /* F50L2G41KA */ 262e5e85009SJon Lin { 0xC8, 0x41, 0x7F, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 263e5e85009SJon Lin 264e5e85009SJon Lin /* UM19A1HISW */ 265e5e85009SJon Lin { 0xB0, 0x24, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 266e5e85009SJon Lin /* UM19A0HCSW */ 267e5e85009SJon Lin { 0xB0, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 268e5e85009SJon Lin /* UM19A0LCSW */ 269e5e85009SJon Lin { 0xB0, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 270e5e85009SJon Lin /* UM19A1LISW */ 271e5e85009SJon Lin { 0xB0, 0x25, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 272*a4bd704eSJon Lin /* UM19A9LISW */ 273*a4bd704eSJon Lin { 0xB0, 0x0D, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 274*a4bd704eSJon Lin /* UM19A9HISW */ 275*a4bd704eSJon Lin { 0xB0, 0x0C, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 276e5e85009SJon Lin 277f28847a8SJon Lin /* ATO25D1GA */ 278b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 279362b1be1SJon Lin /* BWJX08K-2Gb */ 280362b1be1SJon Lin { 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 281629111d3SJon Lin /* JS28U1GQSCAHG-83 */ 282629111d3SJon Lin { 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 2838a654f32SJon Lin /* SGM7000I-S24W1GH */ 2848a654f32SJon Lin { 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 285bf620bf6SJon Lin /* TX25G01 */ 286bf620bf6SJon Lin { 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 287e5e85009SJon Lin 288*a4bd704eSJon Lin /* S35ML01G3, ANV1GCP0CLG, HYF1GQ4UTXCAE, YX25G1E, GSS01GSAM0 */ 289f5e7a59fSJon Lin { 0x01, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status9 }, 290e5e85009SJon Lin /* S35ML02G3, ANV2GCP0CLG, HYF2GQ4UTXCAE, YX25G2E */ 291f5e7a59fSJon Lin { 0x01, 0x25, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 }, 292d4db0b8dSJon Lin /* S35ML04G3 */ 293f5e7a59fSJon Lin { 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 }, 294e5e85009SJon Lin 29506efa4f9SJon Lin /* GSS01GSAK1 */ 29606efa4f9SJon Lin { 0x52, 0xBA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 29706efa4f9SJon Lin /* GSS02GSAK1 */ 29806efa4f9SJon Lin { 0x52, 0xBA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 299*a4bd704eSJon Lin /* GSS02GSAX1 */ 300*a4bd704eSJon Lin { 0x52, 0xCA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 301*a4bd704eSJon Lin /* GSS01GSAX1 */ 302*a4bd704eSJon Lin { 0x52, 0xCA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 303e5e85009SJon Lin 304e5e85009SJon Lin /* XCSP2AAPK */ 305e5e85009SJon Lin { 0x8C, 0xA1, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 306e5e85009SJon Lin /* XCSP1AAPK */ 307e5e85009SJon Lin { 0x8C, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 308*a4bd704eSJon Lin /* F50L1G41LC */ 309*a4bd704eSJon Lin { 0x8C, 0x2C, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 310*a4bd704eSJon Lin 311*a4bd704eSJon Lin /* ZB35Q01BYIG */ 312*a4bd704eSJon Lin { 0x5E, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 313*a4bd704eSJon Lin /* ZB35Q04BYIG */ 314*a4bd704eSJon Lin { 0x5E, 0xA3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 315*a4bd704eSJon Lin 316*a4bd704eSJon Lin /* HSESYHDSW2G */ 317*a4bd704eSJon Lin { 0x3C, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 318ba0501acSDingqiang Lin }; 319ba0501acSDingqiang Lin 320ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 321ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 322ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 323ba0501acSDingqiang Lin 324a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 325ba0501acSDingqiang Lin { 326ba0501acSDingqiang Lin u32 i; 327ba0501acSDingqiang Lin 328ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 329b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 330b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 331b833c879SJon Lin if (spi_nand_tbl[i].id2 && 332b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 333b833c879SJon Lin continue; 334b833c879SJon Lin 335ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 336ba0501acSDingqiang Lin } 337b833c879SJon Lin } 338f28847a8SJon Lin 339ba0501acSDingqiang Lin return NULL; 340ba0501acSDingqiang Lin } 341ba0501acSDingqiang Lin 342ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 343ba0501acSDingqiang Lin { 344ba0501acSDingqiang Lin int ret; 34558463f4dSJon Lin struct rk_sfc_op op; 346ba0501acSDingqiang Lin 34758463f4dSJon Lin op.sfcmd.d32 = 0; 34858463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 34958463f4dSJon Lin 35058463f4dSJon Lin op.sfctrl.d32 = 0; 35158463f4dSJon Lin 35258463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 353ba0501acSDingqiang Lin return ret; 354ba0501acSDingqiang Lin } 355ba0501acSDingqiang Lin 356ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 357ba0501acSDingqiang Lin { 358ba0501acSDingqiang Lin int ret; 35958463f4dSJon Lin struct rk_sfc_op op; 360ba0501acSDingqiang Lin 36158463f4dSJon Lin op.sfcmd.d32 = 0; 362f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 363f28847a8SJon Lin op.sfcmd.b.cs = 2; 364ba0501acSDingqiang Lin 36558463f4dSJon Lin op.sfctrl.d32 = 0; 36658463f4dSJon Lin op.sfctrl.b.datalines = 2; 367f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 368f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 36958463f4dSJon Lin 370f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 371ba0501acSDingqiang Lin return ret; 372ba0501acSDingqiang Lin } 373ba0501acSDingqiang Lin 374ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 375ba0501acSDingqiang Lin { 376ba0501acSDingqiang Lin int ret; 37758463f4dSJon Lin struct rk_sfc_op op; 378ba0501acSDingqiang Lin 37958463f4dSJon Lin op.sfcmd.d32 = 0; 38058463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 38158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 38258463f4dSJon Lin 38358463f4dSJon Lin op.sfctrl.d32 = 0; 38458463f4dSJon Lin op.sfctrl.b.addrbits = 8; 38558463f4dSJon Lin 386ba0501acSDingqiang Lin *data = 0; 387ba0501acSDingqiang Lin 38858463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 389f28847a8SJon Lin 390ba0501acSDingqiang Lin if (ret != SFC_OK) 391ba0501acSDingqiang Lin return ret; 392f28847a8SJon Lin 393ba0501acSDingqiang Lin return SFC_OK; 394ba0501acSDingqiang Lin } 395ba0501acSDingqiang Lin 396ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 397ba0501acSDingqiang Lin { 398ba0501acSDingqiang Lin int ret; 39958463f4dSJon Lin struct rk_sfc_op op; 400ba0501acSDingqiang Lin 401ba0501acSDingqiang Lin sfc_nand_write_en(); 402ba0501acSDingqiang Lin 40358463f4dSJon Lin op.sfcmd.d32 = 0; 40458463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 40558463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 40658463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 407ba0501acSDingqiang Lin 40858463f4dSJon Lin op.sfctrl.d32 = 0; 40958463f4dSJon Lin op.sfctrl.b.addrbits = 8; 41058463f4dSJon Lin 41158463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 412f28847a8SJon Lin 413ba0501acSDingqiang Lin if (ret != SFC_OK) 414ba0501acSDingqiang Lin return ret; 415f28847a8SJon Lin 416ba0501acSDingqiang Lin return ret; 417ba0501acSDingqiang Lin } 418ba0501acSDingqiang Lin 419ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 420ba0501acSDingqiang Lin { 421ba0501acSDingqiang Lin int ret; 422ba0501acSDingqiang Lin int i; 423ba0501acSDingqiang Lin u8 status; 424ba0501acSDingqiang Lin 425ba0501acSDingqiang Lin *data = 0; 426f28847a8SJon Lin 427ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 428ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 429f28847a8SJon Lin 430ba0501acSDingqiang Lin if (ret != SFC_OK) 431ba0501acSDingqiang Lin return ret; 432f28847a8SJon Lin 433ba0501acSDingqiang Lin *data = status; 434f28847a8SJon Lin 435ba0501acSDingqiang Lin if (!(status & (1 << 0))) 436ba0501acSDingqiang Lin return SFC_OK; 437f28847a8SJon Lin 438ba0501acSDingqiang Lin sfc_delay(1); 439ba0501acSDingqiang Lin } 440f28847a8SJon Lin 441f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 442ba0501acSDingqiang Lin } 443ba0501acSDingqiang Lin 4446281205aSDingqiang Lin /* 4456281205aSDingqiang Lin * ecc default: 446a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 447f28847a8SJon Lin * 0b00, No bit errors were detected 448f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 449f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 450f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 451362b1be1SJon Lin * reach the bit flip detection threshold 4526281205aSDingqiang Lin */ 453f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 4546281205aSDingqiang Lin { 45558463f4dSJon Lin u32 ret; 4566281205aSDingqiang Lin u32 i; 4576281205aSDingqiang Lin u8 ecc; 4586281205aSDingqiang Lin u8 status; 4596281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4606281205aSDingqiang Lin 4616281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4626281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 463f28847a8SJon Lin 4646281205aSDingqiang Lin if (ret != SFC_OK) 4656281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 466f28847a8SJon Lin 4676281205aSDingqiang Lin if (!(status & (1 << 0))) 4686281205aSDingqiang Lin break; 469f28847a8SJon Lin 4706281205aSDingqiang Lin sfc_delay(1); 4716281205aSDingqiang Lin } 4726281205aSDingqiang Lin 4736281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4746281205aSDingqiang Lin 4756281205aSDingqiang Lin if (ecc <= 1) 4766281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4776281205aSDingqiang Lin else if (ecc == 2) 47858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4796281205aSDingqiang Lin else 4806281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4816281205aSDingqiang Lin 4826281205aSDingqiang Lin return ret; 4836281205aSDingqiang Lin } 4846281205aSDingqiang Lin 4856281205aSDingqiang Lin /* 4866281205aSDingqiang Lin * ecc spectial type1: 487a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 488f28847a8SJon Lin * 0b00, No bit errors were detected; 489f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 4906281205aSDingqiang Lin * may reach the bit flip detection threshold; 491f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 492f28847a8SJon Lin * 0b11, Reserved. 4936281205aSDingqiang Lin */ 494f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 4956281205aSDingqiang Lin { 49658463f4dSJon Lin u32 ret; 4976281205aSDingqiang Lin u32 i; 4986281205aSDingqiang Lin u8 ecc; 4996281205aSDingqiang Lin u8 status; 5006281205aSDingqiang Lin u32 timeout = 1000 * 1000; 5016281205aSDingqiang Lin 5026281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 5036281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 504f28847a8SJon Lin 5056281205aSDingqiang Lin if (ret != SFC_OK) 5066281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 507f28847a8SJon Lin 5086281205aSDingqiang Lin if (!(status & (1 << 0))) 5096281205aSDingqiang Lin break; 510f28847a8SJon Lin 5116281205aSDingqiang Lin sfc_delay(1); 5126281205aSDingqiang Lin } 5136281205aSDingqiang Lin 5146281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 5156281205aSDingqiang Lin 5166281205aSDingqiang Lin if (ecc == 0) 5176281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 5186281205aSDingqiang Lin else if (ecc == 1) 5196281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 5206281205aSDingqiang Lin else 52158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 5226281205aSDingqiang Lin 5236281205aSDingqiang Lin return ret; 5246281205aSDingqiang Lin } 5256281205aSDingqiang Lin 5266281205aSDingqiang Lin /* 527d9cdd318SJon Lin * ecc spectial type2: 528a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 529f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 530f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 531d9cdd318SJon Lin * reach Flipping Bits; 532f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 533c84f0ed8SJon Lin * not corrected. 534f28847a8SJon Lin * [0b1100, 0b1111], reserved. 535d9cdd318SJon Lin */ 536f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 537d9cdd318SJon Lin { 53858463f4dSJon Lin u32 ret; 539d9cdd318SJon Lin u32 i; 540d9cdd318SJon Lin u8 ecc; 541d9cdd318SJon Lin u8 status, status1; 542d9cdd318SJon Lin u32 timeout = 1000 * 1000; 543d9cdd318SJon Lin 544d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 545d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 546f28847a8SJon Lin 547d9cdd318SJon Lin if (ret != SFC_OK) 548d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 549f28847a8SJon Lin 550d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 551f28847a8SJon Lin 552d9cdd318SJon Lin if (ret != SFC_OK) 553d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 554f28847a8SJon Lin 555d9cdd318SJon Lin if (!(status & (1 << 0))) 556d9cdd318SJon Lin break; 557f28847a8SJon Lin 558d9cdd318SJon Lin sfc_delay(1); 559d9cdd318SJon Lin } 560d9cdd318SJon Lin 561d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 562d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 563f28847a8SJon Lin 564d9cdd318SJon Lin if (ecc < 7) 565d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 566d9cdd318SJon Lin else if (ecc == 7) 567d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 568d9cdd318SJon Lin else 56958463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 570d9cdd318SJon Lin 571d9cdd318SJon Lin return ret; 572d9cdd318SJon Lin } 573d9cdd318SJon Lin 574d9cdd318SJon Lin /* 5756281205aSDingqiang Lin * ecc spectial type3: 576a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 577f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 578f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 5796281205aSDingqiang Lin * reach Flipping Bits; 580f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 5816281205aSDingqiang Lin * not corrected. 582f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 5836281205aSDingqiang Lin * detectio nthreshold 5846281205aSDingqiang Lin */ 585f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 5866281205aSDingqiang Lin { 58758463f4dSJon Lin u32 ret; 5886281205aSDingqiang Lin u32 i; 5896281205aSDingqiang Lin u8 ecc; 5906281205aSDingqiang Lin u8 status, status1; 5916281205aSDingqiang Lin u32 timeout = 1000 * 1000; 5926281205aSDingqiang Lin 5936281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 5946281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 595f28847a8SJon Lin 5966281205aSDingqiang Lin if (ret != SFC_OK) 5976281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 598f28847a8SJon Lin 5996281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 600f28847a8SJon Lin 6016281205aSDingqiang Lin if (ret != SFC_OK) 6026281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 603f28847a8SJon Lin 6046281205aSDingqiang Lin if (!(status & (1 << 0))) 6056281205aSDingqiang Lin break; 606f28847a8SJon Lin 6076281205aSDingqiang Lin sfc_delay(1); 6086281205aSDingqiang Lin } 6096281205aSDingqiang Lin 6106281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 6116281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 612f28847a8SJon Lin 6136281205aSDingqiang Lin if (ecc < 7) 6146281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 6156281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 6166281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 6176281205aSDingqiang Lin else 61858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 6196281205aSDingqiang Lin 6206281205aSDingqiang Lin return ret; 6216281205aSDingqiang Lin } 6226281205aSDingqiang Lin 62325098c06SDingqiang Lin /* 62425098c06SDingqiang Lin * ecc spectial type4: 625a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 626f28847a8SJon Lin * [0b0000], No bit errors were detected; 627f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 62825098c06SDingqiang Lin * reach Flipping Bits; 629f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 63025098c06SDingqiang Lin * not corrected. 631f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 63225098c06SDingqiang Lin * detection threshold 63325098c06SDingqiang Lin * else, reserved 63425098c06SDingqiang Lin */ 635f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 63625098c06SDingqiang Lin { 63758463f4dSJon Lin u32 ret; 63825098c06SDingqiang Lin u32 i; 63925098c06SDingqiang Lin u8 ecc; 64025098c06SDingqiang Lin u8 status; 64125098c06SDingqiang Lin u32 timeout = 1000 * 1000; 64225098c06SDingqiang Lin 64325098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 64425098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 645f28847a8SJon Lin 64625098c06SDingqiang Lin if (ret != SFC_OK) 64725098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 648f28847a8SJon Lin 64925098c06SDingqiang Lin if (!(status & (1 << 0))) 65025098c06SDingqiang Lin break; 651f28847a8SJon Lin 65225098c06SDingqiang Lin sfc_delay(1); 65325098c06SDingqiang Lin } 65425098c06SDingqiang Lin 65525098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 656f28847a8SJon Lin 65725098c06SDingqiang Lin if (ecc < 7) 65825098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 65925098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 66025098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 66125098c06SDingqiang Lin else 66258463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 66325098c06SDingqiang Lin 66425098c06SDingqiang Lin return ret; 66525098c06SDingqiang Lin } 66625098c06SDingqiang Lin 66725098c06SDingqiang Lin /* 66825098c06SDingqiang Lin * ecc spectial type5: 669a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 670f28847a8SJon Lin * [0b000], No bit errors were detected; 671f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 67225098c06SDingqiang Lin * reach Flipping Bits; 673f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 67425098c06SDingqiang Lin * detection threshold 675f28847a8SJon Lin * [0b101, 0b110], Reserved; 676f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 67725098c06SDingqiang Lin * not corrected. 67825098c06SDingqiang Lin */ 679f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 68025098c06SDingqiang Lin { 68158463f4dSJon Lin u32 ret; 68225098c06SDingqiang Lin u32 i; 68325098c06SDingqiang Lin u8 ecc; 68425098c06SDingqiang Lin u8 status; 68525098c06SDingqiang Lin u32 timeout = 1000 * 1000; 68625098c06SDingqiang Lin 68725098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 68825098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 689f28847a8SJon Lin 69025098c06SDingqiang Lin if (ret != SFC_OK) 69125098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 692f28847a8SJon Lin 69325098c06SDingqiang Lin if (!(status & (1 << 0))) 69425098c06SDingqiang Lin break; 695f28847a8SJon Lin 69625098c06SDingqiang Lin sfc_delay(1); 69725098c06SDingqiang Lin } 69825098c06SDingqiang Lin 69925098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 700f28847a8SJon Lin 70125098c06SDingqiang Lin if (ecc < 4) 70225098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 70325098c06SDingqiang Lin else if (ecc == 4) 70425098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 70525098c06SDingqiang Lin else 70658463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 70725098c06SDingqiang Lin 70825098c06SDingqiang Lin return ret; 70925098c06SDingqiang Lin } 71025098c06SDingqiang Lin 711f28847a8SJon Lin /* 712f28847a8SJon Lin * ecc spectial type6: 713f28847a8SJon Lin * ecc bits: 0xC0[4,6] 714f28847a8SJon Lin * [0b000], No bit errors were detected; 715f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 716f28847a8SJon Lin * reach Flipping Bits; 717f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 718f28847a8SJon Lin * not corrected. 719f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 720f28847a8SJon Lin * reach Flipping Bits; 721f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 722f28847a8SJon Lin * detectionthreshold 723f28847a8SJon Lin * others, Reserved. 724f28847a8SJon Lin */ 725f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 726f28847a8SJon Lin { 727f28847a8SJon Lin u32 ret; 728f28847a8SJon Lin u32 i; 729f28847a8SJon Lin u8 ecc; 730f28847a8SJon Lin u8 status; 731f28847a8SJon Lin u32 timeout = 1000 * 1000; 732f28847a8SJon Lin 733f28847a8SJon Lin for (i = 0; i < timeout; i++) { 734f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 735f28847a8SJon Lin 736f28847a8SJon Lin if (ret != SFC_OK) 737f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 738f28847a8SJon Lin 739f28847a8SJon Lin if (!(status & (1 << 0))) 740f28847a8SJon Lin break; 741f28847a8SJon Lin 742f28847a8SJon Lin sfc_delay(1); 743f28847a8SJon Lin } 744f28847a8SJon Lin 745f28847a8SJon Lin ecc = (status >> 4) & 0x07; 746f28847a8SJon Lin 747f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 748f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 749f28847a8SJon Lin else if (ecc == 5) 750f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 751f28847a8SJon Lin else 752f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 753f28847a8SJon Lin 754f28847a8SJon Lin return ret; 755f28847a8SJon Lin } 756f28847a8SJon Lin 757362b1be1SJon Lin /* 758362b1be1SJon Lin * ecc spectial type7: 759362b1be1SJon Lin * ecc bits: 0xC0[4,7] 760362b1be1SJon Lin * [0b0000], No bit errors were detected; 761362b1be1SJon Lin * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 762362b1be1SJon Lin * reach Flipping Bits; 763362b1be1SJon Lin * [0b1000], 8 Bit errors were detected and corrected. Bit error count 764362b1be1SJon Lin * equals the bit flip detectionthreshold; 765362b1be1SJon Lin * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 766362b1be1SJon Lin * others, Reserved. 767362b1be1SJon Lin */ 768362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void) 769362b1be1SJon Lin { 770362b1be1SJon Lin u32 ret; 771362b1be1SJon Lin u32 i; 772362b1be1SJon Lin u8 ecc; 773362b1be1SJon Lin u8 status; 774362b1be1SJon Lin u32 timeout = 1000 * 1000; 775362b1be1SJon Lin 776362b1be1SJon Lin for (i = 0; i < timeout; i++) { 777362b1be1SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 778362b1be1SJon Lin 779362b1be1SJon Lin if (ret != SFC_OK) 780362b1be1SJon Lin return SFC_NAND_ECC_ERROR; 781362b1be1SJon Lin 782362b1be1SJon Lin if (!(status & (1 << 0))) 783362b1be1SJon Lin break; 784362b1be1SJon Lin 785362b1be1SJon Lin sfc_delay(1); 786362b1be1SJon Lin } 787362b1be1SJon Lin 788362b1be1SJon Lin ecc = (status >> 4) & 0xf; 789362b1be1SJon Lin 790362b1be1SJon Lin if (ecc < 7) 791362b1be1SJon Lin ret = SFC_NAND_ECC_OK; 792362b1be1SJon Lin else if (ecc == 7 || ecc == 8) 793362b1be1SJon Lin ret = SFC_NAND_ECC_REFRESH; 794362b1be1SJon Lin else 795362b1be1SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 796362b1be1SJon Lin 797362b1be1SJon Lin return ret; 798362b1be1SJon Lin } 799362b1be1SJon Lin 800629111d3SJon Lin /* 801629111d3SJon Lin * ecc spectial type8: 802629111d3SJon Lin * ecc bits: 0xC0[4,6] 803629111d3SJon Lin * [0b000], No bit errors were detected; 804629111d3SJon Lin * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not 805629111d3SJon Lin * reach Flipping Bits; 806629111d3SJon Lin * [0b100], Bit error count equals the bit flip 807629111d3SJon Lin * detection threshold 808629111d3SJon Lin * others, Reserved. 809629111d3SJon Lin */ 810629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void) 811629111d3SJon Lin { 812629111d3SJon Lin u32 ret; 813629111d3SJon Lin u32 i; 814629111d3SJon Lin u8 ecc; 815629111d3SJon Lin u8 status; 816629111d3SJon Lin u32 timeout = 1000 * 1000; 817629111d3SJon Lin 818629111d3SJon Lin for (i = 0; i < timeout; i++) { 819629111d3SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 820629111d3SJon Lin 821629111d3SJon Lin if (ret != SFC_OK) 822629111d3SJon Lin return SFC_NAND_ECC_ERROR; 823629111d3SJon Lin 824629111d3SJon Lin if (!(status & (1 << 0))) 825629111d3SJon Lin break; 826629111d3SJon Lin 827629111d3SJon Lin sfc_delay(1); 828629111d3SJon Lin } 829629111d3SJon Lin 830629111d3SJon Lin ecc = (status >> 4) & 0x07; 831629111d3SJon Lin 832629111d3SJon Lin if (ecc < 4) 833629111d3SJon Lin ret = SFC_NAND_ECC_OK; 834629111d3SJon Lin else if (ecc == 4) 835629111d3SJon Lin ret = SFC_NAND_ECC_REFRESH; 836629111d3SJon Lin else 837629111d3SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 838629111d3SJon Lin 839629111d3SJon Lin return ret; 840629111d3SJon Lin } 841629111d3SJon Lin 842d4db0b8dSJon Lin /* 843d4db0b8dSJon Lin * ecc spectial type9: 844d4db0b8dSJon Lin * ecc bits: 0xC0[4,5] 845d4db0b8dSJon Lin * 0b00, No bit errors were detected 846d4db0b8dSJon Lin * 0b01, 1-2Bit errors were detected and corrected. 847d4db0b8dSJon Lin * 0b10, 3-4Bit errors were detected and corrected. 848d4db0b8dSJon Lin * 0b11, 11 can be used as uncorrectable 849d4db0b8dSJon Lin */ 850d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void) 851d4db0b8dSJon Lin { 852d4db0b8dSJon Lin u32 ret; 853d4db0b8dSJon Lin u32 i; 854d4db0b8dSJon Lin u8 ecc; 855d4db0b8dSJon Lin u8 status; 856d4db0b8dSJon Lin u32 timeout = 1000 * 1000; 857d4db0b8dSJon Lin 858d4db0b8dSJon Lin for (i = 0; i < timeout; i++) { 859d4db0b8dSJon Lin ret = sfc_nand_read_feature(0xC0, &status); 860d4db0b8dSJon Lin 861d4db0b8dSJon Lin if (ret != SFC_OK) 862d4db0b8dSJon Lin return SFC_NAND_ECC_ERROR; 863d4db0b8dSJon Lin 864d4db0b8dSJon Lin if (!(status & (1 << 0))) 865d4db0b8dSJon Lin break; 866d4db0b8dSJon Lin 867d4db0b8dSJon Lin sfc_delay(1); 868d4db0b8dSJon Lin } 869d4db0b8dSJon Lin 870d4db0b8dSJon Lin ecc = (status >> 4) & 0x03; 871d4db0b8dSJon Lin 872d4db0b8dSJon Lin if (ecc <= 1) 873d4db0b8dSJon Lin ret = SFC_NAND_ECC_OK; 874d4db0b8dSJon Lin else if (ecc == 2) 875d4db0b8dSJon Lin ret = SFC_NAND_ECC_REFRESH; 876d4db0b8dSJon Lin else 877d4db0b8dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 878d4db0b8dSJon Lin 879d4db0b8dSJon Lin return ret; 880d4db0b8dSJon Lin } 881d4db0b8dSJon Lin 882*a4bd704eSJon Lin /* 883*a4bd704eSJon Lin * ecc spectial type8: 884*a4bd704eSJon Lin * ecc bits: 0xC0[4,6] 885*a4bd704eSJon Lin * [0b000], No bit errors were detected; 886*a4bd704eSJon Lin * [0b001, 0b101], 3~7 Bit errors were detected and corrected. Not 887*a4bd704eSJon Lin * reach Flipping Bits; 888*a4bd704eSJon Lin * [0b110], Bit error count equals the bit flip detection threshold 889*a4bd704eSJon Lin * [0b111], Bit errors greater than ECC capability(8 bits) and not corrected; 890*a4bd704eSJon Lin */ 891*a4bd704eSJon Lin static u32 sfc_nand_get_ecc_status10(void) 892*a4bd704eSJon Lin { 893*a4bd704eSJon Lin u32 ret; 894*a4bd704eSJon Lin u32 i; 895*a4bd704eSJon Lin u8 ecc; 896*a4bd704eSJon Lin u8 status; 897*a4bd704eSJon Lin u32 timeout = 1000 * 1000; 898*a4bd704eSJon Lin 899*a4bd704eSJon Lin for (i = 0; i < timeout; i++) { 900*a4bd704eSJon Lin ret = sfc_nand_read_feature(0xC0, &status); 901*a4bd704eSJon Lin 902*a4bd704eSJon Lin if (ret != SFC_OK) 903*a4bd704eSJon Lin return SFC_NAND_ECC_ERROR; 904*a4bd704eSJon Lin 905*a4bd704eSJon Lin if (!(status & (1 << 0))) 906*a4bd704eSJon Lin break; 907*a4bd704eSJon Lin 908*a4bd704eSJon Lin sfc_delay(1); 909*a4bd704eSJon Lin } 910*a4bd704eSJon Lin 911*a4bd704eSJon Lin ecc = (status >> 4) & 0x07; 912*a4bd704eSJon Lin 913*a4bd704eSJon Lin if (ecc < 6) 914*a4bd704eSJon Lin ret = SFC_NAND_ECC_OK; 915*a4bd704eSJon Lin else if (ecc == 6) 916*a4bd704eSJon Lin ret = SFC_NAND_ECC_REFRESH; 917*a4bd704eSJon Lin else 918*a4bd704eSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 919*a4bd704eSJon Lin 920*a4bd704eSJon Lin return ret; 921*a4bd704eSJon Lin } 922*a4bd704eSJon Lin 923c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 924ba0501acSDingqiang Lin { 925ba0501acSDingqiang Lin int ret; 92658463f4dSJon Lin struct rk_sfc_op op; 927ba0501acSDingqiang Lin u8 status; 928ba0501acSDingqiang Lin 929c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 93058463f4dSJon Lin op.sfcmd.d32 = 0; 931f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 93258463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 93358463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 93458463f4dSJon Lin 93558463f4dSJon Lin op.sfctrl.d32 = 0; 93658463f4dSJon Lin 937ba0501acSDingqiang Lin sfc_nand_write_en(); 93858463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 939f28847a8SJon Lin 940ba0501acSDingqiang Lin if (ret != SFC_OK) 941ba0501acSDingqiang Lin return ret; 942f28847a8SJon Lin 943ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 944f28847a8SJon Lin 945ba0501acSDingqiang Lin if (status & (1 << 2)) 946ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 947c84f0ed8SJon Lin 948ba0501acSDingqiang Lin return ret; 949ba0501acSDingqiang Lin } 950ba0501acSDingqiang Lin 951629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len) 952629111d3SJon Lin { 953629111d3SJon Lin int ret; 954629111d3SJon Lin u32 plane; 955629111d3SJon Lin struct rk_sfc_op op; 956629111d3SJon Lin 957629111d3SJon Lin op.sfcmd.d32 = 0; 958629111d3SJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 959629111d3SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 960629111d3SJon Lin op.sfcmd.b.dummybits = 8; 961629111d3SJon Lin 962629111d3SJon Lin op.sfctrl.d32 = 0; 963629111d3SJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 964629111d3SJon Lin op.sfctrl.b.addrbits = 16; 965629111d3SJon Lin 966629111d3SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 967629111d3SJon Lin 968629111d3SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 969629111d3SJon Lin if (ret != SFC_OK) 970629111d3SJon Lin return SFC_NAND_HW_ERROR; 971629111d3SJon Lin 972629111d3SJon Lin return ret; 973629111d3SJon Lin } 974629111d3SJon Lin 975f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 976ba0501acSDingqiang Lin { 977ba0501acSDingqiang Lin int ret; 978415cf080Sjon.lin u32 plane; 97958463f4dSJon Lin struct rk_sfc_op op; 980ba0501acSDingqiang Lin u8 status; 98158463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 982629111d3SJon Lin u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page; 983ba0501acSDingqiang Lin 984c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 985ba0501acSDingqiang Lin sfc_nand_write_en(); 986f28847a8SJon Lin 987ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 98825098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 98925098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 990ba0501acSDingqiang Lin sfc_nand_rw_preset(); 991ba0501acSDingqiang Lin 99258463f4dSJon Lin op.sfcmd.d32 = 0; 99358463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 99458463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 99558463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 996ba0501acSDingqiang Lin 99758463f4dSJon Lin op.sfctrl.d32 = 0; 99858463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 99958463f4dSJon Lin op.sfctrl.b.addrbits = 16; 1000415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 100158463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 1002ba0501acSDingqiang Lin 1003629111d3SJon Lin /* 1004c797b43aSJon Lin * At the moment of power lost or dev running in harsh environment, flash 1005c797b43aSJon Lin * maybe work in a unkonw state and result in bit flip, when this situation 1006c797b43aSJon Lin * is detected by cache recheck, it's better to wait a second for a reliable 1007c797b43aSJon Lin * hardware environment to avoid abnormal data written to flash array. 1008629111d3SJon Lin */ 1009361684bfSJon Lin if (p_nand_info->id0 == MID_GIGADEV) { 1010629111d3SJon Lin sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size); 1011c797b43aSJon Lin if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) { 1012c797b43aSJon Lin rkflash_print_error("%s %x cache bitflip\n", __func__, addr); 1013c797b43aSJon Lin mdelay(1000); 1014c797b43aSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 1015c797b43aSJon Lin } 1016c797b43aSJon Lin } 1017629111d3SJon Lin 101858463f4dSJon Lin op.sfcmd.d32 = 0; 1019f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 102058463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 102158463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 102258463f4dSJon Lin 102358463f4dSJon Lin op.sfctrl.d32 = 0; 102458463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 1025f28847a8SJon Lin 1026ba0501acSDingqiang Lin if (ret != SFC_OK) 1027ba0501acSDingqiang Lin return ret; 1028f28847a8SJon Lin 1029ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 1030ba0501acSDingqiang Lin if (status & (1 << 3)) 1031ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 1032c84f0ed8SJon Lin 1033ba0501acSDingqiang Lin return ret; 1034ba0501acSDingqiang Lin } 1035ba0501acSDingqiang Lin 1036c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 1037c84f0ed8SJon Lin { 1038c84f0ed8SJon Lin int ret; 1039c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 1040c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 1041a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 1042c84f0ed8SJon Lin 1043c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 1044c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 1045a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 1046a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 1047f28847a8SJon Lin 1048c84f0ed8SJon Lin if (sec_per_page == 8) { 1049a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 1050a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 1051c84f0ed8SJon Lin } 1052f28847a8SJon Lin 1053c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 1054c84f0ed8SJon Lin 1055c84f0ed8SJon Lin return ret; 1056c84f0ed8SJon Lin } 1057c84f0ed8SJon Lin 1058a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 1059ba0501acSDingqiang Lin { 1060ba0501acSDingqiang Lin int ret; 1061415cf080Sjon.lin u32 plane; 106258463f4dSJon Lin struct rk_sfc_op op; 10636281205aSDingqiang Lin u32 ecc_result; 1064a6fcac41SJon Lin u8 status; 1065ba0501acSDingqiang Lin 106658463f4dSJon Lin op.sfcmd.d32 = 0; 1067f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 106858463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 106958463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 107058463f4dSJon Lin 107158463f4dSJon Lin op.sfctrl.d32 = 0; 107258463f4dSJon Lin 1073a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 1074f28847a8SJon Lin 1075ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 107625098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 107725098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 1078ba0501acSDingqiang Lin sfc_nand_rw_preset(); 1079ba0501acSDingqiang Lin 1080a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 1081e5e85009SJon Lin if (sfc_nand_dev.manufacturer == 0x01 && status) 1082e5e85009SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 1083e5e85009SJon Lin 1084a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 1085a6fcac41SJon Lin 108658463f4dSJon Lin op.sfcmd.d32 = 0; 108758463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 1088a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 1089a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 109058463f4dSJon Lin 109158463f4dSJon Lin op.sfctrl.d32 = 0; 109258463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 1093a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 1094ba0501acSDingqiang Lin 1095a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 1096a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 1097a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 1098c84f0ed8SJon Lin 1099c84f0ed8SJon Lin if (ret != SFC_OK) 1100f28847a8SJon Lin return SFC_NAND_HW_ERROR; 1101c84f0ed8SJon Lin 1102c84f0ed8SJon Lin return ecc_result; 1103c84f0ed8SJon Lin } 1104c84f0ed8SJon Lin 1105a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 1106a80fd396SJon Lin { 1107a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 1108a80fd396SJon Lin 1109a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 1110a80fd396SJon Lin } 1111a80fd396SJon Lin 1112c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 1113c84f0ed8SJon Lin { 111458463f4dSJon Lin u32 ret; 1115c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 1116c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 1117a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 1118c84f0ed8SJon Lin 1119c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 1120f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 1121a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 1122a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 1123f28847a8SJon Lin 1124f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 1125a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 1126a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 1127f25e3cafSJon Lin } 1128ba0501acSDingqiang Lin 1129f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 1130f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 1131f28847a8SJon Lin 1132c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 1133c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 1134f28847a8SJon Lin 1135ba0501acSDingqiang Lin if (p_data) 1136c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 1137f28847a8SJon Lin 1138ba0501acSDingqiang Lin if (p_spare) 1139c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 1140ba0501acSDingqiang Lin } 1141f25e3cafSJon Lin 1142c84f0ed8SJon Lin return ret; 1143ba0501acSDingqiang Lin } 1144ba0501acSDingqiang Lin 1145c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 1146c84f0ed8SJon Lin { 1147c84f0ed8SJon Lin u32 ret; 1148c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 1149a80fd396SJon Lin u32 marker = 0; 1150c84f0ed8SJon Lin 1151a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 1152f28847a8SJon Lin 1153f28847a8SJon Lin /* unify with mtd framework */ 1154629111d3SJon Lin if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff) 1155a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 1156a80fd396SJon Lin __func__, addr, ret, marker); 1157f28847a8SJon Lin 1158c84f0ed8SJon Lin /* Original bad block */ 1159a80fd396SJon Lin if ((u16)marker != 0xffff) 1160c84f0ed8SJon Lin return true; 1161c84f0ed8SJon Lin 1162c84f0ed8SJon Lin return false; 1163c84f0ed8SJon Lin } 1164c84f0ed8SJon Lin 1165c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 1166c84f0ed8SJon Lin { 1167c84f0ed8SJon Lin u32 ret; 1168c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 1169c84f0ed8SJon Lin 1170c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 1171f28847a8SJon Lin 1172c84f0ed8SJon Lin if (ret) 1173c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 1174f28847a8SJon Lin 1175c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 1176c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 1177f28847a8SJon Lin 1178c84f0ed8SJon Lin if (ret) 1179c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 1180c84f0ed8SJon Lin 1181c84f0ed8SJon Lin return ret; 1182c84f0ed8SJon Lin } 1183c84f0ed8SJon Lin 1184c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 1185ba0501acSDingqiang Lin { 1186ba0501acSDingqiang Lin int ret; 118758463f4dSJon Lin struct rk_sfc_op op; 1188ba0501acSDingqiang Lin 118958463f4dSJon Lin op.sfcmd.d32 = 0; 119058463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 119158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 1192ba0501acSDingqiang Lin 119358463f4dSJon Lin op.sfctrl.d32 = 0; 119458463f4dSJon Lin op.sfctrl.b.addrbits = 8; 119558463f4dSJon Lin 119658463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 1197ba0501acSDingqiang Lin 1198ba0501acSDingqiang Lin return ret; 1199ba0501acSDingqiang Lin } 1200ba0501acSDingqiang Lin 1201ba0501acSDingqiang Lin /* 1202ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 1203ba0501acSDingqiang Lin * If not FF, it's bad blk 1204ba0501acSDingqiang Lin */ 1205ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 1206ba0501acSDingqiang Lin { 1207ba0501acSDingqiang Lin u32 bad_cnt, page; 1208ba0501acSDingqiang Lin u32 blk_per_die; 12092ac88c1bSJon Lin u16 blk; 1210ba0501acSDingqiang Lin 1211c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 1212c84f0ed8SJon Lin 1213ba0501acSDingqiang Lin bad_cnt = 0; 1214ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 1215ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1216f28847a8SJon Lin 1217ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 1218ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 1219ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1220ba0501acSDingqiang Lin 12212ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 1222ba0501acSDingqiang Lin table[bad_cnt++] = blk; 1223c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 1224ba0501acSDingqiang Lin } 1225ba0501acSDingqiang Lin } 1226f28847a8SJon Lin 1227ba0501acSDingqiang Lin return (int)bad_cnt; 1228ba0501acSDingqiang Lin } 1229ba0501acSDingqiang Lin 1230c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 1231ba0501acSDingqiang Lin { 1232ba0501acSDingqiang Lin /* para init */ 1233ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 1234ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 1235ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 1236ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 1237ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 1238ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 1239c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 1240ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 1241ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 1242ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1243ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 1244ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 1245ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1246ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 1247ba0501acSDingqiang Lin 1248ba0501acSDingqiang Lin /* driver register */ 1249ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 1250ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 1251ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 1252ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 125357d18453Sjon.lin g_nand_ops.bch_sel = NULL; 1254ba0501acSDingqiang Lin } 1255ba0501acSDingqiang Lin 1256a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 1257ba0501acSDingqiang Lin { 1258ba0501acSDingqiang Lin int ret = SFC_OK; 1259ba0501acSDingqiang Lin u8 status; 1260ba0501acSDingqiang Lin 1261f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 1262ba0501acSDingqiang Lin 1263ba0501acSDingqiang Lin if (ret != SFC_OK) 1264ba0501acSDingqiang Lin return ret; 1265ba0501acSDingqiang Lin 1266f28847a8SJon Lin if (status & 1) /* is QE bit set */ 1267ba0501acSDingqiang Lin return SFC_OK; 1268ba0501acSDingqiang Lin 1269f28847a8SJon Lin status |= 1; 1270ba0501acSDingqiang Lin 1271f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 1272ba0501acSDingqiang Lin } 1273ba0501acSDingqiang Lin 1274ba0501acSDingqiang Lin u32 sfc_nand_init(void) 1275ba0501acSDingqiang Lin { 1276c84f0ed8SJon Lin u8 status, id_byte[8]; 1277ba0501acSDingqiang Lin 1278c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 1279c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 1280ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 1281f28847a8SJon Lin 1282ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 128358463f4dSJon Lin return (u32)FTL_NO_FLASH; 1284ba0501acSDingqiang Lin 1285a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 1286f28847a8SJon Lin 128745292245SJon Lin if (!p_nand_info) { 128845292245SJon Lin pr_err("The device not support yet!\n"); 128945292245SJon Lin 129058463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 129145292245SJon Lin } 1292ba0501acSDingqiang Lin 1293ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 1294ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 1295c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 1296c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 1297c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 1298ba0501acSDingqiang Lin 1299ba0501acSDingqiang Lin /* disable block lock */ 1300ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 1301ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 1302ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 1303f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 1304f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 1305629111d3SJon Lin sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE); 1306629111d3SJon Lin if (!sfc_nand_dev.recheck_buffer) { 1307629111d3SJon Lin rkflash_print_error("%s recheck_buffer alloc failed\n", __func__); 1308629111d3SJon Lin return -1; 1309629111d3SJon Lin } 1310f28847a8SJon Lin 1311ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 1312f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 1313f28847a8SJon Lin !p_nand_info->has_qe_bits) { 1314ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 1315f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 1316ba0501acSDingqiang Lin } 1317ba0501acSDingqiang Lin } 1318ba0501acSDingqiang Lin 1319ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 1320ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 1321ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 1322f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 1323ba0501acSDingqiang Lin } 1324ba0501acSDingqiang Lin 1325ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 1326c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 1327ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 1328c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 1329c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 1330c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 1331c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 1332c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 1333ba0501acSDingqiang Lin 1334ba0501acSDingqiang Lin return SFC_OK; 1335ba0501acSDingqiang Lin } 1336ba0501acSDingqiang Lin 1337c84f0ed8SJon Lin void sfc_nand_deinit(void) 1338ba0501acSDingqiang Lin { 1339c84f0ed8SJon Lin /* to-do */ 1340629111d3SJon Lin kfree(sfc_nand_dev.recheck_buffer); 1341ba0501acSDingqiang Lin } 1342c84f0ed8SJon Lin 1343c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 1344c84f0ed8SJon Lin { 1345c84f0ed8SJon Lin return &sfc_nand_dev; 1346c84f0ed8SJon Lin } 1347c84f0ed8SJon Lin 1348