[U-Boot] [PATCH v2 1/3] mtd: atmel_nand: runtime to build gf table for pmecc
Andreas Bießmann
andreas.devel at googlemail.com
Wed Oct 29 04:06:03 CET 2014
Hi Bo,
On 29.10.14 03:32, Bo Shen wrote:
> From: Josh Wu <josh.wu at atmel.com>
>
> As in SAMA5D4 SoC, the gf table in ROM code can not be seen.
> So, when we try to use PMECC, we need to build it when do
> initialization.
> Add a macro NO_GALOIS_TABLE_IN_ROM in soc header file. If it
> is defined we will build gf table runtime.
>
> The PMECC use the BCH algorithm, so based on the build_gf_tables()
> function in lib/bch.c, we can build the Galois Field lookup table.
>
> Signed-off-by: Josh Wu <josh.wu at atmel.com>
> Signed-off-by: Bo Shen <voice.shen at atmel.com>
> ---
> Changes in v2:
> - rewrite the gf table build function by Josh.
>
> drivers/mtd/nand/atmel_nand.c | 75 ++++++++++++++++++++++++++++++++++++++-
> drivers/mtd/nand/atmel_nand_ecc.h | 4 +++
> 2 files changed, 78 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index 9114a86..20fcecb 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -762,6 +762,62 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
> }
> #endif
>
> +#if defined(NO_GALOIS_TABLE_IN_ROM)
> +static uint16_t *pmecc_galois_table;
> +static inline int deg(unsigned int poly)
> +{
> + /* polynomial degree is the most-significant bit index */
> + return fls(poly) - 1;
> +}
> +
> +static int build_gf_tables(int mm, unsigned int poly,
> + int16_t *index_of, int16_t *alpha_to)
> +{
> + unsigned int i, x = 1;
> + const unsigned int k = 1 << deg(poly);
> + unsigned int nn = (1 << mm) - 1;
> +
> + /* primitive polynomial must be of degree m */
> + if (k != (1u << mm))
> + return -EINVAL;
> +
> + for (i = 0; i < nn; i++) {
> + alpha_to[i] = x;
> + index_of[x] = i;
> + if (i && (x == 1))
> + /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
> + return -EINVAL;
> + x <<= 1;
> + if (x & k)
> + x ^= poly;
> + }
> +
> + alpha_to[nn] = 1;
> + index_of[0] = 0;
> +
> + return 0;
> +}
> +
> +static uint16_t *create_lookup_table(int sector_size)
> +{
> + int degree = (sector_size == 512) ?
> + PMECC_GF_DIMENSION_13 :
> + PMECC_GF_DIMENSION_14;
> + unsigned int poly = (sector_size == 512) ?
> + PMECC_GF_13_PRIMITIVE_POLY :
> + PMECC_GF_14_PRIMITIVE_POLY;
> + int table_size = (sector_size == 512) ?
> + PMECC_INDEX_TABLE_SIZE_512 :
> + PMECC_INDEX_TABLE_SIZE_1024;
> +
> + int16_t *addr = kzalloc(2 * table_size * sizeof(uint16_t), GFP_KERNEL);
> + if (addr && build_gf_tables(degree, poly, addr, addr + table_size))
> + return NULL;
> +
> + return (uint16_t *)addr;
> +}
> +#endif
> +
> static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
> struct mtd_info *mtd)
> {
> @@ -809,11 +865,18 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
> sector_size = host->pmecc_sector_size;
>
> /* TODO: need check whether cap & sector_size is validate */
> -
> +#if defined(NO_GALOIS_TABLE_IN_ROM)
> + /*
> + * As pmecc_rom_base is the begin of the gallois field table, So the
> + * index offset just set as 0.
> + */
> + host->pmecc_index_table_offset = 0;
> +#else
> if (host->pmecc_sector_size == 512)
> host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512;
> else
> host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_1024;
> +#endif
>
> MTDDEBUG(MTD_DEBUG_LEVEL1,
> "Initialize PMECC params, cap: %d, sector: %d\n",
> @@ -822,7 +885,17 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
> host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC;
> host->pmerrloc = (struct pmecc_errloc_regs __iomem *)
> ATMEL_BASE_PMERRLOC;
> +#if defined(NO_GALOIS_TABLE_IN_ROM)
> + pmecc_galois_table = create_lookup_table(host->pmecc_sector_size);
> + if (!pmecc_galois_table) {
> + dev_err(host->dev, "out of memory\n");
> + return -ENOMEM;
> + }
> +
> + host->pmecc_rom_base = (void __iomem *)pmecc_galois_table;
> +#else
> host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM;
> +#endif
>
> /* ECC is calculated for the whole page (1 step) */
> nand->ecc.size = mtd->writesize;
> diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
> index 92d4ec5..eac860d 100644
> --- a/drivers/mtd/nand/atmel_nand_ecc.h
> +++ b/drivers/mtd/nand/atmel_nand_ecc.h
> @@ -141,6 +141,10 @@ struct pmecc_errloc_regs {
> #define PMECC_GF_DIMENSION_13 13
> #define PMECC_GF_DIMENSION_14 14
>
> +/* Primitive Polynomial used by PMECC */
> +#define PMECC_GF_13_PRIMITIVE_POLY 0x201b
> +#define PMECC_GF_14_PRIMITIVE_POLY 0x4443
> +
> #define PMECC_INDEX_TABLE_SIZE_512 0x2000
> #define PMECC_INDEX_TABLE_SIZE_1024 0x4000
>
>
looks way better! I'll apply this these days.
Best regards
Andreas Bießmann
More information about the U-Boot
mailing list