[U-Boot] [PATCH] am335x: NAND, add BCH16 and 4k page size support

Jordy van Wolferen jordyvanwolferen at gmail.com
Mon Jan 28 13:55:43 CET 2013


Please ignore this.

This enables BCH16 by default, which shouldn't happen. I'll will fix this
and send again

On Mon, Jan 28, 2013 at 1:35 PM, Jordy van Wolferen <
jordyvanwolferen at gmail.com> wrote:

> ---
>  arch/arm/include/asm/arch-am33xx/cpu.h       |   8 +-
>  arch/arm/include/asm/arch-am33xx/omap_gpmc.h |  43 ++++++++
>  drivers/mtd/nand/omap_gpmc.c                 | 154
> +++++++++++++++++----------
>  include/linux/mtd/mtd-abi.h                  |   2 +-
>  4 files changed, 150 insertions(+), 57 deletions(-)
>
> diff --git a/arch/arm/include/asm/arch-am33xx/cpu.h
> b/arch/arm/include/asm/arch-am33xx/cpu.h
> index 16e8a80..0a1f1ff 100644
> --- a/arch/arm/include/asm/arch-am33xx/cpu.h
> +++ b/arch/arm/include/asm/arch-am33xx/cpu.h
> @@ -78,6 +78,10 @@ struct bch_res_0_3 {
>         u32 bch_result_x[4];
>  };
>
> +struct bch_res_4_6 {
> +       u32 bch_result_x[3];
> +};
> +
>  struct gpmc {
>         u8 res1[0x10];
>         u32 sysconfig;          /* 0x10 */
> @@ -107,7 +111,9 @@ struct gpmc {
>         u8 res7[12];            /* 0x224 */
>         u32 testmomde_ctrl;     /* 0x230 */
>         u8 res8[12];            /* 0x234 */
> -       struct bch_res_0_3 bch_result_0_3[2];   /* 0x240 */
> +       struct bch_res_0_3 bch_result_0_3;      /* 0x240 */
> +       u32 dummy[44];          /* not used */
> +       struct bch_res_4_6 bch_result_4_6;      /* 300 */
>  };
>
>  /* Used for board specific gpmc initialization */
> diff --git a/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
> b/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
> index 572f9d0..534fa6e 100644
> --- a/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
> +++ b/arch/arm/include/asm/arch-am33xx/omap_gpmc.h
> @@ -117,4 +117,47 @@
>                 {.offset = 106,\
>                  .length = 8 } } \
>  }
> +
> +#define GPMC_NAND_4K_HW_BCH8_ECC_LAYOUT {\
> +       .eccbytes = 112,\
> +       .eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
> +                               16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
> 26, 27,\
> +                               28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
> 38, 39,\
> +                               40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
> 50, 51,\
> +                               52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
> 62, 63,\
> +                               64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
> 74, 75,\
> +                               76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
> 86, 87,\
> +                               88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
> 98, 99,\
> +                               100, 101, 102, 103, 104, 105, 106, 107,
> 108, 109,\
> +                               110, 111, 112, 113},\
> +       .oobfree = {\
> +               {.offset = 114,\
> +                .length = 110 } } \
> +}
> +
> +#define GPMC_NAND_4K_HW_BCH16_ECC_LAYOUT {\
> +       .eccbytes = 208,\
> +       .eccpos = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
> +                               16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
> 26, 27,\
> +                               28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
> 38, 39,\
> +                               40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
> 50, 51,\
> +                               52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
> 62, 63,\
> +                               64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
> 74, 75,\
> +                               76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
> 86, 87,\
> +                               88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
> 98, 99,\
> +                               100, 101, 102, 103, 104, 105, 106, 107,
> 108, 109,\
> +                               110, 111, 112, 113, 114, 115, 116, 117,
> 118, 119,\
> +                               120, 121, 122, 123, 124, 125, 126, 127,
> 128, 129,\
> +                               130, 131, 132, 133, 134, 135, 136, 137,
> 138, 139,\
> +                               140, 141, 142, 143, 144, 145, 146, 147,
> 148, 149,\
> +                               150, 151, 152, 153, 154, 155, 156, 157,
> 158, 159,\
> +                               160, 161, 162, 163, 164, 165, 166, 167,
> 168, 169,\
> +                               170, 171, 172, 173, 174, 175, 176, 177,
> 178, 179,\
> +                               180, 181, 182, 183, 184, 185, 186, 187,
> 188, 189,\
> +                               190, 191, 192, 193, 194, 195, 196, 197,
> 198, 199,\
> +                               200, 201, 202, 203, 204, 205, 206, 207,
> 208, 209},\
> +       .oobfree = {\
> +               {.offset = 210,\
> +                .length = 14 } } \
> +}
>  #endif /* __ASM_ARCH_OMAP_GPMC_H */
> diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
> index cee394e..5cdacc2 100644
> --- a/drivers/mtd/nand/omap_gpmc.c
> +++ b/drivers/mtd/nand/omap_gpmc.c
> @@ -76,8 +76,8 @@ int omap_spl_dev_ready(struct mtd_info *mtd)
>
>  /*
>   * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
> - *                   GPMC controller
> - * @mtd:        MTD device structure
> + *                                      GPMC controller
> + * @mtd:               MTD device structure
>   *
>   */
>  static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
> @@ -170,19 +170,19 @@ static int __maybe_unused omap_correct_data(struct
> mtd_info *mtd, uint8_t *dat,
>  }
>
>  /*
> - *  omap_calculate_ecc - Generate non-inverted ECC bytes.
> + *     omap_calculate_ecc - Generate non-inverted ECC bytes.
>   *
> - *  Using noninverted ECC can be considered ugly since writing a blank
> - *  page ie. padding will clear the ECC bytes. This is no problem as
> - *  long nobody is trying to write data on the seemingly unused page.
> - *  Reading an erased page will produce an ECC mismatch between
> - *  generated and read ECC bytes that has to be dealt with separately.
> - *  E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
> - *  is used, the result of read will be 0x0 while the ECC offsets of the
> - *  spare area will be 0xFF which will result in an ECC mismatch.
> - *  @mtd:      MTD structure
> - *  @dat:      unused
> - *  @ecc_code: ecc_code buffer
> + *     Using noninverted ECC can be considered ugly since writing a blank
> + *     page ie. padding will clear the ECC bytes. This is no problem as
> + *     long nobody is trying to write data on the seemingly unused page.
> + *     Reading an erased page will produce an ECC mismatch between
> + *     generated and read ECC bytes that has to be dealt with separately.
> + *     E.g. if page is 0xFF (fresh erased), and if HW ECC engine within
> GPMC
> + *     is used, the result of read will be 0x0 while the ECC offsets of
> the
> + *     spare area will be 0xFF which will result in an ECC mismatch.
> + *     @mtd:   MTD structure
> + *     @dat:   unused
> + *     @ecc_code:      ecc_code buffer
>   */
>  static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
>                 const uint8_t *dat, uint8_t *ecc_code)
> @@ -207,8 +207,8 @@ static int __maybe_unused omap_calculate_ecc(struct
> mtd_info *mtd,
>
>  /*
>   * omap_enable_ecc - This function enables the hardware ecc functionality
> - * @mtd:        MTD device structure
> - * @mode:       Read/Write mode
> + * @mtd:               MTD device structure
> + * @mode:              Read/Write mode
>   */
>  static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd,
> int32_t mode)
>  {
> @@ -258,12 +258,12 @@ struct nand_bch_priv {
>  #define ECC_BCH8_NIBBLES       26
>  #define ECC_BCH16_NIBBLES      52
>
> -static struct nand_ecclayout hw_bch8_nand_oob =
> GPMC_NAND_HW_BCH8_ECC_LAYOUT;
> +static struct nand_ecclayout nand_ecclayout =
> GPMC_NAND_4K_HW_BCH16_ECC_LAYOUT;
>
>  static struct nand_bch_priv bch_priv = {
>         .mode = NAND_ECC_HW_BCH,
> -       .type = ECC_BCH8,
> -       .nibbles = ECC_BCH8_NIBBLES
> +       .type = ECC_BCH16,
> +       .nibbles = ECC_BCH16_NIBBLES
>  };
>
>  /*
> @@ -280,21 +280,21 @@ static void omap_read_bch8_result(struct mtd_info
> *mtd, uint8_t big_endian,
>         int8_t i = 0, j;
>
>         if (big_endian) {
> -               ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
> +               ptr = &gpmc_cfg->bch_result_0_3.bch_result_x[3];
>                 ecc_code[i++] = readl(ptr) & 0xFF;
>                 ptr--;
>                 for (j = 0; j < 3; j++) {
>                         ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
>                         ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
> -                       ecc_code[i++] = (readl(ptr) >>  8) & 0xFF;
> +                       ecc_code[i++] = (readl(ptr) >>  8) & 0xFF;
>                         ecc_code[i++] = readl(ptr) & 0xFF;
>                         ptr--;
>                 }
>         } else {
> -               ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
> +               ptr = &gpmc_cfg->bch_result_0_3.bch_result_x[0];
>                 for (j = 0; j < 3; j++) {
>                         ecc_code[i++] = readl(ptr) & 0xFF;
> -                       ecc_code[i++] = (readl(ptr) >>  8) & 0xFF;
> +                       ecc_code[i++] = (readl(ptr) >>  8) & 0xFF;
>                         ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
>                         ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
>                         ptr++;
> @@ -304,6 +304,53 @@ static void omap_read_bch8_result(struct mtd_info
> *mtd, uint8_t big_endian,
>         }
>  }
>
> +static void omap_read_bch16_result(struct mtd_info *mtd, uint8_t
> big_endian,
> +                               uint8_t *ecc_code)
> +{
> +       uint32_t *ptr;
> +       int8_t i = 0, j;
> +       uint32_t data;
> +
> +       if(big_endian) {
> +               ptr = &gpmc_cfg->bch_result_4_6.bch_result_x[2];
> +
> +               for (j = 0; j < 7; j++) {
> +                       if(j == 3) {
> +                               ptr =
> &gpmc_cfg->bch_result_0_3.bch_result_x[3];
> +                       }
> +
> +                       data = readl(ptr);
> +                       ptr--;
> +
> +                       if(i > 0) {
> +                               ecc_code[i++] = (data >> 24) & 0xFF;
> +                               ecc_code[i++] = (data >> 16) & 0xFF;
> +                       }
> +                       ecc_code[i++] = (data >> 8) & 0xFF;
> +                       ecc_code[i++] = data & 0xFF;
> +               }
> +               ecc_code[i++] = 0;
> +               ecc_code[i++] = 0;
> +       }
> +       else {
> +               ptr = &gpmc_cfg->bch_result_0_3.bch_result_x[0];
> +
> +               for (j = 0; j < 7; j++) {
> +                       if(j == 4) {
> +                               ptr =
> &gpmc_cfg->bch_result_4_6.bch_result_x[0];
> +                       }
> +
> +                       data = readl(ptr);
> +                       ptr++;
> +
> +                       ecc_code[i++] = data & 0xFF;
> +                       ecc_code[i++] = (data >> 8) & 0xFF;
> +                       ecc_code[i++] = (data >> 16) & 0xFF;
> +                       ecc_code[i++] = (data >> 24) & 0xFF;
> +               }
> +       }
> +}
> +
>  /*
>   * omap_ecc_disable - Disable H/W ECC calculation
>   *
> @@ -330,7 +377,7 @@ static void omap_rotate_ecc_bch(struct mtd_info *mtd,
> uint8_t *calc_ecc,
>         struct nand_chip *chip = mtd->priv;
>         struct nand_bch_priv *bch = chip->priv;
>         uint8_t n_bytes = 0;
> -       int8_t i, j;
> +       int8_t i;
>
>         switch (bch->type) {
>         case ECC_BCH4:
> @@ -338,7 +385,12 @@ static void omap_rotate_ecc_bch(struct mtd_info *mtd,
> uint8_t *calc_ecc,
>                 break;
>
>         case ECC_BCH16:
> -               n_bytes = 28;
> +               n_bytes = 26;
> +
> +               /* Last 2 register of ELM need to be zero */
> +               syndrome[26] = 0;
> +               syndrome[27] = 0;
> +
>                 break;
>
>         case ECC_BCH8:
> @@ -347,16 +399,17 @@ static void omap_rotate_ecc_bch(struct mtd_info
> *mtd, uint8_t *calc_ecc,
>                 break;
>         }
>
> -       for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
> -               syndrome[i] =  calc_ecc[j];
> +       for (i = 0; i < n_bytes; i++) {
> +               syndrome[i] = calc_ecc[(n_bytes-1)-i];
> +       }
>  }
>
>  /*
> - *  omap_calculate_ecc_bch - Read BCH ECC result
> + *     omap_calculate_ecc_bch - Read BCH ECC result
>   *
> - *  @mtd:      MTD structure
> - *  @dat:      unused
> - *  @ecc_code: ecc_code buffer
> + *     @mtd:   MTD structure
> + *     @dat:   unused
> + *     @ecc_code:      ecc_code buffer
>   */
>  static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t
> *dat,
>                                 uint8_t *ecc_code)
> @@ -368,7 +421,9 @@ static int omap_calculate_ecc_bch(struct mtd_info
> *mtd, const uint8_t *dat,
>
>         if (bch->type == ECC_BCH8)
>                 omap_read_bch8_result(mtd, big_endian, ecc_code);
> -       else /* BCH4 and BCH16 currently not supported */
> +       else if(bch->type == ECC_BCH16)
> +               omap_read_bch16_result(mtd, big_endian, ecc_code);
> +       else /* BCH4 currently not supported */
>                 ret = -1;
>
>         /*
> @@ -434,7 +489,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd,
> uint8_t *dat,
>         struct nand_bch_priv *bch = chip->priv;
>         uint8_t syndrome[28];
>         uint32_t error_count = 0;
> -       uint32_t error_loc[8];
> +       uint32_t error_loc[16];
>         uint32_t i, ecc_flag;
>
>         ecc_flag = 0;
> @@ -470,7 +525,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd,
> uint8_t *dat,
>  /*
>   * omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
>   *                             GPMC controller
> - * @mtd:       MTD device structure
> + * @mtd:          MTD device structure
>   * @mode:      Read/Write mode
>   */
>  static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
> @@ -525,8 +580,8 @@ static void omap_hwecc_init_bch(struct nand_chip
> *chip, int32_t mode)
>
>  /*
>   * omap_enable_ecc_bch- This function enables the bch h/w ecc
> functionality
> - * @mtd:        MTD device structure
> - * @mode:       Read/Write mode
> + * @mtd:               MTD device structure
> + * @mode:              Read/Write mode
>   *
>   */
>  static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode)
> @@ -611,12 +666,13 @@ static int omap_read_page_bch(struct mtd_info *mtd,
> struct nand_chip *chip,
>   */
>  void omap_nand_switch_ecc(int32_t hardware)
>  {
> +#ifndef CONFIG_AM33XX
>         struct nand_chip *nand;
>         struct mtd_info *mtd;
>
>         if (nand_curr_device < 0 ||
> -           nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
> -           !nand_info[nand_curr_device].name) {
> +               nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
> +               !nand_info[nand_curr_device].name) {
>                 printf("Error: Can't switch ecc, no devices available\n");
>                 return;
>         }
> @@ -646,19 +702,6 @@ void omap_nand_switch_ecc(int32_t hardware)
>                 nand->ecc.calculate = omap_calculate_ecc;
>                 omap_hwecc_init(nand);
>                 printf("HW ECC selected\n");
> -#ifdef CONFIG_AM33XX
> -       } else if (hardware == 2) {
> -               nand->ecc.mode = NAND_ECC_HW;
> -               nand->ecc.layout = &hw_bch8_nand_oob;
> -               nand->ecc.size = 512;
> -               nand->ecc.bytes = 14;
> -               nand->ecc.read_page = omap_read_page_bch;
> -               nand->ecc.hwctl = omap_enable_ecc_bch;
> -               nand->ecc.correct = omap_correct_data_bch;
> -               nand->ecc.calculate = omap_calculate_ecc_bch;
> -               omap_hwecc_init_bch(nand, NAND_ECC_READ);
> -               printf("HW BCH8 selected\n");
> -#endif
>         } else {
>                 nand->ecc.mode = NAND_ECC_SOFT;
>                 /* Use mtd default settings */
> @@ -671,6 +714,7 @@ void omap_nand_switch_ecc(int32_t hardware)
>         nand_scan_tail(mtd);
>
>         nand->options &= ~NAND_OWN_BUFFERS;
> +#endif
>  }
>  #endif /* CONFIG_SPL_BUILD */
>
> @@ -684,10 +728,10 @@ void omap_nand_switch_ecc(int32_t hardware)
>   * - ecc.hwctl: function to enable (reset) hardware ecc generator
>   * - ecc.mode: mode of ecc, see defines
>   * - chip_delay: chip dependent delay for transfering data from array to
> - *   read regs (tR)
> + *      read regs (tR)
>   * - options: various chip options. They can partly be set to inform
> - *   nand_scan about special functionality. See the defines for further
> - *   explanation
> + *      nand_scan about special functionality. See the defines for further
> + *      explanation
>   */
>  int board_nand_init(struct nand_chip *nand)
>  {
> @@ -742,7 +786,7 @@ int board_nand_init(struct nand_chip *nand)
>         /* Default ECC mode */
>  #ifdef CONFIG_AM33XX
>         nand->ecc.mode = NAND_ECC_HW;
> -       nand->ecc.layout = &hw_bch8_nand_oob;
> +       nand->ecc.layout = &nand_ecclayout;
>         nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
>         nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
>         nand->ecc.hwctl = omap_enable_ecc_bch;
> diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h
> index 8bdd231..6979a2a 100644
> --- a/include/linux/mtd/mtd-abi.h
> +++ b/include/linux/mtd/mtd-abi.h
> @@ -125,7 +125,7 @@ struct nand_oobfree {
>   */
>  struct nand_ecclayout {
>         uint32_t eccbytes;
> -       uint32_t eccpos[128];
> +       uint32_t eccpos[208];
>         uint32_t oobavail;
>         struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
>  };
> --
> 1.8.1.1
>
>


More information about the U-Boot mailing list