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); 24*362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void); 25f28847a8SJon Lin 26ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = { 27ba0501acSDingqiang Lin /* TC58CVG0S0HxAIx */ 28b833c879SJon Lin { 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 29ba0501acSDingqiang Lin /* TC58CVG1S0HxAIx */ 30b833c879SJon Lin { 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 31a6fcac41SJon Lin /* TC58CVG2S0HRAIJ */ 32b833c879SJon Lin { 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 }, 33a6fcac41SJon Lin /* TC58CVG1S3HRAIJ */ 34b833c879SJon Lin { 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 35a6fcac41SJon Lin /* TC58CVG0S3HRAIJ */ 36b833c879SJon Lin { 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 37f28847a8SJon Lin 38f28847a8SJon Lin /* MX35LF1GE4AB */ 39b833c879SJon Lin { 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 40f28847a8SJon Lin /* MX35LF2GE4AB */ 41b833c879SJon Lin { 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 42f28847a8SJon Lin /* MX35LF2GE4AD */ 43b833c879SJon Lin { 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 44f28847a8SJon Lin /* MX35LF4GE4AD */ 45*362b1be1SJon Lin { 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 }, 46*362b1be1SJon Lin /* MX35UF1GE4AC */ 47*362b1be1SJon Lin { 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 48*362b1be1SJon Lin /* MX35UF2GE4AC */ 49*362b1be1SJon Lin { 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 50f28847a8SJon Lin 51f28847a8SJon Lin /* GD5F1GQ4UAYIG */ 52b833c879SJon Lin { 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 53f28847a8SJon Lin /* GD5F1GQ4RB9IGR */ 54b833c879SJon Lin { 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 55f28847a8SJon Lin /* GD5F2GQ40BY2GR */ 56b833c879SJon Lin { 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 57f28847a8SJon Lin /* GD5F1GQ5UEYIG */ 58b833c879SJon Lin { 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 59f28847a8SJon Lin /* GD5F2GQ5UEYIG */ 60b833c879SJon Lin { 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 }, 61f28847a8SJon Lin /* GD5F1GQ4R */ 62b833c879SJon Lin { 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 }, 63*362b1be1SJon Lin /* GD5F4GQ6RExxG 1*4096 */ 64*362b1be1SJon Lin { 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 }, 65*362b1be1SJon Lin /* GD5F4GQ6UExxG 1*4096 */ 66*362b1be1SJon Lin { 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 }, 67f28847a8SJon Lin 68f28847a8SJon Lin /* W25N01GV */ 69b833c879SJon Lin { 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 70b833c879SJon Lin /* W25N02KVZEIR */ 71b833c879SJon Lin { 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 }, 72f28847a8SJon Lin /* W25N01GW */ 73b833c879SJon Lin { 0xEF, 0xBA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 }, 74f28847a8SJon Lin 75f28847a8SJon Lin /* HYF2GQ4UAACAE */ 76b833c879SJon Lin { 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 77f28847a8SJon Lin /* HYF1GQ4UDACAE */ 78b833c879SJon Lin { 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 79f28847a8SJon Lin /* HYF1GQ4UPACAE */ 80b833c879SJon Lin { 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 81f28847a8SJon Lin /* HYF2GQ4UDACAE */ 82b833c879SJon Lin { 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 83f28847a8SJon Lin /* HYF2GQ4UHCCAE */ 84b833c879SJon Lin { 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 85f28847a8SJon Lin /* HYF4GQ4UAACBE */ 86b833c879SJon Lin { 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 }, 87f28847a8SJon Lin 88f28847a8SJon Lin /* FS35ND01G-S1 */ 89b833c879SJon Lin { 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 90f28847a8SJon Lin /* FS35ND02G-S2 */ 91b833c879SJon Lin { 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 9258463f4dSJon Lin /* FS35ND01G-S1Y2 */ 93b833c879SJon Lin { 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 94f1b20f5aSJon Lin /* FS35ND02G-S3Y2 */ 95b833c879SJon Lin { 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 96f28847a8SJon Lin /* FS35ND04G-S2Y2 1*4096 */ 97b833c879SJon Lin { 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 98f28847a8SJon Lin 99f28847a8SJon Lin /* DS35Q1GA-IB */ 100b833c879SJon Lin { 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 101f28847a8SJon Lin /* DS35Q2GA-IB */ 102b833c879SJon Lin { 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 103f28847a8SJon Lin /* DS35M1GA-1B */ 104b833c879SJon Lin { 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 105f28847a8SJon Lin 106f28847a8SJon Lin /* EM73C044VCC-H */ 107b833c879SJon Lin { 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 108f28847a8SJon Lin /* EM73D044VCE-H */ 109b833c879SJon Lin { 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 110f28847a8SJon Lin /* EM73E044SNA-G */ 111b833c879SJon Lin { 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 }, 112f28847a8SJon Lin 113f28847a8SJon Lin /* XT26G02A */ 114*362b1be1SJon Lin { 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 115f28847a8SJon Lin /* XT26G01A */ 116*362b1be1SJon Lin { 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 117f28847a8SJon Lin /* XT26G04A */ 118*362b1be1SJon Lin { 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 119f28847a8SJon Lin /* XT26G01B */ 120*362b1be1SJon Lin { 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 }, 121f28847a8SJon Lin /* XT26G02B */ 122*362b1be1SJon Lin { 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 }, 123*362b1be1SJon Lin /* XT26G01C */ 124*362b1be1SJon Lin { 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 125*362b1be1SJon Lin /* XT26G02C */ 126*362b1be1SJon Lin { 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 }, 127*362b1be1SJon Lin /* XT26G04C */ 128*362b1be1SJon Lin { 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 }, 129a80fd396SJon Lin 130*362b1be1SJon Lin /* MT29F2G01ABA, XT26G02E, F50L2G41XA */ 131b833c879SJon Lin { 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 }, 132a80fd396SJon Lin 133a80fd396SJon Lin /* FM25S01 */ 134b833c879SJon Lin { 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 135a80fd396SJon Lin /* FM25S01A */ 136b833c879SJon Lin { 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 137a80fd396SJon Lin /* FM25S02A */ 138b833c879SJon Lin { 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 139f28847a8SJon Lin 140f28847a8SJon Lin /* IS37SML01G1 */ 141b833c879SJon Lin { 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 142f28847a8SJon Lin /* F50L1G41LB */ 143b833c879SJon Lin { 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 144f28847a8SJon Lin /* ATO25D1GA */ 145b833c879SJon Lin { 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 }, 146*362b1be1SJon Lin /* BWJX08K-2Gb */ 147*362b1be1SJon Lin { 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 }, 148ba0501acSDingqiang Lin }; 149ba0501acSDingqiang Lin 150ba0501acSDingqiang Lin static struct nand_info *p_nand_info; 151ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4]; 152ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev; 153ba0501acSDingqiang Lin 154a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id) 155ba0501acSDingqiang Lin { 156ba0501acSDingqiang Lin u32 i; 157ba0501acSDingqiang Lin 158ba0501acSDingqiang Lin for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) { 159b833c879SJon Lin if (spi_nand_tbl[i].id0 == nand_id[0] && 160b833c879SJon Lin spi_nand_tbl[i].id1 == nand_id[1]) { 161b833c879SJon Lin if (spi_nand_tbl[i].id2 && 162b833c879SJon Lin spi_nand_tbl[i].id2 != nand_id[2]) 163b833c879SJon Lin continue; 164b833c879SJon Lin 165ba0501acSDingqiang Lin return &spi_nand_tbl[i]; 166ba0501acSDingqiang Lin } 167b833c879SJon Lin } 168f28847a8SJon Lin 169ba0501acSDingqiang Lin return NULL; 170ba0501acSDingqiang Lin } 171ba0501acSDingqiang Lin 172ba0501acSDingqiang Lin static int sfc_nand_write_en(void) 173ba0501acSDingqiang Lin { 174ba0501acSDingqiang Lin int ret; 17558463f4dSJon Lin struct rk_sfc_op op; 176ba0501acSDingqiang Lin 17758463f4dSJon Lin op.sfcmd.d32 = 0; 17858463f4dSJon Lin op.sfcmd.b.cmd = CMD_WRITE_EN; 17958463f4dSJon Lin 18058463f4dSJon Lin op.sfctrl.d32 = 0; 18158463f4dSJon Lin 18258463f4dSJon Lin ret = sfc_request(&op, 0, NULL, 0); 183ba0501acSDingqiang Lin return ret; 184ba0501acSDingqiang Lin } 185ba0501acSDingqiang Lin 186ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void) 187ba0501acSDingqiang Lin { 188ba0501acSDingqiang Lin int ret; 18958463f4dSJon Lin struct rk_sfc_op op; 190ba0501acSDingqiang Lin 19158463f4dSJon Lin op.sfcmd.d32 = 0; 192f28847a8SJon Lin op.sfcmd.b.cmd = 0xff; 193f28847a8SJon Lin op.sfcmd.b.cs = 2; 194ba0501acSDingqiang Lin 19558463f4dSJon Lin op.sfctrl.d32 = 0; 19658463f4dSJon Lin op.sfctrl.b.datalines = 2; 197f28847a8SJon Lin op.sfctrl.b.cmdlines = 2; 198f28847a8SJon Lin op.sfctrl.b.addrlines = 2; 19958463f4dSJon Lin 200f28847a8SJon Lin ret = sfc_request(&op, 0, NULL, 0); 201ba0501acSDingqiang Lin return ret; 202ba0501acSDingqiang Lin } 203ba0501acSDingqiang Lin 204ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data) 205ba0501acSDingqiang Lin { 206ba0501acSDingqiang Lin int ret; 20758463f4dSJon Lin struct rk_sfc_op op; 208ba0501acSDingqiang Lin 20958463f4dSJon Lin op.sfcmd.d32 = 0; 21058463f4dSJon Lin op.sfcmd.b.cmd = 0x0F; 21158463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 21258463f4dSJon Lin 21358463f4dSJon Lin op.sfctrl.d32 = 0; 21458463f4dSJon Lin op.sfctrl.b.addrbits = 8; 21558463f4dSJon Lin 216ba0501acSDingqiang Lin *data = 0; 217ba0501acSDingqiang Lin 21858463f4dSJon Lin ret = sfc_request(&op, addr, data, 1); 219f28847a8SJon Lin 220ba0501acSDingqiang Lin if (ret != SFC_OK) 221ba0501acSDingqiang Lin return ret; 222f28847a8SJon Lin 223ba0501acSDingqiang Lin return SFC_OK; 224ba0501acSDingqiang Lin } 225ba0501acSDingqiang Lin 226ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status) 227ba0501acSDingqiang Lin { 228ba0501acSDingqiang Lin int ret; 22958463f4dSJon Lin struct rk_sfc_op op; 230ba0501acSDingqiang Lin 231ba0501acSDingqiang Lin sfc_nand_write_en(); 232ba0501acSDingqiang Lin 23358463f4dSJon Lin op.sfcmd.d32 = 0; 23458463f4dSJon Lin op.sfcmd.b.cmd = 0x1F; 23558463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 23658463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 237ba0501acSDingqiang Lin 23858463f4dSJon Lin op.sfctrl.d32 = 0; 23958463f4dSJon Lin op.sfctrl.b.addrbits = 8; 24058463f4dSJon Lin 24158463f4dSJon Lin ret = sfc_request(&op, addr, &status, 1); 242f28847a8SJon Lin 243ba0501acSDingqiang Lin if (ret != SFC_OK) 244ba0501acSDingqiang Lin return ret; 245f28847a8SJon Lin 246ba0501acSDingqiang Lin return ret; 247ba0501acSDingqiang Lin } 248ba0501acSDingqiang Lin 249ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout) 250ba0501acSDingqiang Lin { 251ba0501acSDingqiang Lin int ret; 252ba0501acSDingqiang Lin int i; 253ba0501acSDingqiang Lin u8 status; 254ba0501acSDingqiang Lin 255ba0501acSDingqiang Lin *data = 0; 256f28847a8SJon Lin 257ba0501acSDingqiang Lin for (i = 0; i < timeout; i++) { 258ba0501acSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 259f28847a8SJon Lin 260ba0501acSDingqiang Lin if (ret != SFC_OK) 261ba0501acSDingqiang Lin return ret; 262f28847a8SJon Lin 263ba0501acSDingqiang Lin *data = status; 264f28847a8SJon Lin 265ba0501acSDingqiang Lin if (!(status & (1 << 0))) 266ba0501acSDingqiang Lin return SFC_OK; 267f28847a8SJon Lin 268ba0501acSDingqiang Lin sfc_delay(1); 269ba0501acSDingqiang Lin } 270f28847a8SJon Lin 271f28847a8SJon Lin return SFC_NAND_WAIT_TIME_OUT; 272ba0501acSDingqiang Lin } 273ba0501acSDingqiang Lin 2746281205aSDingqiang Lin /* 2756281205aSDingqiang Lin * ecc default: 276a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 277f28847a8SJon Lin * 0b00, No bit errors were detected 278f28847a8SJon Lin * 0b01, Bit errors were detected and corrected. 279f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected. 280f28847a8SJon Lin * 0b11, Bits errors were detected and corrected, bit error count 281*362b1be1SJon Lin * reach the bit flip detection threshold 2826281205aSDingqiang Lin */ 283f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void) 2846281205aSDingqiang Lin { 28558463f4dSJon Lin u32 ret; 2866281205aSDingqiang Lin u32 i; 2876281205aSDingqiang Lin u8 ecc; 2886281205aSDingqiang Lin u8 status; 2896281205aSDingqiang Lin u32 timeout = 1000 * 1000; 2906281205aSDingqiang Lin 2916281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 2926281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 293f28847a8SJon Lin 2946281205aSDingqiang Lin if (ret != SFC_OK) 2956281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 296f28847a8SJon Lin 2976281205aSDingqiang Lin if (!(status & (1 << 0))) 2986281205aSDingqiang Lin break; 299f28847a8SJon Lin 3006281205aSDingqiang Lin sfc_delay(1); 3016281205aSDingqiang Lin } 3026281205aSDingqiang Lin 3036281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3046281205aSDingqiang Lin 3056281205aSDingqiang Lin if (ecc <= 1) 3066281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3076281205aSDingqiang Lin else if (ecc == 2) 30858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3096281205aSDingqiang Lin else 3106281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3116281205aSDingqiang Lin 3126281205aSDingqiang Lin return ret; 3136281205aSDingqiang Lin } 3146281205aSDingqiang Lin 3156281205aSDingqiang Lin /* 3166281205aSDingqiang Lin * ecc spectial type1: 317a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 318f28847a8SJon Lin * 0b00, No bit errors were detected; 319f28847a8SJon Lin * 0b01, Bits errors were detected and corrected, bit error count 3206281205aSDingqiang Lin * may reach the bit flip detection threshold; 321f28847a8SJon Lin * 0b10, Multiple bit errors were detected and not corrected; 322f28847a8SJon Lin * 0b11, Reserved. 3236281205aSDingqiang Lin */ 324f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void) 3256281205aSDingqiang Lin { 32658463f4dSJon Lin u32 ret; 3276281205aSDingqiang Lin u32 i; 3286281205aSDingqiang Lin u8 ecc; 3296281205aSDingqiang Lin u8 status; 3306281205aSDingqiang Lin u32 timeout = 1000 * 1000; 3316281205aSDingqiang Lin 3326281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 3336281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 334f28847a8SJon Lin 3356281205aSDingqiang Lin if (ret != SFC_OK) 3366281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 337f28847a8SJon Lin 3386281205aSDingqiang Lin if (!(status & (1 << 0))) 3396281205aSDingqiang Lin break; 340f28847a8SJon Lin 3416281205aSDingqiang Lin sfc_delay(1); 3426281205aSDingqiang Lin } 3436281205aSDingqiang Lin 3446281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 3456281205aSDingqiang Lin 3466281205aSDingqiang Lin if (ecc == 0) 3476281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 3486281205aSDingqiang Lin else if (ecc == 1) 3496281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 3506281205aSDingqiang Lin else 35158463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 3526281205aSDingqiang Lin 3536281205aSDingqiang Lin return ret; 3546281205aSDingqiang Lin } 3556281205aSDingqiang Lin 3566281205aSDingqiang Lin /* 357d9cdd318SJon Lin * ecc spectial type2: 358a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 359f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 360f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 361d9cdd318SJon Lin * reach Flipping Bits; 362f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 363c84f0ed8SJon Lin * not corrected. 364f28847a8SJon Lin * [0b1100, 0b1111], reserved. 365d9cdd318SJon Lin */ 366f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void) 367d9cdd318SJon Lin { 36858463f4dSJon Lin u32 ret; 369d9cdd318SJon Lin u32 i; 370d9cdd318SJon Lin u8 ecc; 371d9cdd318SJon Lin u8 status, status1; 372d9cdd318SJon Lin u32 timeout = 1000 * 1000; 373d9cdd318SJon Lin 374d9cdd318SJon Lin for (i = 0; i < timeout; i++) { 375d9cdd318SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 376f28847a8SJon Lin 377d9cdd318SJon Lin if (ret != SFC_OK) 378d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 379f28847a8SJon Lin 380d9cdd318SJon Lin ret = sfc_nand_read_feature(0xF0, &status1); 381f28847a8SJon Lin 382d9cdd318SJon Lin if (ret != SFC_OK) 383d9cdd318SJon Lin return SFC_NAND_ECC_ERROR; 384f28847a8SJon Lin 385d9cdd318SJon Lin if (!(status & (1 << 0))) 386d9cdd318SJon Lin break; 387f28847a8SJon Lin 388d9cdd318SJon Lin sfc_delay(1); 389d9cdd318SJon Lin } 390d9cdd318SJon Lin 391d9cdd318SJon Lin ecc = (status >> 4) & 0x03; 392d9cdd318SJon Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 393f28847a8SJon Lin 394d9cdd318SJon Lin if (ecc < 7) 395d9cdd318SJon Lin ret = SFC_NAND_ECC_OK; 396d9cdd318SJon Lin else if (ecc == 7) 397d9cdd318SJon Lin ret = SFC_NAND_ECC_REFRESH; 398d9cdd318SJon Lin else 39958463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 400d9cdd318SJon Lin 401d9cdd318SJon Lin return ret; 402d9cdd318SJon Lin } 403d9cdd318SJon Lin 404d9cdd318SJon Lin /* 4056281205aSDingqiang Lin * ecc spectial type3: 406a6fcac41SJon Lin * ecc bits: 0xC0[4,5] 0xF0[4,5] 407f28847a8SJon Lin * [0b0000, 0b0011], No bit errors were detected; 408f28847a8SJon Lin * [0b0100, 0b0111], Bit errors were detected and corrected. Not 4096281205aSDingqiang Lin * reach Flipping Bits; 410f28847a8SJon Lin * [0b1000, 0b1011], Multiple bit errors were detected and 4116281205aSDingqiang Lin * not corrected. 412f28847a8SJon Lin * [0b1100, 0b1111], Bit error count equals the bit flip 4136281205aSDingqiang Lin * detectio nthreshold 4146281205aSDingqiang Lin */ 415f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void) 4166281205aSDingqiang Lin { 41758463f4dSJon Lin u32 ret; 4186281205aSDingqiang Lin u32 i; 4196281205aSDingqiang Lin u8 ecc; 4206281205aSDingqiang Lin u8 status, status1; 4216281205aSDingqiang Lin u32 timeout = 1000 * 1000; 4226281205aSDingqiang Lin 4236281205aSDingqiang Lin for (i = 0; i < timeout; i++) { 4246281205aSDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 425f28847a8SJon Lin 4266281205aSDingqiang Lin if (ret != SFC_OK) 4276281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 428f28847a8SJon Lin 4296281205aSDingqiang Lin ret = sfc_nand_read_feature(0xF0, &status1); 430f28847a8SJon Lin 4316281205aSDingqiang Lin if (ret != SFC_OK) 4326281205aSDingqiang Lin return SFC_NAND_ECC_ERROR; 433f28847a8SJon Lin 4346281205aSDingqiang Lin if (!(status & (1 << 0))) 4356281205aSDingqiang Lin break; 436f28847a8SJon Lin 4376281205aSDingqiang Lin sfc_delay(1); 4386281205aSDingqiang Lin } 4396281205aSDingqiang Lin 4406281205aSDingqiang Lin ecc = (status >> 4) & 0x03; 4416281205aSDingqiang Lin ecc = (ecc << 2) | ((status1 >> 4) & 0x03); 442f28847a8SJon Lin 4436281205aSDingqiang Lin if (ecc < 7) 4446281205aSDingqiang Lin ret = SFC_NAND_ECC_OK; 4456281205aSDingqiang Lin else if (ecc == 7 || ecc >= 12) 4466281205aSDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 4476281205aSDingqiang Lin else 44858463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 4496281205aSDingqiang Lin 4506281205aSDingqiang Lin return ret; 4516281205aSDingqiang Lin } 4526281205aSDingqiang Lin 45325098c06SDingqiang Lin /* 45425098c06SDingqiang Lin * ecc spectial type4: 455a6fcac41SJon Lin * ecc bits: 0xC0[2,5] 456f28847a8SJon Lin * [0b0000], No bit errors were detected; 457f28847a8SJon Lin * [0b0001, 0b0111], Bit errors were detected and corrected. Not 45825098c06SDingqiang Lin * reach Flipping Bits; 459f28847a8SJon Lin * [0b1000], Multiple bit errors were detected and 46025098c06SDingqiang Lin * not corrected. 461f28847a8SJon Lin * [0b1100], Bit error count equals the bit flip 46225098c06SDingqiang Lin * detectionthreshold 46325098c06SDingqiang Lin * else, reserved 46425098c06SDingqiang Lin */ 465f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void) 46625098c06SDingqiang Lin { 46758463f4dSJon Lin u32 ret; 46825098c06SDingqiang Lin u32 i; 46925098c06SDingqiang Lin u8 ecc; 47025098c06SDingqiang Lin u8 status; 47125098c06SDingqiang Lin u32 timeout = 1000 * 1000; 47225098c06SDingqiang Lin 47325098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 47425098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 475f28847a8SJon Lin 47625098c06SDingqiang Lin if (ret != SFC_OK) 47725098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 478f28847a8SJon Lin 47925098c06SDingqiang Lin if (!(status & (1 << 0))) 48025098c06SDingqiang Lin break; 481f28847a8SJon Lin 48225098c06SDingqiang Lin sfc_delay(1); 48325098c06SDingqiang Lin } 48425098c06SDingqiang Lin 48525098c06SDingqiang Lin ecc = (status >> 2) & 0x0f; 486f28847a8SJon Lin 48725098c06SDingqiang Lin if (ecc < 7) 48825098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 48925098c06SDingqiang Lin else if (ecc == 7 || ecc == 12) 49025098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 49125098c06SDingqiang Lin else 49258463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 49325098c06SDingqiang Lin 49425098c06SDingqiang Lin return ret; 49525098c06SDingqiang Lin } 49625098c06SDingqiang Lin 49725098c06SDingqiang Lin /* 49825098c06SDingqiang Lin * ecc spectial type5: 499a6fcac41SJon Lin * ecc bits: 0xC0[4,6] 500f28847a8SJon Lin * [0b000], No bit errors were detected; 501f28847a8SJon Lin * [0b001, 0b011], Bit errors were detected and corrected. Not 50225098c06SDingqiang Lin * reach Flipping Bits; 503f28847a8SJon Lin * [0b100], Bit error count equals the bit flip 50425098c06SDingqiang Lin * detectionthreshold 505f28847a8SJon Lin * [0b101, 0b110], Reserved; 506f28847a8SJon Lin * [0b111], Multiple bit errors were detected and 50725098c06SDingqiang Lin * not corrected. 50825098c06SDingqiang Lin */ 509f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void) 51025098c06SDingqiang Lin { 51158463f4dSJon Lin u32 ret; 51225098c06SDingqiang Lin u32 i; 51325098c06SDingqiang Lin u8 ecc; 51425098c06SDingqiang Lin u8 status; 51525098c06SDingqiang Lin u32 timeout = 1000 * 1000; 51625098c06SDingqiang Lin 51725098c06SDingqiang Lin for (i = 0; i < timeout; i++) { 51825098c06SDingqiang Lin ret = sfc_nand_read_feature(0xC0, &status); 519f28847a8SJon Lin 52025098c06SDingqiang Lin if (ret != SFC_OK) 52125098c06SDingqiang Lin return SFC_NAND_ECC_ERROR; 522f28847a8SJon Lin 52325098c06SDingqiang Lin if (!(status & (1 << 0))) 52425098c06SDingqiang Lin break; 525f28847a8SJon Lin 52625098c06SDingqiang Lin sfc_delay(1); 52725098c06SDingqiang Lin } 52825098c06SDingqiang Lin 52925098c06SDingqiang Lin ecc = (status >> 4) & 0x07; 530f28847a8SJon Lin 53125098c06SDingqiang Lin if (ecc < 4) 53225098c06SDingqiang Lin ret = SFC_NAND_ECC_OK; 53325098c06SDingqiang Lin else if (ecc == 4) 53425098c06SDingqiang Lin ret = SFC_NAND_ECC_REFRESH; 53525098c06SDingqiang Lin else 53658463f4dSJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 53725098c06SDingqiang Lin 53825098c06SDingqiang Lin return ret; 53925098c06SDingqiang Lin } 54025098c06SDingqiang Lin 541f28847a8SJon Lin /* 542f28847a8SJon Lin * ecc spectial type6: 543f28847a8SJon Lin * ecc bits: 0xC0[4,6] 544f28847a8SJon Lin * [0b000], No bit errors were detected; 545f28847a8SJon Lin * [0b001], 1-3 Bit errors were detected and corrected. Not 546f28847a8SJon Lin * reach Flipping Bits; 547f28847a8SJon Lin * [0b010], Multiple bit errors were detected and 548f28847a8SJon Lin * not corrected. 549f28847a8SJon Lin * [0b011], 4-6 Bit errors were detected and corrected. Not 550f28847a8SJon Lin * reach Flipping Bits; 551f28847a8SJon Lin * [0b101], Bit error count equals the bit flip 552f28847a8SJon Lin * detectionthreshold 553f28847a8SJon Lin * others, Reserved. 554f28847a8SJon Lin */ 555f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void) 556f28847a8SJon Lin { 557f28847a8SJon Lin u32 ret; 558f28847a8SJon Lin u32 i; 559f28847a8SJon Lin u8 ecc; 560f28847a8SJon Lin u8 status; 561f28847a8SJon Lin u32 timeout = 1000 * 1000; 562f28847a8SJon Lin 563f28847a8SJon Lin for (i = 0; i < timeout; i++) { 564f28847a8SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 565f28847a8SJon Lin 566f28847a8SJon Lin if (ret != SFC_OK) 567f28847a8SJon Lin return SFC_NAND_ECC_ERROR; 568f28847a8SJon Lin 569f28847a8SJon Lin if (!(status & (1 << 0))) 570f28847a8SJon Lin break; 571f28847a8SJon Lin 572f28847a8SJon Lin sfc_delay(1); 573f28847a8SJon Lin } 574f28847a8SJon Lin 575f28847a8SJon Lin ecc = (status >> 4) & 0x07; 576f28847a8SJon Lin 577f28847a8SJon Lin if (ecc == 0 || ecc == 1 || ecc == 3) 578f28847a8SJon Lin ret = SFC_NAND_ECC_OK; 579f28847a8SJon Lin else if (ecc == 5) 580f28847a8SJon Lin ret = SFC_NAND_ECC_REFRESH; 581f28847a8SJon Lin else 582f28847a8SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 583f28847a8SJon Lin 584f28847a8SJon Lin return ret; 585f28847a8SJon Lin } 586f28847a8SJon Lin 587*362b1be1SJon Lin /* 588*362b1be1SJon Lin * ecc spectial type7: 589*362b1be1SJon Lin * ecc bits: 0xC0[4,7] 590*362b1be1SJon Lin * [0b0000], No bit errors were detected; 591*362b1be1SJon Lin * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 592*362b1be1SJon Lin * reach Flipping Bits; 593*362b1be1SJon Lin * [0b1000], 8 Bit errors were detected and corrected. Bit error count 594*362b1be1SJon Lin * equals the bit flip detectionthreshold; 595*362b1be1SJon Lin * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 596*362b1be1SJon Lin * others, Reserved. 597*362b1be1SJon Lin */ 598*362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void) 599*362b1be1SJon Lin { 600*362b1be1SJon Lin u32 ret; 601*362b1be1SJon Lin u32 i; 602*362b1be1SJon Lin u8 ecc; 603*362b1be1SJon Lin u8 status; 604*362b1be1SJon Lin u32 timeout = 1000 * 1000; 605*362b1be1SJon Lin 606*362b1be1SJon Lin for (i = 0; i < timeout; i++) { 607*362b1be1SJon Lin ret = sfc_nand_read_feature(0xC0, &status); 608*362b1be1SJon Lin 609*362b1be1SJon Lin if (ret != SFC_OK) 610*362b1be1SJon Lin return SFC_NAND_ECC_ERROR; 611*362b1be1SJon Lin 612*362b1be1SJon Lin if (!(status & (1 << 0))) 613*362b1be1SJon Lin break; 614*362b1be1SJon Lin 615*362b1be1SJon Lin sfc_delay(1); 616*362b1be1SJon Lin } 617*362b1be1SJon Lin 618*362b1be1SJon Lin ecc = (status >> 4) & 0xf; 619*362b1be1SJon Lin 620*362b1be1SJon Lin if (ecc < 7) 621*362b1be1SJon Lin ret = SFC_NAND_ECC_OK; 622*362b1be1SJon Lin else if (ecc == 7 || ecc == 8) 623*362b1be1SJon Lin ret = SFC_NAND_ECC_REFRESH; 624*362b1be1SJon Lin else 625*362b1be1SJon Lin ret = (u32)SFC_NAND_ECC_ERROR; 626*362b1be1SJon Lin 627*362b1be1SJon Lin return ret; 628*362b1be1SJon Lin } 629*362b1be1SJon Lin 630c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr) 631ba0501acSDingqiang Lin { 632ba0501acSDingqiang Lin int ret; 63358463f4dSJon Lin struct rk_sfc_op op; 634ba0501acSDingqiang Lin u8 status; 635ba0501acSDingqiang Lin 636c84f0ed8SJon Lin rkflash_print_dio("%s %x\n", __func__, addr); 63758463f4dSJon Lin op.sfcmd.d32 = 0; 638f28847a8SJon Lin op.sfcmd.b.cmd = 0xd8; 63958463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 64058463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 64158463f4dSJon Lin 64258463f4dSJon Lin op.sfctrl.d32 = 0; 64358463f4dSJon Lin 644ba0501acSDingqiang Lin sfc_nand_write_en(); 64558463f4dSJon Lin ret = sfc_request(&op, addr, NULL, 0); 646f28847a8SJon Lin 647ba0501acSDingqiang Lin if (ret != SFC_OK) 648ba0501acSDingqiang Lin return ret; 649f28847a8SJon Lin 650ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 651f28847a8SJon Lin 652ba0501acSDingqiang Lin if (status & (1 << 2)) 653ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 654c84f0ed8SJon Lin 655ba0501acSDingqiang Lin return ret; 656ba0501acSDingqiang Lin } 657ba0501acSDingqiang Lin 658f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 659ba0501acSDingqiang Lin { 660ba0501acSDingqiang Lin int ret; 661415cf080Sjon.lin u32 plane; 66258463f4dSJon Lin struct rk_sfc_op op; 663ba0501acSDingqiang Lin u8 status; 66458463f4dSJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 665ba0501acSDingqiang Lin 666c84f0ed8SJon Lin rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); 667ba0501acSDingqiang Lin sfc_nand_write_en(); 668f28847a8SJon Lin 669ba0501acSDingqiang Lin if (sfc_nand_dev.prog_lines == DATA_LINES_X4 && 67025098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 67125098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 672ba0501acSDingqiang Lin sfc_nand_rw_preset(); 673ba0501acSDingqiang Lin 67458463f4dSJon Lin op.sfcmd.d32 = 0; 67558463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd; 67658463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 67758463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 678ba0501acSDingqiang Lin 67958463f4dSJon Lin op.sfctrl.d32 = 0; 68058463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.prog_lines; 68158463f4dSJon Lin op.sfctrl.b.addrbits = 16; 682415cf080Sjon.lin plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; 68358463f4dSJon Lin sfc_request(&op, plane, p_page_buf, page_size); 684ba0501acSDingqiang Lin 68558463f4dSJon Lin op.sfcmd.d32 = 0; 686f28847a8SJon Lin op.sfcmd.b.cmd = 0x10; 68758463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 68858463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 68958463f4dSJon Lin 69058463f4dSJon Lin op.sfctrl.d32 = 0; 69158463f4dSJon Lin ret = sfc_request(&op, addr, p_page_buf, 0); 692f28847a8SJon Lin 693ba0501acSDingqiang Lin if (ret != SFC_OK) 694ba0501acSDingqiang Lin return ret; 695f28847a8SJon Lin 696ba0501acSDingqiang Lin ret = sfc_nand_wait_busy(&status, 1000 * 1000); 697f28847a8SJon Lin 698ba0501acSDingqiang Lin if (status & (1 << 3)) 699ba0501acSDingqiang Lin return SFC_NAND_PROG_ERASE_ERROR; 700c84f0ed8SJon Lin 701ba0501acSDingqiang Lin return ret; 702ba0501acSDingqiang Lin } 703ba0501acSDingqiang Lin 704c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 705c84f0ed8SJon Lin { 706c84f0ed8SJon Lin int ret; 707c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 708c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 709a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 710c84f0ed8SJon Lin 711c84f0ed8SJon Lin memcpy(gp_page_buf, p_data, data_size); 712c84f0ed8SJon Lin memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16); 713a6fcac41SJon Lin gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0]; 714a6fcac41SJon Lin gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1]; 715f28847a8SJon Lin 716c84f0ed8SJon Lin if (sec_per_page == 8) { 717a6fcac41SJon Lin gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2]; 718a6fcac41SJon Lin gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3]; 719c84f0ed8SJon Lin } 720f28847a8SJon Lin 721c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 722c84f0ed8SJon Lin 723c84f0ed8SJon Lin return ret; 724c84f0ed8SJon Lin } 725c84f0ed8SJon Lin 726a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len) 727ba0501acSDingqiang Lin { 728ba0501acSDingqiang Lin int ret; 729415cf080Sjon.lin u32 plane; 73058463f4dSJon Lin struct rk_sfc_op op; 7316281205aSDingqiang Lin u32 ecc_result; 732a6fcac41SJon Lin u8 status; 733ba0501acSDingqiang Lin 73458463f4dSJon Lin op.sfcmd.d32 = 0; 735f28847a8SJon Lin op.sfcmd.b.cmd = 0x13; 73658463f4dSJon Lin op.sfcmd.b.rw = SFC_WRITE; 73758463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_24BITS; 73858463f4dSJon Lin 73958463f4dSJon Lin op.sfctrl.d32 = 0; 74058463f4dSJon Lin 741a80fd396SJon Lin sfc_request(&op, row, p_page_buf, 0); 742f28847a8SJon Lin 743ba0501acSDingqiang Lin if (sfc_nand_dev.read_lines == DATA_LINES_X4 && 74425098c06SDingqiang Lin p_nand_info->feature & FEA_SOFT_QOP_BIT && 74525098c06SDingqiang Lin sfc_get_version() < SFC_VER_3) 746ba0501acSDingqiang Lin sfc_nand_rw_preset(); 747ba0501acSDingqiang Lin 748a6fcac41SJon Lin sfc_nand_wait_busy(&status, 1000 * 1000); 749a6fcac41SJon Lin ecc_result = p_nand_info->ecc_status(); 750a6fcac41SJon Lin 75158463f4dSJon Lin op.sfcmd.d32 = 0; 75258463f4dSJon Lin op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; 753a80fd396SJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 754a80fd396SJon Lin op.sfcmd.b.dummybits = 8; 75558463f4dSJon Lin 75658463f4dSJon Lin op.sfctrl.d32 = 0; 75758463f4dSJon Lin op.sfctrl.b.datalines = sfc_nand_dev.read_lines; 758a80fd396SJon Lin op.sfctrl.b.addrbits = 16; 759ba0501acSDingqiang Lin 760a80fd396SJon Lin plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0; 761a80fd396SJon Lin ret = sfc_request(&op, plane | column, p_page_buf, len); 762a80fd396SJon Lin rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]); 763c84f0ed8SJon Lin 764c84f0ed8SJon Lin if (ret != SFC_OK) 765f28847a8SJon Lin return SFC_NAND_HW_ERROR; 766c84f0ed8SJon Lin 767c84f0ed8SJon Lin return ecc_result; 768c84f0ed8SJon Lin } 769c84f0ed8SJon Lin 770a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) 771a80fd396SJon Lin { 772a80fd396SJon Lin u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page; 773a80fd396SJon Lin 774a80fd396SJon Lin return sfc_nand_read(addr, p_page_buf, 0, page_size); 775a80fd396SJon Lin } 776a80fd396SJon Lin 777c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) 778c84f0ed8SJon Lin { 77958463f4dSJon Lin u32 ret; 780c84f0ed8SJon Lin u32 sec_per_page = p_nand_info->sec_per_page; 781c84f0ed8SJon Lin u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE; 782a6fcac41SJon Lin struct nand_mega_area *meta = &p_nand_info->meta; 783c84f0ed8SJon Lin 784c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 785f25e3cafSJon Lin memcpy(p_data, gp_page_buf, data_size); 786a6fcac41SJon Lin p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4]; 787a6fcac41SJon Lin p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4]; 788f28847a8SJon Lin 789f25e3cafSJon Lin if (p_nand_info->sec_per_page == 8) { 790a6fcac41SJon Lin p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4]; 791a6fcac41SJon Lin p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4]; 792f25e3cafSJon Lin } 793ba0501acSDingqiang Lin 794f28847a8SJon Lin if (ret == SFC_NAND_HW_ERROR) 795f28847a8SJon Lin ret = SFC_NAND_ECC_ERROR; 796f28847a8SJon Lin 797c84f0ed8SJon Lin if (ret != SFC_NAND_ECC_OK) { 798c84f0ed8SJon Lin rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret); 799f28847a8SJon Lin 800ba0501acSDingqiang Lin if (p_data) 801c84f0ed8SJon Lin rkflash_print_hex("data:", p_data, 4, 8); 802f28847a8SJon Lin 803ba0501acSDingqiang Lin if (p_spare) 804c84f0ed8SJon Lin rkflash_print_hex("spare:", p_spare, 4, 2); 805ba0501acSDingqiang Lin } 806f25e3cafSJon Lin 807c84f0ed8SJon Lin return ret; 808ba0501acSDingqiang Lin } 809ba0501acSDingqiang Lin 810c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr) 811c84f0ed8SJon Lin { 812c84f0ed8SJon Lin u32 ret; 813c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 814a80fd396SJon Lin u32 marker = 0; 815c84f0ed8SJon Lin 816a80fd396SJon Lin ret = sfc_nand_read(addr, &marker, data_size, 2); 817f28847a8SJon Lin 818f28847a8SJon Lin /* unify with mtd framework */ 819a6fcac41SJon Lin if (ret == SFC_NAND_ECC_ERROR) 820a80fd396SJon Lin rkflash_print_error("%s page= %x ret= %x spare= %x\n", 821a80fd396SJon Lin __func__, addr, ret, marker); 822f28847a8SJon Lin 823c84f0ed8SJon Lin /* Original bad block */ 824a80fd396SJon Lin if ((u16)marker != 0xffff) 825c84f0ed8SJon Lin return true; 826c84f0ed8SJon Lin 827c84f0ed8SJon Lin return false; 828c84f0ed8SJon Lin } 829c84f0ed8SJon Lin 830c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr) 831c84f0ed8SJon Lin { 832c84f0ed8SJon Lin u32 ret; 833c84f0ed8SJon Lin u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; 834c84f0ed8SJon Lin 835c84f0ed8SJon Lin ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); 836f28847a8SJon Lin 837c84f0ed8SJon Lin if (ret) 838c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 839f28847a8SJon Lin 840c84f0ed8SJon Lin gp_page_buf[data_size / 4] = 0x0; 841c84f0ed8SJon Lin ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf); 842f28847a8SJon Lin 843c84f0ed8SJon Lin if (ret) 844c84f0ed8SJon Lin return SFC_NAND_HW_ERROR; 845c84f0ed8SJon Lin 846c84f0ed8SJon Lin return ret; 847c84f0ed8SJon Lin } 848c84f0ed8SJon Lin 849c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data) 850ba0501acSDingqiang Lin { 851ba0501acSDingqiang Lin int ret; 85258463f4dSJon Lin struct rk_sfc_op op; 853ba0501acSDingqiang Lin 85458463f4dSJon Lin op.sfcmd.d32 = 0; 85558463f4dSJon Lin op.sfcmd.b.cmd = CMD_READ_JEDECID; 85658463f4dSJon Lin op.sfcmd.b.addrbits = SFC_ADDR_XBITS; 857ba0501acSDingqiang Lin 85858463f4dSJon Lin op.sfctrl.d32 = 0; 85958463f4dSJon Lin op.sfctrl.b.addrbits = 8; 86058463f4dSJon Lin 86158463f4dSJon Lin ret = sfc_request(&op, 0, data, 3); 862ba0501acSDingqiang Lin 863ba0501acSDingqiang Lin return ret; 864ba0501acSDingqiang Lin } 865ba0501acSDingqiang Lin 866ba0501acSDingqiang Lin /* 867ba0501acSDingqiang Lin * Read the 1st page's 1st byte of a phy_blk 868ba0501acSDingqiang Lin * If not FF, it's bad blk 869ba0501acSDingqiang Lin */ 870ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die) 871ba0501acSDingqiang Lin { 872ba0501acSDingqiang Lin u32 bad_cnt, page; 873ba0501acSDingqiang Lin u32 blk_per_die; 8742ac88c1bSJon Lin u16 blk; 875ba0501acSDingqiang Lin 876c84f0ed8SJon Lin rkflash_print_info("%s\n", __func__); 877c84f0ed8SJon Lin 878ba0501acSDingqiang Lin bad_cnt = 0; 879ba0501acSDingqiang Lin blk_per_die = p_nand_info->plane_per_die * 880ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 881f28847a8SJon Lin 882ba0501acSDingqiang Lin for (blk = 0; blk < blk_per_die; blk++) { 883ba0501acSDingqiang Lin page = (blk + blk_per_die * die) * 884ba0501acSDingqiang Lin p_nand_info->page_per_blk; 885ba0501acSDingqiang Lin 8862ac88c1bSJon Lin if (sfc_nand_check_bad_block(die, page)) { 887ba0501acSDingqiang Lin table[bad_cnt++] = blk; 888c84f0ed8SJon Lin rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk); 889ba0501acSDingqiang Lin } 890ba0501acSDingqiang Lin } 891f28847a8SJon Lin 892ba0501acSDingqiang Lin return (int)bad_cnt; 893ba0501acSDingqiang Lin } 894ba0501acSDingqiang Lin 895c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void) 896ba0501acSDingqiang Lin { 897ba0501acSDingqiang Lin /* para init */ 898ba0501acSDingqiang Lin g_nand_phy_info.nand_type = 1; 899ba0501acSDingqiang Lin g_nand_phy_info.die_num = 1; 900ba0501acSDingqiang Lin g_nand_phy_info.plane_per_die = p_nand_info->plane_per_die; 901ba0501acSDingqiang Lin g_nand_phy_info.blk_per_plane = p_nand_info->blk_per_plane; 902ba0501acSDingqiang Lin g_nand_phy_info.page_per_blk = p_nand_info->page_per_blk; 903ba0501acSDingqiang Lin g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk; 904c84f0ed8SJon Lin g_nand_phy_info.byte_per_sec = SFC_NAND_SECTOR_SIZE; 905ba0501acSDingqiang Lin g_nand_phy_info.sec_per_page = p_nand_info->sec_per_page; 906ba0501acSDingqiang Lin g_nand_phy_info.sec_per_blk = p_nand_info->sec_per_page * 907ba0501acSDingqiang Lin p_nand_info->page_per_blk; 908ba0501acSDingqiang Lin g_nand_phy_info.reserved_blk = 8; 909ba0501acSDingqiang Lin g_nand_phy_info.blk_per_die = p_nand_info->plane_per_die * 910ba0501acSDingqiang Lin p_nand_info->blk_per_plane; 911ba0501acSDingqiang Lin g_nand_phy_info.ecc_bits = p_nand_info->max_ecc_bits; 912ba0501acSDingqiang Lin 913ba0501acSDingqiang Lin /* driver register */ 914ba0501acSDingqiang Lin g_nand_ops.get_bad_blk_list = sfc_nand_get_bad_block_list; 915ba0501acSDingqiang Lin g_nand_ops.erase_blk = sfc_nand_erase_block; 916ba0501acSDingqiang Lin g_nand_ops.prog_page = sfc_nand_prog_page; 917ba0501acSDingqiang Lin g_nand_ops.read_page = sfc_nand_read_page; 91857d18453Sjon.lin g_nand_ops.bch_sel = NULL; 919ba0501acSDingqiang Lin } 920ba0501acSDingqiang Lin 921a6fcac41SJon Lin static int sfc_nand_enable_QE(void) 922ba0501acSDingqiang Lin { 923ba0501acSDingqiang Lin int ret = SFC_OK; 924ba0501acSDingqiang Lin u8 status; 925ba0501acSDingqiang Lin 926f28847a8SJon Lin ret = sfc_nand_read_feature(0xB0, &status); 927ba0501acSDingqiang Lin 928ba0501acSDingqiang Lin if (ret != SFC_OK) 929ba0501acSDingqiang Lin return ret; 930ba0501acSDingqiang Lin 931f28847a8SJon Lin if (status & 1) /* is QE bit set */ 932ba0501acSDingqiang Lin return SFC_OK; 933ba0501acSDingqiang Lin 934f28847a8SJon Lin status |= 1; 935ba0501acSDingqiang Lin 936f28847a8SJon Lin return sfc_nand_write_feature(0xB0, status); 937ba0501acSDingqiang Lin } 938ba0501acSDingqiang Lin 939ba0501acSDingqiang Lin u32 sfc_nand_init(void) 940ba0501acSDingqiang Lin { 941c84f0ed8SJon Lin u8 status, id_byte[8]; 942ba0501acSDingqiang Lin 943c84f0ed8SJon Lin sfc_nand_read_id(id_byte); 944c84f0ed8SJon Lin rkflash_print_error("sfc_nand id: %x %x %x\n", 945ba0501acSDingqiang Lin id_byte[0], id_byte[1], id_byte[2]); 946f28847a8SJon Lin 947ba0501acSDingqiang Lin if (id_byte[0] == 0xFF || id_byte[0] == 0x00) 94858463f4dSJon Lin return (u32)FTL_NO_FLASH; 949ba0501acSDingqiang Lin 950a6fcac41SJon Lin p_nand_info = sfc_nand_get_info(id_byte); 951f28847a8SJon Lin 952ba0501acSDingqiang Lin if (!p_nand_info) 95358463f4dSJon Lin return (u32)FTL_UNSUPPORTED_FLASH; 954ba0501acSDingqiang Lin 955ba0501acSDingqiang Lin sfc_nand_dev.manufacturer = id_byte[0]; 956ba0501acSDingqiang Lin sfc_nand_dev.mem_type = id_byte[1]; 957c84f0ed8SJon Lin sfc_nand_dev.capacity = p_nand_info->density; 958c84f0ed8SJon Lin sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page; 959c84f0ed8SJon Lin sfc_nand_dev.page_size = p_nand_info->sec_per_page; 960ba0501acSDingqiang Lin 961ba0501acSDingqiang Lin /* disable block lock */ 962ba0501acSDingqiang Lin sfc_nand_write_feature(0xA0, 0); 963ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X1; 964ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X1; 965f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x03; 966f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x02; 967f28847a8SJon Lin 968ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_READ) { 969f28847a8SJon Lin if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) || 970f28847a8SJon Lin !p_nand_info->has_qe_bits) { 971ba0501acSDingqiang Lin sfc_nand_dev.read_lines = DATA_LINES_X4; 972f28847a8SJon Lin sfc_nand_dev.page_read_cmd = 0x6b; 973ba0501acSDingqiang Lin } 974ba0501acSDingqiang Lin } 975ba0501acSDingqiang Lin 976ba0501acSDingqiang Lin if (p_nand_info->feature & FEA_4BIT_PROG && 977ba0501acSDingqiang Lin sfc_nand_dev.read_lines == DATA_LINES_X4) { 978ba0501acSDingqiang Lin sfc_nand_dev.prog_lines = DATA_LINES_X4; 979f28847a8SJon Lin sfc_nand_dev.page_prog_cmd = 0x32; 980ba0501acSDingqiang Lin } 981ba0501acSDingqiang Lin 982ba0501acSDingqiang Lin sfc_nand_read_feature(0xA0, &status); 983c84f0ed8SJon Lin rkflash_print_info("sfc_nand A0 = 0x%x\n", status); 984ba0501acSDingqiang Lin sfc_nand_read_feature(0xB0, &status); 985c84f0ed8SJon Lin rkflash_print_info("sfc_nand B0 = 0x%x\n", status); 986c84f0ed8SJon Lin rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines); 987c84f0ed8SJon Lin rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines); 988c84f0ed8SJon Lin rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd); 989c84f0ed8SJon Lin rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd); 990ba0501acSDingqiang Lin 991ba0501acSDingqiang Lin return SFC_OK; 992ba0501acSDingqiang Lin } 993ba0501acSDingqiang Lin 994c84f0ed8SJon Lin void sfc_nand_deinit(void) 995ba0501acSDingqiang Lin { 996c84f0ed8SJon Lin /* to-do */ 997ba0501acSDingqiang Lin } 998c84f0ed8SJon Lin 999c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void) 1000c84f0ed8SJon Lin { 1001c84f0ed8SJon Lin return &sfc_nand_dev; 1002c84f0ed8SJon Lin } 1003c84f0ed8SJon Lin 1004