blob: bb48ebbb96c76aa415ae05d324e0bded0373842a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Christian Hitz55f7bca2011-10-12 09:31:59 +02002/*
3 * This file provides ECC correction for more than 1 bit per block of data,
4 * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
5 *
6 * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
7 *
Christian Hitz55f7bca2011-10-12 09:31:59 +02008 */
9
Tom Riniabb9a042024-05-18 20:20:43 -060010#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070012#include <dm/devres.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060013#include <linux/printk.h>
Christian Hitz55f7bca2011-10-12 09:31:59 +020014/*#include <asm/io.h>*/
15#include <linux/types.h>
16
17#include <linux/bitops.h>
18#include <linux/mtd/mtd.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090019#include <linux/mtd/rawnand.h>
Christian Hitz55f7bca2011-10-12 09:31:59 +020020#include <linux/mtd/nand_bch.h>
21#include <linux/bch.h>
22#include <malloc.h>
23
24/**
25 * struct nand_bch_control - private NAND BCH control structure
26 * @bch: BCH control structure
27 * @ecclayout: private ecc layout for this BCH configuration
28 * @errloc: error location array
29 * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
30 */
31struct nand_bch_control {
32 struct bch_control *bch;
33 struct nand_ecclayout ecclayout;
34 unsigned int *errloc;
35 unsigned char *eccmask;
36};
37
38/**
39 * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
40 * @mtd: MTD block structure
41 * @buf: input buffer with raw data
42 * @code: output buffer with ECC
43 */
44int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
45 unsigned char *code)
46{
Scott Wood17fed142016-05-30 13:57:56 -050047 const struct nand_chip *chip = mtd_to_nand(mtd);
Christian Hitz55f7bca2011-10-12 09:31:59 +020048 struct nand_bch_control *nbc = chip->ecc.priv;
49 unsigned int i;
50
51 memset(code, 0, chip->ecc.bytes);
52 encode_bch(nbc->bch, buf, chip->ecc.size, code);
53
54 /* apply mask so that an erased page is a valid codeword */
55 for (i = 0; i < chip->ecc.bytes; i++)
56 code[i] ^= nbc->eccmask[i];
57
58 return 0;
59}
60
61/**
62 * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
63 * @mtd: MTD block structure
64 * @buf: raw data read from the chip
65 * @read_ecc: ECC from the chip
66 * @calc_ecc: the ECC calculated from raw data
67 *
68 * Detect and correct bit errors for a data byte block
69 */
70int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
71 unsigned char *read_ecc, unsigned char *calc_ecc)
72{
Scott Wood17fed142016-05-30 13:57:56 -050073 const struct nand_chip *chip = mtd_to_nand(mtd);
Christian Hitz55f7bca2011-10-12 09:31:59 +020074 struct nand_bch_control *nbc = chip->ecc.priv;
75 unsigned int *errloc = nbc->errloc;
76 int i, count;
77
78 count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
79 NULL, errloc);
80 if (count > 0) {
81 for (i = 0; i < count; i++) {
82 if (errloc[i] < (chip->ecc.size*8))
83 /* error is located in data, correct it */
84 buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
85 /* else error in ecc, no action needed */
86
Masahiro Yamadaf8a5d512017-10-18 00:10:48 +090087 pr_debug("%s: corrected bitflip %u\n",
88 __func__, errloc[i]);
Christian Hitz55f7bca2011-10-12 09:31:59 +020089 }
90 } else if (count < 0) {
91 printk(KERN_ERR "ecc unrecoverable error\n");
Scott Wood52ab7ce2016-05-30 13:57:58 -050092 count = -EBADMSG;
Christian Hitz55f7bca2011-10-12 09:31:59 +020093 }
94 return count;
95}
96
97/**
98 * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
99 * @mtd: MTD block structure
Christian Hitz55f7bca2011-10-12 09:31:59 +0200100 *
101 * Returns:
102 * a pointer to a new NAND BCH control structure, or NULL upon failure
103 *
104 * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
105 * are used to compute BCH parameters m (Galois field order) and t (error
106 * correction capability). @eccbytes should be equal to the number of bytes
107 * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
108 *
109 * Example: to configure 4 bit correction per 512 bytes, you should pass
110 * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
111 * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
112 */
Scott Wood52ab7ce2016-05-30 13:57:58 -0500113struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
Christian Hitz55f7bca2011-10-12 09:31:59 +0200114{
Scott Wood52ab7ce2016-05-30 13:57:58 -0500115 struct nand_chip *nand = mtd_to_nand(mtd);
Christian Hitz55f7bca2011-10-12 09:31:59 +0200116 unsigned int m, t, eccsteps, i;
Scott Wood52ab7ce2016-05-30 13:57:58 -0500117 struct nand_ecclayout *layout = nand->ecc.layout;
Christian Hitz55f7bca2011-10-12 09:31:59 +0200118 struct nand_bch_control *nbc = NULL;
119 unsigned char *erased_page;
Scott Wood52ab7ce2016-05-30 13:57:58 -0500120 unsigned int eccsize = nand->ecc.size;
121 unsigned int eccbytes = nand->ecc.bytes;
122 unsigned int eccstrength = nand->ecc.strength;
123
124 if (!eccbytes && eccstrength) {
125 eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
126 nand->ecc.bytes = eccbytes;
127 }
Christian Hitz55f7bca2011-10-12 09:31:59 +0200128
129 if (!eccsize || !eccbytes) {
130 printk(KERN_WARNING "ecc parameters not supplied\n");
131 goto fail;
132 }
133
134 m = fls(1+8*eccsize);
135 t = (eccbytes*8)/m;
136
137 nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
138 if (!nbc)
139 goto fail;
140
141 nbc->bch = init_bch(m, t, 0);
142 if (!nbc->bch)
143 goto fail;
144
145 /* verify that eccbytes has the expected value */
146 if (nbc->bch->ecc_bytes != eccbytes) {
147 printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
148 eccbytes, nbc->bch->ecc_bytes);
149 goto fail;
150 }
151
152 eccsteps = mtd->writesize/eccsize;
153
154 /* if no ecc placement scheme was provided, build one */
Scott Wood52ab7ce2016-05-30 13:57:58 -0500155 if (!layout) {
Christian Hitz55f7bca2011-10-12 09:31:59 +0200156
157 /* handle large page devices only */
158 if (mtd->oobsize < 64) {
159 printk(KERN_WARNING "must provide an oob scheme for "
160 "oobsize %d\n", mtd->oobsize);
161 goto fail;
162 }
163
164 layout = &nbc->ecclayout;
165 layout->eccbytes = eccsteps*eccbytes;
166
167 /* reserve 2 bytes for bad block marker */
168 if (layout->eccbytes+2 > mtd->oobsize) {
169 printk(KERN_WARNING "no suitable oob scheme available "
170 "for oobsize %d eccbytes %u\n", mtd->oobsize,
171 eccbytes);
172 goto fail;
173 }
174 /* put ecc bytes at oob tail */
175 for (i = 0; i < layout->eccbytes; i++)
176 layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
177
178 layout->oobfree[0].offset = 2;
179 layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
180
Scott Wood52ab7ce2016-05-30 13:57:58 -0500181 nand->ecc.layout = layout;
Christian Hitz55f7bca2011-10-12 09:31:59 +0200182 }
183
184 /* sanity checks */
185 if (8*(eccsize+eccbytes) >= (1 << m)) {
186 printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
187 goto fail;
188 }
Scott Wood52ab7ce2016-05-30 13:57:58 -0500189 if (layout->eccbytes != (eccsteps*eccbytes)) {
Christian Hitz55f7bca2011-10-12 09:31:59 +0200190 printk(KERN_WARNING "invalid ecc layout\n");
191 goto fail;
192 }
193
194 nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
195 nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
196 if (!nbc->eccmask || !nbc->errloc)
197 goto fail;
198 /*
199 * compute and store the inverted ecc of an erased ecc block
200 */
201 erased_page = kmalloc(eccsize, GFP_KERNEL);
202 if (!erased_page)
203 goto fail;
204
205 memset(erased_page, 0xff, eccsize);
206 memset(nbc->eccmask, 0, eccbytes);
207 encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
208 kfree(erased_page);
209
210 for (i = 0; i < eccbytes; i++)
211 nbc->eccmask[i] ^= 0xff;
212
Scott Wood52ab7ce2016-05-30 13:57:58 -0500213 if (!eccstrength)
214 nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
215
Christian Hitz55f7bca2011-10-12 09:31:59 +0200216 return nbc;
217fail:
218 nand_bch_free(nbc);
219 return NULL;
220}
221
222/**
223 * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
224 * @nbc: NAND BCH control structure
225 */
226void nand_bch_free(struct nand_bch_control *nbc)
227{
228 if (nbc) {
229 free_bch(nbc->bch);
230 kfree(nbc->errloc);
231 kfree(nbc->eccmask);
232 kfree(nbc);
233 }
234}