blob: ae2458fb8a62d2df8ec8b167bf5cbd9a3bd5c022 [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
developera8d7b382023-07-11 21:05:40 +080026@@ -0,0 +1,180 @@
developer5e51fec2023-07-05 20:20:34 +080027+// 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+{
developera8d7b382023-07-11 21:05:40 +080095+ struct nand_device *nand = spinand_to_nand(spinand);
96+
developer5e51fec2023-07-05 20:20:34 +080097+ switch (status & STATUS_ECC_MASK) {
98+ case STATUS_ECC_NO_BITFLIPS:
99+ return 0;
100+
101+ case STATUS_ECC_UNCOR_ERROR:
102+ return -EBADMSG;
103+
104+ case STATUS_ECC_HAS_BITFLIPS:
developera8d7b382023-07-11 21:05:40 +0800105+ return nand->eccreq.strength >> 1;
developer5e51fec2023-07-05 20:20:34 +0800106+
107+ case STATUS_ECC_LIMIT_BITFLIPS:
developera8d7b382023-07-11 21:05:40 +0800108+ return nand->eccreq.strength;
developer5e51fec2023-07-05 20:20:34 +0800109+
110+ default:
111+ break;
112+ }
113+
114+ return -EINVAL;
115+}
116+
117+static const struct spinand_info etron_spinand_table[] = {
118+ /* EM73C 1Gb 3.3V */
119+ SPINAND_INFO("EM73C044VCF",
120+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x25),
121+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
122+ NAND_ECCREQ(4, 512),
123+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
124+ &write_cache_variants,
125+ &update_cache_variants),
126+ SPINAND_HAS_QE_BIT,
127+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
128+ /* EM7xD 2Gb */
129+ SPINAND_INFO("EM73D044VCR",
130+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x41),
131+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
132+ NAND_ECCREQ(4, 512),
133+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
134+ &write_cache_variants,
135+ &update_cache_variants),
136+ SPINAND_HAS_QE_BIT,
137+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
138+ SPINAND_INFO("EM73D044VCO",
139+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3A),
140+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
141+ NAND_ECCREQ(8, 512),
142+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
143+ &write_cache_variants,
144+ &update_cache_variants),
145+ SPINAND_HAS_QE_BIT,
146+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
147+ SPINAND_INFO("EM78D044VCM",
148+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x8E),
149+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
150+ NAND_ECCREQ(8, 512),
151+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
152+ &write_cache_variants,
153+ &update_cache_variants),
154+ SPINAND_HAS_QE_BIT,
155+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
156+ /* EM7xE 4Gb */
157+ SPINAND_INFO("EM73E044VCE",
158+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3B),
159+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
160+ NAND_ECCREQ(8, 512),
161+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
162+ &write_cache_variants,
163+ &update_cache_variants),
164+ SPINAND_HAS_QE_BIT,
165+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
166+ SPINAND_INFO("EM78E044VCD",
167+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x8F),
168+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
169+ NAND_ECCREQ(8, 512),
170+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
171+ &write_cache_variants,
172+ &update_cache_variants),
173+ SPINAND_HAS_QE_BIT,
174+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
175+ /* EM7xF044VCA 8Gb */
176+ SPINAND_INFO("EM73F044VCA",
177+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
178+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
179+ NAND_ECCREQ(8, 512),
180+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
181+ &write_cache_variants,
182+ &update_cache_variants),
183+ SPINAND_HAS_QE_BIT,
184+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
185+ SPINAND_INFO("EM78F044VCA",
186+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x8D),
187+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
188+ NAND_ECCREQ(8, 512),
189+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
190+ &write_cache_variants,
191+ &update_cache_variants),
192+ SPINAND_HAS_QE_BIT,
193+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
194+};
195+
developer5e51fec2023-07-05 20:20:34 +0800196+static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
197+};
198+
199+const struct spinand_manufacturer etron_spinand_manufacturer = {
200+ .id = SPINAND_MFR_ETRON,
201+ .name = "Etron",
202+ .chips = etron_spinand_table,
203+ .nchips = ARRAY_SIZE(etron_spinand_table),
204+ .ops = &etron_spinand_manuf_ops,
205+};
206+
207Index: a/include/linux/mtd/spinand.h
208===================================================================
209--- a/include/linux/mtd/spinand.h
210+++ b/include/linux/mtd/spinand.h
211@@ -238,6 +238,7 @@ struct spinand_manufacturer {
212 };
213
214 /* SPI NAND manufacturers */
215+extern const struct spinand_manufacturer etron_spinand_manufacturer;
216 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
217 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
218 extern const struct spinand_manufacturer micron_spinand_manufacturer;