1ed99f773SBoris Brezillon /* SPDX-License-Identifier: GPL-2.0 */ 2ed99f773SBoris Brezillon /* 3ed99f773SBoris Brezillon * Copyright 2017 - Free Electrons 4ed99f773SBoris Brezillon * 5ed99f773SBoris Brezillon * Authors: 6ed99f773SBoris Brezillon * Boris Brezillon <boris.brezillon@free-electrons.com> 7ed99f773SBoris Brezillon * Peter Pan <peterpandong@micron.com> 8ed99f773SBoris Brezillon */ 9ed99f773SBoris Brezillon 10ed99f773SBoris Brezillon #ifndef __LINUX_MTD_NAND_H 11ed99f773SBoris Brezillon #define __LINUX_MTD_NAND_H 12ed99f773SBoris Brezillon 13ed99f773SBoris Brezillon #include <linux/mtd/mtd.h> 14ed99f773SBoris Brezillon 15ed99f773SBoris Brezillon /** 16ed99f773SBoris Brezillon * struct nand_memory_organization - Memory organization structure 17ed99f773SBoris Brezillon * @bits_per_cell: number of bits per NAND cell 18ed99f773SBoris Brezillon * @pagesize: page size 19ed99f773SBoris Brezillon * @oobsize: OOB area size 20ed99f773SBoris Brezillon * @pages_per_eraseblock: number of pages per eraseblock 21ed99f773SBoris Brezillon * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number) 22ed99f773SBoris Brezillon * @planes_per_lun: number of planes per LUN 23ed99f773SBoris Brezillon * @luns_per_target: number of LUN per target (target is a synonym for die) 24ed99f773SBoris Brezillon * @ntargets: total number of targets exposed by the NAND device 25ed99f773SBoris Brezillon */ 26ed99f773SBoris Brezillon struct nand_memory_organization { 27ed99f773SBoris Brezillon unsigned int bits_per_cell; 28ed99f773SBoris Brezillon unsigned int pagesize; 29ed99f773SBoris Brezillon unsigned int oobsize; 30ed99f773SBoris Brezillon unsigned int pages_per_eraseblock; 31ed99f773SBoris Brezillon unsigned int eraseblocks_per_lun; 32ed99f773SBoris Brezillon unsigned int planes_per_lun; 33ed99f773SBoris Brezillon unsigned int luns_per_target; 34ed99f773SBoris Brezillon unsigned int ntargets; 35ed99f773SBoris Brezillon }; 36ed99f773SBoris Brezillon 37ed99f773SBoris Brezillon #define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt) \ 38ed99f773SBoris Brezillon { \ 39ed99f773SBoris Brezillon .bits_per_cell = (bpc), \ 40ed99f773SBoris Brezillon .pagesize = (ps), \ 41ed99f773SBoris Brezillon .oobsize = (os), \ 42ed99f773SBoris Brezillon .pages_per_eraseblock = (ppe), \ 43ed99f773SBoris Brezillon .eraseblocks_per_lun = (epl), \ 44ed99f773SBoris Brezillon .planes_per_lun = (ppl), \ 45ed99f773SBoris Brezillon .luns_per_target = (lpt), \ 46ed99f773SBoris Brezillon .ntargets = (nt), \ 47ed99f773SBoris Brezillon } 48ed99f773SBoris Brezillon 49ed99f773SBoris Brezillon /** 50ed99f773SBoris Brezillon * struct nand_row_converter - Information needed to convert an absolute offset 51ed99f773SBoris Brezillon * into a row address 52ed99f773SBoris Brezillon * @lun_addr_shift: position of the LUN identifier in the row address 53ed99f773SBoris Brezillon * @eraseblock_addr_shift: position of the eraseblock identifier in the row 54ed99f773SBoris Brezillon * address 55ed99f773SBoris Brezillon */ 56ed99f773SBoris Brezillon struct nand_row_converter { 57ed99f773SBoris Brezillon unsigned int lun_addr_shift; 58ed99f773SBoris Brezillon unsigned int eraseblock_addr_shift; 59ed99f773SBoris Brezillon }; 60ed99f773SBoris Brezillon 61ed99f773SBoris Brezillon /** 62ed99f773SBoris Brezillon * struct nand_pos - NAND position object 63ed99f773SBoris Brezillon * @target: the NAND target/die 64ed99f773SBoris Brezillon * @lun: the LUN identifier 65ed99f773SBoris Brezillon * @plane: the plane within the LUN 66ed99f773SBoris Brezillon * @eraseblock: the eraseblock within the LUN 67ed99f773SBoris Brezillon * @page: the page within the LUN 68ed99f773SBoris Brezillon * 69ed99f773SBoris Brezillon * These information are usually used by specific sub-layers to select the 70ed99f773SBoris Brezillon * appropriate target/die and generate a row address to pass to the device. 71ed99f773SBoris Brezillon */ 72ed99f773SBoris Brezillon struct nand_pos { 73ed99f773SBoris Brezillon unsigned int target; 74ed99f773SBoris Brezillon unsigned int lun; 75ed99f773SBoris Brezillon unsigned int plane; 76ed99f773SBoris Brezillon unsigned int eraseblock; 77ed99f773SBoris Brezillon unsigned int page; 78ed99f773SBoris Brezillon }; 79ed99f773SBoris Brezillon 80ed99f773SBoris Brezillon /** 81ed99f773SBoris Brezillon * struct nand_page_io_req - NAND I/O request object 82ed99f773SBoris Brezillon * @pos: the position this I/O request is targeting 83ed99f773SBoris Brezillon * @dataoffs: the offset within the page 84ed99f773SBoris Brezillon * @datalen: number of data bytes to read from/write to this page 85ed99f773SBoris Brezillon * @databuf: buffer to store data in or get data from 86ed99f773SBoris Brezillon * @ooboffs: the OOB offset within the page 87ed99f773SBoris Brezillon * @ooblen: the number of OOB bytes to read from/write to this page 88ed99f773SBoris Brezillon * @oobbuf: buffer to store OOB data in or get OOB data from 8987a1a21dSBoris Brezillon * @mode: one of the %MTD_OPS_XXX mode 90ed99f773SBoris Brezillon * 91ed99f773SBoris Brezillon * This object is used to pass per-page I/O requests to NAND sub-layers. This 92ed99f773SBoris Brezillon * way all useful information are already formatted in a useful way and 93ed99f773SBoris Brezillon * specific NAND layers can focus on translating these information into 94ed99f773SBoris Brezillon * specific commands/operations. 95ed99f773SBoris Brezillon */ 96ed99f773SBoris Brezillon struct nand_page_io_req { 97ed99f773SBoris Brezillon struct nand_pos pos; 98ed99f773SBoris Brezillon unsigned int dataoffs; 99ed99f773SBoris Brezillon unsigned int datalen; 100ed99f773SBoris Brezillon union { 101ed99f773SBoris Brezillon const void *out; 102ed99f773SBoris Brezillon void *in; 103ed99f773SBoris Brezillon } databuf; 104ed99f773SBoris Brezillon unsigned int ooboffs; 105ed99f773SBoris Brezillon unsigned int ooblen; 106ed99f773SBoris Brezillon union { 107ed99f773SBoris Brezillon const void *out; 108ed99f773SBoris Brezillon void *in; 109ed99f773SBoris Brezillon } oobbuf; 11087a1a21dSBoris Brezillon int mode; 111ed99f773SBoris Brezillon }; 112ed99f773SBoris Brezillon 113ed99f773SBoris Brezillon /** 114ed99f773SBoris Brezillon * struct nand_ecc_req - NAND ECC requirements 115ed99f773SBoris Brezillon * @strength: ECC strength 116ed99f773SBoris Brezillon * @step_size: ECC step/block size 117ed99f773SBoris Brezillon */ 118ed99f773SBoris Brezillon struct nand_ecc_req { 119ed99f773SBoris Brezillon unsigned int strength; 120ed99f773SBoris Brezillon unsigned int step_size; 121ed99f773SBoris Brezillon }; 122ed99f773SBoris Brezillon 123ed99f773SBoris Brezillon #define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) } 124ed99f773SBoris Brezillon 125ed99f773SBoris Brezillon /** 126ed99f773SBoris Brezillon * struct nand_bbt - bad block table object 127ed99f773SBoris Brezillon * @cache: in memory BBT cache 128ed99f773SBoris Brezillon */ 129ed99f773SBoris Brezillon struct nand_bbt { 130ed99f773SBoris Brezillon unsigned long *cache; 131ed99f773SBoris Brezillon }; 132ed99f773SBoris Brezillon 133ed99f773SBoris Brezillon struct nand_device; 134ed99f773SBoris Brezillon 135ed99f773SBoris Brezillon /** 136ed99f773SBoris Brezillon * struct nand_ops - NAND operations 137ed99f773SBoris Brezillon * @erase: erase a specific block. No need to check if the block is bad before 138ed99f773SBoris Brezillon * erasing, this has been taken care of by the generic NAND layer 139ed99f773SBoris Brezillon * @markbad: mark a specific block bad. No need to check if the block is 140ed99f773SBoris Brezillon * already marked bad, this has been taken care of by the generic 141ed99f773SBoris Brezillon * NAND layer. This method should just write the BBM (Bad Block 142ed99f773SBoris Brezillon * Marker) so that future call to struct_nand_ops->isbad() return 143ed99f773SBoris Brezillon * true 144ed99f773SBoris Brezillon * @isbad: check whether a block is bad or not. This method should just read 145ed99f773SBoris Brezillon * the BBM and return whether the block is bad or not based on what it 146ed99f773SBoris Brezillon * reads 147ed99f773SBoris Brezillon * 148ed99f773SBoris Brezillon * These are all low level operations that should be implemented by specialized 149ed99f773SBoris Brezillon * NAND layers (SPI NAND, raw NAND, ...). 150ed99f773SBoris Brezillon */ 151ed99f773SBoris Brezillon struct nand_ops { 152ed99f773SBoris Brezillon int (*erase)(struct nand_device *nand, const struct nand_pos *pos); 153ed99f773SBoris Brezillon int (*markbad)(struct nand_device *nand, const struct nand_pos *pos); 154ed99f773SBoris Brezillon bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos); 155ed99f773SBoris Brezillon }; 156ed99f773SBoris Brezillon 157ed99f773SBoris Brezillon /** 158ed99f773SBoris Brezillon * struct nand_device - NAND device 159ed99f773SBoris Brezillon * @mtd: MTD instance attached to the NAND device 160ed99f773SBoris Brezillon * @memorg: memory layout 161ed99f773SBoris Brezillon * @eccreq: ECC requirements 162ed99f773SBoris Brezillon * @rowconv: position to row address converter 163ed99f773SBoris Brezillon * @bbt: bad block table info 164ed99f773SBoris Brezillon * @ops: NAND operations attached to the NAND device 165ed99f773SBoris Brezillon * 166ed99f773SBoris Brezillon * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND) 167ed99f773SBoris Brezillon * should declare their own NAND object embedding a nand_device struct (that's 168ed99f773SBoris Brezillon * how inheritance is done). 169ed99f773SBoris Brezillon * struct_nand_device->memorg and struct_nand_device->eccreq should be filled 170ed99f773SBoris Brezillon * at device detection time to reflect the NAND device 171ed99f773SBoris Brezillon * capabilities/requirements. Once this is done nanddev_init() can be called. 172ed99f773SBoris Brezillon * It will take care of converting NAND information into MTD ones, which means 173ed99f773SBoris Brezillon * the specialized NAND layers should never manually tweak 174ed99f773SBoris Brezillon * struct_nand_device->mtd except for the ->_read/write() hooks. 175ed99f773SBoris Brezillon */ 176ed99f773SBoris Brezillon struct nand_device { 177ed99f773SBoris Brezillon struct mtd_info *mtd; 178ed99f773SBoris Brezillon struct nand_memory_organization memorg; 179ed99f773SBoris Brezillon struct nand_ecc_req eccreq; 180ed99f773SBoris Brezillon struct nand_row_converter rowconv; 181ed99f773SBoris Brezillon struct nand_bbt bbt; 182ed99f773SBoris Brezillon const struct nand_ops *ops; 183ed99f773SBoris Brezillon }; 184ed99f773SBoris Brezillon 185ed99f773SBoris Brezillon /** 186ed99f773SBoris Brezillon * struct nand_io_iter - NAND I/O iterator 187ed99f773SBoris Brezillon * @req: current I/O request 188ed99f773SBoris Brezillon * @oobbytes_per_page: maximum number of OOB bytes per page 189ed99f773SBoris Brezillon * @dataleft: remaining number of data bytes to read/write 190ed99f773SBoris Brezillon * @oobleft: remaining number of OOB bytes to read/write 191ed99f773SBoris Brezillon * 192ed99f773SBoris Brezillon * Can be used by specialized NAND layers to iterate over all pages covered 193ed99f773SBoris Brezillon * by an MTD I/O request, which should greatly simplifies the boiler-plate 194ed99f773SBoris Brezillon * code needed to read/write data from/to a NAND device. 195ed99f773SBoris Brezillon */ 196ed99f773SBoris Brezillon struct nand_io_iter { 197ed99f773SBoris Brezillon struct nand_page_io_req req; 198ed99f773SBoris Brezillon unsigned int oobbytes_per_page; 199ed99f773SBoris Brezillon unsigned int dataleft; 200ed99f773SBoris Brezillon unsigned int oobleft; 201ed99f773SBoris Brezillon }; 202ed99f773SBoris Brezillon 203ed99f773SBoris Brezillon /** 204ed99f773SBoris Brezillon * mtd_to_nanddev() - Get the NAND device attached to the MTD instance 205ed99f773SBoris Brezillon * @mtd: MTD instance 206ed99f773SBoris Brezillon * 207ed99f773SBoris Brezillon * Return: the NAND device embedding @mtd. 208ed99f773SBoris Brezillon */ 209ed99f773SBoris Brezillon static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd) 210ed99f773SBoris Brezillon { 211ed99f773SBoris Brezillon return mtd->priv; 212ed99f773SBoris Brezillon } 213ed99f773SBoris Brezillon 214ed99f773SBoris Brezillon /** 215ed99f773SBoris Brezillon * nanddev_to_mtd() - Get the MTD device attached to a NAND device 216ed99f773SBoris Brezillon * @nand: NAND device 217ed99f773SBoris Brezillon * 218ed99f773SBoris Brezillon * Return: the MTD device embedded in @nand. 219ed99f773SBoris Brezillon */ 220ed99f773SBoris Brezillon static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand) 221ed99f773SBoris Brezillon { 222ed99f773SBoris Brezillon return nand->mtd; 223ed99f773SBoris Brezillon } 224ed99f773SBoris Brezillon 225ed99f773SBoris Brezillon /* 226ed99f773SBoris Brezillon * nanddev_bits_per_cell() - Get the number of bits per cell 227ed99f773SBoris Brezillon * @nand: NAND device 228ed99f773SBoris Brezillon * 229ed99f773SBoris Brezillon * Return: the number of bits per cell. 230ed99f773SBoris Brezillon */ 231ed99f773SBoris Brezillon static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand) 232ed99f773SBoris Brezillon { 233ed99f773SBoris Brezillon return nand->memorg.bits_per_cell; 234ed99f773SBoris Brezillon } 235ed99f773SBoris Brezillon 236ed99f773SBoris Brezillon /** 237ed99f773SBoris Brezillon * nanddev_page_size() - Get NAND page size 238ed99f773SBoris Brezillon * @nand: NAND device 239ed99f773SBoris Brezillon * 240ed99f773SBoris Brezillon * Return: the page size. 241ed99f773SBoris Brezillon */ 242ed99f773SBoris Brezillon static inline size_t nanddev_page_size(const struct nand_device *nand) 243ed99f773SBoris Brezillon { 244ed99f773SBoris Brezillon return nand->memorg.pagesize; 245ed99f773SBoris Brezillon } 246ed99f773SBoris Brezillon 247ed99f773SBoris Brezillon /** 248ed99f773SBoris Brezillon * nanddev_per_page_oobsize() - Get NAND OOB size 249ed99f773SBoris Brezillon * @nand: NAND device 250ed99f773SBoris Brezillon * 251ed99f773SBoris Brezillon * Return: the OOB size. 252ed99f773SBoris Brezillon */ 253ed99f773SBoris Brezillon static inline unsigned int 254ed99f773SBoris Brezillon nanddev_per_page_oobsize(const struct nand_device *nand) 255ed99f773SBoris Brezillon { 256ed99f773SBoris Brezillon return nand->memorg.oobsize; 257ed99f773SBoris Brezillon } 258ed99f773SBoris Brezillon 259ed99f773SBoris Brezillon /** 260ed99f773SBoris Brezillon * nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock 261ed99f773SBoris Brezillon * @nand: NAND device 262ed99f773SBoris Brezillon * 263ed99f773SBoris Brezillon * Return: the number of pages per eraseblock. 264ed99f773SBoris Brezillon */ 265ed99f773SBoris Brezillon static inline unsigned int 266ed99f773SBoris Brezillon nanddev_pages_per_eraseblock(const struct nand_device *nand) 267ed99f773SBoris Brezillon { 268ed99f773SBoris Brezillon return nand->memorg.pages_per_eraseblock; 269ed99f773SBoris Brezillon } 270ed99f773SBoris Brezillon 271ed99f773SBoris Brezillon /** 272ed99f773SBoris Brezillon * nanddev_per_page_oobsize() - Get NAND erase block size 273ed99f773SBoris Brezillon * @nand: NAND device 274ed99f773SBoris Brezillon * 275ed99f773SBoris Brezillon * Return: the eraseblock size. 276ed99f773SBoris Brezillon */ 277ed99f773SBoris Brezillon static inline size_t nanddev_eraseblock_size(const struct nand_device *nand) 278ed99f773SBoris Brezillon { 279ed99f773SBoris Brezillon return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock; 280ed99f773SBoris Brezillon } 281ed99f773SBoris Brezillon 282ed99f773SBoris Brezillon /** 283ed99f773SBoris Brezillon * nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN 284ed99f773SBoris Brezillon * @nand: NAND device 285ed99f773SBoris Brezillon * 286ed99f773SBoris Brezillon * Return: the number of eraseblocks per LUN. 287ed99f773SBoris Brezillon */ 288ed99f773SBoris Brezillon static inline unsigned int 289ed99f773SBoris Brezillon nanddev_eraseblocks_per_lun(const struct nand_device *nand) 290ed99f773SBoris Brezillon { 291ed99f773SBoris Brezillon return nand->memorg.eraseblocks_per_lun; 292ed99f773SBoris Brezillon } 293ed99f773SBoris Brezillon 294ed99f773SBoris Brezillon /** 295ed99f773SBoris Brezillon * nanddev_target_size() - Get the total size provided by a single target/die 296ed99f773SBoris Brezillon * @nand: NAND device 297ed99f773SBoris Brezillon * 298ed99f773SBoris Brezillon * Return: the total size exposed by a single target/die in bytes. 299ed99f773SBoris Brezillon */ 300ed99f773SBoris Brezillon static inline u64 nanddev_target_size(const struct nand_device *nand) 301ed99f773SBoris Brezillon { 302ed99f773SBoris Brezillon return (u64)nand->memorg.luns_per_target * 303ed99f773SBoris Brezillon nand->memorg.eraseblocks_per_lun * 304ed99f773SBoris Brezillon nand->memorg.pages_per_eraseblock * 305ed99f773SBoris Brezillon nand->memorg.pagesize; 306ed99f773SBoris Brezillon } 307ed99f773SBoris Brezillon 308ed99f773SBoris Brezillon /** 309ed99f773SBoris Brezillon * nanddev_ntarget() - Get the total of targets 310ed99f773SBoris Brezillon * @nand: NAND device 311ed99f773SBoris Brezillon * 312ed99f773SBoris Brezillon * Return: the number of targets/dies exposed by @nand. 313ed99f773SBoris Brezillon */ 314ed99f773SBoris Brezillon static inline unsigned int nanddev_ntargets(const struct nand_device *nand) 315ed99f773SBoris Brezillon { 316ed99f773SBoris Brezillon return nand->memorg.ntargets; 317ed99f773SBoris Brezillon } 318ed99f773SBoris Brezillon 319ed99f773SBoris Brezillon /** 320ed99f773SBoris Brezillon * nanddev_neraseblocks() - Get the total number of erasablocks 321ed99f773SBoris Brezillon * @nand: NAND device 322ed99f773SBoris Brezillon * 323ed99f773SBoris Brezillon * Return: the total number of eraseblocks exposed by @nand. 324ed99f773SBoris Brezillon */ 325ed99f773SBoris Brezillon static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand) 326ed99f773SBoris Brezillon { 327*85c83705SJon Lin return nand->memorg.ntargets * nand->memorg.luns_per_target * 328*85c83705SJon Lin nand->memorg.eraseblocks_per_lun; 329ed99f773SBoris Brezillon } 330ed99f773SBoris Brezillon 331ed99f773SBoris Brezillon /** 332ed99f773SBoris Brezillon * nanddev_size() - Get NAND size 333ed99f773SBoris Brezillon * @nand: NAND device 334ed99f773SBoris Brezillon * 335ed99f773SBoris Brezillon * Return: the total size (in bytes) exposed by @nand. 336ed99f773SBoris Brezillon */ 337ed99f773SBoris Brezillon static inline u64 nanddev_size(const struct nand_device *nand) 338ed99f773SBoris Brezillon { 339ed99f773SBoris Brezillon return nanddev_target_size(nand) * nanddev_ntargets(nand); 340ed99f773SBoris Brezillon } 341ed99f773SBoris Brezillon 342ed99f773SBoris Brezillon /** 343ed99f773SBoris Brezillon * nanddev_get_memorg() - Extract memory organization info from a NAND device 344ed99f773SBoris Brezillon * @nand: NAND device 345ed99f773SBoris Brezillon * 346ed99f773SBoris Brezillon * This can be used by the upper layer to fill the memorg info before calling 347ed99f773SBoris Brezillon * nanddev_init(). 348ed99f773SBoris Brezillon * 349ed99f773SBoris Brezillon * Return: the memorg object embedded in the NAND device. 350ed99f773SBoris Brezillon */ 351ed99f773SBoris Brezillon static inline struct nand_memory_organization * 352ed99f773SBoris Brezillon nanddev_get_memorg(struct nand_device *nand) 353ed99f773SBoris Brezillon { 354ed99f773SBoris Brezillon return &nand->memorg; 355ed99f773SBoris Brezillon } 356ed99f773SBoris Brezillon 357ed99f773SBoris Brezillon int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, 358ed99f773SBoris Brezillon struct module *owner); 359ed99f773SBoris Brezillon void nanddev_cleanup(struct nand_device *nand); 360ed99f773SBoris Brezillon 361ed99f773SBoris Brezillon /** 362ed99f773SBoris Brezillon * nanddev_register() - Register a NAND device 363ed99f773SBoris Brezillon * @nand: NAND device 364ed99f773SBoris Brezillon * 365ed99f773SBoris Brezillon * Register a NAND device. 366ed99f773SBoris Brezillon * This function is just a wrapper around mtd_device_register() 367ed99f773SBoris Brezillon * registering the MTD device embedded in @nand. 368ed99f773SBoris Brezillon * 369ed99f773SBoris Brezillon * Return: 0 in case of success, a negative error code otherwise. 370ed99f773SBoris Brezillon */ 371ed99f773SBoris Brezillon static inline int nanddev_register(struct nand_device *nand) 372ed99f773SBoris Brezillon { 373ed99f773SBoris Brezillon return mtd_device_register(nand->mtd, NULL, 0); 374ed99f773SBoris Brezillon } 375ed99f773SBoris Brezillon 376ed99f773SBoris Brezillon /** 377ed99f773SBoris Brezillon * nanddev_unregister() - Unregister a NAND device 378ed99f773SBoris Brezillon * @nand: NAND device 379ed99f773SBoris Brezillon * 380ed99f773SBoris Brezillon * Unregister a NAND device. 381ed99f773SBoris Brezillon * This function is just a wrapper around mtd_device_unregister() 382ed99f773SBoris Brezillon * unregistering the MTD device embedded in @nand. 383ed99f773SBoris Brezillon * 384ed99f773SBoris Brezillon * Return: 0 in case of success, a negative error code otherwise. 385ed99f773SBoris Brezillon */ 386ed99f773SBoris Brezillon static inline int nanddev_unregister(struct nand_device *nand) 387ed99f773SBoris Brezillon { 388ed99f773SBoris Brezillon return mtd_device_unregister(nand->mtd); 389ed99f773SBoris Brezillon } 390ed99f773SBoris Brezillon 391ed99f773SBoris Brezillon /** 392ed99f773SBoris Brezillon * nanddev_set_of_node() - Attach a DT node to a NAND device 393ed99f773SBoris Brezillon * @nand: NAND device 394ed99f773SBoris Brezillon * @np: DT node 395ed99f773SBoris Brezillon * 396ed99f773SBoris Brezillon * Attach a DT node to a NAND device. 397ed99f773SBoris Brezillon */ 398ed99f773SBoris Brezillon static inline void nanddev_set_of_node(struct nand_device *nand, 399ed99f773SBoris Brezillon const struct device_node *np) 400ed99f773SBoris Brezillon { 401ed99f773SBoris Brezillon mtd_set_of_node(nand->mtd, np); 402ed99f773SBoris Brezillon } 403ed99f773SBoris Brezillon 404ed99f773SBoris Brezillon /** 405ed99f773SBoris Brezillon * nanddev_get_of_node() - Retrieve the DT node attached to a NAND device 406ed99f773SBoris Brezillon * @nand: NAND device 407ed99f773SBoris Brezillon * 408ed99f773SBoris Brezillon * Return: the DT node attached to @nand. 409ed99f773SBoris Brezillon */ 410ed99f773SBoris Brezillon static inline const struct device_node *nanddev_get_of_node(struct nand_device *nand) 411ed99f773SBoris Brezillon { 412ed99f773SBoris Brezillon return mtd_get_of_node(nand->mtd); 413ed99f773SBoris Brezillon } 414ed99f773SBoris Brezillon 415ed99f773SBoris Brezillon /** 416ed99f773SBoris Brezillon * nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position 417ed99f773SBoris Brezillon * @nand: NAND device 418ed99f773SBoris Brezillon * @offs: absolute NAND offset (usually passed by the MTD layer) 419ed99f773SBoris Brezillon * @pos: a NAND position object to fill in 420ed99f773SBoris Brezillon * 421ed99f773SBoris Brezillon * Converts @offs into a nand_pos representation. 422ed99f773SBoris Brezillon * 423ed99f773SBoris Brezillon * Return: the offset within the NAND page pointed by @pos. 424ed99f773SBoris Brezillon */ 425ed99f773SBoris Brezillon static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand, 426ed99f773SBoris Brezillon loff_t offs, 427ed99f773SBoris Brezillon struct nand_pos *pos) 428ed99f773SBoris Brezillon { 429ed99f773SBoris Brezillon unsigned int pageoffs; 430ed99f773SBoris Brezillon u64 tmp = offs; 431ed99f773SBoris Brezillon 432ed99f773SBoris Brezillon pageoffs = do_div(tmp, nand->memorg.pagesize); 433ed99f773SBoris Brezillon pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock); 434ed99f773SBoris Brezillon pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun); 435ed99f773SBoris Brezillon pos->plane = pos->eraseblock % nand->memorg.planes_per_lun; 436ed99f773SBoris Brezillon pos->lun = do_div(tmp, nand->memorg.luns_per_target); 437ed99f773SBoris Brezillon pos->target = tmp; 438ed99f773SBoris Brezillon 439ed99f773SBoris Brezillon return pageoffs; 440ed99f773SBoris Brezillon } 441ed99f773SBoris Brezillon 442ed99f773SBoris Brezillon /** 443ed99f773SBoris Brezillon * nanddev_pos_cmp() - Compare two NAND positions 444ed99f773SBoris Brezillon * @a: First NAND position 445ed99f773SBoris Brezillon * @b: Second NAND position 446ed99f773SBoris Brezillon * 447ed99f773SBoris Brezillon * Compares two NAND positions. 448ed99f773SBoris Brezillon * 449ed99f773SBoris Brezillon * Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b. 450ed99f773SBoris Brezillon */ 451ed99f773SBoris Brezillon static inline int nanddev_pos_cmp(const struct nand_pos *a, 452ed99f773SBoris Brezillon const struct nand_pos *b) 453ed99f773SBoris Brezillon { 454ed99f773SBoris Brezillon if (a->target != b->target) 455ed99f773SBoris Brezillon return a->target < b->target ? -1 : 1; 456ed99f773SBoris Brezillon 457ed99f773SBoris Brezillon if (a->lun != b->lun) 458ed99f773SBoris Brezillon return a->lun < b->lun ? -1 : 1; 459ed99f773SBoris Brezillon 460ed99f773SBoris Brezillon if (a->eraseblock != b->eraseblock) 461ed99f773SBoris Brezillon return a->eraseblock < b->eraseblock ? -1 : 1; 462ed99f773SBoris Brezillon 463ed99f773SBoris Brezillon if (a->page != b->page) 464ed99f773SBoris Brezillon return a->page < b->page ? -1 : 1; 465ed99f773SBoris Brezillon 466ed99f773SBoris Brezillon return 0; 467ed99f773SBoris Brezillon } 468ed99f773SBoris Brezillon 469ed99f773SBoris Brezillon /** 470ed99f773SBoris Brezillon * nanddev_pos_to_offs() - Convert a NAND position into an absolute offset 471ed99f773SBoris Brezillon * @nand: NAND device 472ed99f773SBoris Brezillon * @pos: the NAND position to convert 473ed99f773SBoris Brezillon * 474ed99f773SBoris Brezillon * Converts @pos NAND position into an absolute offset. 475ed99f773SBoris Brezillon * 476ed99f773SBoris Brezillon * Return: the absolute offset. Note that @pos points to the beginning of a 477ed99f773SBoris Brezillon * page, if one wants to point to a specific offset within this page 478ed99f773SBoris Brezillon * the returned offset has to be adjusted manually. 479ed99f773SBoris Brezillon */ 480ed99f773SBoris Brezillon static inline loff_t nanddev_pos_to_offs(struct nand_device *nand, 481ed99f773SBoris Brezillon const struct nand_pos *pos) 482ed99f773SBoris Brezillon { 483ed99f773SBoris Brezillon unsigned int npages; 484ed99f773SBoris Brezillon 485ed99f773SBoris Brezillon npages = pos->page + 486ed99f773SBoris Brezillon ((pos->eraseblock + 487ed99f773SBoris Brezillon (pos->lun + 488ed99f773SBoris Brezillon (pos->target * nand->memorg.luns_per_target)) * 489ed99f773SBoris Brezillon nand->memorg.eraseblocks_per_lun) * 490ed99f773SBoris Brezillon nand->memorg.pages_per_eraseblock); 491ed99f773SBoris Brezillon 492ed99f773SBoris Brezillon return (loff_t)npages * nand->memorg.pagesize; 493ed99f773SBoris Brezillon } 494ed99f773SBoris Brezillon 495ed99f773SBoris Brezillon /** 496ed99f773SBoris Brezillon * nanddev_pos_to_row() - Extract a row address from a NAND position 497ed99f773SBoris Brezillon * @nand: NAND device 498ed99f773SBoris Brezillon * @pos: the position to convert 499ed99f773SBoris Brezillon * 500ed99f773SBoris Brezillon * Converts a NAND position into a row address that can then be passed to the 501ed99f773SBoris Brezillon * device. 502ed99f773SBoris Brezillon * 503ed99f773SBoris Brezillon * Return: the row address extracted from @pos. 504ed99f773SBoris Brezillon */ 505ed99f773SBoris Brezillon static inline unsigned int nanddev_pos_to_row(struct nand_device *nand, 506ed99f773SBoris Brezillon const struct nand_pos *pos) 507ed99f773SBoris Brezillon { 508ed99f773SBoris Brezillon return (pos->lun << nand->rowconv.lun_addr_shift) | 509ed99f773SBoris Brezillon (pos->eraseblock << nand->rowconv.eraseblock_addr_shift) | 510ed99f773SBoris Brezillon pos->page; 511ed99f773SBoris Brezillon } 512ed99f773SBoris Brezillon 513ed99f773SBoris Brezillon /** 514ed99f773SBoris Brezillon * nanddev_pos_next_target() - Move a position to the next target/die 515ed99f773SBoris Brezillon * @nand: NAND device 516ed99f773SBoris Brezillon * @pos: the position to update 517ed99f773SBoris Brezillon * 518ed99f773SBoris Brezillon * Updates @pos to point to the start of the next target/die. Useful when you 519ed99f773SBoris Brezillon * want to iterate over all targets/dies of a NAND device. 520ed99f773SBoris Brezillon */ 521ed99f773SBoris Brezillon static inline void nanddev_pos_next_target(struct nand_device *nand, 522ed99f773SBoris Brezillon struct nand_pos *pos) 523ed99f773SBoris Brezillon { 524ed99f773SBoris Brezillon pos->page = 0; 525ed99f773SBoris Brezillon pos->plane = 0; 526ed99f773SBoris Brezillon pos->eraseblock = 0; 527ed99f773SBoris Brezillon pos->lun = 0; 528ed99f773SBoris Brezillon pos->target++; 529ed99f773SBoris Brezillon } 530ed99f773SBoris Brezillon 531ed99f773SBoris Brezillon /** 532ed99f773SBoris Brezillon * nanddev_pos_next_lun() - Move a position to the next LUN 533ed99f773SBoris Brezillon * @nand: NAND device 534ed99f773SBoris Brezillon * @pos: the position to update 535ed99f773SBoris Brezillon * 536ed99f773SBoris Brezillon * Updates @pos to point to the start of the next LUN. Useful when you want to 537ed99f773SBoris Brezillon * iterate over all LUNs of a NAND device. 538ed99f773SBoris Brezillon */ 539ed99f773SBoris Brezillon static inline void nanddev_pos_next_lun(struct nand_device *nand, 540ed99f773SBoris Brezillon struct nand_pos *pos) 541ed99f773SBoris Brezillon { 542ed99f773SBoris Brezillon if (pos->lun >= nand->memorg.luns_per_target - 1) 543ed99f773SBoris Brezillon return nanddev_pos_next_target(nand, pos); 544ed99f773SBoris Brezillon 545ed99f773SBoris Brezillon pos->lun++; 546ed99f773SBoris Brezillon pos->page = 0; 547ed99f773SBoris Brezillon pos->plane = 0; 548ed99f773SBoris Brezillon pos->eraseblock = 0; 549ed99f773SBoris Brezillon } 550ed99f773SBoris Brezillon 551ed99f773SBoris Brezillon /** 552ed99f773SBoris Brezillon * nanddev_pos_next_eraseblock() - Move a position to the next eraseblock 553ed99f773SBoris Brezillon * @nand: NAND device 554ed99f773SBoris Brezillon * @pos: the position to update 555ed99f773SBoris Brezillon * 556ed99f773SBoris Brezillon * Updates @pos to point to the start of the next eraseblock. Useful when you 557ed99f773SBoris Brezillon * want to iterate over all eraseblocks of a NAND device. 558ed99f773SBoris Brezillon */ 559ed99f773SBoris Brezillon static inline void nanddev_pos_next_eraseblock(struct nand_device *nand, 560ed99f773SBoris Brezillon struct nand_pos *pos) 561ed99f773SBoris Brezillon { 562ed99f773SBoris Brezillon if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1) 563ed99f773SBoris Brezillon return nanddev_pos_next_lun(nand, pos); 564ed99f773SBoris Brezillon 565ed99f773SBoris Brezillon pos->eraseblock++; 566ed99f773SBoris Brezillon pos->page = 0; 567ed99f773SBoris Brezillon pos->plane = pos->eraseblock % nand->memorg.planes_per_lun; 568ed99f773SBoris Brezillon } 569ed99f773SBoris Brezillon 570ed99f773SBoris Brezillon /** 571ed99f773SBoris Brezillon * nanddev_pos_next_eraseblock() - Move a position to the next page 572ed99f773SBoris Brezillon * @nand: NAND device 573ed99f773SBoris Brezillon * @pos: the position to update 574ed99f773SBoris Brezillon * 575ed99f773SBoris Brezillon * Updates @pos to point to the start of the next page. Useful when you want to 576ed99f773SBoris Brezillon * iterate over all pages of a NAND device. 577ed99f773SBoris Brezillon */ 578ed99f773SBoris Brezillon static inline void nanddev_pos_next_page(struct nand_device *nand, 579ed99f773SBoris Brezillon struct nand_pos *pos) 580ed99f773SBoris Brezillon { 581ed99f773SBoris Brezillon if (pos->page >= nand->memorg.pages_per_eraseblock - 1) 582ed99f773SBoris Brezillon return nanddev_pos_next_eraseblock(nand, pos); 583ed99f773SBoris Brezillon 584ed99f773SBoris Brezillon pos->page++; 585ed99f773SBoris Brezillon } 586ed99f773SBoris Brezillon 587ed99f773SBoris Brezillon /** 588ed99f773SBoris Brezillon * nand_io_iter_init - Initialize a NAND I/O iterator 589ed99f773SBoris Brezillon * @nand: NAND device 590ed99f773SBoris Brezillon * @offs: absolute offset 591ed99f773SBoris Brezillon * @req: MTD request 592ed99f773SBoris Brezillon * @iter: NAND I/O iterator 593ed99f773SBoris Brezillon * 594ed99f773SBoris Brezillon * Initializes a NAND iterator based on the information passed by the MTD 595ed99f773SBoris Brezillon * layer. 596ed99f773SBoris Brezillon */ 597ed99f773SBoris Brezillon static inline void nanddev_io_iter_init(struct nand_device *nand, 598ed99f773SBoris Brezillon loff_t offs, struct mtd_oob_ops *req, 599ed99f773SBoris Brezillon struct nand_io_iter *iter) 600ed99f773SBoris Brezillon { 601ed99f773SBoris Brezillon struct mtd_info *mtd = nanddev_to_mtd(nand); 602ed99f773SBoris Brezillon 60387a1a21dSBoris Brezillon iter->req.mode = req->mode; 604ed99f773SBoris Brezillon iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos); 605ed99f773SBoris Brezillon iter->req.ooboffs = req->ooboffs; 606ed99f773SBoris Brezillon iter->oobbytes_per_page = mtd_oobavail(mtd, req); 607ed99f773SBoris Brezillon iter->dataleft = req->len; 608ed99f773SBoris Brezillon iter->oobleft = req->ooblen; 609ed99f773SBoris Brezillon iter->req.databuf.in = req->datbuf; 610ed99f773SBoris Brezillon iter->req.datalen = min_t(unsigned int, 611ed99f773SBoris Brezillon nand->memorg.pagesize - iter->req.dataoffs, 612ed99f773SBoris Brezillon iter->dataleft); 613ed99f773SBoris Brezillon iter->req.oobbuf.in = req->oobbuf; 614ed99f773SBoris Brezillon iter->req.ooblen = min_t(unsigned int, 615ed99f773SBoris Brezillon iter->oobbytes_per_page - iter->req.ooboffs, 616ed99f773SBoris Brezillon iter->oobleft); 617ed99f773SBoris Brezillon } 618ed99f773SBoris Brezillon 619ed99f773SBoris Brezillon /** 620ed99f773SBoris Brezillon * nand_io_iter_next_page - Move to the next page 621ed99f773SBoris Brezillon * @nand: NAND device 622ed99f773SBoris Brezillon * @iter: NAND I/O iterator 623ed99f773SBoris Brezillon * 624ed99f773SBoris Brezillon * Updates the @iter to point to the next page. 625ed99f773SBoris Brezillon */ 626ed99f773SBoris Brezillon static inline void nanddev_io_iter_next_page(struct nand_device *nand, 627ed99f773SBoris Brezillon struct nand_io_iter *iter) 628ed99f773SBoris Brezillon { 629ed99f773SBoris Brezillon nanddev_pos_next_page(nand, &iter->req.pos); 630ed99f773SBoris Brezillon iter->dataleft -= iter->req.datalen; 631ed99f773SBoris Brezillon iter->req.databuf.in += iter->req.datalen; 632ed99f773SBoris Brezillon iter->oobleft -= iter->req.ooblen; 633ed99f773SBoris Brezillon iter->req.oobbuf.in += iter->req.ooblen; 634ed99f773SBoris Brezillon iter->req.dataoffs = 0; 635ed99f773SBoris Brezillon iter->req.ooboffs = 0; 636ed99f773SBoris Brezillon iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize, 637ed99f773SBoris Brezillon iter->dataleft); 638ed99f773SBoris Brezillon iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page, 639ed99f773SBoris Brezillon iter->oobleft); 640ed99f773SBoris Brezillon } 641ed99f773SBoris Brezillon 642ed99f773SBoris Brezillon /** 643ed99f773SBoris Brezillon * nand_io_iter_end - Should end iteration or not 644ed99f773SBoris Brezillon * @nand: NAND device 645ed99f773SBoris Brezillon * @iter: NAND I/O iterator 646ed99f773SBoris Brezillon * 647ed99f773SBoris Brezillon * Check whether @iter has reached the end of the NAND portion it was asked to 648ed99f773SBoris Brezillon * iterate on or not. 649ed99f773SBoris Brezillon * 650ed99f773SBoris Brezillon * Return: true if @iter has reached the end of the iteration request, false 651ed99f773SBoris Brezillon * otherwise. 652ed99f773SBoris Brezillon */ 653ed99f773SBoris Brezillon static inline bool nanddev_io_iter_end(struct nand_device *nand, 654ed99f773SBoris Brezillon const struct nand_io_iter *iter) 655ed99f773SBoris Brezillon { 656ed99f773SBoris Brezillon if (iter->dataleft || iter->oobleft) 657ed99f773SBoris Brezillon return false; 658ed99f773SBoris Brezillon 659ed99f773SBoris Brezillon return true; 660ed99f773SBoris Brezillon } 661ed99f773SBoris Brezillon 662ed99f773SBoris Brezillon /** 663ed99f773SBoris Brezillon * nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O 664ed99f773SBoris Brezillon * request 665ed99f773SBoris Brezillon * @nand: NAND device 666ed99f773SBoris Brezillon * @start: start address to read/write from 667ed99f773SBoris Brezillon * @req: MTD I/O request 668ed99f773SBoris Brezillon * @iter: NAND I/O iterator 669ed99f773SBoris Brezillon * 670ed99f773SBoris Brezillon * Should be used for iterate over pages that are contained in an MTD request. 671ed99f773SBoris Brezillon */ 672ed99f773SBoris Brezillon #define nanddev_io_for_each_page(nand, start, req, iter) \ 673ed99f773SBoris Brezillon for (nanddev_io_iter_init(nand, start, req, iter); \ 674ed99f773SBoris Brezillon !nanddev_io_iter_end(nand, iter); \ 675ed99f773SBoris Brezillon nanddev_io_iter_next_page(nand, iter)) 676ed99f773SBoris Brezillon 677ed99f773SBoris Brezillon bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos); 678ed99f773SBoris Brezillon bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos); 679ed99f773SBoris Brezillon int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos); 680ed99f773SBoris Brezillon int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); 681ed99f773SBoris Brezillon 682ed99f773SBoris Brezillon /* BBT related functions */ 683ed99f773SBoris Brezillon enum nand_bbt_block_status { 684ed99f773SBoris Brezillon NAND_BBT_BLOCK_STATUS_UNKNOWN, 685ed99f773SBoris Brezillon NAND_BBT_BLOCK_GOOD, 686ed99f773SBoris Brezillon NAND_BBT_BLOCK_WORN, 687ed99f773SBoris Brezillon NAND_BBT_BLOCK_RESERVED, 688ed99f773SBoris Brezillon NAND_BBT_BLOCK_FACTORY_BAD, 689ed99f773SBoris Brezillon NAND_BBT_BLOCK_NUM_STATUS, 690ed99f773SBoris Brezillon }; 691ed99f773SBoris Brezillon 692ed99f773SBoris Brezillon int nanddev_bbt_init(struct nand_device *nand); 693ed99f773SBoris Brezillon void nanddev_bbt_cleanup(struct nand_device *nand); 694ed99f773SBoris Brezillon int nanddev_bbt_update(struct nand_device *nand); 695ed99f773SBoris Brezillon int nanddev_bbt_get_block_status(const struct nand_device *nand, 696ed99f773SBoris Brezillon unsigned int entry); 697ed99f773SBoris Brezillon int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry, 698ed99f773SBoris Brezillon enum nand_bbt_block_status status); 699ed99f773SBoris Brezillon int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block); 700ed99f773SBoris Brezillon 701ed99f773SBoris Brezillon /** 702ed99f773SBoris Brezillon * nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry 703ed99f773SBoris Brezillon * @nand: NAND device 704ed99f773SBoris Brezillon * @pos: the NAND position we want to get BBT entry for 705ed99f773SBoris Brezillon * 706ed99f773SBoris Brezillon * Return the BBT entry used to store information about the eraseblock pointed 707ed99f773SBoris Brezillon * by @pos. 708ed99f773SBoris Brezillon * 709ed99f773SBoris Brezillon * Return: the BBT entry storing information about eraseblock pointed by @pos. 710ed99f773SBoris Brezillon */ 711ed99f773SBoris Brezillon static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand, 712ed99f773SBoris Brezillon const struct nand_pos *pos) 713ed99f773SBoris Brezillon { 714ed99f773SBoris Brezillon return pos->eraseblock + 715ed99f773SBoris Brezillon ((pos->lun + (pos->target * nand->memorg.luns_per_target)) * 716ed99f773SBoris Brezillon nand->memorg.eraseblocks_per_lun); 717ed99f773SBoris Brezillon } 718ed99f773SBoris Brezillon 719ed99f773SBoris Brezillon /** 720ed99f773SBoris Brezillon * nanddev_bbt_is_initialized() - Check if the BBT has been initialized 721ed99f773SBoris Brezillon * @nand: NAND device 722ed99f773SBoris Brezillon * 723ed99f773SBoris Brezillon * Return: true if the BBT has been initialized, false otherwise. 724ed99f773SBoris Brezillon */ 725ed99f773SBoris Brezillon static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) 726ed99f773SBoris Brezillon { 727ed99f773SBoris Brezillon return !!nand->bbt.cache; 728ed99f773SBoris Brezillon } 729ed99f773SBoris Brezillon 730ed99f773SBoris Brezillon /* MTD -> NAND helper functions. */ 731ed99f773SBoris Brezillon int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); 732ed99f773SBoris Brezillon 733ed99f773SBoris Brezillon #endif /* __LINUX_MTD_NAND_H */ 734