| .. | .. |
|---|
| 12 | 12 | |
|---|
| 13 | 13 | #include <linux/mtd/mtd.h> |
|---|
| 14 | 14 | |
|---|
| 15 | +struct nand_device; |
|---|
| 16 | + |
|---|
| 15 | 17 | /** |
|---|
| 16 | 18 | * struct nand_memory_organization - Memory organization structure |
|---|
| 17 | 19 | * @bits_per_cell: number of bits per NAND cell |
|---|
| .. | .. |
|---|
| 19 | 21 | * @oobsize: OOB area size |
|---|
| 20 | 22 | * @pages_per_eraseblock: number of pages per eraseblock |
|---|
| 21 | 23 | * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number) |
|---|
| 24 | + * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN |
|---|
| 22 | 25 | * @planes_per_lun: number of planes per LUN |
|---|
| 23 | 26 | * @luns_per_target: number of LUN per target (target is a synonym for die) |
|---|
| 24 | 27 | * @ntargets: total number of targets exposed by the NAND device |
|---|
| .. | .. |
|---|
| 29 | 32 | unsigned int oobsize; |
|---|
| 30 | 33 | unsigned int pages_per_eraseblock; |
|---|
| 31 | 34 | unsigned int eraseblocks_per_lun; |
|---|
| 35 | + unsigned int max_bad_eraseblocks_per_lun; |
|---|
| 32 | 36 | unsigned int planes_per_lun; |
|---|
| 33 | 37 | unsigned int luns_per_target; |
|---|
| 34 | 38 | unsigned int ntargets; |
|---|
| 35 | 39 | }; |
|---|
| 36 | 40 | |
|---|
| 37 | | -#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt) \ |
|---|
| 41 | +#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt) \ |
|---|
| 38 | 42 | { \ |
|---|
| 39 | 43 | .bits_per_cell = (bpc), \ |
|---|
| 40 | 44 | .pagesize = (ps), \ |
|---|
| 41 | 45 | .oobsize = (os), \ |
|---|
| 42 | 46 | .pages_per_eraseblock = (ppe), \ |
|---|
| 43 | 47 | .eraseblocks_per_lun = (epl), \ |
|---|
| 48 | + .max_bad_eraseblocks_per_lun = (mbb), \ |
|---|
| 44 | 49 | .planes_per_lun = (ppl), \ |
|---|
| 45 | 50 | .luns_per_target = (lpt), \ |
|---|
| 46 | 51 | .ntargets = (nt), \ |
|---|
| .. | .. |
|---|
| 78 | 83 | }; |
|---|
| 79 | 84 | |
|---|
| 80 | 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 | + |
|---|
| 95 | +/** |
|---|
| 81 | 96 | * struct nand_page_io_req - NAND I/O request object |
|---|
| 97 | + * @type: the type of page I/O: read or write |
|---|
| 82 | 98 | * @pos: the position this I/O request is targeting |
|---|
| 83 | 99 | * @dataoffs: the offset within the page |
|---|
| 84 | 100 | * @datalen: number of data bytes to read from/write to this page |
|---|
| .. | .. |
|---|
| 94 | 110 | * specific commands/operations. |
|---|
| 95 | 111 | */ |
|---|
| 96 | 112 | struct nand_page_io_req { |
|---|
| 113 | + enum nand_page_io_req_type type; |
|---|
| 97 | 114 | struct nand_pos pos; |
|---|
| 98 | 115 | unsigned int dataoffs; |
|---|
| 99 | 116 | unsigned int datalen; |
|---|
| .. | .. |
|---|
| 110 | 127 | int mode; |
|---|
| 111 | 128 | }; |
|---|
| 112 | 129 | |
|---|
| 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 | + |
|---|
| 113 | 134 | /** |
|---|
| 114 | | - * struct nand_ecc_req - NAND ECC requirements |
|---|
| 115 | | - * @strength: ECC strength |
|---|
| 116 | | - * @step_size: ECC step/block size |
|---|
| 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 |
|---|
| 117 | 141 | */ |
|---|
| 118 | | -struct nand_ecc_req { |
|---|
| 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 | + |
|---|
| 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 | + |
|---|
| 178 | +/** |
|---|
| 179 | + * struct nand_ecc_props - NAND ECC properties |
|---|
| 180 | + * @engine_type: ECC engine type |
|---|
| 181 | + * @placement: OOB placement (if relevant) |
|---|
| 182 | + * @algo: ECC algorithm (if relevant) |
|---|
| 183 | + * @strength: ECC strength |
|---|
| 184 | + * @step_size: Number of bytes per step |
|---|
| 185 | + * @flags: Misc properties |
|---|
| 186 | + */ |
|---|
| 187 | +struct nand_ecc_props { |
|---|
| 188 | + enum nand_ecc_engine_type engine_type; |
|---|
| 189 | + enum nand_ecc_placement placement; |
|---|
| 190 | + enum nand_ecc_algo algo; |
|---|
| 119 | 191 | unsigned int strength; |
|---|
| 120 | 192 | unsigned int step_size; |
|---|
| 193 | + unsigned int flags; |
|---|
| 121 | 194 | }; |
|---|
| 122 | 195 | |
|---|
| 123 | 196 | #define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) } |
|---|
| 124 | 197 | |
|---|
| 198 | +/* NAND ECC misc flags */ |
|---|
| 199 | +#define NAND_ECC_MAXIMIZE_STRENGTH BIT(0) |
|---|
| 200 | + |
|---|
| 201 | +/* nand_bbt option */ |
|---|
| 202 | +#define NANDDEV_BBT_SCANNED BIT(0) |
|---|
| 203 | + |
|---|
| 204 | +/* The maximum number of blocks to scan for a bbt */ |
|---|
| 205 | +#define NANDDEV_BBT_SCAN_MAXBLOCKS 4 |
|---|
| 206 | + |
|---|
| 125 | 207 | /** |
|---|
| 126 | 208 | * struct nand_bbt - bad block table object |
|---|
| 127 | 209 | * @cache: in memory BBT cache |
|---|
| 210 | + * @option: the option of BBT |
|---|
| 211 | + * @version: current memory BBT cache version |
|---|
| 128 | 212 | */ |
|---|
| 129 | 213 | struct nand_bbt { |
|---|
| 130 | 214 | unsigned long *cache; |
|---|
| 215 | +#ifdef CONFIG_MTD_NAND_BBT_USING_FLASH |
|---|
| 216 | + unsigned int option; |
|---|
| 217 | + unsigned int version; |
|---|
| 218 | +#endif |
|---|
| 131 | 219 | }; |
|---|
| 132 | | - |
|---|
| 133 | | -struct nand_device; |
|---|
| 134 | 220 | |
|---|
| 135 | 221 | /** |
|---|
| 136 | 222 | * struct nand_ops - NAND operations |
|---|
| .. | .. |
|---|
| 155 | 241 | }; |
|---|
| 156 | 242 | |
|---|
| 157 | 243 | /** |
|---|
| 244 | + * struct nand_ecc_context - Context for the ECC engine |
|---|
| 245 | + * @conf: basic ECC engine parameters |
|---|
| 246 | + * @total: total number of bytes used for storing ECC codes, this is used by |
|---|
| 247 | + * generic OOB layouts |
|---|
| 248 | + * @priv: ECC engine driver private data |
|---|
| 249 | + */ |
|---|
| 250 | +struct nand_ecc_context { |
|---|
| 251 | + struct nand_ecc_props conf; |
|---|
| 252 | + unsigned int total; |
|---|
| 253 | + void *priv; |
|---|
| 254 | +}; |
|---|
| 255 | + |
|---|
| 256 | +/** |
|---|
| 257 | + * struct nand_ecc_engine_ops - ECC engine operations |
|---|
| 258 | + * @init_ctx: given a desired user configuration for the pointed NAND device, |
|---|
| 259 | + * requests the ECC engine driver to setup a configuration with |
|---|
| 260 | + * values it supports. |
|---|
| 261 | + * @cleanup_ctx: clean the context initialized by @init_ctx. |
|---|
| 262 | + * @prepare_io_req: is called before reading/writing a page to prepare the I/O |
|---|
| 263 | + * request to be performed with ECC correction. |
|---|
| 264 | + * @finish_io_req: is called after reading/writing a page to terminate the I/O |
|---|
| 265 | + * request and ensure proper ECC correction. |
|---|
| 266 | + */ |
|---|
| 267 | +struct nand_ecc_engine_ops { |
|---|
| 268 | + int (*init_ctx)(struct nand_device *nand); |
|---|
| 269 | + void (*cleanup_ctx)(struct nand_device *nand); |
|---|
| 270 | + int (*prepare_io_req)(struct nand_device *nand, |
|---|
| 271 | + struct nand_page_io_req *req); |
|---|
| 272 | + int (*finish_io_req)(struct nand_device *nand, |
|---|
| 273 | + struct nand_page_io_req *req); |
|---|
| 274 | +}; |
|---|
| 275 | + |
|---|
| 276 | +/** |
|---|
| 277 | + * struct nand_ecc_engine - ECC engine abstraction for NAND devices |
|---|
| 278 | + * @ops: ECC engine operations |
|---|
| 279 | + */ |
|---|
| 280 | +struct nand_ecc_engine { |
|---|
| 281 | + struct nand_ecc_engine_ops *ops; |
|---|
| 282 | +}; |
|---|
| 283 | + |
|---|
| 284 | +void of_get_nand_ecc_user_config(struct nand_device *nand); |
|---|
| 285 | +int nand_ecc_init_ctx(struct nand_device *nand); |
|---|
| 286 | +void nand_ecc_cleanup_ctx(struct nand_device *nand); |
|---|
| 287 | +int nand_ecc_prepare_io_req(struct nand_device *nand, |
|---|
| 288 | + struct nand_page_io_req *req); |
|---|
| 289 | +int nand_ecc_finish_io_req(struct nand_device *nand, |
|---|
| 290 | + struct nand_page_io_req *req); |
|---|
| 291 | +bool nand_ecc_is_strong_enough(struct nand_device *nand); |
|---|
| 292 | + |
|---|
| 293 | +/** |
|---|
| 294 | + * struct nand_ecc - Information relative to the ECC |
|---|
| 295 | + * @defaults: Default values, depend on the underlying subsystem |
|---|
| 296 | + * @requirements: ECC requirements from the NAND chip perspective |
|---|
| 297 | + * @user_conf: User desires in terms of ECC parameters |
|---|
| 298 | + * @ctx: ECC context for the ECC engine, derived from the device @requirements |
|---|
| 299 | + * the @user_conf and the @defaults |
|---|
| 300 | + * @ondie_engine: On-die ECC engine reference, if any |
|---|
| 301 | + * @engine: ECC engine actually bound |
|---|
| 302 | + */ |
|---|
| 303 | +struct nand_ecc { |
|---|
| 304 | + struct nand_ecc_props defaults; |
|---|
| 305 | + struct nand_ecc_props requirements; |
|---|
| 306 | + struct nand_ecc_props user_conf; |
|---|
| 307 | + struct nand_ecc_context ctx; |
|---|
| 308 | + struct nand_ecc_engine *ondie_engine; |
|---|
| 309 | + struct nand_ecc_engine *engine; |
|---|
| 310 | +}; |
|---|
| 311 | + |
|---|
| 312 | +/** |
|---|
| 158 | 313 | * struct nand_device - NAND device |
|---|
| 159 | 314 | * @mtd: MTD instance attached to the NAND device |
|---|
| 160 | 315 | * @memorg: memory layout |
|---|
| 161 | | - * @eccreq: ECC requirements |
|---|
| 316 | + * @ecc: NAND ECC object attached to the NAND device |
|---|
| 162 | 317 | * @rowconv: position to row address converter |
|---|
| 163 | 318 | * @bbt: bad block table info |
|---|
| 164 | 319 | * @ops: NAND operations attached to the NAND device |
|---|
| .. | .. |
|---|
| 166 | 321 | * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND) |
|---|
| 167 | 322 | * should declare their own NAND object embedding a nand_device struct (that's |
|---|
| 168 | 323 | * how inheritance is done). |
|---|
| 169 | | - * struct_nand_device->memorg and struct_nand_device->eccreq should be filled |
|---|
| 170 | | - * at device detection time to reflect the NAND device |
|---|
| 324 | + * struct_nand_device->memorg and struct_nand_device->ecc.requirements should |
|---|
| 325 | + * be filled at device detection time to reflect the NAND device |
|---|
| 171 | 326 | * capabilities/requirements. Once this is done nanddev_init() can be called. |
|---|
| 172 | 327 | * It will take care of converting NAND information into MTD ones, which means |
|---|
| 173 | 328 | * the specialized NAND layers should never manually tweak |
|---|
| .. | .. |
|---|
| 176 | 331 | struct nand_device { |
|---|
| 177 | 332 | struct mtd_info mtd; |
|---|
| 178 | 333 | struct nand_memory_organization memorg; |
|---|
| 179 | | - struct nand_ecc_req eccreq; |
|---|
| 334 | + struct nand_ecc ecc; |
|---|
| 180 | 335 | struct nand_row_converter rowconv; |
|---|
| 181 | 336 | struct nand_bbt bbt; |
|---|
| 182 | 337 | const struct nand_ops *ops; |
|---|
| .. | .. |
|---|
| 269 | 424 | } |
|---|
| 270 | 425 | |
|---|
| 271 | 426 | /** |
|---|
| 427 | + * nanddev_pages_per_target() - Get the number of pages per target |
|---|
| 428 | + * @nand: NAND device |
|---|
| 429 | + * |
|---|
| 430 | + * Return: the number of pages per target. |
|---|
| 431 | + */ |
|---|
| 432 | +static inline unsigned int |
|---|
| 433 | +nanddev_pages_per_target(const struct nand_device *nand) |
|---|
| 434 | +{ |
|---|
| 435 | + return nand->memorg.pages_per_eraseblock * |
|---|
| 436 | + nand->memorg.eraseblocks_per_lun * |
|---|
| 437 | + nand->memorg.luns_per_target; |
|---|
| 438 | +} |
|---|
| 439 | + |
|---|
| 440 | +/** |
|---|
| 272 | 441 | * nanddev_per_page_oobsize() - Get NAND erase block size |
|---|
| 273 | 442 | * @nand: NAND device |
|---|
| 274 | 443 | * |
|---|
| .. | .. |
|---|
| 289 | 458 | nanddev_eraseblocks_per_lun(const struct nand_device *nand) |
|---|
| 290 | 459 | { |
|---|
| 291 | 460 | return nand->memorg.eraseblocks_per_lun; |
|---|
| 461 | +} |
|---|
| 462 | + |
|---|
| 463 | +/** |
|---|
| 464 | + * nanddev_eraseblocks_per_target() - Get the number of eraseblocks per target |
|---|
| 465 | + * @nand: NAND device |
|---|
| 466 | + * |
|---|
| 467 | + * Return: the number of eraseblocks per target. |
|---|
| 468 | + */ |
|---|
| 469 | +static inline unsigned int |
|---|
| 470 | +nanddev_eraseblocks_per_target(const struct nand_device *nand) |
|---|
| 471 | +{ |
|---|
| 472 | + return nand->memorg.eraseblocks_per_lun * nand->memorg.luns_per_target; |
|---|
| 292 | 473 | } |
|---|
| 293 | 474 | |
|---|
| 294 | 475 | /** |
|---|
| .. | .. |
|---|
| 317 | 498 | } |
|---|
| 318 | 499 | |
|---|
| 319 | 500 | /** |
|---|
| 320 | | - * nanddev_neraseblocks() - Get the total number of erasablocks |
|---|
| 501 | + * nanddev_neraseblocks() - Get the total number of eraseblocks |
|---|
| 321 | 502 | * @nand: NAND device |
|---|
| 322 | 503 | * |
|---|
| 323 | 504 | * Return: the total number of eraseblocks exposed by @nand. |
|---|
| .. | .. |
|---|
| 352 | 533 | nanddev_get_memorg(struct nand_device *nand) |
|---|
| 353 | 534 | { |
|---|
| 354 | 535 | return &nand->memorg; |
|---|
| 536 | +} |
|---|
| 537 | + |
|---|
| 538 | +/** |
|---|
| 539 | + * nanddev_get_ecc_conf() - Extract the ECC configuration from a NAND device |
|---|
| 540 | + * @nand: NAND device |
|---|
| 541 | + */ |
|---|
| 542 | +static inline const struct nand_ecc_props * |
|---|
| 543 | +nanddev_get_ecc_conf(struct nand_device *nand) |
|---|
| 544 | +{ |
|---|
| 545 | + return &nand->ecc.ctx.conf; |
|---|
| 546 | +} |
|---|
| 547 | + |
|---|
| 548 | +/** |
|---|
| 549 | + * nanddev_get_ecc_requirements() - Extract the ECC requirements from a NAND |
|---|
| 550 | + * device |
|---|
| 551 | + * @nand: NAND device |
|---|
| 552 | + */ |
|---|
| 553 | +static inline const struct nand_ecc_props * |
|---|
| 554 | +nanddev_get_ecc_requirements(struct nand_device *nand) |
|---|
| 555 | +{ |
|---|
| 556 | + return &nand->ecc.requirements; |
|---|
| 557 | +} |
|---|
| 558 | + |
|---|
| 559 | +/** |
|---|
| 560 | + * nanddev_set_ecc_requirements() - Assign the ECC requirements of a NAND |
|---|
| 561 | + * device |
|---|
| 562 | + * @nand: NAND device |
|---|
| 563 | + * @reqs: Requirements |
|---|
| 564 | + */ |
|---|
| 565 | +static inline void |
|---|
| 566 | +nanddev_set_ecc_requirements(struct nand_device *nand, |
|---|
| 567 | + const struct nand_ecc_props *reqs) |
|---|
| 568 | +{ |
|---|
| 569 | + nand->ecc.requirements = *reqs; |
|---|
| 355 | 570 | } |
|---|
| 356 | 571 | |
|---|
| 357 | 572 | int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, |
|---|
| .. | .. |
|---|
| 595 | 810 | * layer. |
|---|
| 596 | 811 | */ |
|---|
| 597 | 812 | static inline void nanddev_io_iter_init(struct nand_device *nand, |
|---|
| 813 | + enum nand_page_io_req_type reqtype, |
|---|
| 598 | 814 | loff_t offs, struct mtd_oob_ops *req, |
|---|
| 599 | 815 | struct nand_io_iter *iter) |
|---|
| 600 | 816 | { |
|---|
| 601 | 817 | struct mtd_info *mtd = nanddev_to_mtd(nand); |
|---|
| 602 | 818 | |
|---|
| 819 | + iter->req.type = reqtype; |
|---|
| 603 | 820 | iter->req.mode = req->mode; |
|---|
| 604 | 821 | iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos); |
|---|
| 605 | 822 | iter->req.ooboffs = req->ooboffs; |
|---|
| .. | .. |
|---|
| 669 | 886 | * |
|---|
| 670 | 887 | * Should be used for iterate over pages that are contained in an MTD request. |
|---|
| 671 | 888 | */ |
|---|
| 672 | | -#define nanddev_io_for_each_page(nand, start, req, iter) \ |
|---|
| 673 | | - for (nanddev_io_iter_init(nand, start, req, iter); \ |
|---|
| 889 | +#define nanddev_io_for_each_page(nand, type, start, req, iter) \ |
|---|
| 890 | + for (nanddev_io_iter_init(nand, type, start, req, iter); \ |
|---|
| 674 | 891 | !nanddev_io_iter_end(nand, iter); \ |
|---|
| 675 | 892 | nanddev_io_iter_next_page(nand, iter)) |
|---|
| 676 | 893 | |
|---|
| .. | .. |
|---|
| 729 | 946 | |
|---|
| 730 | 947 | /* MTD -> NAND helper functions. */ |
|---|
| 731 | 948 | int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); |
|---|
| 949 | +int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len); |
|---|
| 732 | 950 | |
|---|
| 733 | 951 | #endif /* __LINUX_MTD_NAND_H */ |
|---|