aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHuang Shijie <b32955@freescale.com>2013-05-16 23:17:34 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:05:59 -0400
commit0d17442b52ffd0187e58bdbc27b8fee07401df01 (patch)
tree62b49439efdd52f0303942c0ad00450cd17af9ac /drivers
parentee3a2a3b69f5e4cca79ac437d12bba592ba66930 (diff)
mtd: gpmi: set the BCH's geometry with the ecc info
If the nand chip provides us the ECC info, we can use it firstly. The set_geometry_by_ecc_info() will use the ECC info, and calculate the parameters we need. Rename the old code to legacy_set_geometry() which will takes effect when there is no ECC info from the nand chip or we fails in the ECC info case. Signed-off-by: Huang Shijie <b32955@freescale.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c132
1 files changed, 131 insertions, 1 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 6213c53820e6..0c3e64793882 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -111,7 +111,132 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
111 return true; 111 return true;
112} 112}
113 113
114int common_nfc_set_geometry(struct gpmi_nand_data *this) 114/*
115 * If we can get the ECC information from the nand chip, we do not
116 * need to calculate them ourselves.
117 *
118 * We may have available oob space in this case.
119 */
120static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
121{
122 struct bch_geometry *geo = &this->bch_geometry;
123 struct mtd_info *mtd = &this->mtd;
124 struct nand_chip *chip = mtd->priv;
125 struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
126 unsigned int block_mark_bit_offset;
127
128 if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
129 return false;
130
131 switch (chip->ecc_step_ds) {
132 case SZ_512:
133 geo->gf_len = 13;
134 break;
135 case SZ_1K:
136 geo->gf_len = 14;
137 break;
138 default:
139 dev_err(this->dev,
140 "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
141 chip->ecc_strength_ds, chip->ecc_step_ds);
142 return false;
143 }
144 geo->ecc_chunk_size = chip->ecc_step_ds;
145 geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
146 if (!gpmi_check_ecc(this))
147 return false;
148
149 /* Keep the C >= O */
150 if (geo->ecc_chunk_size < mtd->oobsize) {
151 dev_err(this->dev,
152 "unsupported nand chip. ecc size: %d, oob size : %d\n",
153 chip->ecc_step_ds, mtd->oobsize);
154 return false;
155 }
156
157 /* The default value, see comment in the legacy_set_geometry(). */
158 geo->metadata_size = 10;
159
160 geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
161
162 /*
163 * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
164 *
165 * | P |
166 * |<----------------------------------------------------->|
167 * | |
168 * | (Block Mark) |
169 * | P' | | | |
170 * |<-------------------------------------------->| D | | O' |
171 * | |<---->| |<--->|
172 * V V V V V
173 * +---+----------+-+----------+-+----------+-+----------+-+-----+
174 * | M | data |E| data |E| data |E| data |E| |
175 * +---+----------+-+----------+-+----------+-+----------+-+-----+
176 * ^ ^
177 * | O |
178 * |<------------>|
179 * | |
180 *
181 * P : the page size for BCH module.
182 * E : The ECC strength.
183 * G : the length of Galois Field.
184 * N : The chunk count of per page.
185 * M : the metasize of per page.
186 * C : the ecc chunk size, aka the "data" above.
187 * P': the nand chip's page size.
188 * O : the nand chip's oob size.
189 * O': the free oob.
190 *
191 * The formula for P is :
192 *
193 * E * G * N
194 * P = ------------ + P' + M
195 * 8
196 *
197 * The position of block mark moves forward in the ECC-based view
198 * of page, and the delta is:
199 *
200 * E * G * (N - 1)
201 * D = (---------------- + M)
202 * 8
203 *
204 * Please see the comment in legacy_set_geometry().
205 * With the condition C >= O , we still can get same result.
206 * So the bit position of the physical block mark within the ECC-based
207 * view of the page is :
208 * (P' - D) * 8
209 */
210 geo->page_size = mtd->writesize + geo->metadata_size +
211 (geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
212
213 /* The available oob size we have. */
214 if (geo->page_size < mtd->writesize + mtd->oobsize) {
215 of->offset = geo->page_size - mtd->writesize;
216 of->length = mtd->oobsize - of->offset;
217 mtd->oobavail = gpmi_hw_ecclayout.oobavail = of->length;
218 }
219
220 geo->payload_size = mtd->writesize;
221
222 geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
223 geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
224 + ALIGN(geo->ecc_chunk_count, 4);
225
226 if (!this->swap_block_mark)
227 return true;
228
229 /* For bit swap. */
230 block_mark_bit_offset = mtd->writesize * 8 -
231 (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
232 + geo->metadata_size * 8);
233
234 geo->block_mark_byte_offset = block_mark_bit_offset / 8;
235 geo->block_mark_bit_offset = block_mark_bit_offset % 8;
236 return true;
237}
238
239static int legacy_set_geometry(struct gpmi_nand_data *this)
115{ 240{
116 struct bch_geometry *geo = &this->bch_geometry; 241 struct bch_geometry *geo = &this->bch_geometry;
117 struct mtd_info *mtd = &this->mtd; 242 struct mtd_info *mtd = &this->mtd;
@@ -223,6 +348,11 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
223 return 0; 348 return 0;
224} 349}
225 350
351int common_nfc_set_geometry(struct gpmi_nand_data *this)
352{
353 return set_geometry_by_ecc_info(this) ? 0 : legacy_set_geometry(this);
354}
355
226struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) 356struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
227{ 357{
228 int chipnr = this->current_chip; 358 int chipnr = this->current_chip;