xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/hyf.c (revision 2108666d04676fdf09d2990864c21a4c80c6ff39)
1b66d41c2SJon Lin // SPDX-License-Identifier: GPL-2.0
2b66d41c2SJon Lin /*
3d3fa6ff3SJon Lin  * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd
4b66d41c2SJon Lin  *
5b66d41c2SJon Lin  * Authors:
6d3fa6ff3SJon Lin  *	Dingqiang Lin <jon.lin@rock-chips.com>
7b66d41c2SJon Lin  */
8b66d41c2SJon Lin 
9b66d41c2SJon Lin #ifndef __UBOOT__
10b66d41c2SJon Lin #include <linux/device.h>
11b66d41c2SJon Lin #include <linux/kernel.h>
12b66d41c2SJon Lin #endif
13b66d41c2SJon Lin #include <linux/mtd/spinand.h>
14b66d41c2SJon Lin 
15b66d41c2SJon Lin #define SPINAND_MFR_HYF		0xC9
16b66d41c2SJon Lin 
17b66d41c2SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
18b66d41c2SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
19b66d41c2SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
20b66d41c2SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
21b66d41c2SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
22b66d41c2SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
23b66d41c2SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
24b66d41c2SJon Lin 
25b66d41c2SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
26b66d41c2SJon Lin 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
27b66d41c2SJon Lin 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
28b66d41c2SJon Lin 
29b66d41c2SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
30b66d41c2SJon Lin 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
31b66d41c2SJon Lin 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
32b66d41c2SJon Lin 
hyf1gq4upacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)33b66d41c2SJon Lin static int hyf1gq4upacae_ooblayout_ecc(struct mtd_info *mtd, int section,
34b66d41c2SJon Lin 				       struct mtd_oob_region *region)
35b66d41c2SJon Lin {
36b66d41c2SJon Lin 	if (section)
37b66d41c2SJon Lin 		return -ERANGE;
38b66d41c2SJon Lin 
39b66d41c2SJon Lin 	region->offset = 64;
40b66d41c2SJon Lin 	region->length = 64;
41b66d41c2SJon Lin 
42b66d41c2SJon Lin 	return 0;
43b66d41c2SJon Lin }
44b66d41c2SJon Lin 
hyf1gq4upacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)45b66d41c2SJon Lin static int hyf1gq4upacae_ooblayout_free(struct mtd_info *mtd, int section,
46b66d41c2SJon Lin 					struct mtd_oob_region *region)
47b66d41c2SJon Lin {
48b66d41c2SJon Lin 	if (section)
49b66d41c2SJon Lin 		return -ERANGE;
50b66d41c2SJon Lin 
51b66d41c2SJon Lin 	region->offset = 1;
52b66d41c2SJon Lin 	region->length = 63;
53b66d41c2SJon Lin 
54b66d41c2SJon Lin 	return 0;
55b66d41c2SJon Lin }
56b66d41c2SJon Lin 
57b66d41c2SJon Lin static const struct mtd_ooblayout_ops hyf1gq4upacae_ooblayout = {
58b66d41c2SJon Lin 	.ecc = hyf1gq4upacae_ooblayout_ecc,
59b66d41c2SJon Lin 	.rfree = hyf1gq4upacae_ooblayout_free,
60b66d41c2SJon Lin };
61b66d41c2SJon Lin 
hyf1gq4udacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)62b66d41c2SJon Lin static int hyf1gq4udacae_ooblayout_ecc(struct mtd_info *mtd, int section,
63b66d41c2SJon Lin 				       struct mtd_oob_region *region)
64b66d41c2SJon Lin {
65b66d41c2SJon Lin 	if (section > 3)
66b66d41c2SJon Lin 		return -ERANGE;
67b66d41c2SJon Lin 
68b66d41c2SJon Lin 	region->offset = (16 * section) + 8;
69b66d41c2SJon Lin 	region->length = 8;
70b66d41c2SJon Lin 
71b66d41c2SJon Lin 	return 0;
72b66d41c2SJon Lin }
73b66d41c2SJon Lin 
hyf1gq4udacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)74b66d41c2SJon Lin static int hyf1gq4udacae_ooblayout_free(struct mtd_info *mtd, int section,
75b66d41c2SJon Lin 					struct mtd_oob_region *region)
76b66d41c2SJon Lin {
77b66d41c2SJon Lin 	if (section > 3)
78b66d41c2SJon Lin 		return -ERANGE;
79b66d41c2SJon Lin 
80b66d41c2SJon Lin 	region->offset = (16 * section) + 4;
81b66d41c2SJon Lin 	region->length = 4;
82b66d41c2SJon Lin 
83b66d41c2SJon Lin 	return 0;
84b66d41c2SJon Lin }
85b66d41c2SJon Lin 
86b66d41c2SJon Lin static const struct mtd_ooblayout_ops hyf1gq4udacae_ooblayout = {
87b66d41c2SJon Lin 	.ecc = hyf1gq4udacae_ooblayout_ecc,
88b66d41c2SJon Lin 	.rfree = hyf1gq4udacae_ooblayout_free,
89b66d41c2SJon Lin };
90b66d41c2SJon Lin 
hyf2gq4uaacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)915fe488ffSJon Lin static int hyf2gq4uaacae_ooblayout_ecc(struct mtd_info *mtd, int section,
925fe488ffSJon Lin 				       struct mtd_oob_region *region)
935fe488ffSJon Lin {
945fe488ffSJon Lin 	if (section > 3)
955fe488ffSJon Lin 		return -ERANGE;
965fe488ffSJon Lin 
975fe488ffSJon Lin 	region->offset = (32 * section) + 8;
985fe488ffSJon Lin 	region->length = 24;
995fe488ffSJon Lin 
1005fe488ffSJon Lin 	return 0;
1015fe488ffSJon Lin }
1025fe488ffSJon Lin 
hyf2gq4uaacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)1035fe488ffSJon Lin static int hyf2gq4uaacae_ooblayout_free(struct mtd_info *mtd, int section,
1045fe488ffSJon Lin 					struct mtd_oob_region *region)
1055fe488ffSJon Lin {
1065fe488ffSJon Lin 	if (section > 3)
1075fe488ffSJon Lin 		return -ERANGE;
1085fe488ffSJon Lin 
109*2108666dSJon Lin 	region->offset = 32 * section;
1105fe488ffSJon Lin 	region->length = 8;
1115fe488ffSJon Lin 
1125fe488ffSJon Lin 	return 0;
1135fe488ffSJon Lin }
1145fe488ffSJon Lin 
1155fe488ffSJon Lin static const struct mtd_ooblayout_ops hyf2gq4uaacae_ooblayout = {
1165fe488ffSJon Lin 	.ecc = hyf2gq4uaacae_ooblayout_ecc,
1175fe488ffSJon Lin 	.rfree = hyf2gq4uaacae_ooblayout_free,
1185fe488ffSJon Lin };
1195fe488ffSJon Lin 
hyf1gq4udacae_ecc_get_status(struct spinand_device * spinand,u8 status)120b66d41c2SJon Lin static int hyf1gq4udacae_ecc_get_status(struct spinand_device *spinand,
121b66d41c2SJon Lin 					u8 status)
122b66d41c2SJon Lin {
123b66d41c2SJon Lin 	struct nand_device *nand = spinand_to_nand(spinand);
124b66d41c2SJon Lin 
125b66d41c2SJon Lin 	switch (status & STATUS_ECC_MASK) {
126b66d41c2SJon Lin 	case STATUS_ECC_NO_BITFLIPS:
127b66d41c2SJon Lin 		return 0;
128b66d41c2SJon Lin 
129b66d41c2SJon Lin 	case STATUS_ECC_UNCOR_ERROR:
130b66d41c2SJon Lin 		return -EBADMSG;
131b66d41c2SJon Lin 
132b66d41c2SJon Lin 	case STATUS_ECC_HAS_BITFLIPS:
133b66d41c2SJon Lin 		return 1;
134b66d41c2SJon Lin 
135b66d41c2SJon Lin 	default:
136b66d41c2SJon Lin 		return nand->eccreq.strength;
137b66d41c2SJon Lin 	}
138b66d41c2SJon Lin 
139b66d41c2SJon Lin 	return -EINVAL;
140b66d41c2SJon Lin }
141b66d41c2SJon Lin 
142b66d41c2SJon Lin static const struct spinand_info hyf_spinand_table[] = {
14381afcfe1SJon Lin 	SPINAND_INFO("HYF1GQ4UPACAE",
144ac39ced8SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xA1),
145b66d41c2SJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
146b66d41c2SJon Lin 		     NAND_ECCREQ(1, 512),
147b66d41c2SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
148b66d41c2SJon Lin 					      &write_cache_variants,
149b66d41c2SJon Lin 					      &update_cache_variants),
150b66d41c2SJon Lin 		     SPINAND_HAS_QE_BIT,
151b66d41c2SJon Lin 		     SPINAND_ECCINFO(&hyf1gq4upacae_ooblayout, NULL)),
15281afcfe1SJon Lin 	SPINAND_INFO("HYF1GQ4UDACAE",
153ac39ced8SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
1545fe488ffSJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
155b66d41c2SJon Lin 		     NAND_ECCREQ(4, 512),
156b66d41c2SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
157b66d41c2SJon Lin 					      &write_cache_variants,
158b66d41c2SJon Lin 					      &update_cache_variants),
159b66d41c2SJon Lin 		     SPINAND_HAS_QE_BIT,
160b66d41c2SJon Lin 		     SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
161b66d41c2SJon Lin 				     hyf1gq4udacae_ecc_get_status)),
16281afcfe1SJon Lin 	SPINAND_INFO("HYF1GQ4UDACAE",
163ac39ced8SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x22),
164a792c7e0SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
165a792c7e0SJon Lin 		     NAND_ECCREQ(4, 512),
166a792c7e0SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
167a792c7e0SJon Lin 					      &write_cache_variants,
168a792c7e0SJon Lin 					      &update_cache_variants),
169a792c7e0SJon Lin 		     SPINAND_HAS_QE_BIT,
170a792c7e0SJon Lin 		     SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
171a792c7e0SJon Lin 				     hyf1gq4udacae_ecc_get_status)),
17281afcfe1SJon Lin 	SPINAND_INFO("HYF2GQ4UAACAE",
173ac39ced8SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
1745fe488ffSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
1755fe488ffSJon Lin 		     NAND_ECCREQ(14, 512),
1765fe488ffSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1775fe488ffSJon Lin 					      &write_cache_variants,
1785fe488ffSJon Lin 					      &update_cache_variants),
1795fe488ffSJon Lin 		     SPINAND_HAS_QE_BIT,
1805fe488ffSJon Lin 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
1815fe488ffSJon Lin 				     hyf1gq4udacae_ecc_get_status)),
18281afcfe1SJon Lin 	SPINAND_INFO("HYF2GQ4UHCCAE",
183ac39ced8SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x5A),
1845fe488ffSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
1855fe488ffSJon Lin 		     NAND_ECCREQ(14, 512),
1865fe488ffSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1875fe488ffSJon Lin 					      &write_cache_variants,
1885fe488ffSJon Lin 					      &update_cache_variants),
1895fe488ffSJon Lin 		     SPINAND_HAS_QE_BIT,
1905fe488ffSJon Lin 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
1915fe488ffSJon Lin 				     hyf1gq4udacae_ecc_get_status)),
19281afcfe1SJon Lin 	SPINAND_INFO("HYF4GQ4UAACBE",
193ac39ced8SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xD4),
194a792c7e0SJon Lin 		     NAND_MEMORG(1, 4096, 128, 64, 2048, 1, 1, 1),
195a792c7e0SJon Lin 		     NAND_ECCREQ(4, 512),
196a792c7e0SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
197a792c7e0SJon Lin 					      &write_cache_variants,
198a792c7e0SJon Lin 					      &update_cache_variants),
199a792c7e0SJon Lin 		     SPINAND_HAS_QE_BIT,
200a792c7e0SJon Lin 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
201a792c7e0SJon Lin 				     hyf1gq4udacae_ecc_get_status)),
202*2108666dSJon Lin 	SPINAND_INFO("HYF2GQ4IAACAE",
203*2108666dSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x82),
204*2108666dSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
205*2108666dSJon Lin 		     NAND_ECCREQ(14, 512),
206*2108666dSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
207*2108666dSJon Lin 					      &write_cache_variants,
208*2108666dSJon Lin 					      &update_cache_variants),
209*2108666dSJon Lin 		     SPINAND_HAS_QE_BIT,
210*2108666dSJon Lin 		     SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
211*2108666dSJon Lin 				     hyf1gq4udacae_ecc_get_status)),
212*2108666dSJon Lin 	SPINAND_INFO("HYF1GQ4IDACAE",
213*2108666dSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x81),
214*2108666dSJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
215*2108666dSJon Lin 		     NAND_ECCREQ(4, 512),
216*2108666dSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
217*2108666dSJon Lin 					      &write_cache_variants,
218*2108666dSJon Lin 					      &update_cache_variants),
219*2108666dSJon Lin 		     SPINAND_HAS_QE_BIT,
220*2108666dSJon Lin 		     SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
221*2108666dSJon Lin 				     hyf1gq4udacae_ecc_get_status)),
222b66d41c2SJon Lin };
223b66d41c2SJon Lin 
224b66d41c2SJon Lin static const struct spinand_manufacturer_ops hyf_spinand_manuf_ops = {
225b66d41c2SJon Lin };
226b66d41c2SJon Lin 
227b66d41c2SJon Lin const struct spinand_manufacturer hyf_spinand_manufacturer = {
228b66d41c2SJon Lin 	.id = SPINAND_MFR_HYF,
229b66d41c2SJon Lin 	.name = "hyf",
23081afcfe1SJon Lin 	.chips = hyf_spinand_table,
23181afcfe1SJon Lin 	.nchips = ARRAY_SIZE(hyf_spinand_table),
232b66d41c2SJon Lin 	.ops = &hyf_spinand_manuf_ops,
233b66d41c2SJon Lin };
234