@@ -111,7 +111,132 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
111111 return true;
112112}
113113
114- int 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+ */
120+ static 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+
239+ static int legacy_set_geometry (struct gpmi_nand_data * this )
115240{
116241 struct bch_geometry * geo = & this -> bch_geometry ;
117242 struct mtd_info * mtd = & this -> mtd ;
@@ -223,6 +348,11 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
223348 return 0 ;
224349}
225350
351+ int 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+
226356struct dma_chan * get_dma_chan (struct gpmi_nand_data * this )
227357{
228358 int chipnr = this -> current_chip ;
0 commit comments