mtd: nand: Introduce the ECC engine framework

Create a generic ECC engine framework. This is a base to instantiate ECC
engine objects.

If we really want to be generic, bindings must evolve, so here is the
new logic. The following three properties are mutually exclusive:
- The nand-no-ecc-engine boolean property is set and there is no
  ECC engine to retrieve.
- The nand-use-soft-ecc-engine boolean property is set and the core
  will force using the use of software correction.
- There is a nand-ecc-engine property pointing at a node which will
  act as ECC engine.

It the later case, the property may reference:
- The NAND chip node itself (for the on-die ECC case).
- The parent node if the NAND controller embeds an ECC engine.
- Any other node being an external ECC controller as well.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200827085208.16276-9-miquel.raynal@bootlin.com
This commit is contained in:
Miquel Raynal 2020-08-27 10:51:56 +02:00
parent b440915af2
commit a8c7ffdb5f
4 changed files with 608 additions and 0 deletions

View file

@ -127,6 +127,40 @@ struct nand_page_io_req {
int mode;
};
const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void);
const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void);
const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void);
/**
* enum nand_ecc_engine_type - NAND ECC engine type
* @NAND_ECC_ENGINE_TYPE_INVALID: Invalid value
* @NAND_ECC_ENGINE_TYPE_NONE: No ECC correction
* @NAND_ECC_ENGINE_TYPE_SOFT: Software ECC correction
* @NAND_ECC_ENGINE_TYPE_ON_HOST: On host hardware ECC correction
* @NAND_ECC_ENGINE_TYPE_ON_DIE: On chip hardware ECC correction
*/
enum nand_ecc_engine_type {
NAND_ECC_ENGINE_TYPE_INVALID,
NAND_ECC_ENGINE_TYPE_NONE,
NAND_ECC_ENGINE_TYPE_SOFT,
NAND_ECC_ENGINE_TYPE_ON_HOST,
NAND_ECC_ENGINE_TYPE_ON_DIE,
};
/**
* enum nand_ecc_placement - NAND ECC bytes placement
* @NAND_ECC_PLACEMENT_UNKNOWN: The actual position of the ECC bytes is unknown
* @NAND_ECC_PLACEMENT_OOB: The ECC bytes are located in the OOB area
* @NAND_ECC_PLACEMENT_INTERLEAVED: Syndrome layout, there are ECC bytes
* interleaved with regular data in the main
* area
*/
enum nand_ecc_placement {
NAND_ECC_PLACEMENT_UNKNOWN,
NAND_ECC_PLACEMENT_OOB,
NAND_ECC_PLACEMENT_INTERLEAVED,
};
/**
* enum nand_ecc_algo - NAND ECC algorithm
* @NAND_ECC_ALGO_UNKNOWN: Unknown algorithm
@ -143,16 +177,27 @@ enum nand_ecc_algo {
/**
* struct nand_ecc_props - NAND ECC properties
* @engine_type: ECC engine type
* @placement: OOB placement (if relevant)
* @algo: ECC algorithm (if relevant)
* @strength: ECC strength
* @step_size: Number of bytes per step
* @flags: Misc properties
*/
struct nand_ecc_props {
enum nand_ecc_engine_type engine_type;
enum nand_ecc_placement placement;
enum nand_ecc_algo algo;
unsigned int strength;
unsigned int step_size;
unsigned int flags;
};
#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
/* NAND ECC misc flags */
#define NAND_ECC_MAXIMIZE_STRENGTH BIT(0)
/**
* struct nand_bbt - bad block table object
* @cache: in memory BBT cache
@ -183,6 +228,75 @@ struct nand_ops {
bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos);
};
/**
* struct nand_ecc_context - Context for the ECC engine
* @conf: basic ECC engine parameters
* @total: total number of bytes used for storing ECC codes, this is used by
* generic OOB layouts
* @priv: ECC engine driver private data
*/
struct nand_ecc_context {
struct nand_ecc_props conf;
unsigned int total;
void *priv;
};
/**
* struct nand_ecc_engine_ops - ECC engine operations
* @init_ctx: given a desired user configuration for the pointed NAND device,
* requests the ECC engine driver to setup a configuration with
* values it supports.
* @cleanup_ctx: clean the context initialized by @init_ctx.
* @prepare_io_req: is called before reading/writing a page to prepare the I/O
* request to be performed with ECC correction.
* @finish_io_req: is called after reading/writing a page to terminate the I/O
* request and ensure proper ECC correction.
*/
struct nand_ecc_engine_ops {
int (*init_ctx)(struct nand_device *nand);
void (*cleanup_ctx)(struct nand_device *nand);
int (*prepare_io_req)(struct nand_device *nand,
struct nand_page_io_req *req);
int (*finish_io_req)(struct nand_device *nand,
struct nand_page_io_req *req);
};
/**
* struct nand_ecc_engine - ECC engine abstraction for NAND devices
* @ops: ECC engine operations
*/
struct nand_ecc_engine {
struct nand_ecc_engine_ops *ops;
};
void of_get_nand_ecc_user_config(struct nand_device *nand);
int nand_ecc_init_ctx(struct nand_device *nand);
void nand_ecc_cleanup_ctx(struct nand_device *nand);
int nand_ecc_prepare_io_req(struct nand_device *nand,
struct nand_page_io_req *req);
int nand_ecc_finish_io_req(struct nand_device *nand,
struct nand_page_io_req *req);
bool nand_ecc_is_strong_enough(struct nand_device *nand);
/**
* struct nand_ecc - Information relative to the ECC
* @defaults: Default values, depend on the underlying subsystem
* @requirements: ECC requirements from the NAND chip perspective
* @user_conf: User desires in terms of ECC parameters
* @ctx: ECC context for the ECC engine, derived from the device @requirements
* the @user_conf and the @defaults
* @ondie_engine: On-die ECC engine reference, if any
* @engine: ECC engine actually bound
*/
struct nand_ecc {
struct nand_ecc_props defaults;
struct nand_ecc_props requirements;
struct nand_ecc_props user_conf;
struct nand_ecc_context ctx;
struct nand_ecc_engine *ondie_engine;
struct nand_ecc_engine *engine;
};
/**
* struct nand_device - NAND device
* @mtd: MTD instance attached to the NAND device