blob: 860a8d94d7deb244833bfbfd3b15bb1b45b1b261 [file] [log] [blame]
developerd2bdfc32022-03-18 21:25:39 +08001--- a/drivers/mtd/nand/spi/winbond.c
2+++ b/drivers/mtd/nand/spi/winbond.c
developer6207d3c2022-12-08 19:06:30 +08003@@ -15,6 +15,23 @@
developerd2bdfc32022-03-18 21:25:39 +08004
5 #define WINBOND_CFG_BUF_READ BIT(3)
6
7+#define W25N02_N04KV_STATUS_ECC_MASK (3 << 4)
8+#define W25N02_N04KV_STATUS_ECC_NO_BITFLIPS (0 << 4)
9+#define W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS (1 << 4)
10+#define W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
11+#define W25N02_N04KV_STATUS_ECC_UNCOR_ERROR (2 << 4)
12+
13+#define W25N01_M02GV_STATUS_ECC_MASK (3 << 4)
14+#define W25N01_M02GV_STATUS_ECC_NO_BITFLIPS (0 << 4)
15+#define W25N01_M02GV_STATUS_ECC_1_BITFLIPS (1 << 4)
16+#define W25N01_M02GV_STATUS_ECC_UNCOR_ERROR (2 << 4)
17+
developerd2bdfc32022-03-18 21:25:39 +080018+#define W25N01KV_STATUS_ECC_MASK (3 << 4)
19+#define W25N01KV_STATUS_ECC_NO_BITFLIPS (0 << 4)
20+#define W25N01KV_STATUS_ECC_1_3_BITFLIPS (1 << 4)
21+#define W25N01KV_STATUS_ECC_4_BITFLIPS (3 << 4)
22+#define W25N01KV_STATUS_ECC_UNCOR_ERROR (2 << 4)
developerd2bdfc32022-03-18 21:25:39 +080023+
24 static SPINAND_OP_VARIANTS(read_cache_variants,
25 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
26 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
developer6207d3c2022-12-08 19:06:30 +080027@@ -31,6 +48,29 @@ static SPINAND_OP_VARIANTS(update_cache_
developerd2bdfc32022-03-18 21:25:39 +080028 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
29 SPINAND_PROG_LOAD(false, 0, NULL, 0));
30
31+static int w25n02kv_n04kv_ooblayout_ecc(struct mtd_info *mtd, int section,
32+ struct mtd_oob_region *region)
33+{
34+ return -ERANGE;
35+}
36+
37+static int w25n02kv_n04kv_ooblayout_free(struct mtd_info *mtd, int section,
38+ struct mtd_oob_region *region)
39+{
40+ if (section > 3)
41+ return -ERANGE;
42+
43+ region->offset = (16 * section) + 2;
44+ region->length = 14;
45+
46+ return 0;
47+}
48+
49+static const struct mtd_ooblayout_ops w25n02kv_n04kv_ooblayout = {
50+ .ecc = w25n02kv_n04kv_ooblayout_ecc,
51+ .free = w25n02kv_n04kv_ooblayout_free,
52+};
53+
54 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
55 struct mtd_oob_region *region)
56 {
developer6207d3c2022-12-08 19:06:30 +080057@@ -74,9 +114,61 @@ static int w25m02gv_select_target(struct
developerd2bdfc32022-03-18 21:25:39 +080058 return spi_mem_exec_op(spinand->spimem, &op);
59 }
60
developerd2bdfc32022-03-18 21:25:39 +080061+static int w25n01kv_ecc_get_status(struct spinand_device *spinand,
62+ u8 status)
63+{
64+ switch (status & W25N01KV_STATUS_ECC_MASK) {
65+ case W25N01KV_STATUS_ECC_NO_BITFLIPS:
66+ return 0;
67+
68+ case W25N01KV_STATUS_ECC_1_3_BITFLIPS:
69+ return 3;
70+
71+ case W25N01KV_STATUS_ECC_4_BITFLIPS:
72+ return 4;
73+
74+ case W25N01KV_STATUS_ECC_UNCOR_ERROR:
75+ return -EBADMSG;
76+
77+ default:
78+ break;
79+ }
80+
81+ return -EINVAL;
82+}
developerd2bdfc32022-03-18 21:25:39 +080083+
84+static int w25n02kv_n04kv_ecc_get_status(struct spinand_device *spinand,
85+ u8 status)
86+{
87+ switch (status & W25N02_N04KV_STATUS_ECC_MASK) {
88+ case W25N02_N04KV_STATUS_ECC_NO_BITFLIPS:
89+ return 0;
90+
91+ case W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS:
92+ return 3;
93+
94+ case W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS:
95+ return 4;
96+
97+ /* W25N02_N04KV_use internal 8bit ECC algorithm.
98+ * But the ECC strength is 4 bit requried.
99+ * Return 3 if the bit bit flip count less than 5.
100+ * Return 4 if the bit bit flip count more than 5 to 8.
101+ */
102+
103+ case W25N02_N04KV_STATUS_ECC_UNCOR_ERROR:
104+ return -EBADMSG;
105+
106+ default:
107+ break;
108+ }
109+
110+ return -EINVAL;
111+}
112+
113 static const struct spinand_info winbond_spinand_table[] = {
114 SPINAND_INFO("W25M02GV",
115- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
116+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
117 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
118 NAND_ECCREQ(1, 512),
119 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer6207d3c2022-12-08 19:06:30 +0800120@@ -85,8 +177,18 @@ static const struct spinand_info winbond
developerd2bdfc32022-03-18 21:25:39 +0800121 0,
122 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
123 SPINAND_SELECT_TARGET(w25m02gv_select_target)),
developerd2bdfc32022-03-18 21:25:39 +0800124+ SPINAND_INFO("W25N01KV",
developer6207d3c2022-12-08 19:06:30 +0800125+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
126+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
developerd2bdfc32022-03-18 21:25:39 +0800127+ NAND_ECCREQ(4, 512),
128+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
129+ &write_cache_variants,
130+ &update_cache_variants),
131+ 0,
132+ SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
133+ w25n01kv_ecc_get_status)),
developerd2bdfc32022-03-18 21:25:39 +0800134 SPINAND_INFO("W25N01GV",
135- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
136+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
137 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
138 NAND_ECCREQ(1, 512),
139 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer6207d3c2022-12-08 19:06:30 +0800140@@ -94,6 +196,29 @@ static const struct spinand_info winbond
developerd2bdfc32022-03-18 21:25:39 +0800141 &update_cache_variants),
142 0,
143 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
developerd2bdfc32022-03-18 21:25:39 +0800144+ SPINAND_INFO("W25N02KV",
145+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
146+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
147+ NAND_ECCREQ(4, 512),
148+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
149+ &write_cache_variants,
150+ &update_cache_variants),
151+ 0,
152+ SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
153+ w25n02kv_n04kv_ecc_get_status)),
154+ /* W25N04KV has 2-die(lun), however, it can select die automatically.
155+ * Treat it as single die here and double block size.
156+ */
157+ SPINAND_INFO("W25N04KV",
158+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
159+ NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
160+ NAND_ECCREQ(4, 512),
161+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
162+ &write_cache_variants,
163+ &update_cache_variants),
164+ 0,
165+ SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
166+ w25n02kv_n04kv_ecc_get_status)),
167 };
168
169 static int winbond_spinand_init(struct spinand_device *spinand)