1ed13557fSPeter Pan // SPDX-License-Identifier: GPL-2.0
2ed13557fSPeter Pan /*
3ed13557fSPeter Pan * Copyright (c) 2016-2017 Micron Technology, Inc.
4ed13557fSPeter Pan *
5ed13557fSPeter Pan * Authors:
6ed13557fSPeter Pan * Peter Pan <peterpandong@micron.com>
7ed13557fSPeter Pan */
8ed13557fSPeter Pan
9ed13557fSPeter Pan #ifndef __UBOOT__
10ed13557fSPeter Pan #include <linux/device.h>
11ed13557fSPeter Pan #include <linux/kernel.h>
12ed13557fSPeter Pan #endif
13ed13557fSPeter Pan #include <linux/mtd/spinand.h>
14ed13557fSPeter Pan
15ed13557fSPeter Pan #define SPINAND_MFR_MICRON 0x2c
16ed13557fSPeter Pan
17ed13557fSPeter Pan #define MICRON_STATUS_ECC_MASK GENMASK(7, 4)
18ed13557fSPeter Pan #define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
19ed13557fSPeter Pan #define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
20ed13557fSPeter Pan #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
21ed13557fSPeter Pan #define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
22ed13557fSPeter Pan
23ed13557fSPeter Pan static SPINAND_OP_VARIANTS(read_cache_variants,
24ed13557fSPeter Pan SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
25ed13557fSPeter Pan SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
26ed13557fSPeter Pan SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
27ed13557fSPeter Pan SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
28ed13557fSPeter Pan SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
29ed13557fSPeter Pan SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
30ed13557fSPeter Pan
31ed13557fSPeter Pan static SPINAND_OP_VARIANTS(write_cache_variants,
32ed13557fSPeter Pan SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
33ed13557fSPeter Pan SPINAND_PROG_LOAD(true, 0, NULL, 0));
34ed13557fSPeter Pan
35ed13557fSPeter Pan static SPINAND_OP_VARIANTS(update_cache_variants,
36ed13557fSPeter Pan SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
37ed13557fSPeter Pan SPINAND_PROG_LOAD(false, 0, NULL, 0));
38ed13557fSPeter Pan
mt29f2g01abagd_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)39ed13557fSPeter Pan static int mt29f2g01abagd_ooblayout_ecc(struct mtd_info *mtd, int section,
40ed13557fSPeter Pan struct mtd_oob_region *region)
41ed13557fSPeter Pan {
42ed13557fSPeter Pan if (section)
43ed13557fSPeter Pan return -ERANGE;
44ed13557fSPeter Pan
45ed13557fSPeter Pan region->offset = 64;
46ed13557fSPeter Pan region->length = 64;
47ed13557fSPeter Pan
48ed13557fSPeter Pan return 0;
49ed13557fSPeter Pan }
50ed13557fSPeter Pan
mt29f2g01abagd_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)51ed13557fSPeter Pan static int mt29f2g01abagd_ooblayout_free(struct mtd_info *mtd, int section,
52ed13557fSPeter Pan struct mtd_oob_region *region)
53ed13557fSPeter Pan {
54ed13557fSPeter Pan if (section)
55ed13557fSPeter Pan return -ERANGE;
56ed13557fSPeter Pan
57ed13557fSPeter Pan /* Reserve 2 bytes for the BBM. */
58ed13557fSPeter Pan region->offset = 2;
59ed13557fSPeter Pan region->length = 62;
60ed13557fSPeter Pan
61ed13557fSPeter Pan return 0;
62ed13557fSPeter Pan }
63ed13557fSPeter Pan
64ed13557fSPeter Pan static const struct mtd_ooblayout_ops mt29f2g01abagd_ooblayout = {
65ed13557fSPeter Pan .ecc = mt29f2g01abagd_ooblayout_ecc,
66301f8dd1SSimon Glass .rfree = mt29f2g01abagd_ooblayout_free,
67ed13557fSPeter Pan };
68ed13557fSPeter Pan
mt29f2g01abagd_ecc_get_status(struct spinand_device * spinand,u8 status)69ed13557fSPeter Pan static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
70ed13557fSPeter Pan u8 status)
71ed13557fSPeter Pan {
72ed13557fSPeter Pan switch (status & MICRON_STATUS_ECC_MASK) {
73ed13557fSPeter Pan case STATUS_ECC_NO_BITFLIPS:
74ed13557fSPeter Pan return 0;
75ed13557fSPeter Pan
76ed13557fSPeter Pan case STATUS_ECC_UNCOR_ERROR:
77ed13557fSPeter Pan return -EBADMSG;
78ed13557fSPeter Pan
79ed13557fSPeter Pan case MICRON_STATUS_ECC_1TO3_BITFLIPS:
80ed13557fSPeter Pan return 3;
81ed13557fSPeter Pan
82ed13557fSPeter Pan case MICRON_STATUS_ECC_4TO6_BITFLIPS:
83ed13557fSPeter Pan return 6;
84ed13557fSPeter Pan
85ed13557fSPeter Pan case MICRON_STATUS_ECC_7TO8_BITFLIPS:
86ed13557fSPeter Pan return 8;
87ed13557fSPeter Pan
88ed13557fSPeter Pan default:
89ed13557fSPeter Pan break;
90ed13557fSPeter Pan }
91ed13557fSPeter Pan
92ed13557fSPeter Pan return -EINVAL;
93ed13557fSPeter Pan }
94ed13557fSPeter Pan
mt29f4g01abafd_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)95*0a9399fcSJon Lin static int mt29f4g01abafd_ooblayout_ecc(struct mtd_info *mtd, int section,
96*0a9399fcSJon Lin struct mtd_oob_region *region)
97*0a9399fcSJon Lin {
98*0a9399fcSJon Lin if (section)
99*0a9399fcSJon Lin return -ERANGE;
100*0a9399fcSJon Lin
101*0a9399fcSJon Lin region->offset = mtd->oobsize / 2;
102*0a9399fcSJon Lin region->length = mtd->oobsize / 2;
103*0a9399fcSJon Lin
104*0a9399fcSJon Lin return 0;
105*0a9399fcSJon Lin }
106*0a9399fcSJon Lin
mt29f4g01abafd_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)107*0a9399fcSJon Lin static int mt29f4g01abafd_ooblayout_free(struct mtd_info *mtd, int section,
108*0a9399fcSJon Lin struct mtd_oob_region *region)
109*0a9399fcSJon Lin {
110*0a9399fcSJon Lin if (section)
111*0a9399fcSJon Lin return -ERANGE;
112*0a9399fcSJon Lin
113*0a9399fcSJon Lin region->offset = 2;
114*0a9399fcSJon Lin region->length = mtd->oobsize / 2 - 2;
115*0a9399fcSJon Lin
116*0a9399fcSJon Lin return 0;
117*0a9399fcSJon Lin }
118*0a9399fcSJon Lin
119*0a9399fcSJon Lin static const struct mtd_ooblayout_ops mt29f4g01abafd_ooblayout = {
120*0a9399fcSJon Lin .ecc = mt29f4g01abafd_ooblayout_ecc,
121*0a9399fcSJon Lin .rfree = mt29f4g01abafd_ooblayout_free,
122*0a9399fcSJon Lin };
123*0a9399fcSJon Lin
124*0a9399fcSJon Lin /*
125*0a9399fcSJon Lin * ecc bits: 0xC0[4,6]
126*0a9399fcSJon Lin * [0b000], No bit errors were detected;
127*0a9399fcSJon Lin * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not
128*0a9399fcSJon Lin * reach Flipping Bits;
129*0a9399fcSJon Lin * [0b101], Bit error count equals the bit flip
130*0a9399fcSJon Lin * detection threshold
131*0a9399fcSJon Lin * [0b010], Multiple bit errors were detected and
132*0a9399fcSJon Lin * not corrected.
133*0a9399fcSJon Lin * others, Reserved.
134*0a9399fcSJon Lin */
mt29f4g01abafd_ecc_ecc_get_status(struct spinand_device * spinand,u8 status)135*0a9399fcSJon Lin static int mt29f4g01abafd_ecc_ecc_get_status(struct spinand_device *spinand,
136*0a9399fcSJon Lin u8 status)
137*0a9399fcSJon Lin {
138*0a9399fcSJon Lin struct nand_device *nand = spinand_to_nand(spinand);
139*0a9399fcSJon Lin u8 eccsr = (status & GENMASK(6, 4)) >> 4;
140*0a9399fcSJon Lin
141*0a9399fcSJon Lin if (eccsr <= 1 || eccsr == 3)
142*0a9399fcSJon Lin return eccsr;
143*0a9399fcSJon Lin else if (eccsr == 5)
144*0a9399fcSJon Lin return nand->eccreq.strength;
145*0a9399fcSJon Lin else
146*0a9399fcSJon Lin return -EBADMSG;
147*0a9399fcSJon Lin }
148*0a9399fcSJon Lin
149ed13557fSPeter Pan static const struct spinand_info micron_spinand_table[] = {
15081afcfe1SJon Lin SPINAND_INFO("MT29F2G01ABAGD",
15181afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
152ed13557fSPeter Pan NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
153ed13557fSPeter Pan NAND_ECCREQ(8, 512),
154ed13557fSPeter Pan SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
155ed13557fSPeter Pan &write_cache_variants,
156ed13557fSPeter Pan &update_cache_variants),
157ed13557fSPeter Pan 0,
158ed13557fSPeter Pan SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout,
159ed13557fSPeter Pan mt29f2g01abagd_ecc_get_status)),
16081afcfe1SJon Lin SPINAND_INFO("MT29F1G01ABAGD",
16181afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
162b9d47743SJon Lin NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
163b9d47743SJon Lin NAND_ECCREQ(8, 512),
164b9d47743SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
165b9d47743SJon Lin &write_cache_variants,
166b9d47743SJon Lin &update_cache_variants),
167b9d47743SJon Lin 0,
168b9d47743SJon Lin SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout,
169b9d47743SJon Lin mt29f2g01abagd_ecc_get_status)),
170*0a9399fcSJon Lin SPINAND_INFO("MT29F4G01ABAFD",
171*0a9399fcSJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
172*0a9399fcSJon Lin NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
173*0a9399fcSJon Lin NAND_ECCREQ(8, 512),
174*0a9399fcSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
175*0a9399fcSJon Lin &write_cache_variants,
176*0a9399fcSJon Lin &update_cache_variants),
177*0a9399fcSJon Lin 0,
178*0a9399fcSJon Lin SPINAND_ECCINFO(&mt29f4g01abafd_ooblayout, mt29f4g01abafd_ecc_ecc_get_status)),
179ed13557fSPeter Pan };
180ed13557fSPeter Pan
181ed13557fSPeter Pan static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
182ed13557fSPeter Pan };
183ed13557fSPeter Pan
184ed13557fSPeter Pan const struct spinand_manufacturer micron_spinand_manufacturer = {
185ed13557fSPeter Pan .id = SPINAND_MFR_MICRON,
186ed13557fSPeter Pan .name = "Micron",
18781afcfe1SJon Lin .chips = micron_spinand_table,
18881afcfe1SJon Lin .nchips = ARRAY_SIZE(micron_spinand_table),
189ed13557fSPeter Pan .ops = µn_spinand_manuf_ops,
190ed13557fSPeter Pan };
191