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