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

来源:互联网 发布:windows sever 2012 编辑:程序博客网 时间:2024/06/08 00:14
SubmitterJordy van WolferenDateJan. 28, 2013, 1:35 p.m.Message ID<1359380140-9842-1-git-send-email-jordyvanwolferen@gmail.com>Downloadmbox|patchPermalink/patch/216188/StateSupersededDelegated to:Tom RiniHeadersshow

Comments

Jordy van Wolferen - Jan. 28, 2013, 1:35 p.m.
This is tested with a custom AM3359 (rev 2.0) board.NAND chip: MT29F16G08ABABAWPThis code allows me to boot from ROM code.The ROM code forces BCH16 on NAND chips with a 4k page size.BCH16 is not enabled by default.--- 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                 | 150 +++++++++++++++++---------- include/linux/mtd/mtd-abi.h                  |   2 +- 4 files changed, 148 insertions(+), 55 deletions(-)--1.8.1.1

Patch

diff --git a/arch/arm/include/asm/arch-am33xx/cpu.h b/arch/arm/include/asm/arch-am33xx/cpu.hindex 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.hindex 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.cindex cee394e..3c42a54 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,7 +258,7 @@  struct nand_bch_priv { #define ECC_BCH8_NIBBLES26 #define ECC_BCH16_NIBBLES52-static struct nand_ecclayout hw_bch8_nand_oob = GPMC_NAND_HW_BCH8_ECC_LAYOUT;+static struct nand_ecclayout nand_ecclayout = GPMC_NAND_HW_BCH8_ECC_LAYOUT; static struct nand_bch_priv bch_priv = { .mode = NAND_ECC_HW_BCH,@@ -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.hindex 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]; };
0 0
原创粉丝点击