Message ID | 1414549973-23558-2-git-send-email-voice.shen@atmel.com |
---|---|
State | Superseded, archived |
Delegated to: | Andreas Bießmann |
Headers | show |
Hi Bo, On 29.10.14 03:32, Bo Shen wrote: > From: Josh Wu <josh.wu@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@atmel.com> > Signed-off-by: Bo Shen <voice.shen@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
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