xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/hyf.c (revision 156fbe7cda4b7fa76135bfe4f47f55d5f0cc51a7)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd
4  *
5  * Authors:
6  *	Dingqiang Lin <jon.lin@rock-chips.com>
7  */
8 
9 #ifndef __UBOOT__
10 #include <linux/device.h>
11 #include <linux/kernel.h>
12 #endif
13 #include <linux/mtd/spinand.h>
14 
15 #define SPINAND_MFR_HYF		0xC9
16 
17 static SPINAND_OP_VARIANTS(read_cache_variants,
18 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
19 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
20 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
21 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
22 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
23 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
24 
25 static SPINAND_OP_VARIANTS(write_cache_variants,
26 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
27 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
28 
29 static SPINAND_OP_VARIANTS(update_cache_variants,
30 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
31 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
32 
33 static int hyf1gq4upacae_ooblayout_ecc(struct mtd_info *mtd, int section,
34 				       struct mtd_oob_region *region)
35 {
36 	if (section)
37 		return -ERANGE;
38 
39 	region->offset = 64;
40 	region->length = 64;
41 
42 	return 0;
43 }
44 
45 static int hyf1gq4upacae_ooblayout_free(struct mtd_info *mtd, int section,
46 					struct mtd_oob_region *region)
47 {
48 	if (section)
49 		return -ERANGE;
50 
51 	region->offset = 1;
52 	region->length = 63;
53 
54 	return 0;
55 }
56 
57 static const struct mtd_ooblayout_ops hyf1gq4upacae_ooblayout = {
58 	.ecc = hyf1gq4upacae_ooblayout_ecc,
59 	.rfree = hyf1gq4upacae_ooblayout_free,
60 };
61 
62 static int hyf1gq4udacae_ooblayout_ecc(struct mtd_info *mtd, int section,
63 				       struct mtd_oob_region *region)
64 {
65 	if (section > 3)
66 		return -ERANGE;
67 
68 	region->offset = (16 * section) + 8;
69 	region->length = 8;
70 
71 	return 0;
72 }
73 
74 static int hyf1gq4udacae_ooblayout_free(struct mtd_info *mtd, int section,
75 					struct mtd_oob_region *region)
76 {
77 	if (section > 3)
78 		return -ERANGE;
79 
80 	region->offset = (16 * section) + 4;
81 	region->length = 4;
82 
83 	return 0;
84 }
85 
86 static const struct mtd_ooblayout_ops hyf1gq4udacae_ooblayout = {
87 	.ecc = hyf1gq4udacae_ooblayout_ecc,
88 	.rfree = hyf1gq4udacae_ooblayout_free,
89 };
90 
91 static int hyf2gq4uaacae_ooblayout_ecc(struct mtd_info *mtd, int section,
92 				       struct mtd_oob_region *region)
93 {
94 	if (section > 3)
95 		return -ERANGE;
96 
97 	region->offset = (32 * section) + 8;
98 	region->length = 24;
99 
100 	return 0;
101 }
102 
103 static int hyf2gq4uaacae_ooblayout_free(struct mtd_info *mtd, int section,
104 					struct mtd_oob_region *region)
105 {
106 	if (section > 3)
107 		return -ERANGE;
108 
109 	region->offset = 16 * section;
110 	region->length = 8;
111 
112 	return 0;
113 }
114 
115 static const struct mtd_ooblayout_ops hyf2gq4uaacae_ooblayout = {
116 	.ecc = hyf2gq4uaacae_ooblayout_ecc,
117 	.rfree = hyf2gq4uaacae_ooblayout_free,
118 };
119 
120 static int hyf1gq4udacae_ecc_get_status(struct spinand_device *spinand,
121 					u8 status)
122 {
123 	struct nand_device *nand = spinand_to_nand(spinand);
124 
125 	switch (status & STATUS_ECC_MASK) {
126 	case STATUS_ECC_NO_BITFLIPS:
127 		return 0;
128 
129 	case STATUS_ECC_UNCOR_ERROR:
130 		return -EBADMSG;
131 
132 	case STATUS_ECC_HAS_BITFLIPS:
133 		return 1;
134 
135 	default:
136 		return nand->eccreq.strength;
137 	}
138 
139 	return -EINVAL;
140 }
141 
142 static const struct spinand_info hyf_spinand_table[] = {
143 	SPINAND_INFO("HYF1GQ4UPACAE", 0xA1,
144 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
145 		     NAND_ECCREQ(1, 512),
146 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
147 					      &write_cache_variants,
148 					      &update_cache_variants),
149 		     SPINAND_HAS_QE_BIT,
150 		     SPINAND_ECCINFO(&hyf1gq4upacae_ooblayout, NULL)),
151 	SPINAND_INFO("HYF1GQ4UDACAE", 0x21,
152 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
153 		     NAND_ECCREQ(4, 512),
154 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
155 					      &write_cache_variants,
156 					      &update_cache_variants),
157 		     SPINAND_HAS_QE_BIT,
158 		     SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
159 				     hyf1gq4udacae_ecc_get_status)),
160 	SPINAND_INFO("HYF1GQ4UDACAE", 0x22,
161 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
162 		     NAND_ECCREQ(4, 512),
163 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
164 					      &write_cache_variants,
165 					      &update_cache_variants),
166 		     SPINAND_HAS_QE_BIT,
167 		     SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
168 				     hyf1gq4udacae_ecc_get_status)),
169 	SPINAND_INFO("HYF2GQ4UAACAE", 0x52,
170 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
171 		     NAND_ECCREQ(14, 512),
172 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
173 					      &write_cache_variants,
174 					      &update_cache_variants),
175 		     SPINAND_HAS_QE_BIT,
176 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
177 				     hyf1gq4udacae_ecc_get_status)),
178 	SPINAND_INFO("HYF2GQ4UHCCAE", 0x5A,
179 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
180 		     NAND_ECCREQ(14, 512),
181 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
182 					      &write_cache_variants,
183 					      &update_cache_variants),
184 		     SPINAND_HAS_QE_BIT,
185 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
186 				     hyf1gq4udacae_ecc_get_status)),
187 	SPINAND_INFO("HYF4GQ4UAACBE", 0xD4,
188 		     NAND_MEMORG(1, 4096, 128, 64, 2048, 1, 1, 1),
189 		     NAND_ECCREQ(4, 512),
190 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
191 					      &write_cache_variants,
192 					      &update_cache_variants),
193 		     SPINAND_HAS_QE_BIT,
194 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
195 				     hyf1gq4udacae_ecc_get_status)),
196 };
197 
198 /**
199  * hyf_spinand_detect - initialize device related part in spinand_device
200  * struct if it is a hyf device.
201  * @spinand: SPI NAND device structure
202  */
203 static int hyf_spinand_detect(struct spinand_device *spinand)
204 {
205 	u8 *id = spinand->id.data;
206 	int ret;
207 
208 	/*
209 	 * hyf SPI NAND read ID needs a dummy byte, so the first byte in
210 	 * raw_id is garbage.
211 	 */
212 	if (id[1] != SPINAND_MFR_HYF)
213 		return 0;
214 
215 	ret = spinand_match_and_init(spinand, hyf_spinand_table,
216 				     ARRAY_SIZE(hyf_spinand_table),
217 				     id[2]);
218 	if (ret)
219 		return ret;
220 
221 	return 1;
222 }
223 
224 static const struct spinand_manufacturer_ops hyf_spinand_manuf_ops = {
225 	.detect = hyf_spinand_detect,
226 };
227 
228 const struct spinand_manufacturer hyf_spinand_manufacturer = {
229 	.id = SPINAND_MFR_HYF,
230 	.name = "hyf",
231 	.ops = &hyf_spinand_manuf_ops,
232 };
233