* 'master' of git://git.denx.de/u-boot-nand-flash: nand/fsl_elbc: Convert to self-init nand: Introduce CONFIG_SYS_NAND_SELF_INIT nand_spl: store ecc data on the stack mtd/nand: Add ONFI support for FSL NAND controller nand: make 1-bit software ECC configurable nand: Sanitize ONFI strings. nand: Merge changes to BBT from Linux nand driver nand: Merge changes from Linux nand driver nand: cleanup whitespace nand: Add more NAND types from Linux nand driver nand: Merge BCH code from Linux nand driver NAND: Remove additional (CONFIG_SYS)_NAND_MAX_CHIPS NAND: remove NAND_MAX_CHIPS definitions nand_spl_simple: store ecc data on the stackmaster
commit
0990dc6178
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,236 @@ |
||||
/*
|
||||
* This file provides ECC correction for more than 1 bit per block of data, |
||||
* using binary BCH codes. It relies on the generic BCH library lib/bch.c. |
||||
* |
||||
* Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> |
||||
* |
||||
* This file is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU General Public License as published by the |
||||
* Free Software Foundation; either version 2 or (at your option) any |
||||
* later version. |
||||
* |
||||
* This file is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
||||
* for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along |
||||
* with this file; if not, write to the Free Software Foundation, Inc., |
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
/*#include <asm/io.h>*/ |
||||
#include <linux/types.h> |
||||
|
||||
#include <linux/bitops.h> |
||||
#include <linux/mtd/mtd.h> |
||||
#include <linux/mtd/nand.h> |
||||
#include <linux/mtd/nand_bch.h> |
||||
#include <linux/bch.h> |
||||
#include <malloc.h> |
||||
|
||||
/**
|
||||
* struct nand_bch_control - private NAND BCH control structure |
||||
* @bch: BCH control structure |
||||
* @ecclayout: private ecc layout for this BCH configuration |
||||
* @errloc: error location array |
||||
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid |
||||
*/ |
||||
struct nand_bch_control { |
||||
struct bch_control *bch; |
||||
struct nand_ecclayout ecclayout; |
||||
unsigned int *errloc; |
||||
unsigned char *eccmask; |
||||
}; |
||||
|
||||
/**
|
||||
* nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block |
||||
* @mtd: MTD block structure |
||||
* @buf: input buffer with raw data |
||||
* @code: output buffer with ECC |
||||
*/ |
||||
int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, |
||||
unsigned char *code) |
||||
{ |
||||
const struct nand_chip *chip = mtd->priv; |
||||
struct nand_bch_control *nbc = chip->ecc.priv; |
||||
unsigned int i; |
||||
|
||||
memset(code, 0, chip->ecc.bytes); |
||||
encode_bch(nbc->bch, buf, chip->ecc.size, code); |
||||
|
||||
/* apply mask so that an erased page is a valid codeword */ |
||||
for (i = 0; i < chip->ecc.bytes; i++) |
||||
code[i] ^= nbc->eccmask[i]; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) |
||||
* @mtd: MTD block structure |
||||
* @buf: raw data read from the chip |
||||
* @read_ecc: ECC from the chip |
||||
* @calc_ecc: the ECC calculated from raw data |
||||
* |
||||
* Detect and correct bit errors for a data byte block |
||||
*/ |
||||
int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, |
||||
unsigned char *read_ecc, unsigned char *calc_ecc) |
||||
{ |
||||
const struct nand_chip *chip = mtd->priv; |
||||
struct nand_bch_control *nbc = chip->ecc.priv; |
||||
unsigned int *errloc = nbc->errloc; |
||||
int i, count; |
||||
|
||||
count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, |
||||
NULL, errloc); |
||||
if (count > 0) { |
||||
for (i = 0; i < count; i++) { |
||||
if (errloc[i] < (chip->ecc.size*8)) |
||||
/* error is located in data, correct it */ |
||||
buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); |
||||
/* else error in ecc, no action needed */ |
||||
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", |
||||
__func__, errloc[i]); |
||||
} |
||||
} else if (count < 0) { |
||||
printk(KERN_ERR "ecc unrecoverable error\n"); |
||||
count = -1; |
||||
} |
||||
return count; |
||||
} |
||||
|
||||
/**
|
||||
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction |
||||
* @mtd: MTD block structure |
||||
* @eccsize: ecc block size in bytes |
||||
* @eccbytes: ecc length in bytes |
||||
* @ecclayout: output default layout |
||||
* |
||||
* Returns: |
||||
* a pointer to a new NAND BCH control structure, or NULL upon failure |
||||
* |
||||
* Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes |
||||
* are used to compute BCH parameters m (Galois field order) and t (error |
||||
* correction capability). @eccbytes should be equal to the number of bytes |
||||
* required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. |
||||
* |
||||
* Example: to configure 4 bit correction per 512 bytes, you should pass |
||||
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) |
||||
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) |
||||
*/ |
||||
struct nand_bch_control * |
||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, |
||||
struct nand_ecclayout **ecclayout) |
||||
{ |
||||
unsigned int m, t, eccsteps, i; |
||||
struct nand_ecclayout *layout; |
||||
struct nand_bch_control *nbc = NULL; |
||||
unsigned char *erased_page; |
||||
|
||||
if (!eccsize || !eccbytes) { |
||||
printk(KERN_WARNING "ecc parameters not supplied\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
m = fls(1+8*eccsize); |
||||
t = (eccbytes*8)/m; |
||||
|
||||
nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); |
||||
if (!nbc) |
||||
goto fail; |
||||
|
||||
nbc->bch = init_bch(m, t, 0); |
||||
if (!nbc->bch) |
||||
goto fail; |
||||
|
||||
/* verify that eccbytes has the expected value */ |
||||
if (nbc->bch->ecc_bytes != eccbytes) { |
||||
printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", |
||||
eccbytes, nbc->bch->ecc_bytes); |
||||
goto fail; |
||||
} |
||||
|
||||
eccsteps = mtd->writesize/eccsize; |
||||
|
||||
/* if no ecc placement scheme was provided, build one */ |
||||
if (!*ecclayout) { |
||||
|
||||
/* handle large page devices only */ |
||||
if (mtd->oobsize < 64) { |
||||
printk(KERN_WARNING "must provide an oob scheme for " |
||||
"oobsize %d\n", mtd->oobsize); |
||||
goto fail; |
||||
} |
||||
|
||||
layout = &nbc->ecclayout; |
||||
layout->eccbytes = eccsteps*eccbytes; |
||||
|
||||
/* reserve 2 bytes for bad block marker */ |
||||
if (layout->eccbytes+2 > mtd->oobsize) { |
||||
printk(KERN_WARNING "no suitable oob scheme available " |
||||
"for oobsize %d eccbytes %u\n", mtd->oobsize, |
||||
eccbytes); |
||||
goto fail; |
||||
} |
||||
/* put ecc bytes at oob tail */ |
||||
for (i = 0; i < layout->eccbytes; i++) |
||||
layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; |
||||
|
||||
layout->oobfree[0].offset = 2; |
||||
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; |
||||
|
||||
*ecclayout = layout; |
||||
} |
||||
|
||||
/* sanity checks */ |
||||
if (8*(eccsize+eccbytes) >= (1 << m)) { |
||||
printk(KERN_WARNING "eccsize %u is too large\n", eccsize); |
||||
goto fail; |
||||
} |
||||
if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) { |
||||
printk(KERN_WARNING "invalid ecc layout\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); |
||||
nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); |
||||
if (!nbc->eccmask || !nbc->errloc) |
||||
goto fail; |
||||
/*
|
||||
* compute and store the inverted ecc of an erased ecc block |
||||
*/ |
||||
erased_page = kmalloc(eccsize, GFP_KERNEL); |
||||
if (!erased_page) |
||||
goto fail; |
||||
|
||||
memset(erased_page, 0xff, eccsize); |
||||
memset(nbc->eccmask, 0, eccbytes); |
||||
encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); |
||||
kfree(erased_page); |
||||
|
||||
for (i = 0; i < eccbytes; i++) |
||||
nbc->eccmask[i] ^= 0xff; |
||||
|
||||
return nbc; |
||||
fail: |
||||
nand_bch_free(nbc); |
||||
return NULL; |
||||
} |
||||
|
||||
/**
|
||||
* nand_bch_free - [NAND Interface] Release NAND BCH ECC resources |
||||
* @nbc: NAND BCH control structure |
||||
*/ |
||||
void nand_bch_free(struct nand_bch_control *nbc) |
||||
{ |
||||
if (nbc) { |
||||
free_bch(nbc->bch); |
||||
kfree(nbc->errloc); |
||||
kfree(nbc->eccmask); |
||||
kfree(nbc); |
||||
} |
||||
} |
@ -0,0 +1,79 @@ |
||||
/*
|
||||
* Generic binary BCH encoding/decoding library |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU General Public License version 2 as published by |
||||
* the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
||||
* more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along with |
||||
* this program; if not, write to the Free Software Foundation, Inc., 51 |
||||
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
* |
||||
* Copyright © 2011 Parrot S.A. |
||||
* |
||||
* Author: Ivan Djelic <ivan.djelic@parrot.com> |
||||
* |
||||
* Description: |
||||
* |
||||
* This library provides runtime configurable encoding/decoding of binary |
||||
* Bose-Chaudhuri-Hocquenghem (BCH) codes. |
||||
*/ |
||||
#ifndef _BCH_H |
||||
#define _BCH_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
/**
|
||||
* struct bch_control - BCH control structure |
||||
* @m: Galois field order |
||||
* @n: maximum codeword size in bits (= 2^m-1) |
||||
* @t: error correction capability in bits |
||||
* @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t) |
||||
* @ecc_bytes: ecc max size (m*t bits) in bytes |
||||
* @a_pow_tab: Galois field GF(2^m) exponentiation lookup table |
||||
* @a_log_tab: Galois field GF(2^m) log lookup table |
||||
* @mod8_tab: remainder generator polynomial lookup tables |
||||
* @ecc_buf: ecc parity words buffer |
||||
* @ecc_buf2: ecc parity words buffer |
||||
* @xi_tab: GF(2^m) base for solving degree 2 polynomial roots |
||||
* @syn: syndrome buffer |
||||
* @cache: log-based polynomial representation buffer |
||||
* @elp: error locator polynomial |
||||
* @poly_2t: temporary polynomials of degree 2t |
||||
*/ |
||||
struct bch_control { |
||||
unsigned int m; |
||||
unsigned int n; |
||||
unsigned int t; |
||||
unsigned int ecc_bits; |
||||
unsigned int ecc_bytes; |
||||
/* private: */ |
||||
uint16_t *a_pow_tab; |
||||
uint16_t *a_log_tab; |
||||
uint32_t *mod8_tab; |
||||
uint32_t *ecc_buf; |
||||
uint32_t *ecc_buf2; |
||||
unsigned int *xi_tab; |
||||
unsigned int *syn; |
||||
int *cache; |
||||
struct gf_poly *elp; |
||||
struct gf_poly *poly_2t[4]; |
||||
}; |
||||
|
||||
struct bch_control *init_bch(int m, int t, unsigned int prim_poly); |
||||
|
||||
void free_bch(struct bch_control *bch); |
||||
|
||||
void encode_bch(struct bch_control *bch, const uint8_t *data, |
||||
unsigned int len, uint8_t *ecc); |
||||
|
||||
int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, |
||||
const uint8_t *recv_ecc, const uint8_t *calc_ecc, |
||||
const unsigned int *syn, unsigned int *errloc); |
||||
|
||||
#endif /* _BCH_H */ |
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* This file is the header for the NAND BCH ECC implementation. |
||||
*/ |
||||
|
||||
#ifndef __MTD_NAND_BCH_H__ |
||||
#define __MTD_NAND_BCH_H__ |
||||
|
||||
struct mtd_info; |
||||
struct nand_bch_control; |
||||
|
||||
#if defined(CONFIG_NAND_ECC_BCH) |
||||
|
||||
static inline int mtd_nand_has_bch(void) { return 1; } |
||||
|
||||
/*
|
||||
* Calculate BCH ecc code |
||||
*/ |
||||
int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat, |
||||
u_char *ecc_code); |
||||
|
||||
/*
|
||||
* Detect and correct bit errors |
||||
*/ |
||||
int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, |
||||
u_char *calc_ecc); |
||||
/*
|
||||
* Initialize BCH encoder/decoder |
||||
*/ |
||||
struct nand_bch_control * |
||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, |
||||
unsigned int eccbytes, struct nand_ecclayout **ecclayout); |
||||
/*
|
||||
* Release BCH encoder/decoder resources |
||||
*/ |
||||
void nand_bch_free(struct nand_bch_control *nbc); |
||||
|
||||
#else /* !CONFIG_NAND_ECC_BCH */ |
||||
|
||||
static inline int mtd_nand_has_bch(void) { return 0; } |
||||
|
||||
static inline int |
||||
nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat, |
||||
u_char *ecc_code) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
static inline int |
||||
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, |
||||
unsigned char *read_ecc, unsigned char *calc_ecc) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
static inline struct nand_bch_control * |
||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, |
||||
unsigned int eccbytes, struct nand_ecclayout **ecclayout) |
||||
{ |
||||
return NULL; |
||||
} |
||||
|
||||
static inline void nand_bch_free(struct nand_bch_control *nbc) {} |
||||
|
||||
#endif /* CONFIG_NAND_ECC_BCH */ |
||||
|
||||
#endif /* __MTD_NAND_BCH_H__ */ |
Loading…
Reference in new issue