blob: 68a6f12ce7e6aeb91475f7cdd653230bafd8aa58 [file] [log] [blame]
developer5e51fec2023-07-05 20:20:34 +08001Index: a/drivers/mtd/nand/spi/Makefile
2===================================================================
3--- a/drivers/mtd/nand/spi/Makefile
4+++ b/drivers/mtd/nand/spi/Makefile
5@@ -1,3 +1,3 @@
6 # SPDX-License-Identifier: GPL-2.0
7-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
8+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o etron.o
9 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
10Index: a/drivers/mtd/nand/spi/core.c
11===================================================================
12--- a/drivers/mtd/nand/spi/core.c
13+++ b/drivers/mtd/nand/spi/core.c
14@@ -754,6 +754,7 @@ static const struct nand_ops spinand_ops
15 };
16
17 static const struct spinand_manufacturer *spinand_manufacturers[] = {
18+ &etron_spinand_manufacturer,
19 &gigadevice_spinand_manufacturer,
20 &macronix_spinand_manufacturer,
21 &micron_spinand_manufacturer,
22Index: a/drivers/mtd/nand/spi/etron.c
23===================================================================
24--- /dev/null
25+++ b/drivers/mtd/nand/spi/etron.c
26@@ -0,0 +1,196 @@
27+// SPDX-License-Identifier: GPL-2.0
28+/*
29+ * Copyright (c) 2020 Etron Technology, Inc.
30+ *
31+ */
32+
33+#include <linux/device.h>
34+#include <linux/kernel.h>
35+#include <linux/mtd/spinand.h>
36+
37+#define SPINAND_MFR_ETRON 0xD5
38+
39+#define STATUS_ECC_LIMIT_BITFLIPS (3 << 4)
40+
41+static SPINAND_OP_VARIANTS(read_cache_variants,
42+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
43+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
44+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
45+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
46+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
47+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
48+
49+static SPINAND_OP_VARIANTS(write_cache_variants,
50+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
51+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
52+
53+static SPINAND_OP_VARIANTS(update_cache_variants,
54+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
55+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
56+
57+static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
58+ struct mtd_oob_region *region)
59+{
60+ if (section > 3)
61+ return -ERANGE;
62+
63+ region->offset = (14 * section) + 72;
64+ region->length = 14;
65+
66+ return 0;
67+}
68+
69+static int etron_ooblayout_free(struct mtd_info *mtd, int section,
70+ struct mtd_oob_region *region)
71+{
72+ if (section > 3)
73+ return -ERANGE;
74+
75+ if (section) {
76+ region->offset = 18 * section;
77+ region->length = 18;
78+ } else {
79+ /* section 0 has one byte reserved for bad block mark */
80+ region->offset = 2;
81+ region->length = 16;
82+ }
83+
84+ return 0;
85+}
86+
87+static const struct mtd_ooblayout_ops etron_ooblayout = {
88+ .ecc = etron_ooblayout_ecc,
89+ .free = etron_ooblayout_free,
90+};
91+
92+static int etron_ecc_get_status(struct spinand_device *spinand,
93+ u8 status)
94+{
95+ switch (status & STATUS_ECC_MASK) {
96+ case STATUS_ECC_NO_BITFLIPS:
97+ return 0;
98+
99+ case STATUS_ECC_UNCOR_ERROR:
100+ return -EBADMSG;
101+
102+ case STATUS_ECC_HAS_BITFLIPS:
103+ return 1;
104+
105+ case STATUS_ECC_LIMIT_BITFLIPS:
106+ return 3;
107+
108+
109+ default:
110+ break;
111+ }
112+
113+ return -EINVAL;
114+}
115+
116+static const struct spinand_info etron_spinand_table[] = {
117+ /* EM73C 1Gb 3.3V */
118+ SPINAND_INFO("EM73C044VCF",
119+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x25),
120+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
121+ NAND_ECCREQ(4, 512),
122+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
123+ &write_cache_variants,
124+ &update_cache_variants),
125+ SPINAND_HAS_QE_BIT,
126+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
127+ /* EM7xD 2Gb */
128+ SPINAND_INFO("EM73D044VCR",
129+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x41),
130+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
131+ NAND_ECCREQ(4, 512),
132+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
133+ &write_cache_variants,
134+ &update_cache_variants),
135+ SPINAND_HAS_QE_BIT,
136+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
137+ SPINAND_INFO("EM73D044VCO",
138+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3A),
139+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
140+ NAND_ECCREQ(8, 512),
141+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
142+ &write_cache_variants,
143+ &update_cache_variants),
144+ SPINAND_HAS_QE_BIT,
145+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
146+ SPINAND_INFO("EM78D044VCM",
147+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x8E),
148+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
149+ NAND_ECCREQ(8, 512),
150+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
151+ &write_cache_variants,
152+ &update_cache_variants),
153+ SPINAND_HAS_QE_BIT,
154+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
155+ /* EM7xE 4Gb */
156+ SPINAND_INFO("EM73E044VCE",
157+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3B),
158+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
159+ NAND_ECCREQ(8, 512),
160+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
161+ &write_cache_variants,
162+ &update_cache_variants),
163+ SPINAND_HAS_QE_BIT,
164+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
165+ SPINAND_INFO("EM78E044VCD",
166+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x8F),
167+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
168+ NAND_ECCREQ(8, 512),
169+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
170+ &write_cache_variants,
171+ &update_cache_variants),
172+ SPINAND_HAS_QE_BIT,
173+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
174+ /* EM7xF044VCA 8Gb */
175+ SPINAND_INFO("EM73F044VCA",
176+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
177+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
178+ NAND_ECCREQ(8, 512),
179+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
180+ &write_cache_variants,
181+ &update_cache_variants),
182+ SPINAND_HAS_QE_BIT,
183+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
184+ SPINAND_INFO("EM78F044VCA",
185+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x8D),
186+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
187+ NAND_ECCREQ(8, 512),
188+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
189+ &write_cache_variants,
190+ &update_cache_variants),
191+ SPINAND_HAS_QE_BIT,
192+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
193+};
194+
195+static int etron_spinand_detect(struct spinand_device *spinand)
196+{
197+ u8 *id = spinand->id.data;
198+ int ret;
199+
200+ if (id[1] != SPINAND_MFR_ETRON)
201+ return 0;
202+
203+ ret = spinand_match_and_init(spinand, etron_spinand_table,
204+ ARRAY_SIZE(etron_spinand_table),
205+ id[2]);
206+ if (ret)
207+ return ret;
208+
209+ return 1;
210+}
211+
212+static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
213+};
214+
215+const struct spinand_manufacturer etron_spinand_manufacturer = {
216+ .id = SPINAND_MFR_ETRON,
217+ .name = "Etron",
218+ .chips = etron_spinand_table,
219+ .nchips = ARRAY_SIZE(etron_spinand_table),
220+ .ops = &etron_spinand_manuf_ops,
221+};
222+
223Index: a/include/linux/mtd/spinand.h
224===================================================================
225--- a/include/linux/mtd/spinand.h
226+++ b/include/linux/mtd/spinand.h
227@@ -238,6 +238,7 @@ struct spinand_manufacturer {
228 };
229
230 /* SPI NAND manufacturers */
231+extern const struct spinand_manufacturer etron_spinand_manufacturer;
232 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
233 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
234 extern const struct spinand_manufacturer micron_spinand_manufacturer;