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 }, 70f28847a8SJon Lin 71f28847a8SJon Lin /* W25N01GV */ 72b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 73b833c879SJon Lin /* W25N02KVZEIR */ 74b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 75629111d3SJon Lin /* W25N04KVZEIR */ 76629111d3SJon Lin { 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 }, 77f28847a8SJon Lin /* W25N01GW */ 78b833c879SJon Lin { 0xEF, 0xBA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 798a654f32SJon Lin /* W25N512GVEIG */ 808a654f32SJon Lin { 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 81f28847a8SJon Lin 82f28847a8SJon Lin /* HYF2GQ4UAACAE */ 83b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 84f28847a8SJon Lin /* HYF1GQ4UDACAE */ 85b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 86f28847a8SJon Lin /* HYF1GQ4UPACAE */ 87b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 88f28847a8SJon Lin /* HYF2GQ4UDACAE */ 89b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 90f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 91b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 92f28847a8SJon Lin /* HYF4GQ4UAACBE */ 93b833c879SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 94f28847a8SJon Lin 95f28847a8SJon Lin /* FS35ND01G-S1 */ 96b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 97f28847a8SJon Lin /* FS35ND02G-S2 */ 98b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 9958463f4dSJon Lin /* FS35ND01G-S1Y2 */ 100b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 101f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 102b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 103f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 104b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 105f28847a8SJon Lin 106f28847a8SJon Lin /* DS35Q1GA-IB */ 107b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 108f28847a8SJon Lin /* DS35Q2GA-IB */ 109b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 110f28847a8SJon Lin /* DS35M1GA-1B */ 111b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 112629111d3SJon Lin /* DS35Q2GB-IB */ 113629111d3SJon Lin { 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 114f28847a8SJon Lin 115f28847a8SJon Lin /* EM73C044VCC-H */ 116b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 117f28847a8SJon Lin /* EM73D044VCE-H */ 118b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 119f28847a8SJon Lin /* EM73E044SNA-G */ 120b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 121629111d3SJon Lin /* EM73C044VCF-H */ 122629111d3SJon Lin { 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 123f28847a8SJon Lin 124f28847a8SJon Lin /* XT26G02A */ 125362b1be1SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 126f28847a8SJon Lin /* XT26G01A */ 127362b1be1SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 128f28847a8SJon Lin /* XT26G04A */ 129362b1be1SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 130f28847a8SJon Lin /* XT26G01B */ 131362b1be1SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 132f28847a8SJon Lin /* XT26G02B */ 133362b1be1SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 134362b1be1SJon Lin /* XT26G01C */ 135362b1be1SJon Lin { 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 136362b1be1SJon Lin /* XT26G02C */ 137362b1be1SJon Lin { 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 138362b1be1SJon Lin /* XT26G04C */ 139362b1be1SJon Lin { 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 }, 140629111d3SJon Lin /* XT26G11C */ 141629111d3SJon Lin { 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 142a80fd396SJon Lin 143362b1be1SJon Lin /* MT29F2G01ABA, XT26G02E, F50L2G41XA */ 144629111d3SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 145629111d3SJon Lin /* MT29F1G01ABA, F50L1G41XA */ 146629111d3SJon Lin { 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 147a80fd396SJon Lin 148a80fd396SJon Lin /* FM25S01 */ 149b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 150a80fd396SJon Lin /* FM25S01A */ 151b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 152a80fd396SJon Lin /* FM25S02A */ 153b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 154f28847a8SJon Lin 155f28847a8SJon Lin /* IS37SML01G1 */ 156b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 157f28847a8SJon Lin /* F50L1G41LB */ 158b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 159f28847a8SJon Lin /* ATO25D1GA */ 160b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 161362b1be1SJon Lin /* BWJX08K-2Gb */ 162362b1be1SJon Lin { 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 163629111d3SJon Lin /* JS28U1GQSCAHG-83 */ 164629111d3SJon Lin { 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 }, 1658a654f32SJon Lin /* SGM7000I-S24W1GH */ 1668a654f32SJon Lin { 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 167ba0501acSDingqiang Lin }; 168ba0501acSDingqiang Lin 169ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 170ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 171ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 172ba0501acSDingqiang Lin 173a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 174ba0501acSDingqiang Lin { 175ba0501acSDingqiang Lin u32 i; 176ba0501acSDingqiang Lin 177ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 178b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 179b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 180b833c879SJon Lin if (spi_nand_tbl[i].id2 && 181b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 182b833c879SJon Lin continue; 183b833c879SJon Lin 184ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 185ba0501acSDingqiang Lin } 186b833c879SJon Lin } 187f28847a8SJon Lin 188ba0501acSDingqiang Lin return NULL; 189ba0501acSDingqiang Lin } 190ba0501acSDingqiang Lin 191ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 192ba0501acSDingqiang Lin { 193ba0501acSDingqiang Lin int ret; 19458463f4dSJon Lin struct rk_sfc_op op; 195ba0501acSDingqiang Lin 19658463f4dSJon Lin op.sfcmd.d32 = 0; 19758463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 19858463f4dSJon Lin 19958463f4dSJon Lin op.sfctrl.d32 = 0; 20058463f4dSJon Lin 20158463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 202ba0501acSDingqiang Lin return ret; 203ba0501acSDingqiang Lin } 204ba0501acSDingqiang Lin 205ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 206ba0501acSDingqiang Lin { 207ba0501acSDingqiang Lin int ret; 20858463f4dSJon Lin struct rk_sfc_op op; 209ba0501acSDingqiang Lin 21058463f4dSJon Lin op.sfcmd.d32 = 0; 211f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 212f28847a8SJon Lin op.sfcmd.b.cs = 2; 213ba0501acSDingqiang Lin 21458463f4dSJon Lin op.sfctrl.d32 = 0; 21558463f4dSJon Lin op.sfctrl.b.datalines = 2; 216f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 217f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 21858463f4dSJon Lin 219f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 220ba0501acSDingqiang Lin return ret; 221ba0501acSDingqiang Lin } 222ba0501acSDingqiang Lin 223ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 224ba0501acSDingqiang Lin { 225ba0501acSDingqiang Lin int ret; 22658463f4dSJon Lin struct rk_sfc_op op; 227ba0501acSDingqiang Lin 22858463f4dSJon Lin op.sfcmd.d32 = 0; 22958463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 23058463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 23158463f4dSJon Lin 23258463f4dSJon Lin op.sfctrl.d32 = 0; 23358463f4dSJon Lin op.sfctrl.b.addrbits = 8; 23458463f4dSJon Lin 235ba0501acSDingqiang Lin *data = 0; 236ba0501acSDingqiang Lin 23758463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 238f28847a8SJon Lin 239ba0501acSDingqiang Lin if (ret != SFC_OK) 240ba0501acSDingqiang Lin return ret; 241f28847a8SJon Lin 242ba0501acSDingqiang Lin return SFC_OK; 243ba0501acSDingqiang Lin } 244ba0501acSDingqiang Lin 245ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 246ba0501acSDingqiang Lin { 247ba0501acSDingqiang Lin int ret; 24858463f4dSJon Lin struct rk_sfc_op op; 249ba0501acSDingqiang Lin 250ba0501acSDingqiang Lin sfc_nand_write_en(); 251ba0501acSDingqiang Lin 25258463f4dSJon Lin op.sfcmd.d32 = 0; 25358463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 25458463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 25558463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 256ba0501acSDingqiang Lin 25758463f4dSJon Lin op.sfctrl.d32 = 0; 25858463f4dSJon Lin op.sfctrl.b.addrbits = 8; 25958463f4dSJon Lin 26058463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 261f28847a8SJon Lin 262ba0501acSDingqiang Lin if (ret != SFC_OK) 263ba0501acSDingqiang Lin return ret; 264f28847a8SJon Lin 265ba0501acSDingqiang Lin return ret; 266ba0501acSDingqiang Lin } 267ba0501acSDingqiang Lin 268ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 269ba0501acSDingqiang Lin { 270ba0501acSDingqiang Lin int ret; 271ba0501acSDingqiang Lin int i; 272ba0501acSDingqiang Lin u8 status; 273ba0501acSDingqiang Lin 274ba0501acSDingqiang Lin *data = 0; 275f28847a8SJon Lin 276ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 277ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 278f28847a8SJon Lin 279ba0501acSDingqiang Lin if (ret != SFC_OK) 280ba0501acSDingqiang Lin return ret; 281f28847a8SJon Lin 282ba0501acSDingqiang Lin *data = status; 283f28847a8SJon Lin 284ba0501acSDingqiang Lin if (!(status & (1 << 0))) 285ba0501acSDingqiang Lin return SFC_OK; 286f28847a8SJon Lin 287ba0501acSDingqiang Lin sfc_delay(1); 288ba0501acSDingqiang Lin } 289f28847a8SJon Lin 290f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 291ba0501acSDingqiang Lin } 292ba0501acSDingqiang Lin 2936281205aSDingqiang Lin /* 2946281205aSDingqiang Lin * ecc default: 295a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 296f28847a8SJon Lin * 0b00, No bit errors were detected 297f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 298f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 299f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 300362b1be1SJon Lin * reach the bit flip detection threshold 3016281205aSDingqiang Lin */ 302f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 3036281205aSDingqiang Lin { 30458463f4dSJon Lin u32 ret; 3056281205aSDingqiang Lin u32 i; 3066281205aSDingqiang Lin u8 ecc; 3076281205aSDingqiang Lin u8 status; 3086281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3096281205aSDingqiang Lin 3106281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3116281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 312f28847a8SJon Lin 3136281205aSDingqiang Lin if (ret != SFC_OK) 3146281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 315f28847a8SJon Lin 3166281205aSDingqiang Lin if (!(status & (1 << 0))) 3176281205aSDingqiang Lin break; 318f28847a8SJon Lin 3196281205aSDingqiang Lin sfc_delay(1); 3206281205aSDingqiang Lin } 3216281205aSDingqiang Lin 3226281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3236281205aSDingqiang Lin 3246281205aSDingqiang Lin if (ecc <= 1) 3256281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3266281205aSDingqiang Lin else if (ecc == 2) 32758463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3286281205aSDingqiang Lin else 3296281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3306281205aSDingqiang Lin 3316281205aSDingqiang Lin return ret; 3326281205aSDingqiang Lin } 3336281205aSDingqiang Lin 3346281205aSDingqiang Lin /* 3356281205aSDingqiang Lin * ecc spectial type1: 336a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 337f28847a8SJon Lin * 0b00, No bit errors were detected; 338f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 3396281205aSDingqiang Lin * may reach the bit flip detection threshold; 340f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 341f28847a8SJon Lin * 0b11, Reserved. 3426281205aSDingqiang Lin */ 343f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 3446281205aSDingqiang Lin { 34558463f4dSJon Lin u32 ret; 3466281205aSDingqiang Lin u32 i; 3476281205aSDingqiang Lin u8 ecc; 3486281205aSDingqiang Lin u8 status; 3496281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3506281205aSDingqiang Lin 3516281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3526281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 353f28847a8SJon Lin 3546281205aSDingqiang Lin if (ret != SFC_OK) 3556281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 356f28847a8SJon Lin 3576281205aSDingqiang Lin if (!(status & (1 << 0))) 3586281205aSDingqiang Lin break; 359f28847a8SJon Lin 3606281205aSDingqiang Lin sfc_delay(1); 3616281205aSDingqiang Lin } 3626281205aSDingqiang Lin 3636281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3646281205aSDingqiang Lin 3656281205aSDingqiang Lin if (ecc == 0) 3666281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3676281205aSDingqiang Lin else if (ecc == 1) 3686281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3696281205aSDingqiang Lin else 37058463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3716281205aSDingqiang Lin 3726281205aSDingqiang Lin return ret; 3736281205aSDingqiang Lin } 3746281205aSDingqiang Lin 3756281205aSDingqiang Lin /* 376d9cdd318SJon Lin * ecc spectial type2: 377a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 378f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 379f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 380d9cdd318SJon Lin * reach Flipping Bits; 381f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 382c84f0ed8SJon Lin * not corrected. 383f28847a8SJon Lin * [0b1100, 0b1111], reserved. 384d9cdd318SJon Lin */ 385f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 386d9cdd318SJon Lin { 38758463f4dSJon Lin u32 ret; 388d9cdd318SJon Lin u32 i; 389d9cdd318SJon Lin u8 ecc; 390d9cdd318SJon Lin u8 status, status1; 391d9cdd318SJon Lin u32 timeout = 1000 * 1000; 392d9cdd318SJon Lin 393d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 394d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 395f28847a8SJon Lin 396d9cdd318SJon Lin if (ret != SFC_OK) 397d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 398f28847a8SJon Lin 399d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 400f28847a8SJon Lin 401d9cdd318SJon Lin if (ret != SFC_OK) 402d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 403f28847a8SJon Lin 404d9cdd318SJon Lin if (!(status & (1 << 0))) 405d9cdd318SJon Lin break; 406f28847a8SJon Lin 407d9cdd318SJon Lin sfc_delay(1); 408d9cdd318SJon Lin } 409d9cdd318SJon Lin 410d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 411d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 412f28847a8SJon Lin 413d9cdd318SJon Lin if (ecc < 7) 414d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 415d9cdd318SJon Lin else if (ecc == 7) 416d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 417d9cdd318SJon Lin else 41858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 419d9cdd318SJon Lin 420d9cdd318SJon Lin return ret; 421d9cdd318SJon Lin } 422d9cdd318SJon Lin 423d9cdd318SJon Lin /* 4246281205aSDingqiang Lin * ecc spectial type3: 425a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 426f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 427f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 4286281205aSDingqiang Lin * reach Flipping Bits; 429f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 4306281205aSDingqiang Lin * not corrected. 431f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 4326281205aSDingqiang Lin * detectio nthreshold 4336281205aSDingqiang Lin */ 434f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 4356281205aSDingqiang Lin { 43658463f4dSJon Lin u32 ret; 4376281205aSDingqiang Lin u32 i; 4386281205aSDingqiang Lin u8 ecc; 4396281205aSDingqiang Lin u8 status, status1; 4406281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4416281205aSDingqiang Lin 4426281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4436281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 444f28847a8SJon Lin 4456281205aSDingqiang Lin if (ret != SFC_OK) 4466281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 447f28847a8SJon Lin 4486281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 449f28847a8SJon Lin 4506281205aSDingqiang Lin if (ret != SFC_OK) 4516281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 452f28847a8SJon Lin 4536281205aSDingqiang Lin if (!(status & (1 << 0))) 4546281205aSDingqiang Lin break; 455f28847a8SJon Lin 4566281205aSDingqiang Lin sfc_delay(1); 4576281205aSDingqiang Lin } 4586281205aSDingqiang Lin 4596281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4606281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 461f28847a8SJon Lin 4626281205aSDingqiang Lin if (ecc < 7) 4636281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4646281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 4656281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4666281205aSDingqiang Lin else 46758463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4686281205aSDingqiang Lin 4696281205aSDingqiang Lin return ret; 4706281205aSDingqiang Lin } 4716281205aSDingqiang Lin 47225098c06SDingqiang Lin /* 47325098c06SDingqiang Lin * ecc spectial type4: 474a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 475f28847a8SJon Lin * [0b0000], No bit errors were detected; 476f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 47725098c06SDingqiang Lin * reach Flipping Bits; 478f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 47925098c06SDingqiang Lin * not corrected. 480f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 48125098c06SDingqiang Lin * detection threshold 48225098c06SDingqiang Lin * else, reserved 48325098c06SDingqiang Lin */ 484f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 48525098c06SDingqiang Lin { 48658463f4dSJon Lin u32 ret; 48725098c06SDingqiang Lin u32 i; 48825098c06SDingqiang Lin u8 ecc; 48925098c06SDingqiang Lin u8 status; 49025098c06SDingqiang Lin u32 timeout = 1000 * 1000; 49125098c06SDingqiang Lin 49225098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 49325098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 494f28847a8SJon Lin 49525098c06SDingqiang Lin if (ret != SFC_OK) 49625098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 497f28847a8SJon Lin 49825098c06SDingqiang Lin if (!(status & (1 << 0))) 49925098c06SDingqiang Lin break; 500f28847a8SJon Lin 50125098c06SDingqiang Lin sfc_delay(1); 50225098c06SDingqiang Lin } 50325098c06SDingqiang Lin 50425098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 505f28847a8SJon Lin 50625098c06SDingqiang Lin if (ecc < 7) 50725098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 50825098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 50925098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 51025098c06SDingqiang Lin else 51158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 51225098c06SDingqiang Lin 51325098c06SDingqiang Lin return ret; 51425098c06SDingqiang Lin } 51525098c06SDingqiang Lin 51625098c06SDingqiang Lin /* 51725098c06SDingqiang Lin * ecc spectial type5: 518a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 519f28847a8SJon Lin * [0b000], No bit errors were detected; 520f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 52125098c06SDingqiang Lin * reach Flipping Bits; 522f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 52325098c06SDingqiang Lin * detection threshold 524f28847a8SJon Lin * [0b101, 0b110], Reserved; 525f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 52625098c06SDingqiang Lin * not corrected. 52725098c06SDingqiang Lin */ 528f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 52925098c06SDingqiang Lin { 53058463f4dSJon Lin u32 ret; 53125098c06SDingqiang Lin u32 i; 53225098c06SDingqiang Lin u8 ecc; 53325098c06SDingqiang Lin u8 status; 53425098c06SDingqiang Lin u32 timeout = 1000 * 1000; 53525098c06SDingqiang Lin 53625098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 53725098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 538f28847a8SJon Lin 53925098c06SDingqiang Lin if (ret != SFC_OK) 54025098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 541f28847a8SJon Lin 54225098c06SDingqiang Lin if (!(status & (1 << 0))) 54325098c06SDingqiang Lin break; 544f28847a8SJon Lin 54525098c06SDingqiang Lin sfc_delay(1); 54625098c06SDingqiang Lin } 54725098c06SDingqiang Lin 54825098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 549f28847a8SJon Lin 55025098c06SDingqiang Lin if (ecc < 4) 55125098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 55225098c06SDingqiang Lin else if (ecc == 4) 55325098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 55425098c06SDingqiang Lin else 55558463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 55625098c06SDingqiang Lin 55725098c06SDingqiang Lin return ret; 55825098c06SDingqiang Lin } 55925098c06SDingqiang Lin 560f28847a8SJon Lin /* 561f28847a8SJon Lin * ecc spectial type6: 562f28847a8SJon Lin * ecc bits: 0xC0[4,6] 563f28847a8SJon Lin * [0b000], No bit errors were detected; 564f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 565f28847a8SJon Lin * reach Flipping Bits; 566f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 567f28847a8SJon Lin * not corrected. 568f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 569f28847a8SJon Lin * reach Flipping Bits; 570f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 571f28847a8SJon Lin * detectionthreshold 572f28847a8SJon Lin * others, Reserved. 573f28847a8SJon Lin */ 574f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 575f28847a8SJon Lin { 576f28847a8SJon Lin u32 ret; 577f28847a8SJon Lin u32 i; 578f28847a8SJon Lin u8 ecc; 579f28847a8SJon Lin u8 status; 580f28847a8SJon Lin u32 timeout = 1000 * 1000; 581f28847a8SJon Lin 582f28847a8SJon Lin for (i = 0; i < timeout; i++) { 583f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 584f28847a8SJon Lin 585f28847a8SJon Lin if (ret != SFC_OK) 586f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 587f28847a8SJon Lin 588f28847a8SJon Lin if (!(status & (1 << 0))) 589f28847a8SJon Lin break; 590f28847a8SJon Lin 591f28847a8SJon Lin sfc_delay(1); 592f28847a8SJon Lin } 593f28847a8SJon Lin 594f28847a8SJon Lin ecc = (status >> 4) & 0x07; 595f28847a8SJon Lin 596f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 597f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 598f28847a8SJon Lin else if (ecc == 5) 599f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 600f28847a8SJon Lin else 601f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 602f28847a8SJon Lin 603f28847a8SJon Lin return ret; 604f28847a8SJon Lin } 605f28847a8SJon Lin 606362b1be1SJon Lin /* 607362b1be1SJon Lin * ecc spectial type7: 608362b1be1SJon Lin * ecc bits: 0xC0[4,7] 609362b1be1SJon Lin * [0b0000], No bit errors were detected; 610362b1be1SJon Lin * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 611362b1be1SJon Lin * reach Flipping Bits; 612362b1be1SJon Lin * [0b1000], 8 Bit errors were detected and corrected. Bit error count 613362b1be1SJon Lin * equals the bit flip detectionthreshold; 614362b1be1SJon Lin * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 615362b1be1SJon Lin * others, Reserved. 616362b1be1SJon Lin */ 617362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void) 618362b1be1SJon Lin { 619362b1be1SJon Lin u32 ret; 620362b1be1SJon Lin u32 i; 621362b1be1SJon Lin u8 ecc; 622362b1be1SJon Lin u8 status; 623362b1be1SJon Lin u32 timeout = 1000 * 1000; 624362b1be1SJon Lin 625362b1be1SJon Lin for (i = 0; i < timeout; i++) { 626362b1be1SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 627362b1be1SJon Lin 628362b1be1SJon Lin if (ret != SFC_OK) 629362b1be1SJon Lin return SFC_NAND_ECC_ERROR; 630362b1be1SJon Lin 631362b1be1SJon Lin if (!(status & (1 << 0))) 632362b1be1SJon Lin break; 633362b1be1SJon Lin 634362b1be1SJon Lin sfc_delay(1); 635362b1be1SJon Lin } 636362b1be1SJon Lin 637362b1be1SJon Lin ecc = (status >> 4) & 0xf; 638362b1be1SJon Lin 639362b1be1SJon Lin if (ecc < 7) 640362b1be1SJon Lin ret = SFC_NAND_ECC_OK; 641362b1be1SJon Lin else if (ecc == 7 || ecc == 8) 642362b1be1SJon Lin ret = SFC_NAND_ECC_REFRESH; 643362b1be1SJon Lin else 644362b1be1SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 645362b1be1SJon Lin 646362b1be1SJon Lin return ret; 647362b1be1SJon Lin } 648362b1be1SJon Lin 649629111d3SJon Lin /* 650629111d3SJon Lin * ecc spectial type8: 651629111d3SJon Lin * ecc bits: 0xC0[4,6] 652629111d3SJon Lin * [0b000], No bit errors were detected; 653629111d3SJon Lin * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not 654629111d3SJon Lin * reach Flipping Bits; 655629111d3SJon Lin * [0b100], Bit error count equals the bit flip 656629111d3SJon Lin * detection threshold 657629111d3SJon Lin * others, Reserved. 658629111d3SJon Lin */ 659629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void) 660629111d3SJon Lin { 661629111d3SJon Lin u32 ret; 662629111d3SJon Lin u32 i; 663629111d3SJon Lin u8 ecc; 664629111d3SJon Lin u8 status; 665629111d3SJon Lin u32 timeout = 1000 * 1000; 666629111d3SJon Lin 667629111d3SJon Lin for (i = 0; i < timeout; i++) { 668629111d3SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 669629111d3SJon Lin 670629111d3SJon Lin if (ret != SFC_OK) 671629111d3SJon Lin return SFC_NAND_ECC_ERROR; 672629111d3SJon Lin 673629111d3SJon Lin if (!(status & (1 << 0))) 674629111d3SJon Lin break; 675629111d3SJon Lin 676629111d3SJon Lin sfc_delay(1); 677629111d3SJon Lin } 678629111d3SJon Lin 679629111d3SJon Lin ecc = (status >> 4) & 0x07; 680629111d3SJon Lin 681629111d3SJon Lin if (ecc < 4) 682629111d3SJon Lin ret = SFC_NAND_ECC_OK; 683629111d3SJon Lin else if (ecc == 4) 684629111d3SJon Lin ret = SFC_NAND_ECC_REFRESH; 685629111d3SJon Lin else 686629111d3SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 687629111d3SJon Lin 688629111d3SJon Lin return ret; 689629111d3SJon Lin } 690629111d3SJon Lin 691c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 692ba0501acSDingqiang Lin { 693ba0501acSDingqiang Lin int ret; 69458463f4dSJon Lin struct rk_sfc_op op; 695ba0501acSDingqiang Lin u8 status; 696ba0501acSDingqiang Lin 697c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 69858463f4dSJon Lin op.sfcmd.d32 = 0; 699f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 70058463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 70158463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 70258463f4dSJon Lin 70358463f4dSJon Lin op.sfctrl.d32 = 0; 70458463f4dSJon Lin 705ba0501acSDingqiang Lin sfc_nand_write_en(); 70658463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 707f28847a8SJon Lin 708ba0501acSDingqiang Lin if (ret != SFC_OK) 709ba0501acSDingqiang Lin return ret; 710f28847a8SJon Lin 711ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 712f28847a8SJon Lin 713ba0501acSDingqiang Lin if (status & (1 << 2)) 714ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 715c84f0ed8SJon Lin 716ba0501acSDingqiang Lin return ret; 717ba0501acSDingqiang Lin } 718ba0501acSDingqiang Lin 719629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len) 720629111d3SJon Lin { 721629111d3SJon Lin int ret; 722629111d3SJon Lin u32 plane; 723629111d3SJon Lin struct rk_sfc_op op; 724629111d3SJon Lin 725629111d3SJon Lin op.sfcmd.d32 = 0; 726629111d3SJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 727629111d3SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 728629111d3SJon Lin op.sfcmd.b.dummybits = 8; 729629111d3SJon Lin 730629111d3SJon Lin op.sfctrl.d32 = 0; 731629111d3SJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 732629111d3SJon Lin op.sfctrl.b.addrbits = 16; 733629111d3SJon Lin 734629111d3SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 735629111d3SJon Lin 736629111d3SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 737629111d3SJon Lin if (ret != SFC_OK) 738629111d3SJon Lin return SFC_NAND_HW_ERROR; 739629111d3SJon Lin 740629111d3SJon Lin return ret; 741629111d3SJon Lin } 742629111d3SJon Lin 743f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 744ba0501acSDingqiang Lin { 745ba0501acSDingqiang Lin int ret; 746415cf080Sjon.lin u32 plane; 74758463f4dSJon Lin struct rk_sfc_op op; 748ba0501acSDingqiang Lin u8 status; 74958463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 750629111d3SJon Lin u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page; 751ba0501acSDingqiang Lin 752c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 753ba0501acSDingqiang Lin sfc_nand_write_en(); 754f28847a8SJon Lin 755ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 75625098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 75725098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 758ba0501acSDingqiang Lin sfc_nand_rw_preset(); 759ba0501acSDingqiang Lin 76058463f4dSJon Lin op.sfcmd.d32 = 0; 76158463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 76258463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 76358463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 764ba0501acSDingqiang Lin 76558463f4dSJon Lin op.sfctrl.d32 = 0; 76658463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 76758463f4dSJon Lin op.sfctrl.b.addrbits = 16; 768415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 76958463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 770ba0501acSDingqiang Lin 771629111d3SJon Lin /* 772*c797b43aSJon Lin * At the moment of power lost or dev running in harsh environment, flash 773*c797b43aSJon Lin * maybe work in a unkonw state and result in bit flip, when this situation 774*c797b43aSJon Lin * is detected by cache recheck, it's better to wait a second for a reliable 775*c797b43aSJon Lin * hardware environment to avoid abnormal data written to flash array. 776629111d3SJon Lin */ 777*c797b43aSJon Lin if (p_nand_info->id0 != MID_XTX) { 778629111d3SJon Lin sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size); 779*c797b43aSJon Lin if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) { 780*c797b43aSJon Lin rkflash_print_error("%s %x cache bitflip\n", __func__, addr); 781*c797b43aSJon Lin mdelay(1000); 782*c797b43aSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 783*c797b43aSJon Lin } 784*c797b43aSJon Lin } 785629111d3SJon Lin 78658463f4dSJon Lin op.sfcmd.d32 = 0; 787f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 78858463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 78958463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 79058463f4dSJon Lin 79158463f4dSJon Lin op.sfctrl.d32 = 0; 79258463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 793f28847a8SJon Lin 794ba0501acSDingqiang Lin if (ret != SFC_OK) 795ba0501acSDingqiang Lin return ret; 796f28847a8SJon Lin 797ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 798ba0501acSDingqiang Lin if (status & (1 << 3)) 799ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 800c84f0ed8SJon Lin 801ba0501acSDingqiang Lin return ret; 802ba0501acSDingqiang Lin } 803ba0501acSDingqiang Lin 804c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 805c84f0ed8SJon Lin { 806c84f0ed8SJon Lin int ret; 807c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 808c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 809a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 810c84f0ed8SJon Lin 811c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 812c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 813a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 814a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 815f28847a8SJon Lin 816c84f0ed8SJon Lin if (sec_per_page == 8) { 817a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 818a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 819c84f0ed8SJon Lin } 820f28847a8SJon Lin 821c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 822c84f0ed8SJon Lin 823c84f0ed8SJon Lin return ret; 824c84f0ed8SJon Lin } 825c84f0ed8SJon Lin 826a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 827ba0501acSDingqiang Lin { 828ba0501acSDingqiang Lin int ret; 829415cf080Sjon.lin u32 plane; 83058463f4dSJon Lin struct rk_sfc_op op; 8316281205aSDingqiang Lin u32 ecc_result; 832a6fcac41SJon Lin u8 status; 833ba0501acSDingqiang Lin 83458463f4dSJon Lin op.sfcmd.d32 = 0; 835f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 83658463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 83758463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 83858463f4dSJon Lin 83958463f4dSJon Lin op.sfctrl.d32 = 0; 84058463f4dSJon Lin 841a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 842f28847a8SJon Lin 843ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 84425098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 84525098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 846ba0501acSDingqiang Lin sfc_nand_rw_preset(); 847ba0501acSDingqiang Lin 848a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 849a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 850a6fcac41SJon Lin 85158463f4dSJon Lin op.sfcmd.d32 = 0; 85258463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 853a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 854a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 85558463f4dSJon Lin 85658463f4dSJon Lin op.sfctrl.d32 = 0; 85758463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 858a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 859ba0501acSDingqiang Lin 860a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 861a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 862a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 863c84f0ed8SJon Lin 864c84f0ed8SJon Lin if (ret != SFC_OK) 865f28847a8SJon Lin return SFC_NAND_HW_ERROR; 866c84f0ed8SJon Lin 867c84f0ed8SJon Lin return ecc_result; 868c84f0ed8SJon Lin } 869c84f0ed8SJon Lin 870a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 871a80fd396SJon Lin { 872a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 873a80fd396SJon Lin 874a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 875a80fd396SJon Lin } 876a80fd396SJon Lin 877c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 878c84f0ed8SJon Lin { 87958463f4dSJon Lin u32 ret; 880c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 881c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 882a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 883c84f0ed8SJon Lin 884c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 885f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 886a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 887a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 888f28847a8SJon Lin 889f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 890a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 891a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 892f25e3cafSJon Lin } 893ba0501acSDingqiang Lin 894f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 895f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 896f28847a8SJon Lin 897c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 898c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 899f28847a8SJon Lin 900ba0501acSDingqiang Lin if (p_data) 901c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 902f28847a8SJon Lin 903ba0501acSDingqiang Lin if (p_spare) 904c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 905ba0501acSDingqiang Lin } 906f25e3cafSJon Lin 907c84f0ed8SJon Lin return ret; 908ba0501acSDingqiang Lin } 909ba0501acSDingqiang Lin 910c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 911c84f0ed8SJon Lin { 912c84f0ed8SJon Lin u32 ret; 913c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 914a80fd396SJon Lin u32 marker = 0; 915c84f0ed8SJon Lin 916a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 917f28847a8SJon Lin 918f28847a8SJon Lin /* unify with mtd framework */ 919629111d3SJon Lin if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff) 920a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 921a80fd396SJon Lin __func__, addr, ret, marker); 922f28847a8SJon Lin 923c84f0ed8SJon Lin /* Original bad block */ 924a80fd396SJon Lin if ((u16)marker != 0xffff) 925c84f0ed8SJon Lin return true; 926c84f0ed8SJon Lin 927c84f0ed8SJon Lin return false; 928c84f0ed8SJon Lin } 929c84f0ed8SJon Lin 930c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 931c84f0ed8SJon Lin { 932c84f0ed8SJon Lin u32 ret; 933c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 934c84f0ed8SJon Lin 935c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 936f28847a8SJon Lin 937c84f0ed8SJon Lin if (ret) 938c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 939f28847a8SJon Lin 940c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 941c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 942f28847a8SJon Lin 943c84f0ed8SJon Lin if (ret) 944c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 945c84f0ed8SJon Lin 946c84f0ed8SJon Lin return ret; 947c84f0ed8SJon Lin } 948c84f0ed8SJon Lin 949c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 950ba0501acSDingqiang Lin { 951ba0501acSDingqiang Lin int ret; 95258463f4dSJon Lin struct rk_sfc_op op; 953ba0501acSDingqiang Lin 95458463f4dSJon Lin op.sfcmd.d32 = 0; 95558463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 95658463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 957ba0501acSDingqiang Lin 95858463f4dSJon Lin op.sfctrl.d32 = 0; 95958463f4dSJon Lin op.sfctrl.b.addrbits = 8; 96058463f4dSJon Lin 96158463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 962ba0501acSDingqiang Lin 963ba0501acSDingqiang Lin return ret; 964ba0501acSDingqiang Lin } 965ba0501acSDingqiang Lin 966ba0501acSDingqiang Lin /* 967ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 968ba0501acSDingqiang Lin * If not FF, it's bad blk 969ba0501acSDingqiang Lin */ 970ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 971ba0501acSDingqiang Lin { 972ba0501acSDingqiang Lin u32 bad_cnt, page; 973ba0501acSDingqiang Lin u32 blk_per_die; 9742ac88c1bSJon Lin u16 blk; 975ba0501acSDingqiang Lin 976c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 977c84f0ed8SJon Lin 978ba0501acSDingqiang Lin bad_cnt = 0; 979ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 980ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 981f28847a8SJon Lin 982ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 983ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 984ba0501acSDingqiang Lin p_nand_info->page_per_blk; 985ba0501acSDingqiang Lin 9862ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 987ba0501acSDingqiang Lin table[bad_cnt++] = blk; 988c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 989ba0501acSDingqiang Lin } 990ba0501acSDingqiang Lin } 991f28847a8SJon Lin 992ba0501acSDingqiang Lin return (int)bad_cnt; 993ba0501acSDingqiang Lin } 994ba0501acSDingqiang Lin 995c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 996ba0501acSDingqiang Lin { 997ba0501acSDingqiang Lin /* para init */ 998ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 999ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 1000ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 1001ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 1002ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 1003ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 1004c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 1005ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 1006ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 1007ba0501acSDingqiang Lin p_nand_info->page_per_blk; 1008ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 1009ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 1010ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 1011ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 1012ba0501acSDingqiang Lin 1013ba0501acSDingqiang Lin /* driver register */ 1014ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 1015ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 1016ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 1017ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 101857d18453Sjon.lin g_nand_ops.bch_sel = NULL; 1019ba0501acSDingqiang Lin } 1020ba0501acSDingqiang Lin 1021a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 1022ba0501acSDingqiang Lin { 1023ba0501acSDingqiang Lin int ret = SFC_OK; 1024ba0501acSDingqiang Lin u8 status; 1025ba0501acSDingqiang Lin 1026f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 1027ba0501acSDingqiang Lin 1028ba0501acSDingqiang Lin if (ret != SFC_OK) 1029ba0501acSDingqiang Lin return ret; 1030ba0501acSDingqiang Lin 1031f28847a8SJon Lin if (status & 1) /* is QE bit set */ 1032ba0501acSDingqiang Lin return SFC_OK; 1033ba0501acSDingqiang Lin 1034f28847a8SJon Lin status |= 1; 1035ba0501acSDingqiang Lin 1036f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 1037ba0501acSDingqiang Lin } 1038ba0501acSDingqiang Lin 1039ba0501acSDingqiang Lin u32 sfc_nand_init(void) 1040ba0501acSDingqiang Lin { 1041c84f0ed8SJon Lin u8 status, id_byte[8]; 1042ba0501acSDingqiang Lin 1043c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 1044c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 1045ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 1046f28847a8SJon Lin 1047ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 104858463f4dSJon Lin return (u32)FTL_NO_FLASH; 1049ba0501acSDingqiang Lin 1050a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 1051f28847a8SJon Lin 1052ba0501acSDingqiang Lin if (!p_nand_info) 105358463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 1054ba0501acSDingqiang Lin 1055ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 1056ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 1057c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 1058c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 1059c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 1060ba0501acSDingqiang Lin 1061ba0501acSDingqiang Lin /* disable block lock */ 1062ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 1063ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 1064ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 1065f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 1066f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 1067629111d3SJon Lin sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE); 1068629111d3SJon Lin if (!sfc_nand_dev.recheck_buffer) { 1069629111d3SJon Lin rkflash_print_error("%s recheck_buffer alloc failed\n", __func__); 1070629111d3SJon Lin return -1; 1071629111d3SJon Lin } 1072f28847a8SJon Lin 1073ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 1074f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 1075f28847a8SJon Lin !p_nand_info->has_qe_bits) { 1076ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 1077f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 1078ba0501acSDingqiang Lin } 1079ba0501acSDingqiang Lin } 1080ba0501acSDingqiang Lin 1081ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 1082ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 1083ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 1084f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 1085ba0501acSDingqiang Lin } 1086ba0501acSDingqiang Lin 1087ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 1088c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 1089ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 1090c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 1091c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 1092c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 1093c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 1094c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 1095ba0501acSDingqiang Lin 1096ba0501acSDingqiang Lin return SFC_OK; 1097ba0501acSDingqiang Lin } 1098ba0501acSDingqiang Lin 1099c84f0ed8SJon Lin void sfc_nand_deinit(void) 1100ba0501acSDingqiang Lin { 1101c84f0ed8SJon Lin /* to-do */ 1102629111d3SJon Lin kfree(sfc_nand_dev.recheck_buffer); 1103ba0501acSDingqiang Lin } 1104c84f0ed8SJon Lin 1105c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 1106c84f0ed8SJon Lin { 1107c84f0ed8SJon Lin return &sfc_nand_dev; 1108c84f0ed8SJon Lin } 1109c84f0ed8SJon Lin 1110