Commit | Line | Data |
---|---|---|
9c3736a3 BB |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
3 | * Copyright 2017 - Free Electrons | |
4 | * | |
5 | * Authors: | |
6 | * Boris Brezillon <boris.brezillon@free-electrons.com> | |
7 | * Peter Pan <peterpandong@micron.com> | |
8 | */ | |
9 | ||
10 | #ifndef __LINUX_MTD_NAND_H | |
11 | #define __LINUX_MTD_NAND_H | |
12 | ||
13 | #include <linux/mtd/mtd.h> | |
14 | ||
33d226f5 MR |
15 | struct nand_device; |
16 | ||
9c3736a3 BB |
17 | /** |
18 | * struct nand_memory_organization - Memory organization structure | |
19 | * @bits_per_cell: number of bits per NAND cell | |
20 | * @pagesize: page size | |
21 | * @oobsize: OOB area size | |
22 | * @pages_per_eraseblock: number of pages per eraseblock | |
23 | * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number) | |
377e517b | 24 | * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN |
9c3736a3 BB |
25 | * @planes_per_lun: number of planes per LUN |
26 | * @luns_per_target: number of LUN per target (target is a synonym for die) | |
27 | * @ntargets: total number of targets exposed by the NAND device | |
28 | */ | |
29 | struct nand_memory_organization { | |
30 | unsigned int bits_per_cell; | |
31 | unsigned int pagesize; | |
32 | unsigned int oobsize; | |
33 | unsigned int pages_per_eraseblock; | |
34 | unsigned int eraseblocks_per_lun; | |
377e517b | 35 | unsigned int max_bad_eraseblocks_per_lun; |
9c3736a3 BB |
36 | unsigned int planes_per_lun; |
37 | unsigned int luns_per_target; | |
38 | unsigned int ntargets; | |
39 | }; | |
40 | ||
377e517b | 41 | #define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt) \ |
9c3736a3 BB |
42 | { \ |
43 | .bits_per_cell = (bpc), \ | |
44 | .pagesize = (ps), \ | |
45 | .oobsize = (os), \ | |
46 | .pages_per_eraseblock = (ppe), \ | |
47 | .eraseblocks_per_lun = (epl), \ | |
377e517b | 48 | .max_bad_eraseblocks_per_lun = (mbb), \ |
9c3736a3 BB |
49 | .planes_per_lun = (ppl), \ |
50 | .luns_per_target = (lpt), \ | |
51 | .ntargets = (nt), \ | |
52 | } | |
53 | ||
54 | /** | |
55 | * struct nand_row_converter - Information needed to convert an absolute offset | |
56 | * into a row address | |
57 | * @lun_addr_shift: position of the LUN identifier in the row address | |
58 | * @eraseblock_addr_shift: position of the eraseblock identifier in the row | |
59 | * address | |
60 | */ | |
61 | struct nand_row_converter { | |
62 | unsigned int lun_addr_shift; | |
63 | unsigned int eraseblock_addr_shift; | |
64 | }; | |
65 | ||
66 | /** | |
67 | * struct nand_pos - NAND position object | |
68 | * @target: the NAND target/die | |
69 | * @lun: the LUN identifier | |
70 | * @plane: the plane within the LUN | |
71 | * @eraseblock: the eraseblock within the LUN | |
72 | * @page: the page within the LUN | |
73 | * | |
74 | * These information are usually used by specific sub-layers to select the | |
75 | * appropriate target/die and generate a row address to pass to the device. | |
76 | */ | |
77 | struct nand_pos { | |
78 | unsigned int target; | |
79 | unsigned int lun; | |
80 | unsigned int plane; | |
81 | unsigned int eraseblock; | |
82 | unsigned int page; | |
83 | }; | |
84 | ||
701981ca MR |
85 | /** |
86 | * enum nand_page_io_req_type - Direction of an I/O request | |
87 | * @NAND_PAGE_READ: from the chip, to the controller | |
88 | * @NAND_PAGE_WRITE: from the controller, to the chip | |
89 | */ | |
90 | enum nand_page_io_req_type { | |
91 | NAND_PAGE_READ = 0, | |
92 | NAND_PAGE_WRITE, | |
93 | }; | |
94 | ||
9c3736a3 BB |
95 | /** |
96 | * struct nand_page_io_req - NAND I/O request object | |
701981ca | 97 | * @type: the type of page I/O: read or write |
9c3736a3 BB |
98 | * @pos: the position this I/O request is targeting |
99 | * @dataoffs: the offset within the page | |
100 | * @datalen: number of data bytes to read from/write to this page | |
101 | * @databuf: buffer to store data in or get data from | |
102 | * @ooboffs: the OOB offset within the page | |
103 | * @ooblen: the number of OOB bytes to read from/write to this page | |
104 | * @oobbuf: buffer to store OOB data in or get OOB data from | |
f567c71f | 105 | * @mode: one of the %MTD_OPS_XXX mode |
9c3736a3 BB |
106 | * |
107 | * This object is used to pass per-page I/O requests to NAND sub-layers. This | |
108 | * way all useful information are already formatted in a useful way and | |
109 | * specific NAND layers can focus on translating these information into | |
110 | * specific commands/operations. | |
111 | */ | |
112 | struct nand_page_io_req { | |
701981ca | 113 | enum nand_page_io_req_type type; |
9c3736a3 BB |
114 | struct nand_pos pos; |
115 | unsigned int dataoffs; | |
116 | unsigned int datalen; | |
117 | union { | |
118 | const void *out; | |
119 | void *in; | |
120 | } databuf; | |
121 | unsigned int ooboffs; | |
122 | unsigned int ooblen; | |
123 | union { | |
124 | const void *out; | |
125 | void *in; | |
126 | } oobbuf; | |
f567c71f | 127 | int mode; |
9c3736a3 BB |
128 | }; |
129 | ||
a8c7ffdb MR |
130 | const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void); |
131 | const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void); | |
132 | const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void); | |
133 | ||
134 | /** | |
135 | * enum nand_ecc_engine_type - NAND ECC engine type | |
136 | * @NAND_ECC_ENGINE_TYPE_INVALID: Invalid value | |
137 | * @NAND_ECC_ENGINE_TYPE_NONE: No ECC correction | |
138 | * @NAND_ECC_ENGINE_TYPE_SOFT: Software ECC correction | |
139 | * @NAND_ECC_ENGINE_TYPE_ON_HOST: On host hardware ECC correction | |
140 | * @NAND_ECC_ENGINE_TYPE_ON_DIE: On chip hardware ECC correction | |
141 | */ | |
142 | enum nand_ecc_engine_type { | |
143 | NAND_ECC_ENGINE_TYPE_INVALID, | |
144 | NAND_ECC_ENGINE_TYPE_NONE, | |
145 | NAND_ECC_ENGINE_TYPE_SOFT, | |
146 | NAND_ECC_ENGINE_TYPE_ON_HOST, | |
147 | NAND_ECC_ENGINE_TYPE_ON_DIE, | |
148 | }; | |
149 | ||
150 | /** | |
151 | * enum nand_ecc_placement - NAND ECC bytes placement | |
152 | * @NAND_ECC_PLACEMENT_UNKNOWN: The actual position of the ECC bytes is unknown | |
153 | * @NAND_ECC_PLACEMENT_OOB: The ECC bytes are located in the OOB area | |
154 | * @NAND_ECC_PLACEMENT_INTERLEAVED: Syndrome layout, there are ECC bytes | |
155 | * interleaved with regular data in the main | |
156 | * area | |
157 | */ | |
158 | enum nand_ecc_placement { | |
159 | NAND_ECC_PLACEMENT_UNKNOWN, | |
160 | NAND_ECC_PLACEMENT_OOB, | |
161 | NAND_ECC_PLACEMENT_INTERLEAVED, | |
162 | }; | |
163 | ||
f2f64c1e MR |
164 | /** |
165 | * enum nand_ecc_algo - NAND ECC algorithm | |
166 | * @NAND_ECC_ALGO_UNKNOWN: Unknown algorithm | |
167 | * @NAND_ECC_ALGO_HAMMING: Hamming algorithm | |
168 | * @NAND_ECC_ALGO_BCH: Bose-Chaudhuri-Hocquenghem algorithm | |
169 | * @NAND_ECC_ALGO_RS: Reed-Solomon algorithm | |
170 | */ | |
171 | enum nand_ecc_algo { | |
172 | NAND_ECC_ALGO_UNKNOWN, | |
173 | NAND_ECC_ALGO_HAMMING, | |
174 | NAND_ECC_ALGO_BCH, | |
175 | NAND_ECC_ALGO_RS, | |
176 | }; | |
177 | ||
9c3736a3 | 178 | /** |
85f54c55 | 179 | * struct nand_ecc_props - NAND ECC properties |
a8c7ffdb MR |
180 | * @engine_type: ECC engine type |
181 | * @placement: OOB placement (if relevant) | |
182 | * @algo: ECC algorithm (if relevant) | |
9c3736a3 | 183 | * @strength: ECC strength |
85f54c55 | 184 | * @step_size: Number of bytes per step |
a8c7ffdb | 185 | * @flags: Misc properties |
9c3736a3 | 186 | */ |
85f54c55 | 187 | struct nand_ecc_props { |
a8c7ffdb MR |
188 | enum nand_ecc_engine_type engine_type; |
189 | enum nand_ecc_placement placement; | |
190 | enum nand_ecc_algo algo; | |
9c3736a3 BB |
191 | unsigned int strength; |
192 | unsigned int step_size; | |
a8c7ffdb | 193 | unsigned int flags; |
9c3736a3 BB |
194 | }; |
195 | ||
196 | #define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) } | |
197 | ||
a8c7ffdb MR |
198 | /* NAND ECC misc flags */ |
199 | #define NAND_ECC_MAXIMIZE_STRENGTH BIT(0) | |
200 | ||
9c3736a3 BB |
201 | /** |
202 | * struct nand_bbt - bad block table object | |
203 | * @cache: in memory BBT cache | |
204 | */ | |
205 | struct nand_bbt { | |
206 | unsigned long *cache; | |
207 | }; | |
208 | ||
9c3736a3 BB |
209 | /** |
210 | * struct nand_ops - NAND operations | |
211 | * @erase: erase a specific block. No need to check if the block is bad before | |
212 | * erasing, this has been taken care of by the generic NAND layer | |
213 | * @markbad: mark a specific block bad. No need to check if the block is | |
214 | * already marked bad, this has been taken care of by the generic | |
215 | * NAND layer. This method should just write the BBM (Bad Block | |
216 | * Marker) so that future call to struct_nand_ops->isbad() return | |
217 | * true | |
218 | * @isbad: check whether a block is bad or not. This method should just read | |
219 | * the BBM and return whether the block is bad or not based on what it | |
220 | * reads | |
221 | * | |
222 | * These are all low level operations that should be implemented by specialized | |
223 | * NAND layers (SPI NAND, raw NAND, ...). | |
224 | */ | |
225 | struct nand_ops { | |
226 | int (*erase)(struct nand_device *nand, const struct nand_pos *pos); | |
227 | int (*markbad)(struct nand_device *nand, const struct nand_pos *pos); | |
228 | bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos); | |
229 | }; | |
230 | ||
a8c7ffdb MR |
231 | /** |
232 | * struct nand_ecc_context - Context for the ECC engine | |
233 | * @conf: basic ECC engine parameters | |
2bc61184 | 234 | * @nsteps: number of ECC steps |
a8c7ffdb MR |
235 | * @total: total number of bytes used for storing ECC codes, this is used by |
236 | * generic OOB layouts | |
237 | * @priv: ECC engine driver private data | |
238 | */ | |
239 | struct nand_ecc_context { | |
240 | struct nand_ecc_props conf; | |
2bc61184 | 241 | unsigned int nsteps; |
a8c7ffdb MR |
242 | unsigned int total; |
243 | void *priv; | |
244 | }; | |
245 | ||
246 | /** | |
247 | * struct nand_ecc_engine_ops - ECC engine operations | |
248 | * @init_ctx: given a desired user configuration for the pointed NAND device, | |
249 | * requests the ECC engine driver to setup a configuration with | |
250 | * values it supports. | |
251 | * @cleanup_ctx: clean the context initialized by @init_ctx. | |
252 | * @prepare_io_req: is called before reading/writing a page to prepare the I/O | |
253 | * request to be performed with ECC correction. | |
254 | * @finish_io_req: is called after reading/writing a page to terminate the I/O | |
255 | * request and ensure proper ECC correction. | |
256 | */ | |
257 | struct nand_ecc_engine_ops { | |
258 | int (*init_ctx)(struct nand_device *nand); | |
259 | void (*cleanup_ctx)(struct nand_device *nand); | |
260 | int (*prepare_io_req)(struct nand_device *nand, | |
261 | struct nand_page_io_req *req); | |
262 | int (*finish_io_req)(struct nand_device *nand, | |
263 | struct nand_page_io_req *req); | |
264 | }; | |
265 | ||
96489c1c MR |
266 | /** |
267 | * enum nand_ecc_engine_integration - How the NAND ECC engine is integrated | |
268 | * @NAND_ECC_ENGINE_INTEGRATION_INVALID: Invalid value | |
269 | * @NAND_ECC_ENGINE_INTEGRATION_PIPELINED: Pipelined engine, performs on-the-fly | |
270 | * correction, does not need to copy | |
271 | * data around | |
272 | * @NAND_ECC_ENGINE_INTEGRATION_EXTERNAL: External engine, needs to bring the | |
273 | * data into its own area before use | |
274 | */ | |
275 | enum nand_ecc_engine_integration { | |
276 | NAND_ECC_ENGINE_INTEGRATION_INVALID, | |
277 | NAND_ECC_ENGINE_INTEGRATION_PIPELINED, | |
278 | NAND_ECC_ENGINE_INTEGRATION_EXTERNAL, | |
279 | }; | |
280 | ||
a8c7ffdb MR |
281 | /** |
282 | * struct nand_ecc_engine - ECC engine abstraction for NAND devices | |
96489c1c MR |
283 | * @dev: Host device |
284 | * @node: Private field for registration time | |
a8c7ffdb | 285 | * @ops: ECC engine operations |
96489c1c MR |
286 | * @integration: How the engine is integrated with the host |
287 | * (only relevant on %NAND_ECC_ENGINE_TYPE_ON_HOST engines) | |
288 | * @priv: Private data | |
a8c7ffdb MR |
289 | */ |
290 | struct nand_ecc_engine { | |
96489c1c MR |
291 | struct device *dev; |
292 | struct list_head node; | |
a8c7ffdb | 293 | struct nand_ecc_engine_ops *ops; |
96489c1c MR |
294 | enum nand_ecc_engine_integration integration; |
295 | void *priv; | |
a8c7ffdb MR |
296 | }; |
297 | ||
298 | void of_get_nand_ecc_user_config(struct nand_device *nand); | |
299 | int nand_ecc_init_ctx(struct nand_device *nand); | |
300 | void nand_ecc_cleanup_ctx(struct nand_device *nand); | |
301 | int nand_ecc_prepare_io_req(struct nand_device *nand, | |
302 | struct nand_page_io_req *req); | |
303 | int nand_ecc_finish_io_req(struct nand_device *nand, | |
304 | struct nand_page_io_req *req); | |
305 | bool nand_ecc_is_strong_enough(struct nand_device *nand); | |
00360eba MR |
306 | |
307 | #if IS_REACHABLE(CONFIG_MTD_NAND_CORE) | |
96489c1c MR |
308 | int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine); |
309 | int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine); | |
00360eba MR |
310 | #else |
311 | static inline int | |
312 | nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine) | |
313 | { | |
314 | return -ENOTSUPP; | |
315 | } | |
316 | static inline int | |
317 | nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine) | |
318 | { | |
319 | return -ENOTSUPP; | |
320 | } | |
321 | #endif | |
322 | ||
53fbdeeb | 323 | struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand); |
da429b96 | 324 | struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand); |
96489c1c MR |
325 | struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand); |
326 | void nand_ecc_put_on_host_hw_engine(struct nand_device *nand); | |
5145abeb | 327 | struct device *nand_ecc_get_engine_dev(struct device *host); |
a8c7ffdb | 328 | |
35fe1b98 MR |
329 | #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING) |
330 | struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void); | |
331 | #else | |
332 | static inline struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void) | |
333 | { | |
334 | return NULL; | |
335 | } | |
336 | #endif /* CONFIG_MTD_NAND_ECC_SW_HAMMING */ | |
337 | ||
9994bb3f MR |
338 | #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH) |
339 | struct nand_ecc_engine *nand_ecc_sw_bch_get_engine(void); | |
340 | #else | |
341 | static inline struct nand_ecc_engine *nand_ecc_sw_bch_get_engine(void) | |
342 | { | |
343 | return NULL; | |
344 | } | |
345 | #endif /* CONFIG_MTD_NAND_ECC_SW_BCH */ | |
346 | ||
51e7bf45 MR |
347 | /** |
348 | * struct nand_ecc_req_tweak_ctx - Help for automatically tweaking requests | |
349 | * @orig_req: Pointer to the original IO request | |
350 | * @nand: Related NAND device, to have access to its memory organization | |
351 | * @page_buffer_size: Real size of the page buffer to use (can be set by the | |
352 | * user before the tweaking mechanism initialization) | |
353 | * @oob_buffer_size: Real size of the OOB buffer to use (can be set by the | |
354 | * user before the tweaking mechanism initialization) | |
355 | * @spare_databuf: Data bounce buffer | |
356 | * @spare_oobbuf: OOB bounce buffer | |
357 | * @bounce_data: Flag indicating a data bounce buffer is used | |
358 | * @bounce_oob: Flag indicating an OOB bounce buffer is used | |
359 | */ | |
360 | struct nand_ecc_req_tweak_ctx { | |
361 | struct nand_page_io_req orig_req; | |
362 | struct nand_device *nand; | |
363 | unsigned int page_buffer_size; | |
364 | unsigned int oob_buffer_size; | |
365 | void *spare_databuf; | |
366 | void *spare_oobbuf; | |
367 | bool bounce_data; | |
368 | bool bounce_oob; | |
369 | }; | |
370 | ||
371 | int nand_ecc_init_req_tweaking(struct nand_ecc_req_tweak_ctx *ctx, | |
372 | struct nand_device *nand); | |
373 | void nand_ecc_cleanup_req_tweaking(struct nand_ecc_req_tweak_ctx *ctx); | |
374 | void nand_ecc_tweak_req(struct nand_ecc_req_tweak_ctx *ctx, | |
375 | struct nand_page_io_req *req); | |
376 | void nand_ecc_restore_req(struct nand_ecc_req_tweak_ctx *ctx, | |
377 | struct nand_page_io_req *req); | |
378 | ||
a8c7ffdb MR |
379 | /** |
380 | * struct nand_ecc - Information relative to the ECC | |
381 | * @defaults: Default values, depend on the underlying subsystem | |
382 | * @requirements: ECC requirements from the NAND chip perspective | |
383 | * @user_conf: User desires in terms of ECC parameters | |
384 | * @ctx: ECC context for the ECC engine, derived from the device @requirements | |
385 | * the @user_conf and the @defaults | |
386 | * @ondie_engine: On-die ECC engine reference, if any | |
387 | * @engine: ECC engine actually bound | |
388 | */ | |
389 | struct nand_ecc { | |
390 | struct nand_ecc_props defaults; | |
391 | struct nand_ecc_props requirements; | |
392 | struct nand_ecc_props user_conf; | |
393 | struct nand_ecc_context ctx; | |
394 | struct nand_ecc_engine *ondie_engine; | |
395 | struct nand_ecc_engine *engine; | |
396 | }; | |
397 | ||
9c3736a3 BB |
398 | /** |
399 | * struct nand_device - NAND device | |
400 | * @mtd: MTD instance attached to the NAND device | |
401 | * @memorg: memory layout | |
93ef92f6 | 402 | * @ecc: NAND ECC object attached to the NAND device |
9c3736a3 BB |
403 | * @rowconv: position to row address converter |
404 | * @bbt: bad block table info | |
405 | * @ops: NAND operations attached to the NAND device | |
406 | * | |
407 | * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND) | |
408 | * should declare their own NAND object embedding a nand_device struct (that's | |
409 | * how inheritance is done). | |
93ef92f6 MR |
410 | * struct_nand_device->memorg and struct_nand_device->ecc.requirements should |
411 | * be filled at device detection time to reflect the NAND device | |
9c3736a3 BB |
412 | * capabilities/requirements. Once this is done nanddev_init() can be called. |
413 | * It will take care of converting NAND information into MTD ones, which means | |
414 | * the specialized NAND layers should never manually tweak | |
415 | * struct_nand_device->mtd except for the ->_read/write() hooks. | |
416 | */ | |
417 | struct nand_device { | |
418 | struct mtd_info mtd; | |
419 | struct nand_memory_organization memorg; | |
93ef92f6 | 420 | struct nand_ecc ecc; |
9c3736a3 BB |
421 | struct nand_row_converter rowconv; |
422 | struct nand_bbt bbt; | |
423 | const struct nand_ops *ops; | |
424 | }; | |
425 | ||
426 | /** | |
427 | * struct nand_io_iter - NAND I/O iterator | |
428 | * @req: current I/O request | |
429 | * @oobbytes_per_page: maximum number of OOB bytes per page | |
430 | * @dataleft: remaining number of data bytes to read/write | |
431 | * @oobleft: remaining number of OOB bytes to read/write | |
432 | * | |
433 | * Can be used by specialized NAND layers to iterate over all pages covered | |
434 | * by an MTD I/O request, which should greatly simplifies the boiler-plate | |
435 | * code needed to read/write data from/to a NAND device. | |
436 | */ | |
437 | struct nand_io_iter { | |
438 | struct nand_page_io_req req; | |
439 | unsigned int oobbytes_per_page; | |
440 | unsigned int dataleft; | |
441 | unsigned int oobleft; | |
442 | }; | |
443 | ||
444 | /** | |
445 | * mtd_to_nanddev() - Get the NAND device attached to the MTD instance | |
446 | * @mtd: MTD instance | |
447 | * | |
448 | * Return: the NAND device embedding @mtd. | |
449 | */ | |
450 | static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd) | |
451 | { | |
452 | return container_of(mtd, struct nand_device, mtd); | |
453 | } | |
454 | ||
455 | /** | |
456 | * nanddev_to_mtd() - Get the MTD device attached to a NAND device | |
457 | * @nand: NAND device | |
458 | * | |
459 | * Return: the MTD device embedded in @nand. | |
460 | */ | |
461 | static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand) | |
462 | { | |
463 | return &nand->mtd; | |
464 | } | |
465 | ||
466 | /* | |
467 | * nanddev_bits_per_cell() - Get the number of bits per cell | |
468 | * @nand: NAND device | |
469 | * | |
470 | * Return: the number of bits per cell. | |
471 | */ | |
472 | static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand) | |
473 | { | |
474 | return nand->memorg.bits_per_cell; | |
475 | } | |
476 | ||
477 | /** | |
478 | * nanddev_page_size() - Get NAND page size | |
479 | * @nand: NAND device | |
480 | * | |
481 | * Return: the page size. | |
482 | */ | |
483 | static inline size_t nanddev_page_size(const struct nand_device *nand) | |
484 | { | |
485 | return nand->memorg.pagesize; | |
486 | } | |
487 | ||
488 | /** | |
489 | * nanddev_per_page_oobsize() - Get NAND OOB size | |
490 | * @nand: NAND device | |
491 | * | |
492 | * Return: the OOB size. | |
493 | */ | |
494 | static inline unsigned int | |
495 | nanddev_per_page_oobsize(const struct nand_device *nand) | |
496 | { | |
497 | return nand->memorg.oobsize; | |
498 | } | |
499 | ||
500 | /** | |
501 | * nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock | |
502 | * @nand: NAND device | |
503 | * | |
504 | * Return: the number of pages per eraseblock. | |
505 | */ | |
506 | static inline unsigned int | |
507 | nanddev_pages_per_eraseblock(const struct nand_device *nand) | |
508 | { | |
509 | return nand->memorg.pages_per_eraseblock; | |
510 | } | |
511 | ||
46b01d7e BB |
512 | /** |
513 | * nanddev_pages_per_target() - Get the number of pages per target | |
514 | * @nand: NAND device | |
515 | * | |
516 | * Return: the number of pages per target. | |
517 | */ | |
518 | static inline unsigned int | |
519 | nanddev_pages_per_target(const struct nand_device *nand) | |
520 | { | |
521 | return nand->memorg.pages_per_eraseblock * | |
522 | nand->memorg.eraseblocks_per_lun * | |
523 | nand->memorg.luns_per_target; | |
524 | } | |
525 | ||
9c3736a3 BB |
526 | /** |
527 | * nanddev_per_page_oobsize() - Get NAND erase block size | |
528 | * @nand: NAND device | |
529 | * | |
530 | * Return: the eraseblock size. | |
531 | */ | |
532 | static inline size_t nanddev_eraseblock_size(const struct nand_device *nand) | |
533 | { | |
534 | return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock; | |
535 | } | |
536 | ||
537 | /** | |
538 | * nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN | |
539 | * @nand: NAND device | |
540 | * | |
541 | * Return: the number of eraseblocks per LUN. | |
542 | */ | |
543 | static inline unsigned int | |
544 | nanddev_eraseblocks_per_lun(const struct nand_device *nand) | |
545 | { | |
546 | return nand->memorg.eraseblocks_per_lun; | |
547 | } | |
548 | ||
7c4ecca1 BB |
549 | /** |
550 | * nanddev_eraseblocks_per_target() - Get the number of eraseblocks per target | |
551 | * @nand: NAND device | |
552 | * | |
553 | * Return: the number of eraseblocks per target. | |
554 | */ | |
555 | static inline unsigned int | |
556 | nanddev_eraseblocks_per_target(const struct nand_device *nand) | |
557 | { | |
558 | return nand->memorg.eraseblocks_per_lun * nand->memorg.luns_per_target; | |
559 | } | |
560 | ||
9c3736a3 BB |
561 | /** |
562 | * nanddev_target_size() - Get the total size provided by a single target/die | |
563 | * @nand: NAND device | |
564 | * | |
565 | * Return: the total size exposed by a single target/die in bytes. | |
566 | */ | |
567 | static inline u64 nanddev_target_size(const struct nand_device *nand) | |
568 | { | |
569 | return (u64)nand->memorg.luns_per_target * | |
570 | nand->memorg.eraseblocks_per_lun * | |
571 | nand->memorg.pages_per_eraseblock * | |
572 | nand->memorg.pagesize; | |
573 | } | |
574 | ||
575 | /** | |
576 | * nanddev_ntarget() - Get the total of targets | |
577 | * @nand: NAND device | |
578 | * | |
579 | * Return: the number of targets/dies exposed by @nand. | |
580 | */ | |
581 | static inline unsigned int nanddev_ntargets(const struct nand_device *nand) | |
582 | { | |
583 | return nand->memorg.ntargets; | |
584 | } | |
585 | ||
586 | /** | |
0c43125f | 587 | * nanddev_neraseblocks() - Get the total number of eraseblocks |
9c3736a3 BB |
588 | * @nand: NAND device |
589 | * | |
590 | * Return: the total number of eraseblocks exposed by @nand. | |
591 | */ | |
592 | static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand) | |
593 | { | |
d098093b BB |
594 | return nand->memorg.ntargets * nand->memorg.luns_per_target * |
595 | nand->memorg.eraseblocks_per_lun; | |
9c3736a3 BB |
596 | } |
597 | ||
598 | /** | |
599 | * nanddev_size() - Get NAND size | |
600 | * @nand: NAND device | |
601 | * | |
602 | * Return: the total size (in bytes) exposed by @nand. | |
603 | */ | |
604 | static inline u64 nanddev_size(const struct nand_device *nand) | |
605 | { | |
606 | return nanddev_target_size(nand) * nanddev_ntargets(nand); | |
607 | } | |
608 | ||
609 | /** | |
610 | * nanddev_get_memorg() - Extract memory organization info from a NAND device | |
611 | * @nand: NAND device | |
612 | * | |
613 | * This can be used by the upper layer to fill the memorg info before calling | |
614 | * nanddev_init(). | |
615 | * | |
616 | * Return: the memorg object embedded in the NAND device. | |
617 | */ | |
618 | static inline struct nand_memory_organization * | |
619 | nanddev_get_memorg(struct nand_device *nand) | |
620 | { | |
621 | return &nand->memorg; | |
622 | } | |
623 | ||
d193792a MR |
624 | /** |
625 | * nanddev_get_ecc_conf() - Extract the ECC configuration from a NAND device | |
626 | * @nand: NAND device | |
627 | */ | |
628 | static inline const struct nand_ecc_props * | |
629 | nanddev_get_ecc_conf(struct nand_device *nand) | |
630 | { | |
93ef92f6 | 631 | return &nand->ecc.ctx.conf; |
d193792a MR |
632 | } |
633 | ||
e3554b10 MR |
634 | /** |
635 | * nanddev_get_ecc_nsteps() - Extract the number of ECC steps | |
636 | * @nand: NAND device | |
637 | */ | |
638 | static inline unsigned int | |
639 | nanddev_get_ecc_nsteps(struct nand_device *nand) | |
640 | { | |
641 | return nand->ecc.ctx.nsteps; | |
642 | } | |
643 | ||
ba4a40a4 MR |
644 | /** |
645 | * nanddev_get_ecc_bytes_per_step() - Extract the number of ECC bytes per step | |
646 | * @nand: NAND device | |
647 | */ | |
648 | static inline unsigned int | |
649 | nanddev_get_ecc_bytes_per_step(struct nand_device *nand) | |
650 | { | |
651 | return nand->ecc.ctx.total / nand->ecc.ctx.nsteps; | |
652 | } | |
653 | ||
3316c8e3 MR |
654 | /** |
655 | * nanddev_get_ecc_requirements() - Extract the ECC requirements from a NAND | |
656 | * device | |
657 | * @nand: NAND device | |
658 | */ | |
659 | static inline const struct nand_ecc_props * | |
660 | nanddev_get_ecc_requirements(struct nand_device *nand) | |
661 | { | |
93ef92f6 | 662 | return &nand->ecc.requirements; |
3316c8e3 MR |
663 | } |
664 | ||
665 | /** | |
666 | * nanddev_set_ecc_requirements() - Assign the ECC requirements of a NAND | |
667 | * device | |
668 | * @nand: NAND device | |
669 | * @reqs: Requirements | |
670 | */ | |
671 | static inline void | |
672 | nanddev_set_ecc_requirements(struct nand_device *nand, | |
673 | const struct nand_ecc_props *reqs) | |
674 | { | |
93ef92f6 | 675 | nand->ecc.requirements = *reqs; |
3316c8e3 MR |
676 | } |
677 | ||
9c3736a3 BB |
678 | int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, |
679 | struct module *owner); | |
680 | void nanddev_cleanup(struct nand_device *nand); | |
681 | ||
682 | /** | |
683 | * nanddev_register() - Register a NAND device | |
684 | * @nand: NAND device | |
685 | * | |
686 | * Register a NAND device. | |
687 | * This function is just a wrapper around mtd_device_register() | |
688 | * registering the MTD device embedded in @nand. | |
689 | * | |
690 | * Return: 0 in case of success, a negative error code otherwise. | |
691 | */ | |
692 | static inline int nanddev_register(struct nand_device *nand) | |
693 | { | |
694 | return mtd_device_register(&nand->mtd, NULL, 0); | |
695 | } | |
696 | ||
697 | /** | |
698 | * nanddev_unregister() - Unregister a NAND device | |
699 | * @nand: NAND device | |
700 | * | |
701 | * Unregister a NAND device. | |
702 | * This function is just a wrapper around mtd_device_unregister() | |
703 | * unregistering the MTD device embedded in @nand. | |
704 | * | |
705 | * Return: 0 in case of success, a negative error code otherwise. | |
706 | */ | |
707 | static inline int nanddev_unregister(struct nand_device *nand) | |
708 | { | |
709 | return mtd_device_unregister(&nand->mtd); | |
710 | } | |
711 | ||
712 | /** | |
713 | * nanddev_set_of_node() - Attach a DT node to a NAND device | |
714 | * @nand: NAND device | |
715 | * @np: DT node | |
716 | * | |
717 | * Attach a DT node to a NAND device. | |
718 | */ | |
719 | static inline void nanddev_set_of_node(struct nand_device *nand, | |
720 | struct device_node *np) | |
721 | { | |
722 | mtd_set_of_node(&nand->mtd, np); | |
723 | } | |
724 | ||
725 | /** | |
726 | * nanddev_get_of_node() - Retrieve the DT node attached to a NAND device | |
727 | * @nand: NAND device | |
728 | * | |
729 | * Return: the DT node attached to @nand. | |
730 | */ | |
731 | static inline struct device_node *nanddev_get_of_node(struct nand_device *nand) | |
732 | { | |
733 | return mtd_get_of_node(&nand->mtd); | |
734 | } | |
735 | ||
736 | /** | |
737 | * nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position | |
738 | * @nand: NAND device | |
739 | * @offs: absolute NAND offset (usually passed by the MTD layer) | |
740 | * @pos: a NAND position object to fill in | |
741 | * | |
742 | * Converts @offs into a nand_pos representation. | |
743 | * | |
744 | * Return: the offset within the NAND page pointed by @pos. | |
745 | */ | |
746 | static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand, | |
747 | loff_t offs, | |
748 | struct nand_pos *pos) | |
749 | { | |
750 | unsigned int pageoffs; | |
751 | u64 tmp = offs; | |
752 | ||
753 | pageoffs = do_div(tmp, nand->memorg.pagesize); | |
754 | pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock); | |
755 | pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun); | |
756 | pos->plane = pos->eraseblock % nand->memorg.planes_per_lun; | |
757 | pos->lun = do_div(tmp, nand->memorg.luns_per_target); | |
758 | pos->target = tmp; | |
759 | ||
760 | return pageoffs; | |
761 | } | |
762 | ||
763 | /** | |
764 | * nanddev_pos_cmp() - Compare two NAND positions | |
765 | * @a: First NAND position | |
766 | * @b: Second NAND position | |
767 | * | |
768 | * Compares two NAND positions. | |
769 | * | |
770 | * Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b. | |
771 | */ | |
772 | static inline int nanddev_pos_cmp(const struct nand_pos *a, | |
773 | const struct nand_pos *b) | |
774 | { | |
775 | if (a->target != b->target) | |
776 | return a->target < b->target ? -1 : 1; | |
777 | ||
778 | if (a->lun != b->lun) | |
779 | return a->lun < b->lun ? -1 : 1; | |
780 | ||
781 | if (a->eraseblock != b->eraseblock) | |
782 | return a->eraseblock < b->eraseblock ? -1 : 1; | |
783 | ||
784 | if (a->page != b->page) | |
785 | return a->page < b->page ? -1 : 1; | |
786 | ||
787 | return 0; | |
788 | } | |
789 | ||
790 | /** | |
791 | * nanddev_pos_to_offs() - Convert a NAND position into an absolute offset | |
792 | * @nand: NAND device | |
793 | * @pos: the NAND position to convert | |
794 | * | |
795 | * Converts @pos NAND position into an absolute offset. | |
796 | * | |
797 | * Return: the absolute offset. Note that @pos points to the beginning of a | |
798 | * page, if one wants to point to a specific offset within this page | |
799 | * the returned offset has to be adjusted manually. | |
800 | */ | |
801 | static inline loff_t nanddev_pos_to_offs(struct nand_device *nand, | |
802 | const struct nand_pos *pos) | |
803 | { | |
804 | unsigned int npages; | |
805 | ||
806 | npages = pos->page + | |
807 | ((pos->eraseblock + | |
808 | (pos->lun + | |
809 | (pos->target * nand->memorg.luns_per_target)) * | |
810 | nand->memorg.eraseblocks_per_lun) * | |
811 | nand->memorg.pages_per_eraseblock); | |
812 | ||
813 | return (loff_t)npages * nand->memorg.pagesize; | |
814 | } | |
815 | ||
816 | /** | |
817 | * nanddev_pos_to_row() - Extract a row address from a NAND position | |
818 | * @nand: NAND device | |
819 | * @pos: the position to convert | |
820 | * | |
821 | * Converts a NAND position into a row address that can then be passed to the | |
822 | * device. | |
823 | * | |
824 | * Return: the row address extracted from @pos. | |
825 | */ | |
826 | static inline unsigned int nanddev_pos_to_row(struct nand_device *nand, | |
827 | const struct nand_pos *pos) | |
828 | { | |
829 | return (pos->lun << nand->rowconv.lun_addr_shift) | | |
830 | (pos->eraseblock << nand->rowconv.eraseblock_addr_shift) | | |
831 | pos->page; | |
832 | } | |
833 | ||
834 | /** | |
835 | * nanddev_pos_next_target() - Move a position to the next target/die | |
836 | * @nand: NAND device | |
837 | * @pos: the position to update | |
838 | * | |
839 | * Updates @pos to point to the start of the next target/die. Useful when you | |
840 | * want to iterate over all targets/dies of a NAND device. | |
841 | */ | |
842 | static inline void nanddev_pos_next_target(struct nand_device *nand, | |
843 | struct nand_pos *pos) | |
844 | { | |
845 | pos->page = 0; | |
846 | pos->plane = 0; | |
847 | pos->eraseblock = 0; | |
848 | pos->lun = 0; | |
849 | pos->target++; | |
850 | } | |
851 | ||
852 | /** | |
853 | * nanddev_pos_next_lun() - Move a position to the next LUN | |
854 | * @nand: NAND device | |
855 | * @pos: the position to update | |
856 | * | |
857 | * Updates @pos to point to the start of the next LUN. Useful when you want to | |
858 | * iterate over all LUNs of a NAND device. | |
859 | */ | |
860 | static inline void nanddev_pos_next_lun(struct nand_device *nand, | |
861 | struct nand_pos *pos) | |
862 | { | |
863 | if (pos->lun >= nand->memorg.luns_per_target - 1) | |
864 | return nanddev_pos_next_target(nand, pos); | |
865 | ||
866 | pos->lun++; | |
867 | pos->page = 0; | |
868 | pos->plane = 0; | |
869 | pos->eraseblock = 0; | |
870 | } | |
871 | ||
872 | /** | |
873 | * nanddev_pos_next_eraseblock() - Move a position to the next eraseblock | |
874 | * @nand: NAND device | |
875 | * @pos: the position to update | |
876 | * | |
877 | * Updates @pos to point to the start of the next eraseblock. Useful when you | |
878 | * want to iterate over all eraseblocks of a NAND device. | |
879 | */ | |
880 | static inline void nanddev_pos_next_eraseblock(struct nand_device *nand, | |
881 | struct nand_pos *pos) | |
882 | { | |
883 | if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1) | |
884 | return nanddev_pos_next_lun(nand, pos); | |
885 | ||
886 | pos->eraseblock++; | |
887 | pos->page = 0; | |
888 | pos->plane = pos->eraseblock % nand->memorg.planes_per_lun; | |
889 | } | |
890 | ||
891 | /** | |
98ee3fc7 | 892 | * nanddev_pos_next_page() - Move a position to the next page |
9c3736a3 BB |
893 | * @nand: NAND device |
894 | * @pos: the position to update | |
895 | * | |
896 | * Updates @pos to point to the start of the next page. Useful when you want to | |
897 | * iterate over all pages of a NAND device. | |
898 | */ | |
899 | static inline void nanddev_pos_next_page(struct nand_device *nand, | |
900 | struct nand_pos *pos) | |
901 | { | |
902 | if (pos->page >= nand->memorg.pages_per_eraseblock - 1) | |
903 | return nanddev_pos_next_eraseblock(nand, pos); | |
904 | ||
905 | pos->page++; | |
906 | } | |
907 | ||
908 | /** | |
909 | * nand_io_iter_init - Initialize a NAND I/O iterator | |
910 | * @nand: NAND device | |
911 | * @offs: absolute offset | |
912 | * @req: MTD request | |
913 | * @iter: NAND I/O iterator | |
914 | * | |
915 | * Initializes a NAND iterator based on the information passed by the MTD | |
916 | * layer. | |
917 | */ | |
918 | static inline void nanddev_io_iter_init(struct nand_device *nand, | |
701981ca | 919 | enum nand_page_io_req_type reqtype, |
9c3736a3 BB |
920 | loff_t offs, struct mtd_oob_ops *req, |
921 | struct nand_io_iter *iter) | |
922 | { | |
923 | struct mtd_info *mtd = nanddev_to_mtd(nand); | |
924 | ||
701981ca | 925 | iter->req.type = reqtype; |
f567c71f | 926 | iter->req.mode = req->mode; |
9c3736a3 BB |
927 | iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos); |
928 | iter->req.ooboffs = req->ooboffs; | |
929 | iter->oobbytes_per_page = mtd_oobavail(mtd, req); | |
930 | iter->dataleft = req->len; | |
931 | iter->oobleft = req->ooblen; | |
932 | iter->req.databuf.in = req->datbuf; | |
933 | iter->req.datalen = min_t(unsigned int, | |
934 | nand->memorg.pagesize - iter->req.dataoffs, | |
935 | iter->dataleft); | |
936 | iter->req.oobbuf.in = req->oobbuf; | |
937 | iter->req.ooblen = min_t(unsigned int, | |
938 | iter->oobbytes_per_page - iter->req.ooboffs, | |
939 | iter->oobleft); | |
940 | } | |
941 | ||
942 | /** | |
943 | * nand_io_iter_next_page - Move to the next page | |
944 | * @nand: NAND device | |
945 | * @iter: NAND I/O iterator | |
946 | * | |
947 | * Updates the @iter to point to the next page. | |
948 | */ | |
949 | static inline void nanddev_io_iter_next_page(struct nand_device *nand, | |
950 | struct nand_io_iter *iter) | |
951 | { | |
952 | nanddev_pos_next_page(nand, &iter->req.pos); | |
953 | iter->dataleft -= iter->req.datalen; | |
954 | iter->req.databuf.in += iter->req.datalen; | |
955 | iter->oobleft -= iter->req.ooblen; | |
956 | iter->req.oobbuf.in += iter->req.ooblen; | |
957 | iter->req.dataoffs = 0; | |
958 | iter->req.ooboffs = 0; | |
959 | iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize, | |
960 | iter->dataleft); | |
961 | iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page, | |
962 | iter->oobleft); | |
963 | } | |
964 | ||
965 | /** | |
966 | * nand_io_iter_end - Should end iteration or not | |
967 | * @nand: NAND device | |
968 | * @iter: NAND I/O iterator | |
969 | * | |
970 | * Check whether @iter has reached the end of the NAND portion it was asked to | |
971 | * iterate on or not. | |
972 | * | |
973 | * Return: true if @iter has reached the end of the iteration request, false | |
974 | * otherwise. | |
975 | */ | |
976 | static inline bool nanddev_io_iter_end(struct nand_device *nand, | |
977 | const struct nand_io_iter *iter) | |
978 | { | |
979 | if (iter->dataleft || iter->oobleft) | |
980 | return false; | |
981 | ||
982 | return true; | |
983 | } | |
984 | ||
985 | /** | |
986 | * nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O | |
987 | * request | |
988 | * @nand: NAND device | |
989 | * @start: start address to read/write from | |
990 | * @req: MTD I/O request | |
991 | * @iter: NAND I/O iterator | |
992 | * | |
993 | * Should be used for iterate over pages that are contained in an MTD request. | |
994 | */ | |
701981ca MR |
995 | #define nanddev_io_for_each_page(nand, type, start, req, iter) \ |
996 | for (nanddev_io_iter_init(nand, type, start, req, iter); \ | |
9c3736a3 BB |
997 | !nanddev_io_iter_end(nand, iter); \ |
998 | nanddev_io_iter_next_page(nand, iter)) | |
999 | ||
1000 | bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos); | |
1001 | bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos); | |
9c3736a3 BB |
1002 | int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); |
1003 | ||
6b0c3b84 MR |
1004 | /* ECC related functions */ |
1005 | int nanddev_ecc_engine_init(struct nand_device *nand); | |
1006 | void nanddev_ecc_engine_cleanup(struct nand_device *nand); | |
1007 | ||
cda32a61 MR |
1008 | static inline void *nand_to_ecc_ctx(struct nand_device *nand) |
1009 | { | |
1010 | return nand->ecc.ctx.priv; | |
1011 | } | |
1012 | ||
9c3736a3 BB |
1013 | /* BBT related functions */ |
1014 | enum nand_bbt_block_status { | |
1015 | NAND_BBT_BLOCK_STATUS_UNKNOWN, | |
1016 | NAND_BBT_BLOCK_GOOD, | |
1017 | NAND_BBT_BLOCK_WORN, | |
1018 | NAND_BBT_BLOCK_RESERVED, | |
1019 | NAND_BBT_BLOCK_FACTORY_BAD, | |
1020 | NAND_BBT_BLOCK_NUM_STATUS, | |
1021 | }; | |
1022 | ||
1023 | int nanddev_bbt_init(struct nand_device *nand); | |
1024 | void nanddev_bbt_cleanup(struct nand_device *nand); | |
1025 | int nanddev_bbt_update(struct nand_device *nand); | |
1026 | int nanddev_bbt_get_block_status(const struct nand_device *nand, | |
1027 | unsigned int entry); | |
1028 | int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry, | |
1029 | enum nand_bbt_block_status status); | |
1030 | int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block); | |
1031 | ||
1032 | /** | |
1033 | * nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry | |
1034 | * @nand: NAND device | |
1035 | * @pos: the NAND position we want to get BBT entry for | |
1036 | * | |
1037 | * Return the BBT entry used to store information about the eraseblock pointed | |
1038 | * by @pos. | |
1039 | * | |
1040 | * Return: the BBT entry storing information about eraseblock pointed by @pos. | |
1041 | */ | |
1042 | static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand, | |
1043 | const struct nand_pos *pos) | |
1044 | { | |
1045 | return pos->eraseblock + | |
1046 | ((pos->lun + (pos->target * nand->memorg.luns_per_target)) * | |
1047 | nand->memorg.eraseblocks_per_lun); | |
1048 | } | |
1049 | ||
1050 | /** | |
1051 | * nanddev_bbt_is_initialized() - Check if the BBT has been initialized | |
1052 | * @nand: NAND device | |
1053 | * | |
1054 | * Return: true if the BBT has been initialized, false otherwise. | |
1055 | */ | |
1056 | static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) | |
1057 | { | |
1058 | return !!nand->bbt.cache; | |
1059 | } | |
1060 | ||
1061 | /* MTD -> NAND helper functions. */ | |
1062 | int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); | |
377e517b | 1063 | int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len); |
9c3736a3 BB |
1064 | |
1065 | #endif /* __LINUX_MTD_NAND_H */ |