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