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); 26f28847a8SJon Lin 27ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 28ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 29b833c879SJon Lin { 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 30ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 31b833c879SJon Lin { 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 32a6fcac41SJon Lin /* TC58CVG2S0HRAIJ */ 33b833c879SJon Lin { 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 }, 34a6fcac41SJon Lin /* TC58CVG1S3HRAIJ */ 35b833c879SJon Lin { 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 36a6fcac41SJon Lin /* TC58CVG0S3HRAIJ */ 37b833c879SJon Lin { 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 38f28847a8SJon Lin 39f28847a8SJon Lin /* MX35LF1GE4AB */ 40b833c879SJon Lin { 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 41f28847a8SJon Lin /* MX35LF2GE4AB */ 42b833c879SJon Lin { 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 43f28847a8SJon Lin /* MX35LF2GE4AD */ 44b833c879SJon Lin { 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 45f28847a8SJon Lin /* MX35LF4GE4AD */ 46362b1be1SJon Lin { 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 47362b1be1SJon Lin /* MX35UF1GE4AC */ 48362b1be1SJon Lin { 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 49362b1be1SJon Lin /* MX35UF2GE4AC */ 50362b1be1SJon Lin { 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 51f28847a8SJon Lin 52f28847a8SJon Lin /* GD5F1GQ4UAYIG */ 53b833c879SJon Lin { 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 54f28847a8SJon Lin /* GD5F1GQ4RB9IGR */ 55b833c879SJon Lin { 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 56f28847a8SJon Lin /* GD5F2GQ40BY2GR */ 57b833c879SJon Lin { 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 58f28847a8SJon Lin /* GD5F1GQ5UEYIG */ 59b833c879SJon Lin { 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 60f28847a8SJon Lin /* GD5F2GQ5UEYIG */ 61b833c879SJon Lin { 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 62f28847a8SJon Lin /* GD5F1GQ4R */ 63b833c879SJon Lin { 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 64362b1be1SJon Lin /* GD5F4GQ6RExxG 1*4096 */ 65362b1be1SJon Lin { 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 }, 66362b1be1SJon Lin /* GD5F4GQ6UExxG 1*4096 */ 67362b1be1SJon Lin { 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 }, 688a654f32SJon Lin /* GD5F1GQ4UExxH */ 698a654f32SJon Lin { 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 70bf620bf6SJon Lin /* GD5F1GQ5REYIG */ 71bf620bf6SJon Lin { 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 72bf620bf6SJon Lin /* GD5F2GQ5REYIG */ 73bf620bf6SJon Lin { 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 74bf620bf6SJon Lin /* GD5F2GM7RxG */ 75bf620bf6SJon Lin { 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 76bf620bf6SJon Lin /* GD5F2GM7UxG */ 77bf620bf6SJon Lin { 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 7845292245SJon Lin /* GD5F1GM7UxG */ 7945292245SJon Lin { 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 80f28847a8SJon Lin 81f28847a8SJon Lin /* W25N01GV */ 82b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 83b833c879SJon Lin /* W25N02KVZEIR */ 84b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 85629111d3SJon Lin /* W25N04KVZEIR */ 86629111d3SJon Lin { 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 }, 87f28847a8SJon Lin /* W25N01GW */ 88*7bdae1e3SJon Lin { 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 89*7bdae1e3SJon Lin /* W25N02KW */ 90*7bdae1e3SJon Lin { 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 918a654f32SJon Lin /* W25N512GVEIG */ 928a654f32SJon Lin { 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 93f28847a8SJon Lin 94f28847a8SJon Lin /* HYF2GQ4UAACAE */ 95b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 96f28847a8SJon Lin /* HYF1GQ4UDACAE */ 97b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 98f28847a8SJon Lin /* HYF1GQ4UPACAE */ 99b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 100f28847a8SJon Lin /* HYF2GQ4UDACAE */ 101b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 102f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 103b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 104f28847a8SJon Lin /* HYF4GQ4UAACBE */ 105b833c879SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 106f28847a8SJon Lin 107f28847a8SJon Lin /* FS35ND01G-S1 */ 108b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 109f28847a8SJon Lin /* FS35ND02G-S2 */ 110b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 11158463f4dSJon Lin /* FS35ND01G-S1Y2 */ 112b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 113f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 114b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 115f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 116b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 117bf620bf6SJon Lin /* F35SQA001G */ 118bf620bf6SJon Lin { 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 11945292245SJon Lin /* F35SQA002G */ 12045292245SJon Lin { 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 121f28847a8SJon Lin 122f28847a8SJon Lin /* DS35Q1GA-IB */ 123b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 124f28847a8SJon Lin /* DS35Q2GA-IB */ 125b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 126f28847a8SJon Lin /* DS35M1GA-1B */ 127b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 128bf620bf6SJon Lin /* DS35M2GA-IB */ 129bf620bf6SJon Lin { 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 130629111d3SJon Lin /* DS35Q2GB-IB */ 131629111d3SJon Lin { 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 132bf620bf6SJon Lin /* DS35M1GB-IB */ 133bf620bf6SJon Lin { 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 134f28847a8SJon Lin 135f28847a8SJon Lin /* EM73C044VCC-H */ 136b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 137f28847a8SJon Lin /* EM73D044VCE-H */ 138b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 139f28847a8SJon Lin /* EM73E044SNA-G */ 140b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 141629111d3SJon Lin /* EM73C044VCF-H */ 142629111d3SJon Lin { 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 143f28847a8SJon Lin 144f28847a8SJon Lin /* XT26G02A */ 145362b1be1SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 146f28847a8SJon Lin /* XT26G01A */ 147362b1be1SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 148f28847a8SJon Lin /* XT26G04A */ 149362b1be1SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 150f28847a8SJon Lin /* XT26G01B */ 151362b1be1SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 152f28847a8SJon Lin /* XT26G02B */ 153362b1be1SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 154362b1be1SJon Lin /* XT26G01C */ 155362b1be1SJon Lin { 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 156362b1be1SJon Lin /* XT26G02C */ 157362b1be1SJon Lin { 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 158362b1be1SJon Lin /* XT26G04C */ 159362b1be1SJon Lin { 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 }, 160629111d3SJon Lin /* XT26G11C */ 161629111d3SJon Lin { 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 162a80fd396SJon Lin 163362b1be1SJon Lin /* MT29F2G01ABA, XT26G02E, F50L2G41XA */ 164629111d3SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 165629111d3SJon Lin /* MT29F1G01ABA, F50L1G41XA */ 166629111d3SJon Lin { 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 167a80fd396SJon Lin 168a80fd396SJon Lin /* FM25S01 */ 169b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 170a80fd396SJon Lin /* FM25S01A */ 171b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 172a80fd396SJon Lin /* FM25S02A */ 173b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 174*7bdae1e3SJon Lin /* FM25LS01 */ 175*7bdae1e3SJon Lin { 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 176f28847a8SJon Lin 177f28847a8SJon Lin /* IS37SML01G1 */ 178b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 179f28847a8SJon Lin /* F50L1G41LB */ 180b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 181f28847a8SJon Lin /* ATO25D1GA */ 182b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 183362b1be1SJon Lin /* BWJX08K-2Gb */ 184362b1be1SJon Lin { 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 185629111d3SJon Lin /* JS28U1GQSCAHG-83 */ 186629111d3SJon Lin { 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 1878a654f32SJon Lin /* SGM7000I-S24W1GH */ 1888a654f32SJon Lin { 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 189bf620bf6SJon Lin /* TX25G01 */ 190bf620bf6SJon Lin { 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 191ba0501acSDingqiang Lin }; 192ba0501acSDingqiang Lin 193ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 194ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 195ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 196ba0501acSDingqiang Lin 197a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 198ba0501acSDingqiang Lin { 199ba0501acSDingqiang Lin u32 i; 200ba0501acSDingqiang Lin 201ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 202b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 203b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 204b833c879SJon Lin if (spi_nand_tbl[i].id2 && 205b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 206b833c879SJon Lin continue; 207b833c879SJon Lin 208ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 209ba0501acSDingqiang Lin } 210b833c879SJon Lin } 211f28847a8SJon Lin 212ba0501acSDingqiang Lin return NULL; 213ba0501acSDingqiang Lin } 214ba0501acSDingqiang Lin 215ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 216ba0501acSDingqiang Lin { 217ba0501acSDingqiang Lin int ret; 21858463f4dSJon Lin struct rk_sfc_op op; 219ba0501acSDingqiang Lin 22058463f4dSJon Lin op.sfcmd.d32 = 0; 22158463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 22258463f4dSJon Lin 22358463f4dSJon Lin op.sfctrl.d32 = 0; 22458463f4dSJon Lin 22558463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 226ba0501acSDingqiang Lin return ret; 227ba0501acSDingqiang Lin } 228ba0501acSDingqiang Lin 229ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 230ba0501acSDingqiang Lin { 231ba0501acSDingqiang Lin int ret; 23258463f4dSJon Lin struct rk_sfc_op op; 233ba0501acSDingqiang Lin 23458463f4dSJon Lin op.sfcmd.d32 = 0; 235f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 236f28847a8SJon Lin op.sfcmd.b.cs = 2; 237ba0501acSDingqiang Lin 23858463f4dSJon Lin op.sfctrl.d32 = 0; 23958463f4dSJon Lin op.sfctrl.b.datalines = 2; 240f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 241f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 24258463f4dSJon Lin 243f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 244ba0501acSDingqiang Lin return ret; 245ba0501acSDingqiang Lin } 246ba0501acSDingqiang Lin 247ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 248ba0501acSDingqiang Lin { 249ba0501acSDingqiang Lin int ret; 25058463f4dSJon Lin struct rk_sfc_op op; 251ba0501acSDingqiang Lin 25258463f4dSJon Lin op.sfcmd.d32 = 0; 25358463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 25458463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 25558463f4dSJon Lin 25658463f4dSJon Lin op.sfctrl.d32 = 0; 25758463f4dSJon Lin op.sfctrl.b.addrbits = 8; 25858463f4dSJon Lin 259ba0501acSDingqiang Lin *data = 0; 260ba0501acSDingqiang Lin 26158463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 262f28847a8SJon Lin 263ba0501acSDingqiang Lin if (ret != SFC_OK) 264ba0501acSDingqiang Lin return ret; 265f28847a8SJon Lin 266ba0501acSDingqiang Lin return SFC_OK; 267ba0501acSDingqiang Lin } 268ba0501acSDingqiang Lin 269ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 270ba0501acSDingqiang Lin { 271ba0501acSDingqiang Lin int ret; 27258463f4dSJon Lin struct rk_sfc_op op; 273ba0501acSDingqiang Lin 274ba0501acSDingqiang Lin sfc_nand_write_en(); 275ba0501acSDingqiang Lin 27658463f4dSJon Lin op.sfcmd.d32 = 0; 27758463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 27858463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 27958463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 280ba0501acSDingqiang Lin 28158463f4dSJon Lin op.sfctrl.d32 = 0; 28258463f4dSJon Lin op.sfctrl.b.addrbits = 8; 28358463f4dSJon Lin 28458463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 285f28847a8SJon Lin 286ba0501acSDingqiang Lin if (ret != SFC_OK) 287ba0501acSDingqiang Lin return ret; 288f28847a8SJon Lin 289ba0501acSDingqiang Lin return ret; 290ba0501acSDingqiang Lin } 291ba0501acSDingqiang Lin 292ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 293ba0501acSDingqiang Lin { 294ba0501acSDingqiang Lin int ret; 295ba0501acSDingqiang Lin int i; 296ba0501acSDingqiang Lin u8 status; 297ba0501acSDingqiang Lin 298ba0501acSDingqiang Lin *data = 0; 299f28847a8SJon Lin 300ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 301ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 302f28847a8SJon Lin 303ba0501acSDingqiang Lin if (ret != SFC_OK) 304ba0501acSDingqiang Lin return ret; 305f28847a8SJon Lin 306ba0501acSDingqiang Lin *data = status; 307f28847a8SJon Lin 308ba0501acSDingqiang Lin if (!(status & (1 << 0))) 309ba0501acSDingqiang Lin return SFC_OK; 310f28847a8SJon Lin 311ba0501acSDingqiang Lin sfc_delay(1); 312ba0501acSDingqiang Lin } 313f28847a8SJon Lin 314f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 315ba0501acSDingqiang Lin } 316ba0501acSDingqiang Lin 3176281205aSDingqiang Lin /* 3186281205aSDingqiang Lin * ecc default: 319a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 320f28847a8SJon Lin * 0b00, No bit errors were detected 321f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 322f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 323f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 324362b1be1SJon Lin * reach the bit flip detection threshold 3256281205aSDingqiang Lin */ 326f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 3276281205aSDingqiang Lin { 32858463f4dSJon Lin u32 ret; 3296281205aSDingqiang Lin u32 i; 3306281205aSDingqiang Lin u8 ecc; 3316281205aSDingqiang Lin u8 status; 3326281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3336281205aSDingqiang Lin 3346281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3356281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 336f28847a8SJon Lin 3376281205aSDingqiang Lin if (ret != SFC_OK) 3386281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 339f28847a8SJon Lin 3406281205aSDingqiang Lin if (!(status & (1 << 0))) 3416281205aSDingqiang Lin break; 342f28847a8SJon Lin 3436281205aSDingqiang Lin sfc_delay(1); 3446281205aSDingqiang Lin } 3456281205aSDingqiang Lin 3466281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3476281205aSDingqiang Lin 3486281205aSDingqiang Lin if (ecc <= 1) 3496281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3506281205aSDingqiang Lin else if (ecc == 2) 35158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3526281205aSDingqiang Lin else 3536281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3546281205aSDingqiang Lin 3556281205aSDingqiang Lin return ret; 3566281205aSDingqiang Lin } 3576281205aSDingqiang Lin 3586281205aSDingqiang Lin /* 3596281205aSDingqiang Lin * ecc spectial type1: 360a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 361f28847a8SJon Lin * 0b00, No bit errors were detected; 362f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 3636281205aSDingqiang Lin * may reach the bit flip detection threshold; 364f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 365f28847a8SJon Lin * 0b11, Reserved. 3666281205aSDingqiang Lin */ 367f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 3686281205aSDingqiang Lin { 36958463f4dSJon Lin u32 ret; 3706281205aSDingqiang Lin u32 i; 3716281205aSDingqiang Lin u8 ecc; 3726281205aSDingqiang Lin u8 status; 3736281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3746281205aSDingqiang Lin 3756281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3766281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 377f28847a8SJon Lin 3786281205aSDingqiang Lin if (ret != SFC_OK) 3796281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 380f28847a8SJon Lin 3816281205aSDingqiang Lin if (!(status & (1 << 0))) 3826281205aSDingqiang Lin break; 383f28847a8SJon Lin 3846281205aSDingqiang Lin sfc_delay(1); 3856281205aSDingqiang Lin } 3866281205aSDingqiang Lin 3876281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3886281205aSDingqiang Lin 3896281205aSDingqiang Lin if (ecc == 0) 3906281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3916281205aSDingqiang Lin else if (ecc == 1) 3926281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3936281205aSDingqiang Lin else 39458463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3956281205aSDingqiang Lin 3966281205aSDingqiang Lin return ret; 3976281205aSDingqiang Lin } 3986281205aSDingqiang Lin 3996281205aSDingqiang Lin /* 400d9cdd318SJon Lin * ecc spectial type2: 401a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 402f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 403f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 404d9cdd318SJon Lin * reach Flipping Bits; 405f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 406c84f0ed8SJon Lin * not corrected. 407f28847a8SJon Lin * [0b1100, 0b1111], reserved. 408d9cdd318SJon Lin */ 409f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 410d9cdd318SJon Lin { 41158463f4dSJon Lin u32 ret; 412d9cdd318SJon Lin u32 i; 413d9cdd318SJon Lin u8 ecc; 414d9cdd318SJon Lin u8 status, status1; 415d9cdd318SJon Lin u32 timeout = 1000 * 1000; 416d9cdd318SJon Lin 417d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 418d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 419f28847a8SJon Lin 420d9cdd318SJon Lin if (ret != SFC_OK) 421d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 422f28847a8SJon Lin 423d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 424f28847a8SJon Lin 425d9cdd318SJon Lin if (ret != SFC_OK) 426d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 427f28847a8SJon Lin 428d9cdd318SJon Lin if (!(status & (1 << 0))) 429d9cdd318SJon Lin break; 430f28847a8SJon Lin 431d9cdd318SJon Lin sfc_delay(1); 432d9cdd318SJon Lin } 433d9cdd318SJon Lin 434d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 435d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 436f28847a8SJon Lin 437d9cdd318SJon Lin if (ecc < 7) 438d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 439d9cdd318SJon Lin else if (ecc == 7) 440d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 441d9cdd318SJon Lin else 44258463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 443d9cdd318SJon Lin 444d9cdd318SJon Lin return ret; 445d9cdd318SJon Lin } 446d9cdd318SJon Lin 447d9cdd318SJon Lin /* 4486281205aSDingqiang Lin * ecc spectial type3: 449a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 450f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 451f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 4526281205aSDingqiang Lin * reach Flipping Bits; 453f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 4546281205aSDingqiang Lin * not corrected. 455f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 4566281205aSDingqiang Lin * detectio nthreshold 4576281205aSDingqiang Lin */ 458f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 4596281205aSDingqiang Lin { 46058463f4dSJon Lin u32 ret; 4616281205aSDingqiang Lin u32 i; 4626281205aSDingqiang Lin u8 ecc; 4636281205aSDingqiang Lin u8 status, status1; 4646281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4656281205aSDingqiang Lin 4666281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4676281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 468f28847a8SJon Lin 4696281205aSDingqiang Lin if (ret != SFC_OK) 4706281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 471f28847a8SJon Lin 4726281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 473f28847a8SJon Lin 4746281205aSDingqiang Lin if (ret != SFC_OK) 4756281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 476f28847a8SJon Lin 4776281205aSDingqiang Lin if (!(status & (1 << 0))) 4786281205aSDingqiang Lin break; 479f28847a8SJon Lin 4806281205aSDingqiang Lin sfc_delay(1); 4816281205aSDingqiang Lin } 4826281205aSDingqiang Lin 4836281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4846281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 485f28847a8SJon Lin 4866281205aSDingqiang Lin if (ecc < 7) 4876281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4886281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 4896281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4906281205aSDingqiang Lin else 49158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4926281205aSDingqiang Lin 4936281205aSDingqiang Lin return ret; 4946281205aSDingqiang Lin } 4956281205aSDingqiang Lin 49625098c06SDingqiang Lin /* 49725098c06SDingqiang Lin * ecc spectial type4: 498a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 499f28847a8SJon Lin * [0b0000], No bit errors were detected; 500f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 50125098c06SDingqiang Lin * reach Flipping Bits; 502f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 50325098c06SDingqiang Lin * not corrected. 504f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 50525098c06SDingqiang Lin * detection threshold 50625098c06SDingqiang Lin * else, reserved 50725098c06SDingqiang Lin */ 508f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 50925098c06SDingqiang Lin { 51058463f4dSJon Lin u32 ret; 51125098c06SDingqiang Lin u32 i; 51225098c06SDingqiang Lin u8 ecc; 51325098c06SDingqiang Lin u8 status; 51425098c06SDingqiang Lin u32 timeout = 1000 * 1000; 51525098c06SDingqiang Lin 51625098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 51725098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 518f28847a8SJon Lin 51925098c06SDingqiang Lin if (ret != SFC_OK) 52025098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 521f28847a8SJon Lin 52225098c06SDingqiang Lin if (!(status & (1 << 0))) 52325098c06SDingqiang Lin break; 524f28847a8SJon Lin 52525098c06SDingqiang Lin sfc_delay(1); 52625098c06SDingqiang Lin } 52725098c06SDingqiang Lin 52825098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 529f28847a8SJon Lin 53025098c06SDingqiang Lin if (ecc < 7) 53125098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 53225098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 53325098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 53425098c06SDingqiang Lin else 53558463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 53625098c06SDingqiang Lin 53725098c06SDingqiang Lin return ret; 53825098c06SDingqiang Lin } 53925098c06SDingqiang Lin 54025098c06SDingqiang Lin /* 54125098c06SDingqiang Lin * ecc spectial type5: 542a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 543f28847a8SJon Lin * [0b000], No bit errors were detected; 544f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 54525098c06SDingqiang Lin * reach Flipping Bits; 546f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 54725098c06SDingqiang Lin * detection threshold 548f28847a8SJon Lin * [0b101, 0b110], Reserved; 549f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 55025098c06SDingqiang Lin * not corrected. 55125098c06SDingqiang Lin */ 552f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 55325098c06SDingqiang Lin { 55458463f4dSJon Lin u32 ret; 55525098c06SDingqiang Lin u32 i; 55625098c06SDingqiang Lin u8 ecc; 55725098c06SDingqiang Lin u8 status; 55825098c06SDingqiang Lin u32 timeout = 1000 * 1000; 55925098c06SDingqiang Lin 56025098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 56125098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 562f28847a8SJon Lin 56325098c06SDingqiang Lin if (ret != SFC_OK) 56425098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 565f28847a8SJon Lin 56625098c06SDingqiang Lin if (!(status & (1 << 0))) 56725098c06SDingqiang Lin break; 568f28847a8SJon Lin 56925098c06SDingqiang Lin sfc_delay(1); 57025098c06SDingqiang Lin } 57125098c06SDingqiang Lin 57225098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 573f28847a8SJon Lin 57425098c06SDingqiang Lin if (ecc < 4) 57525098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 57625098c06SDingqiang Lin else if (ecc == 4) 57725098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 57825098c06SDingqiang Lin else 57958463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 58025098c06SDingqiang Lin 58125098c06SDingqiang Lin return ret; 58225098c06SDingqiang Lin } 58325098c06SDingqiang Lin 584f28847a8SJon Lin /* 585f28847a8SJon Lin * ecc spectial type6: 586f28847a8SJon Lin * ecc bits: 0xC0[4,6] 587f28847a8SJon Lin * [0b000], No bit errors were detected; 588f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 589f28847a8SJon Lin * reach Flipping Bits; 590f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 591f28847a8SJon Lin * not corrected. 592f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 593f28847a8SJon Lin * reach Flipping Bits; 594f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 595f28847a8SJon Lin * detectionthreshold 596f28847a8SJon Lin * others, Reserved. 597f28847a8SJon Lin */ 598f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 599f28847a8SJon Lin { 600f28847a8SJon Lin u32 ret; 601f28847a8SJon Lin u32 i; 602f28847a8SJon Lin u8 ecc; 603f28847a8SJon Lin u8 status; 604f28847a8SJon Lin u32 timeout = 1000 * 1000; 605f28847a8SJon Lin 606f28847a8SJon Lin for (i = 0; i < timeout; i++) { 607f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 608f28847a8SJon Lin 609f28847a8SJon Lin if (ret != SFC_OK) 610f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 611f28847a8SJon Lin 612f28847a8SJon Lin if (!(status & (1 << 0))) 613f28847a8SJon Lin break; 614f28847a8SJon Lin 615f28847a8SJon Lin sfc_delay(1); 616f28847a8SJon Lin } 617f28847a8SJon Lin 618f28847a8SJon Lin ecc = (status >> 4) & 0x07; 619f28847a8SJon Lin 620f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 621f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 622f28847a8SJon Lin else if (ecc == 5) 623f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 624f28847a8SJon Lin else 625f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 626f28847a8SJon Lin 627f28847a8SJon Lin return ret; 628f28847a8SJon Lin } 629f28847a8SJon Lin 630362b1be1SJon Lin /* 631362b1be1SJon Lin * ecc spectial type7: 632362b1be1SJon Lin * ecc bits: 0xC0[4,7] 633362b1be1SJon Lin * [0b0000], No bit errors were detected; 634362b1be1SJon Lin * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 635362b1be1SJon Lin * reach Flipping Bits; 636362b1be1SJon Lin * [0b1000], 8 Bit errors were detected and corrected. Bit error count 637362b1be1SJon Lin * equals the bit flip detectionthreshold; 638362b1be1SJon Lin * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 639362b1be1SJon Lin * others, Reserved. 640362b1be1SJon Lin */ 641362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void) 642362b1be1SJon Lin { 643362b1be1SJon Lin u32 ret; 644362b1be1SJon Lin u32 i; 645362b1be1SJon Lin u8 ecc; 646362b1be1SJon Lin u8 status; 647362b1be1SJon Lin u32 timeout = 1000 * 1000; 648362b1be1SJon Lin 649362b1be1SJon Lin for (i = 0; i < timeout; i++) { 650362b1be1SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 651362b1be1SJon Lin 652362b1be1SJon Lin if (ret != SFC_OK) 653362b1be1SJon Lin return SFC_NAND_ECC_ERROR; 654362b1be1SJon Lin 655362b1be1SJon Lin if (!(status & (1 << 0))) 656362b1be1SJon Lin break; 657362b1be1SJon Lin 658362b1be1SJon Lin sfc_delay(1); 659362b1be1SJon Lin } 660362b1be1SJon Lin 661362b1be1SJon Lin ecc = (status >> 4) & 0xf; 662362b1be1SJon Lin 663362b1be1SJon Lin if (ecc < 7) 664362b1be1SJon Lin ret = SFC_NAND_ECC_OK; 665362b1be1SJon Lin else if (ecc == 7 || ecc == 8) 666362b1be1SJon Lin ret = SFC_NAND_ECC_REFRESH; 667362b1be1SJon Lin else 668362b1be1SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 669362b1be1SJon Lin 670362b1be1SJon Lin return ret; 671362b1be1SJon Lin } 672362b1be1SJon Lin 673629111d3SJon Lin /* 674629111d3SJon Lin * ecc spectial type8: 675629111d3SJon Lin * ecc bits: 0xC0[4,6] 676629111d3SJon Lin * [0b000], No bit errors were detected; 677629111d3SJon Lin * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not 678629111d3SJon Lin * reach Flipping Bits; 679629111d3SJon Lin * [0b100], Bit error count equals the bit flip 680629111d3SJon Lin * detection threshold 681629111d3SJon Lin * others, Reserved. 682629111d3SJon Lin */ 683629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void) 684629111d3SJon Lin { 685629111d3SJon Lin u32 ret; 686629111d3SJon Lin u32 i; 687629111d3SJon Lin u8 ecc; 688629111d3SJon Lin u8 status; 689629111d3SJon Lin u32 timeout = 1000 * 1000; 690629111d3SJon Lin 691629111d3SJon Lin for (i = 0; i < timeout; i++) { 692629111d3SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 693629111d3SJon Lin 694629111d3SJon Lin if (ret != SFC_OK) 695629111d3SJon Lin return SFC_NAND_ECC_ERROR; 696629111d3SJon Lin 697629111d3SJon Lin if (!(status & (1 << 0))) 698629111d3SJon Lin break; 699629111d3SJon Lin 700629111d3SJon Lin sfc_delay(1); 701629111d3SJon Lin } 702629111d3SJon Lin 703629111d3SJon Lin ecc = (status >> 4) & 0x07; 704629111d3SJon Lin 705629111d3SJon Lin if (ecc < 4) 706629111d3SJon Lin ret = SFC_NAND_ECC_OK; 707629111d3SJon Lin else if (ecc == 4) 708629111d3SJon Lin ret = SFC_NAND_ECC_REFRESH; 709629111d3SJon Lin else 710629111d3SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 711629111d3SJon Lin 712629111d3SJon Lin return ret; 713629111d3SJon Lin } 714629111d3SJon Lin 715c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 716ba0501acSDingqiang Lin { 717ba0501acSDingqiang Lin int ret; 71858463f4dSJon Lin struct rk_sfc_op op; 719ba0501acSDingqiang Lin u8 status; 720ba0501acSDingqiang Lin 721c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 72258463f4dSJon Lin op.sfcmd.d32 = 0; 723f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 72458463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 72558463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 72658463f4dSJon Lin 72758463f4dSJon Lin op.sfctrl.d32 = 0; 72858463f4dSJon Lin 729ba0501acSDingqiang Lin sfc_nand_write_en(); 73058463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 731f28847a8SJon Lin 732ba0501acSDingqiang Lin if (ret != SFC_OK) 733ba0501acSDingqiang Lin return ret; 734f28847a8SJon Lin 735ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 736f28847a8SJon Lin 737ba0501acSDingqiang Lin if (status & (1 << 2)) 738ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 739c84f0ed8SJon Lin 740ba0501acSDingqiang Lin return ret; 741ba0501acSDingqiang Lin } 742ba0501acSDingqiang Lin 743629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len) 744629111d3SJon Lin { 745629111d3SJon Lin int ret; 746629111d3SJon Lin u32 plane; 747629111d3SJon Lin struct rk_sfc_op op; 748629111d3SJon Lin 749629111d3SJon Lin op.sfcmd.d32 = 0; 750629111d3SJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 751629111d3SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 752629111d3SJon Lin op.sfcmd.b.dummybits = 8; 753629111d3SJon Lin 754629111d3SJon Lin op.sfctrl.d32 = 0; 755629111d3SJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 756629111d3SJon Lin op.sfctrl.b.addrbits = 16; 757629111d3SJon Lin 758629111d3SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 759629111d3SJon Lin 760629111d3SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 761629111d3SJon Lin if (ret != SFC_OK) 762629111d3SJon Lin return SFC_NAND_HW_ERROR; 763629111d3SJon Lin 764629111d3SJon Lin return ret; 765629111d3SJon Lin } 766629111d3SJon Lin 767f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 768ba0501acSDingqiang Lin { 769ba0501acSDingqiang Lin int ret; 770415cf080Sjon.lin u32 plane; 77158463f4dSJon Lin struct rk_sfc_op op; 772ba0501acSDingqiang Lin u8 status; 77358463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 774629111d3SJon Lin u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page; 775ba0501acSDingqiang Lin 776c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 777ba0501acSDingqiang Lin sfc_nand_write_en(); 778f28847a8SJon Lin 779ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 78025098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 78125098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 782ba0501acSDingqiang Lin sfc_nand_rw_preset(); 783ba0501acSDingqiang Lin 78458463f4dSJon Lin op.sfcmd.d32 = 0; 78558463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 78658463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 78758463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 788ba0501acSDingqiang Lin 78958463f4dSJon Lin op.sfctrl.d32 = 0; 79058463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 79158463f4dSJon Lin op.sfctrl.b.addrbits = 16; 792415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 79358463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 794ba0501acSDingqiang Lin 795629111d3SJon Lin /* 796c797b43aSJon Lin * At the moment of power lost or dev running in harsh environment, flash 797c797b43aSJon Lin * maybe work in a unkonw state and result in bit flip, when this situation 798c797b43aSJon Lin * is detected by cache recheck, it's better to wait a second for a reliable 799c797b43aSJon Lin * hardware environment to avoid abnormal data written to flash array. 800629111d3SJon Lin */ 801361684bfSJon Lin if (p_nand_info->id0 == MID_GIGADEV) { 802629111d3SJon Lin sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size); 803c797b43aSJon Lin if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) { 804c797b43aSJon Lin rkflash_print_error("%s %x cache bitflip\n", __func__, addr); 805c797b43aSJon Lin mdelay(1000); 806c797b43aSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 807c797b43aSJon Lin } 808c797b43aSJon Lin } 809629111d3SJon Lin 81058463f4dSJon Lin op.sfcmd.d32 = 0; 811f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 81258463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 81358463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 81458463f4dSJon Lin 81558463f4dSJon Lin op.sfctrl.d32 = 0; 81658463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 817f28847a8SJon Lin 818ba0501acSDingqiang Lin if (ret != SFC_OK) 819ba0501acSDingqiang Lin return ret; 820f28847a8SJon Lin 821ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 822ba0501acSDingqiang Lin if (status & (1 << 3)) 823ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 824c84f0ed8SJon Lin 825ba0501acSDingqiang Lin return ret; 826ba0501acSDingqiang Lin } 827ba0501acSDingqiang Lin 828c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 829c84f0ed8SJon Lin { 830c84f0ed8SJon Lin int ret; 831c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 832c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 833a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 834c84f0ed8SJon Lin 835c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 836c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 837a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 838a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 839f28847a8SJon Lin 840c84f0ed8SJon Lin if (sec_per_page == 8) { 841a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 842a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 843c84f0ed8SJon Lin } 844f28847a8SJon Lin 845c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 846c84f0ed8SJon Lin 847c84f0ed8SJon Lin return ret; 848c84f0ed8SJon Lin } 849c84f0ed8SJon Lin 850a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 851ba0501acSDingqiang Lin { 852ba0501acSDingqiang Lin int ret; 853415cf080Sjon.lin u32 plane; 85458463f4dSJon Lin struct rk_sfc_op op; 8556281205aSDingqiang Lin u32 ecc_result; 856a6fcac41SJon Lin u8 status; 857ba0501acSDingqiang Lin 85858463f4dSJon Lin op.sfcmd.d32 = 0; 859f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 86058463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 86158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 86258463f4dSJon Lin 86358463f4dSJon Lin op.sfctrl.d32 = 0; 86458463f4dSJon Lin 865a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 866f28847a8SJon Lin 867ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 86825098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 86925098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 870ba0501acSDingqiang Lin sfc_nand_rw_preset(); 871ba0501acSDingqiang Lin 872a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 873a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 874a6fcac41SJon Lin 87558463f4dSJon Lin op.sfcmd.d32 = 0; 87658463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 877a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 878a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 87958463f4dSJon Lin 88058463f4dSJon Lin op.sfctrl.d32 = 0; 88158463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 882a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 883ba0501acSDingqiang Lin 884a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 885a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 886a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 887c84f0ed8SJon Lin 888c84f0ed8SJon Lin if (ret != SFC_OK) 889f28847a8SJon Lin return SFC_NAND_HW_ERROR; 890c84f0ed8SJon Lin 891c84f0ed8SJon Lin return ecc_result; 892c84f0ed8SJon Lin } 893c84f0ed8SJon Lin 894a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 895a80fd396SJon Lin { 896a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 897a80fd396SJon Lin 898a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 899a80fd396SJon Lin } 900a80fd396SJon Lin 901c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 902c84f0ed8SJon Lin { 90358463f4dSJon Lin u32 ret; 904c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 905c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 906a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 907c84f0ed8SJon Lin 908c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 909f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 910a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 911a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 912f28847a8SJon Lin 913f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 914a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 915a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 916f25e3cafSJon Lin } 917ba0501acSDingqiang Lin 918f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 919f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 920f28847a8SJon Lin 921c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 922c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 923f28847a8SJon Lin 924ba0501acSDingqiang Lin if (p_data) 925c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 926f28847a8SJon Lin 927ba0501acSDingqiang Lin if (p_spare) 928c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 929ba0501acSDingqiang Lin } 930f25e3cafSJon Lin 931c84f0ed8SJon Lin return ret; 932ba0501acSDingqiang Lin } 933ba0501acSDingqiang Lin 934c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 935c84f0ed8SJon Lin { 936c84f0ed8SJon Lin u32 ret; 937c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 938a80fd396SJon Lin u32 marker = 0; 939c84f0ed8SJon Lin 940a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 941f28847a8SJon Lin 942f28847a8SJon Lin /* unify with mtd framework */ 943629111d3SJon Lin if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff) 944a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 945a80fd396SJon Lin __func__, addr, ret, marker); 946f28847a8SJon Lin 947c84f0ed8SJon Lin /* Original bad block */ 948a80fd396SJon Lin if ((u16)marker != 0xffff) 949c84f0ed8SJon Lin return true; 950c84f0ed8SJon Lin 951c84f0ed8SJon Lin return false; 952c84f0ed8SJon Lin } 953c84f0ed8SJon Lin 954c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 955c84f0ed8SJon Lin { 956c84f0ed8SJon Lin u32 ret; 957c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 958c84f0ed8SJon Lin 959c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 960f28847a8SJon Lin 961c84f0ed8SJon Lin if (ret) 962c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 963f28847a8SJon Lin 964c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 965c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 966f28847a8SJon Lin 967c84f0ed8SJon Lin if (ret) 968c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 969c84f0ed8SJon Lin 970c84f0ed8SJon Lin return ret; 971c84f0ed8SJon Lin } 972c84f0ed8SJon Lin 973c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 974ba0501acSDingqiang Lin { 975ba0501acSDingqiang Lin int ret; 97658463f4dSJon Lin struct rk_sfc_op op; 977ba0501acSDingqiang Lin 97858463f4dSJon Lin op.sfcmd.d32 = 0; 97958463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 98058463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 981ba0501acSDingqiang Lin 98258463f4dSJon Lin op.sfctrl.d32 = 0; 98358463f4dSJon Lin op.sfctrl.b.addrbits = 8; 98458463f4dSJon Lin 98558463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 986ba0501acSDingqiang Lin 987ba0501acSDingqiang Lin return ret; 988ba0501acSDingqiang Lin } 989ba0501acSDingqiang Lin 990ba0501acSDingqiang Lin /* 991ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 992ba0501acSDingqiang Lin * If not FF, it's bad blk 993ba0501acSDingqiang Lin */ 994ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 995ba0501acSDingqiang Lin { 996ba0501acSDingqiang Lin u32 bad_cnt, page; 997ba0501acSDingqiang Lin u32 blk_per_die; 9982ac88c1bSJon Lin u16 blk; 999ba0501acSDingqiang Lin 1000c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 1001c84f0ed8SJon Lin 1002ba0501acSDingqiang Lin bad_cnt = 0; 1003ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 1004ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1005f28847a8SJon Lin 1006ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 1007ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 1008ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1009ba0501acSDingqiang Lin 10102ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 1011ba0501acSDingqiang Lin table[bad_cnt++] = blk; 1012c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 1013ba0501acSDingqiang Lin } 1014ba0501acSDingqiang Lin } 1015f28847a8SJon Lin 1016ba0501acSDingqiang Lin return (int)bad_cnt; 1017ba0501acSDingqiang Lin } 1018ba0501acSDingqiang Lin 1019c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 1020ba0501acSDingqiang Lin { 1021ba0501acSDingqiang Lin /* para init */ 1022ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 1023ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 1024ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 1025ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 1026ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 1027ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 1028c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 1029ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 1030ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 1031ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1032ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 1033ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 1034ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1035ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 1036ba0501acSDingqiang Lin 1037ba0501acSDingqiang Lin /* driver register */ 1038ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 1039ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 1040ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 1041ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 104257d18453Sjon.lin g_nand_ops.bch_sel = NULL; 1043ba0501acSDingqiang Lin } 1044ba0501acSDingqiang Lin 1045a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 1046ba0501acSDingqiang Lin { 1047ba0501acSDingqiang Lin int ret = SFC_OK; 1048ba0501acSDingqiang Lin u8 status; 1049ba0501acSDingqiang Lin 1050f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 1051ba0501acSDingqiang Lin 1052ba0501acSDingqiang Lin if (ret != SFC_OK) 1053ba0501acSDingqiang Lin return ret; 1054ba0501acSDingqiang Lin 1055f28847a8SJon Lin if (status & 1) /* is QE bit set */ 1056ba0501acSDingqiang Lin return SFC_OK; 1057ba0501acSDingqiang Lin 1058f28847a8SJon Lin status |= 1; 1059ba0501acSDingqiang Lin 1060f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 1061ba0501acSDingqiang Lin } 1062ba0501acSDingqiang Lin 1063ba0501acSDingqiang Lin u32 sfc_nand_init(void) 1064ba0501acSDingqiang Lin { 1065c84f0ed8SJon Lin u8 status, id_byte[8]; 1066ba0501acSDingqiang Lin 1067c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 1068c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 1069ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 1070f28847a8SJon Lin 1071ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 107258463f4dSJon Lin return (u32)FTL_NO_FLASH; 1073ba0501acSDingqiang Lin 1074a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 1075f28847a8SJon Lin 107645292245SJon Lin if (!p_nand_info) { 107745292245SJon Lin pr_err("The device not support yet!\n"); 107845292245SJon Lin 107958463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 108045292245SJon Lin } 1081ba0501acSDingqiang Lin 1082ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 1083ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 1084c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 1085c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 1086c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 1087ba0501acSDingqiang Lin 1088ba0501acSDingqiang Lin /* disable block lock */ 1089ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 1090ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 1091ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 1092f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 1093f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 1094629111d3SJon Lin sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE); 1095629111d3SJon Lin if (!sfc_nand_dev.recheck_buffer) { 1096629111d3SJon Lin rkflash_print_error("%s recheck_buffer alloc failed\n", __func__); 1097629111d3SJon Lin return -1; 1098629111d3SJon Lin } 1099f28847a8SJon Lin 1100ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 1101f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 1102f28847a8SJon Lin !p_nand_info->has_qe_bits) { 1103ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 1104f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 1105ba0501acSDingqiang Lin } 1106ba0501acSDingqiang Lin } 1107ba0501acSDingqiang Lin 1108ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 1109ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 1110ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 1111f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 1112ba0501acSDingqiang Lin } 1113ba0501acSDingqiang Lin 1114ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 1115c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 1116ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 1117c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 1118c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 1119c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 1120c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 1121c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 1122ba0501acSDingqiang Lin 1123ba0501acSDingqiang Lin return SFC_OK; 1124ba0501acSDingqiang Lin } 1125ba0501acSDingqiang Lin 1126c84f0ed8SJon Lin void sfc_nand_deinit(void) 1127ba0501acSDingqiang Lin { 1128c84f0ed8SJon Lin /* to-do */ 1129629111d3SJon Lin kfree(sfc_nand_dev.recheck_buffer); 1130ba0501acSDingqiang Lin } 1131c84f0ed8SJon Lin 1132c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 1133c84f0ed8SJon Lin { 1134c84f0ed8SJon Lin return &sfc_nand_dev; 1135c84f0ed8SJon Lin } 1136c84f0ed8SJon Lin 1137