Commit 63b29d80823be9ce7763cadc115012d0fba69700

Authored by Peng Fan
Committed by Scott Wood
1 parent d6b6303dbe

mtd: nand: mxs support oobsize bigger than 512

If ecc chunk data size is 512 and oobsize is bigger than 512, there is
a chance that block_mark_bit_offset conflicts with bch ecc area.

The following graph is modified from kernel gpmi-nand.c driver with
each data block 512 bytes. We can see that Block Mark conflicts with
ecc area from bch view. We can enlarge the ecc chunk size to avoid
this problem to those oobsize which is larger than 512.

   |                          P                                        |
   |<----------------------------------------------------------------->|
   |                                                                   |
   |                                                (Block Mark)       |
   |                      P'                             |           | |   |
   |<--------------------------------------------------->|     D     | | O'|
   |                                                     |<--------->| |<->|
   V                                                     V           V V   V
   +---+--------------+-+--------------+-+--------------+-+----------+-+---+
   | M |   data       |E|   data       |E|   data       |E|   data   |E|   |
   +---+--------------+-+--------------+-+--------------+-+----------+-+---+
                                                        ^                  ^
                                                        |         O        |
                                                        |<---------------->|

       P : the page size for BCH module.
       E : The ECC strength.
       G : the length of Galois Field.
       N : The chunk count of per page.
       M : the metasize of per page.
       C : the ecc chunk size, aka the "data" above.
       P': the nand chip's page size.
       O : the nand chip's oob size.
       O': the free oob.

Signed-off-by: Peng Fan <Peng.Fan@freescale.com>
Reviewed-by: Marek Vasut <marex@denx.de>
Tested-By: Tim Harvey <tharvey@gateworks.com>

Showing 2 changed files with 25 additions and 9 deletions Side-by-side Diff

arch/arm/include/asm/imx-common/regs-bch.h
... ... @@ -148,6 +148,7 @@
148 148 #define BCH_FLASHLAYOUT0_ECC0_ECC30 (0xf << 12)
149 149 #define BCH_FLASHLAYOUT0_ECC0_ECC32 (0x10 << 12)
150 150 #define BCH_FLASHLAYOUT0_GF13_0_GF14_1 (1 << 10)
  151 +#define BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET 10
151 152 #define BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0xfff
152 153 #define BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET 0
153 154  
... ... @@ -178,6 +179,7 @@
178 179 #define BCH_FLASHLAYOUT1_ECCN_ECC30 (0xf << 12)
179 180 #define BCH_FLASHLAYOUT1_ECCN_ECC32 (0x10 << 12)
180 181 #define BCH_FLASHLAYOUT1_GF13_0_GF14_1 (1 << 10)
  182 +#define BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET 10
181 183 #define BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0xfff
182 184 #define BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET 0
183 185  
drivers/mtd/nand/mxs_nand.c
... ... @@ -68,6 +68,8 @@
68 68 };
69 69  
70 70 struct nand_ecclayout fake_ecc_layout;
  71 +static int chunk_data_size = MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
  72 +static int galois_field = 13;
71 73  
72 74 /*
73 75 * Cache management functions
74 76  
... ... @@ -130,12 +132,12 @@
130 132  
131 133 static uint32_t mxs_nand_ecc_chunk_cnt(uint32_t page_data_size)
132 134 {
133   - return page_data_size / MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
  135 + return page_data_size / chunk_data_size;
134 136 }
135 137  
136 138 static uint32_t mxs_nand_ecc_size_in_bits(uint32_t ecc_strength)
137 139 {
138   - return ecc_strength * MXS_NAND_BITS_PER_ECC_LEVEL;
  140 + return ecc_strength * galois_field;
139 141 }
140 142  
141 143 static uint32_t mxs_nand_aux_status_offset(void)
... ... @@ -157,8 +159,8 @@
157 159 * (page oob size - meta data size) * (bits per byte)
158 160 */
159 161 ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
160   - / (MXS_NAND_BITS_PER_ECC_LEVEL *
161   - mxs_nand_ecc_chunk_cnt(page_data_size));
  162 + / (galois_field *
  163 + mxs_nand_ecc_chunk_cnt(page_data_size));
162 164  
163 165 return round_down(ecc_strength, 2);
164 166 }
... ... @@ -173,7 +175,7 @@
173 175 uint32_t block_mark_chunk_bit_offset;
174 176 uint32_t block_mark_bit_offset;
175 177  
176   - chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
  178 + chunk_data_size_in_bits = chunk_data_size * 8;
177 179 chunk_ecc_size_in_bits = mxs_nand_ecc_size_in_bits(ecc_strength);
178 180  
179 181 chunk_total_size_in_bits =
... ... @@ -972,6 +974,16 @@
972 974 struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
973 975 uint32_t tmp;
974 976  
  977 + if (mtd->oobsize > MXS_NAND_CHUNK_DATA_CHUNK_SIZE) {
  978 + galois_field = 14;
  979 + chunk_data_size = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 2;
  980 + }
  981 +
  982 + if (mtd->oobsize > chunk_data_size) {
  983 + printf("Not support the NAND chips whose oob size is larger then %d bytes!\n", chunk_data_size);
  984 + return -EINVAL;
  985 + }
  986 +
975 987 /* Configure BCH and set NFC geometry */
976 988 mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
977 989  
978 990  
... ... @@ -981,16 +993,18 @@
981 993 tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
982 994 tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
983 995 << BCH_FLASHLAYOUT0_ECC0_OFFSET;
984   - tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE
985   - >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
  996 + tmp |= chunk_data_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
  997 + tmp |= (14 == galois_field ? 1 : 0) <<
  998 + BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
986 999 writel(tmp, &bch_regs->hw_bch_flash0layout0);
987 1000  
988 1001 tmp = (mtd->writesize + mtd->oobsize)
989 1002 << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
990 1003 tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
991 1004 << BCH_FLASHLAYOUT1_ECCN_OFFSET;
992   - tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE
993   - >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
  1005 + tmp |= chunk_data_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
  1006 + tmp |= (14 == galois_field ? 1 : 0) <<
  1007 + BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
994 1008 writel(tmp, &bch_regs->hw_bch_flash0layout1);
995 1009  
996 1010 /* Set *all* chip selects to use layout 0 */