Commit 63b29d80823be9ce7763cadc115012d0fba69700
Committed by
Scott Wood
1 parent
d6b6303dbe
Exists in
v2017.01-smarct4x
and in
30 other branches
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 */ |