xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/esmt.c (revision 2c3c84fc7fd0ab439baf1e634c8b5504daa40db4)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Grandstream Networks, Inc
4  *
5  * Authors:
6  *	Carl <xjxia@grandstream.cn>
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_ESMT		0xC8
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 f50lxx41x_ooblayout_ecc(struct mtd_info *mtd, int section,
34 				   struct mtd_oob_region *region)
35 {
36 	if (section > 3)
37 		return -ERANGE;
38 
39 	region->offset = (16 * section) + 8;
40 	region->length = 8;
41 
42 	return 0;
43 }
44 
45 static int f50lxx41x_ooblayout_free(struct mtd_info *mtd, int section,
46 				    struct mtd_oob_region *region)
47 {
48 	if (section > 3)
49 		return -ERANGE;
50 
51 	region->offset = (16 * section) + 2;
52 	region->length = 6;
53 
54 	return 0;
55 }
56 
57 static const struct mtd_ooblayout_ops f50lxx41x_ooblayout = {
58 	.ecc = f50lxx41x_ooblayout_ecc,
59 	.rfree = f50lxx41x_ooblayout_free,
60 };
61 
62 static int f50l2g41ka_ooblayout_ecc(struct mtd_info *mtd, int section,
63 				    struct mtd_oob_region *region)
64 {
65 	if (section)
66 		return -ERANGE;
67 
68 	region->offset = mtd->oobsize / 2;
69 	region->length = mtd->oobsize / 2;
70 
71 	return 0;
72 }
73 
74 static int f50l2g41ka_ooblayout_free(struct mtd_info *mtd, int section,
75 				     struct mtd_oob_region *region)
76 {
77 	if (section)
78 		return -ERANGE;
79 
80 	region->offset = 2;
81 	region->length = mtd->oobsize / 2 - 2;
82 
83 	return 0;
84 }
85 
86 static const struct mtd_ooblayout_ops f50l2g41ka_ooblayout = {
87 	.ecc = f50l2g41ka_ooblayout_ecc,
88 	.rfree = f50l2g41ka_ooblayout_free,
89 };
90 
91 /*
92  * ecc bits: 0xC0[4,6]
93  * [0b000], No bit errors were detected;
94  * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not
95  *	reach Flipping Bits;
96  * [0b101], Bit error count equals the bit flip
97  *	detection threshold
98  * [0b010], Multiple bit errors were detected and
99  *	not corrected.
100  * others, Reserved.
101  */
102 static int f50l2g41ka_ecc_ecc_get_status(struct spinand_device *spinand,
103 					 u8 status)
104 {
105 	struct nand_device *nand = spinand_to_nand(spinand);
106 	u8 eccsr = (status & GENMASK(6, 4)) >> 4;
107 
108 	if (eccsr <= 1 || eccsr == 3)
109 		return eccsr;
110 	else if (eccsr == 5)
111 		return nand->eccreq.strength;
112 	else
113 		return -EBADMSG;
114 }
115 
116 static const struct spinand_info esmt_spinand_table[] = {
117 	SPINAND_INFO("F50L1G41LB",
118 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x01),
119 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
120 		     NAND_ECCREQ(1, 512),
121 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
122 					      &write_cache_variants,
123 					      &update_cache_variants),
124 		     0,
125 		     SPINAND_ECCINFO(&f50lxx41x_ooblayout, NULL)),
126 	SPINAND_INFO("F50L2G41KA",
127 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41, 0x7F),
128 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
129 		     NAND_ECCREQ(8, 512),
130 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
131 					      &write_cache_variants,
132 					      &update_cache_variants),
133 		     0,
134 		     SPINAND_ECCINFO(&f50l2g41ka_ooblayout, f50l2g41ka_ecc_ecc_get_status)),
135 };
136 
137 static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
138 };
139 
140 const struct spinand_manufacturer esmt_spinand_manufacturer = {
141 	.id = SPINAND_MFR_ESMT,
142 	.name = "esmt",
143 	.chips = esmt_spinand_table,
144 	.nchips = ARRAY_SIZE(esmt_spinand_table),
145 	.ops = &esmt_spinand_manuf_ops,
146 };
147