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); 24f28847a8SJon Lin 25ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 26ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 27*b833c879SJon Lin { 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 28ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 29*b833c879SJon Lin { 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 30a6fcac41SJon Lin /* TC58CVG2S0HRAIJ */ 31*b833c879SJon Lin { 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 }, 32a6fcac41SJon Lin /* TC58CVG1S3HRAIJ */ 33*b833c879SJon Lin { 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 34a6fcac41SJon Lin /* TC58CVG0S3HRAIJ */ 35*b833c879SJon Lin { 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 36f28847a8SJon Lin 37f28847a8SJon Lin /* MX35LF1GE4AB */ 38*b833c879SJon Lin { 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 39f28847a8SJon Lin /* MX35LF2GE4AB */ 40*b833c879SJon Lin { 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 41f28847a8SJon Lin /* MX35LF2GE4AD */ 42*b833c879SJon Lin { 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 43f28847a8SJon Lin /* MX35LF4GE4AD */ 44*b833c879SJon Lin { 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 45f28847a8SJon Lin /* MT29F1G01ZAC */ 46*b833c879SJon Lin { 0x2C, 0x12, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 47f28847a8SJon Lin 48f28847a8SJon Lin /* GD5F1GQ4UAYIG */ 49*b833c879SJon Lin { 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 50f28847a8SJon Lin /* GD5F1GQ4RB9IGR */ 51*b833c879SJon Lin { 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 52f28847a8SJon Lin /* GD5F2GQ40BY2GR */ 53*b833c879SJon Lin { 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 54f28847a8SJon Lin /* GD5F1GQ5UEYIG */ 55*b833c879SJon Lin { 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 56f28847a8SJon Lin /* GD5F2GQ5UEYIG */ 57*b833c879SJon Lin { 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 58f28847a8SJon Lin /* GD5F1GQ4R */ 59*b833c879SJon Lin { 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 60f28847a8SJon Lin 61f28847a8SJon Lin /* W25N01GV */ 62*b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 63*b833c879SJon Lin /* W25N02KVZEIR */ 64*b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 65f28847a8SJon Lin /* W25N01GW */ 66*b833c879SJon Lin { 0xEF, 0xBA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 67f28847a8SJon Lin 68f28847a8SJon Lin /* HYF2GQ4UAACAE */ 69*b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 70f28847a8SJon Lin /* HYF1GQ4UDACAE */ 71*b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 72f28847a8SJon Lin /* HYF1GQ4UPACAE */ 73*b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 74f28847a8SJon Lin /* HYF2GQ4UDACAE */ 75*b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 76f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 77*b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 78f28847a8SJon Lin /* HYF4GQ4UAACBE */ 79*b833c879SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 80f28847a8SJon Lin 81f28847a8SJon Lin /* FS35ND01G-S1 */ 82*b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 83f28847a8SJon Lin /* FS35ND02G-S2 */ 84*b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 8558463f4dSJon Lin /* FS35ND01G-S1Y2 */ 86*b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 87f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 88*b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 89f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 90*b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 91f28847a8SJon Lin 92f28847a8SJon Lin /* DS35Q1GA-IB */ 93*b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 94f28847a8SJon Lin /* DS35Q2GA-IB */ 95*b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 96f28847a8SJon Lin /* DS35M1GA-1B */ 97*b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 98f28847a8SJon Lin 99f28847a8SJon Lin /* EM73C044VCC-H */ 100*b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 101f28847a8SJon Lin /* EM73D044VCE-H */ 102*b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 103f28847a8SJon Lin /* EM73E044SNA-G */ 104*b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 105f28847a8SJon Lin 106f28847a8SJon Lin /* XT26G02A */ 107*b833c879SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 108f28847a8SJon Lin /* XT26G01A */ 109*b833c879SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 110f28847a8SJon Lin /* XT26G04A */ 111*b833c879SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 112f28847a8SJon Lin /* XT26G01B */ 113*b833c879SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 114f28847a8SJon Lin /* XT26G02B */ 115*b833c879SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 116a80fd396SJon Lin 117a80fd396SJon Lin /* MT29F2G1ABA, XT26G02E, F50L2G41XA */ 118*b833c879SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 119a80fd396SJon Lin 120a80fd396SJon Lin /* FM25S01 */ 121*b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 122a80fd396SJon Lin /* FM25S01A */ 123*b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 124a80fd396SJon Lin /* FM25S02A */ 125*b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 126f28847a8SJon Lin 127f28847a8SJon Lin /* IS37SML01G1 */ 128*b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 129f28847a8SJon Lin /* F50L1G41LB */ 130*b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 131f28847a8SJon Lin /* ATO25D1GA */ 132*b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 133ba0501acSDingqiang Lin }; 134ba0501acSDingqiang Lin 135ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 136ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 137ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 138ba0501acSDingqiang Lin 139a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 140ba0501acSDingqiang Lin { 141ba0501acSDingqiang Lin u32 i; 142ba0501acSDingqiang Lin 143ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 144*b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 145*b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 146*b833c879SJon Lin if (spi_nand_tbl[i].id2 && 147*b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 148*b833c879SJon Lin continue; 149*b833c879SJon Lin 150ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 151ba0501acSDingqiang Lin } 152*b833c879SJon Lin } 153f28847a8SJon Lin 154ba0501acSDingqiang Lin return NULL; 155ba0501acSDingqiang Lin } 156ba0501acSDingqiang Lin 157ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 158ba0501acSDingqiang Lin { 159ba0501acSDingqiang Lin int ret; 16058463f4dSJon Lin struct rk_sfc_op op; 161ba0501acSDingqiang Lin 16258463f4dSJon Lin op.sfcmd.d32 = 0; 16358463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 16458463f4dSJon Lin 16558463f4dSJon Lin op.sfctrl.d32 = 0; 16658463f4dSJon Lin 16758463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 168ba0501acSDingqiang Lin return ret; 169ba0501acSDingqiang Lin } 170ba0501acSDingqiang Lin 171ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 172ba0501acSDingqiang Lin { 173ba0501acSDingqiang Lin int ret; 17458463f4dSJon Lin struct rk_sfc_op op; 175ba0501acSDingqiang Lin 17658463f4dSJon Lin op.sfcmd.d32 = 0; 177f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 178f28847a8SJon Lin op.sfcmd.b.cs = 2; 179ba0501acSDingqiang Lin 18058463f4dSJon Lin op.sfctrl.d32 = 0; 18158463f4dSJon Lin op.sfctrl.b.datalines = 2; 182f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 183f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 18458463f4dSJon Lin 185f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 186ba0501acSDingqiang Lin return ret; 187ba0501acSDingqiang Lin } 188ba0501acSDingqiang Lin 189ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 190ba0501acSDingqiang Lin { 191ba0501acSDingqiang Lin int ret; 19258463f4dSJon Lin struct rk_sfc_op op; 193ba0501acSDingqiang Lin 19458463f4dSJon Lin op.sfcmd.d32 = 0; 19558463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 19658463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 19758463f4dSJon Lin 19858463f4dSJon Lin op.sfctrl.d32 = 0; 19958463f4dSJon Lin op.sfctrl.b.addrbits = 8; 20058463f4dSJon Lin 201ba0501acSDingqiang Lin *data = 0; 202ba0501acSDingqiang Lin 20358463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 204f28847a8SJon Lin 205ba0501acSDingqiang Lin if (ret != SFC_OK) 206ba0501acSDingqiang Lin return ret; 207f28847a8SJon Lin 208ba0501acSDingqiang Lin return SFC_OK; 209ba0501acSDingqiang Lin } 210ba0501acSDingqiang Lin 211ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 212ba0501acSDingqiang Lin { 213ba0501acSDingqiang Lin int ret; 21458463f4dSJon Lin struct rk_sfc_op op; 215ba0501acSDingqiang Lin 216ba0501acSDingqiang Lin sfc_nand_write_en(); 217ba0501acSDingqiang Lin 21858463f4dSJon Lin op.sfcmd.d32 = 0; 21958463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 22058463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 22158463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 222ba0501acSDingqiang Lin 22358463f4dSJon Lin op.sfctrl.d32 = 0; 22458463f4dSJon Lin op.sfctrl.b.addrbits = 8; 22558463f4dSJon Lin 22658463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 227f28847a8SJon Lin 228ba0501acSDingqiang Lin if (ret != SFC_OK) 229ba0501acSDingqiang Lin return ret; 230f28847a8SJon Lin 231ba0501acSDingqiang Lin return ret; 232ba0501acSDingqiang Lin } 233ba0501acSDingqiang Lin 234ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 235ba0501acSDingqiang Lin { 236ba0501acSDingqiang Lin int ret; 237ba0501acSDingqiang Lin int i; 238ba0501acSDingqiang Lin u8 status; 239ba0501acSDingqiang Lin 240ba0501acSDingqiang Lin *data = 0; 241f28847a8SJon Lin 242ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 243ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 244f28847a8SJon Lin 245ba0501acSDingqiang Lin if (ret != SFC_OK) 246ba0501acSDingqiang Lin return ret; 247f28847a8SJon Lin 248ba0501acSDingqiang Lin *data = status; 249f28847a8SJon Lin 250ba0501acSDingqiang Lin if (!(status & (1 << 0))) 251ba0501acSDingqiang Lin return SFC_OK; 252f28847a8SJon Lin 253ba0501acSDingqiang Lin sfc_delay(1); 254ba0501acSDingqiang Lin } 255f28847a8SJon Lin 256f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 257ba0501acSDingqiang Lin } 258ba0501acSDingqiang Lin 2596281205aSDingqiang Lin /* 2606281205aSDingqiang Lin * ecc default: 261a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 262f28847a8SJon Lin * 0b00, No bit errors were detected 263f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 264f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 265f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 2666281205aSDingqiang Lin * exceed the bit flip detection threshold 2676281205aSDingqiang Lin */ 268f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 2696281205aSDingqiang Lin { 27058463f4dSJon Lin u32 ret; 2716281205aSDingqiang Lin u32 i; 2726281205aSDingqiang Lin u8 ecc; 2736281205aSDingqiang Lin u8 status; 2746281205aSDingqiang Lin u32 timeout = 1000 * 1000; 2756281205aSDingqiang Lin 2766281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 2776281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 278f28847a8SJon Lin 2796281205aSDingqiang Lin if (ret != SFC_OK) 2806281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 281f28847a8SJon Lin 2826281205aSDingqiang Lin if (!(status & (1 << 0))) 2836281205aSDingqiang Lin break; 284f28847a8SJon Lin 2856281205aSDingqiang Lin sfc_delay(1); 2866281205aSDingqiang Lin } 2876281205aSDingqiang Lin 2886281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 2896281205aSDingqiang Lin 2906281205aSDingqiang Lin if (ecc <= 1) 2916281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 2926281205aSDingqiang Lin else if (ecc == 2) 29358463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 2946281205aSDingqiang Lin else 2956281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 2966281205aSDingqiang Lin 2976281205aSDingqiang Lin return ret; 2986281205aSDingqiang Lin } 2996281205aSDingqiang Lin 3006281205aSDingqiang Lin /* 3016281205aSDingqiang Lin * ecc spectial type1: 302a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 303f28847a8SJon Lin * 0b00, No bit errors were detected; 304f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 3056281205aSDingqiang Lin * may reach the bit flip detection threshold; 306f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 307f28847a8SJon Lin * 0b11, Reserved. 3086281205aSDingqiang Lin */ 309f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 3106281205aSDingqiang Lin { 31158463f4dSJon Lin u32 ret; 3126281205aSDingqiang Lin u32 i; 3136281205aSDingqiang Lin u8 ecc; 3146281205aSDingqiang Lin u8 status; 3156281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3166281205aSDingqiang Lin 3176281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3186281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 319f28847a8SJon Lin 3206281205aSDingqiang Lin if (ret != SFC_OK) 3216281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 322f28847a8SJon Lin 3236281205aSDingqiang Lin if (!(status & (1 << 0))) 3246281205aSDingqiang Lin break; 325f28847a8SJon Lin 3266281205aSDingqiang Lin sfc_delay(1); 3276281205aSDingqiang Lin } 3286281205aSDingqiang Lin 3296281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3306281205aSDingqiang Lin 3316281205aSDingqiang Lin if (ecc == 0) 3326281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3336281205aSDingqiang Lin else if (ecc == 1) 3346281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3356281205aSDingqiang Lin else 33658463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3376281205aSDingqiang Lin 3386281205aSDingqiang Lin return ret; 3396281205aSDingqiang Lin } 3406281205aSDingqiang Lin 3416281205aSDingqiang Lin /* 342d9cdd318SJon Lin * ecc spectial type2: 343a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 344f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 345f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 346d9cdd318SJon Lin * reach Flipping Bits; 347f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 348c84f0ed8SJon Lin * not corrected. 349f28847a8SJon Lin * [0b1100, 0b1111], reserved. 350d9cdd318SJon Lin */ 351f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 352d9cdd318SJon Lin { 35358463f4dSJon Lin u32 ret; 354d9cdd318SJon Lin u32 i; 355d9cdd318SJon Lin u8 ecc; 356d9cdd318SJon Lin u8 status, status1; 357d9cdd318SJon Lin u32 timeout = 1000 * 1000; 358d9cdd318SJon Lin 359d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 360d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 361f28847a8SJon Lin 362d9cdd318SJon Lin if (ret != SFC_OK) 363d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 364f28847a8SJon Lin 365d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 366f28847a8SJon Lin 367d9cdd318SJon Lin if (ret != SFC_OK) 368d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 369f28847a8SJon Lin 370d9cdd318SJon Lin if (!(status & (1 << 0))) 371d9cdd318SJon Lin break; 372f28847a8SJon Lin 373d9cdd318SJon Lin sfc_delay(1); 374d9cdd318SJon Lin } 375d9cdd318SJon Lin 376d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 377d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 378f28847a8SJon Lin 379d9cdd318SJon Lin if (ecc < 7) 380d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 381d9cdd318SJon Lin else if (ecc == 7) 382d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 383d9cdd318SJon Lin else 38458463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 385d9cdd318SJon Lin 386d9cdd318SJon Lin return ret; 387d9cdd318SJon Lin } 388d9cdd318SJon Lin 389d9cdd318SJon Lin /* 3906281205aSDingqiang Lin * ecc spectial type3: 391a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 392f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 393f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 3946281205aSDingqiang Lin * reach Flipping Bits; 395f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 3966281205aSDingqiang Lin * not corrected. 397f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 3986281205aSDingqiang Lin * detectio nthreshold 3996281205aSDingqiang Lin */ 400f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 4016281205aSDingqiang Lin { 40258463f4dSJon Lin u32 ret; 4036281205aSDingqiang Lin u32 i; 4046281205aSDingqiang Lin u8 ecc; 4056281205aSDingqiang Lin u8 status, status1; 4066281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4076281205aSDingqiang Lin 4086281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4096281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 410f28847a8SJon Lin 4116281205aSDingqiang Lin if (ret != SFC_OK) 4126281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 413f28847a8SJon Lin 4146281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 415f28847a8SJon Lin 4166281205aSDingqiang Lin if (ret != SFC_OK) 4176281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 418f28847a8SJon Lin 4196281205aSDingqiang Lin if (!(status & (1 << 0))) 4206281205aSDingqiang Lin break; 421f28847a8SJon Lin 4226281205aSDingqiang Lin sfc_delay(1); 4236281205aSDingqiang Lin } 4246281205aSDingqiang Lin 4256281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4266281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 427f28847a8SJon Lin 4286281205aSDingqiang Lin if (ecc < 7) 4296281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4306281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 4316281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4326281205aSDingqiang Lin else 43358463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4346281205aSDingqiang Lin 4356281205aSDingqiang Lin return ret; 4366281205aSDingqiang Lin } 4376281205aSDingqiang Lin 43825098c06SDingqiang Lin /* 43925098c06SDingqiang Lin * ecc spectial type4: 440a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 441f28847a8SJon Lin * [0b0000], No bit errors were detected; 442f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 44325098c06SDingqiang Lin * reach Flipping Bits; 444f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 44525098c06SDingqiang Lin * not corrected. 446f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 44725098c06SDingqiang Lin * detectionthreshold 44825098c06SDingqiang Lin * else, reserved 44925098c06SDingqiang Lin */ 450f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 45125098c06SDingqiang Lin { 45258463f4dSJon Lin u32 ret; 45325098c06SDingqiang Lin u32 i; 45425098c06SDingqiang Lin u8 ecc; 45525098c06SDingqiang Lin u8 status; 45625098c06SDingqiang Lin u32 timeout = 1000 * 1000; 45725098c06SDingqiang Lin 45825098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 45925098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 460f28847a8SJon Lin 46125098c06SDingqiang Lin if (ret != SFC_OK) 46225098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 463f28847a8SJon Lin 46425098c06SDingqiang Lin if (!(status & (1 << 0))) 46525098c06SDingqiang Lin break; 466f28847a8SJon Lin 46725098c06SDingqiang Lin sfc_delay(1); 46825098c06SDingqiang Lin } 46925098c06SDingqiang Lin 47025098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 471f28847a8SJon Lin 47225098c06SDingqiang Lin if (ecc < 7) 47325098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 47425098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 47525098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 47625098c06SDingqiang Lin else 47758463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 47825098c06SDingqiang Lin 47925098c06SDingqiang Lin return ret; 48025098c06SDingqiang Lin } 48125098c06SDingqiang Lin 48225098c06SDingqiang Lin /* 48325098c06SDingqiang Lin * ecc spectial type5: 484a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 485f28847a8SJon Lin * [0b000], No bit errors were detected; 486f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 48725098c06SDingqiang Lin * reach Flipping Bits; 488f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 48925098c06SDingqiang Lin * detectionthreshold 490f28847a8SJon Lin * [0b101, 0b110], Reserved; 491f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 49225098c06SDingqiang Lin * not corrected. 49325098c06SDingqiang Lin */ 494f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 49525098c06SDingqiang Lin { 49658463f4dSJon Lin u32 ret; 49725098c06SDingqiang Lin u32 i; 49825098c06SDingqiang Lin u8 ecc; 49925098c06SDingqiang Lin u8 status; 50025098c06SDingqiang Lin u32 timeout = 1000 * 1000; 50125098c06SDingqiang Lin 50225098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 50325098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 504f28847a8SJon Lin 50525098c06SDingqiang Lin if (ret != SFC_OK) 50625098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 507f28847a8SJon Lin 50825098c06SDingqiang Lin if (!(status & (1 << 0))) 50925098c06SDingqiang Lin break; 510f28847a8SJon Lin 51125098c06SDingqiang Lin sfc_delay(1); 51225098c06SDingqiang Lin } 51325098c06SDingqiang Lin 51425098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 515f28847a8SJon Lin 51625098c06SDingqiang Lin if (ecc < 4) 51725098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 51825098c06SDingqiang Lin else if (ecc == 4) 51925098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 52025098c06SDingqiang Lin else 52158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 52225098c06SDingqiang Lin 52325098c06SDingqiang Lin return ret; 52425098c06SDingqiang Lin } 52525098c06SDingqiang Lin 526f28847a8SJon Lin /* 527f28847a8SJon Lin * ecc spectial type6: 528f28847a8SJon Lin * ecc bits: 0xC0[4,6] 529f28847a8SJon Lin * [0b000], No bit errors were detected; 530f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 531f28847a8SJon Lin * reach Flipping Bits; 532f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 533f28847a8SJon Lin * not corrected. 534f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 535f28847a8SJon Lin * reach Flipping Bits; 536f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 537f28847a8SJon Lin * detectionthreshold 538f28847a8SJon Lin * others, Reserved. 539f28847a8SJon Lin */ 540f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 541f28847a8SJon Lin { 542f28847a8SJon Lin u32 ret; 543f28847a8SJon Lin u32 i; 544f28847a8SJon Lin u8 ecc; 545f28847a8SJon Lin u8 status; 546f28847a8SJon Lin u32 timeout = 1000 * 1000; 547f28847a8SJon Lin 548f28847a8SJon Lin for (i = 0; i < timeout; i++) { 549f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 550f28847a8SJon Lin 551f28847a8SJon Lin if (ret != SFC_OK) 552f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 553f28847a8SJon Lin 554f28847a8SJon Lin if (!(status & (1 << 0))) 555f28847a8SJon Lin break; 556f28847a8SJon Lin 557f28847a8SJon Lin sfc_delay(1); 558f28847a8SJon Lin } 559f28847a8SJon Lin 560f28847a8SJon Lin ecc = (status >> 4) & 0x07; 561f28847a8SJon Lin 562f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 563f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 564f28847a8SJon Lin else if (ecc == 5) 565f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 566f28847a8SJon Lin else 567f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 568f28847a8SJon Lin 569f28847a8SJon Lin return ret; 570f28847a8SJon Lin } 571f28847a8SJon Lin 572c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 573ba0501acSDingqiang Lin { 574ba0501acSDingqiang Lin int ret; 57558463f4dSJon Lin struct rk_sfc_op op; 576ba0501acSDingqiang Lin u8 status; 577ba0501acSDingqiang Lin 578c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 57958463f4dSJon Lin op.sfcmd.d32 = 0; 580f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 58158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 58258463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 58358463f4dSJon Lin 58458463f4dSJon Lin op.sfctrl.d32 = 0; 58558463f4dSJon Lin 586ba0501acSDingqiang Lin sfc_nand_write_en(); 58758463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 588f28847a8SJon Lin 589ba0501acSDingqiang Lin if (ret != SFC_OK) 590ba0501acSDingqiang Lin return ret; 591f28847a8SJon Lin 592ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 593f28847a8SJon Lin 594ba0501acSDingqiang Lin if (status & (1 << 2)) 595ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 596c84f0ed8SJon Lin 597ba0501acSDingqiang Lin return ret; 598ba0501acSDingqiang Lin } 599ba0501acSDingqiang Lin 600f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 601ba0501acSDingqiang Lin { 602ba0501acSDingqiang Lin int ret; 603415cf080Sjon.lin u32 plane; 60458463f4dSJon Lin struct rk_sfc_op op; 605ba0501acSDingqiang Lin u8 status; 60658463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 607ba0501acSDingqiang Lin 608c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 609ba0501acSDingqiang Lin sfc_nand_write_en(); 610f28847a8SJon Lin 611ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 61225098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 61325098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 614ba0501acSDingqiang Lin sfc_nand_rw_preset(); 615ba0501acSDingqiang Lin 61658463f4dSJon Lin op.sfcmd.d32 = 0; 61758463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 61858463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 61958463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 620ba0501acSDingqiang Lin 62158463f4dSJon Lin op.sfctrl.d32 = 0; 62258463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 62358463f4dSJon Lin op.sfctrl.b.addrbits = 16; 624415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 62558463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 626ba0501acSDingqiang Lin 62758463f4dSJon Lin op.sfcmd.d32 = 0; 628f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 62958463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 63058463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 63158463f4dSJon Lin 63258463f4dSJon Lin op.sfctrl.d32 = 0; 63358463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 634f28847a8SJon Lin 635ba0501acSDingqiang Lin if (ret != SFC_OK) 636ba0501acSDingqiang Lin return ret; 637f28847a8SJon Lin 638ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 639f28847a8SJon Lin 640ba0501acSDingqiang Lin if (status & (1 << 3)) 641ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 642c84f0ed8SJon Lin 643ba0501acSDingqiang Lin return ret; 644ba0501acSDingqiang Lin } 645ba0501acSDingqiang Lin 646c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 647c84f0ed8SJon Lin { 648c84f0ed8SJon Lin int ret; 649c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 650c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 651a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 652c84f0ed8SJon Lin 653c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 654c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 655a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 656a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 657f28847a8SJon Lin 658c84f0ed8SJon Lin if (sec_per_page == 8) { 659a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 660a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 661c84f0ed8SJon Lin } 662f28847a8SJon Lin 663c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 664c84f0ed8SJon Lin 665c84f0ed8SJon Lin return ret; 666c84f0ed8SJon Lin } 667c84f0ed8SJon Lin 668a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 669ba0501acSDingqiang Lin { 670ba0501acSDingqiang Lin int ret; 671415cf080Sjon.lin u32 plane; 67258463f4dSJon Lin struct rk_sfc_op op; 6736281205aSDingqiang Lin u32 ecc_result; 674a6fcac41SJon Lin u8 status; 675ba0501acSDingqiang Lin 67658463f4dSJon Lin op.sfcmd.d32 = 0; 677f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 67858463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 67958463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 68058463f4dSJon Lin 68158463f4dSJon Lin op.sfctrl.d32 = 0; 68258463f4dSJon Lin 683a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 684f28847a8SJon Lin 685ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 68625098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 68725098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 688ba0501acSDingqiang Lin sfc_nand_rw_preset(); 689ba0501acSDingqiang Lin 690a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 691a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 692a6fcac41SJon Lin 69358463f4dSJon Lin op.sfcmd.d32 = 0; 69458463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 695a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 696a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 69758463f4dSJon Lin 69858463f4dSJon Lin op.sfctrl.d32 = 0; 69958463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 700a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 701ba0501acSDingqiang Lin 702a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 703a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 704a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 705c84f0ed8SJon Lin 706c84f0ed8SJon Lin if (ret != SFC_OK) 707f28847a8SJon Lin return SFC_NAND_HW_ERROR; 708c84f0ed8SJon Lin 709c84f0ed8SJon Lin return ecc_result; 710c84f0ed8SJon Lin } 711c84f0ed8SJon Lin 712a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 713a80fd396SJon Lin { 714a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 715a80fd396SJon Lin 716a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 717a80fd396SJon Lin } 718a80fd396SJon Lin 719c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 720c84f0ed8SJon Lin { 72158463f4dSJon Lin u32 ret; 722c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 723c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 724a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 725c84f0ed8SJon Lin 726c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 727f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 728a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 729a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 730f28847a8SJon Lin 731f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 732a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 733a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 734f25e3cafSJon Lin } 735ba0501acSDingqiang Lin 736f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 737f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 738f28847a8SJon Lin 739c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 740c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 741f28847a8SJon Lin 742ba0501acSDingqiang Lin if (p_data) 743c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 744f28847a8SJon Lin 745ba0501acSDingqiang Lin if (p_spare) 746c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 747ba0501acSDingqiang Lin } 748f25e3cafSJon Lin 749c84f0ed8SJon Lin return ret; 750ba0501acSDingqiang Lin } 751ba0501acSDingqiang Lin 752c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 753c84f0ed8SJon Lin { 754c84f0ed8SJon Lin u32 ret; 755c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 756a80fd396SJon Lin u32 marker = 0; 757c84f0ed8SJon Lin 758a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 759f28847a8SJon Lin 760f28847a8SJon Lin /* unify with mtd framework */ 761a6fcac41SJon Lin if (ret == SFC_NAND_ECC_ERROR) 762a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 763a80fd396SJon Lin __func__, addr, ret, marker); 764f28847a8SJon Lin 765c84f0ed8SJon Lin /* Original bad block */ 766a80fd396SJon Lin if ((u16)marker != 0xffff) 767c84f0ed8SJon Lin return true; 768c84f0ed8SJon Lin 769c84f0ed8SJon Lin return false; 770c84f0ed8SJon Lin } 771c84f0ed8SJon Lin 772c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 773c84f0ed8SJon Lin { 774c84f0ed8SJon Lin u32 ret; 775c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 776c84f0ed8SJon Lin 777c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 778f28847a8SJon Lin 779c84f0ed8SJon Lin if (ret) 780c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 781f28847a8SJon Lin 782c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 783c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 784f28847a8SJon Lin 785c84f0ed8SJon Lin if (ret) 786c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 787c84f0ed8SJon Lin 788c84f0ed8SJon Lin return ret; 789c84f0ed8SJon Lin } 790c84f0ed8SJon Lin 791c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 792ba0501acSDingqiang Lin { 793ba0501acSDingqiang Lin int ret; 79458463f4dSJon Lin struct rk_sfc_op op; 795ba0501acSDingqiang Lin 79658463f4dSJon Lin op.sfcmd.d32 = 0; 79758463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 79858463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 799ba0501acSDingqiang Lin 80058463f4dSJon Lin op.sfctrl.d32 = 0; 80158463f4dSJon Lin op.sfctrl.b.addrbits = 8; 80258463f4dSJon Lin 80358463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 804ba0501acSDingqiang Lin 805ba0501acSDingqiang Lin return ret; 806ba0501acSDingqiang Lin } 807ba0501acSDingqiang Lin 808ba0501acSDingqiang Lin /* 809ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 810ba0501acSDingqiang Lin * If not FF, it's bad blk 811ba0501acSDingqiang Lin */ 812ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 813ba0501acSDingqiang Lin { 814ba0501acSDingqiang Lin u32 bad_cnt, page; 815ba0501acSDingqiang Lin u32 blk_per_die; 8162ac88c1bSJon Lin u16 blk; 817ba0501acSDingqiang Lin 818c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 819c84f0ed8SJon Lin 820ba0501acSDingqiang Lin bad_cnt = 0; 821ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 822ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 823f28847a8SJon Lin 824ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 825ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 826ba0501acSDingqiang Lin p_nand_info->page_per_blk; 827ba0501acSDingqiang Lin 8282ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 829ba0501acSDingqiang Lin table[bad_cnt++] = blk; 830c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 831ba0501acSDingqiang Lin } 832ba0501acSDingqiang Lin } 833f28847a8SJon Lin 834ba0501acSDingqiang Lin return (int)bad_cnt; 835ba0501acSDingqiang Lin } 836ba0501acSDingqiang Lin 837c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 838ba0501acSDingqiang Lin { 839ba0501acSDingqiang Lin /* para init */ 840ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 841ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 842ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 843ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 844ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 845ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 846c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 847ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 848ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 849ba0501acSDingqiang Lin p_nand_info->page_per_blk; 850ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 851ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 852ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 853ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 854ba0501acSDingqiang Lin 855ba0501acSDingqiang Lin /* driver register */ 856ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 857ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 858ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 859ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 86057d18453Sjon.lin g_nand_ops.bch_sel = NULL; 861ba0501acSDingqiang Lin } 862ba0501acSDingqiang Lin 863a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 864ba0501acSDingqiang Lin { 865ba0501acSDingqiang Lin int ret = SFC_OK; 866ba0501acSDingqiang Lin u8 status; 867ba0501acSDingqiang Lin 868f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 869ba0501acSDingqiang Lin 870ba0501acSDingqiang Lin if (ret != SFC_OK) 871ba0501acSDingqiang Lin return ret; 872ba0501acSDingqiang Lin 873f28847a8SJon Lin if (status & 1) /* is QE bit set */ 874ba0501acSDingqiang Lin return SFC_OK; 875ba0501acSDingqiang Lin 876f28847a8SJon Lin status |= 1; 877ba0501acSDingqiang Lin 878f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 879ba0501acSDingqiang Lin } 880ba0501acSDingqiang Lin 881ba0501acSDingqiang Lin u32 sfc_nand_init(void) 882ba0501acSDingqiang Lin { 883c84f0ed8SJon Lin u8 status, id_byte[8]; 884ba0501acSDingqiang Lin 885c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 886c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 887ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 888f28847a8SJon Lin 889ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 89058463f4dSJon Lin return (u32)FTL_NO_FLASH; 891ba0501acSDingqiang Lin 892a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 893f28847a8SJon Lin 894ba0501acSDingqiang Lin if (!p_nand_info) 89558463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 896ba0501acSDingqiang Lin 897ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 898ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 899c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 900c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 901c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 902ba0501acSDingqiang Lin 903ba0501acSDingqiang Lin /* disable block lock */ 904ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 905ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 906ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 907f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 908f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 909f28847a8SJon Lin 910ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 911f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 912f28847a8SJon Lin !p_nand_info->has_qe_bits) { 913ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 914f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 915ba0501acSDingqiang Lin } 916ba0501acSDingqiang Lin } 917ba0501acSDingqiang Lin 918ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 919ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 920ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 921f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 922ba0501acSDingqiang Lin } 923ba0501acSDingqiang Lin 924ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 925c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 926ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 927c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 928c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 929c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 930c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 931c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 932ba0501acSDingqiang Lin 933ba0501acSDingqiang Lin return SFC_OK; 934ba0501acSDingqiang Lin } 935ba0501acSDingqiang Lin 936c84f0ed8SJon Lin void sfc_nand_deinit(void) 937ba0501acSDingqiang Lin { 938c84f0ed8SJon Lin /* to-do */ 939ba0501acSDingqiang Lin } 940c84f0ed8SJon Lin 941c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 942c84f0ed8SJon Lin { 943c84f0ed8SJon Lin return &sfc_nand_dev; 944c84f0ed8SJon Lin } 945c84f0ed8SJon Lin 946