From 97d90da8a886949f09bb4754843fb0b504956ad2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 30 Nov 2017 18:01:29 +0100 Subject: mtd: nand: provide several helpers to do common NAND operations This is part of the process of removing direct calls to ->cmdfunc() outside of the core in order to introduce a better interface to execute NAND operations. Here we provide several helpers and make use of them to remove all direct calls to ->cmdfunc(). This way, we can easily modify those helpers to make use of the new ->exec_op() interface when available. Signed-off-by: Boris Brezillon [miquel.raynal@free-electrons.com: rebased and fixed some conflicts] Signed-off-by: Miquel Raynal Acked-by: Masahiro Yamada --- include/linux/mtd/rawnand.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 749bb08c4772..fd99d5137d71 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1316,6 +1316,35 @@ int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, /* Reset and initialize a NAND device */ int nand_reset(struct nand_chip *chip, int chipnr); +/* NAND operation helpers */ +int nand_reset_op(struct nand_chip *chip); +int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, + unsigned int len); +int nand_status_op(struct nand_chip *chip, u8 *status); +int nand_exit_status_op(struct nand_chip *chip); +int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock); +int nand_read_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, void *buf, unsigned int len); +int nand_change_read_column_op(struct nand_chip *chip, + unsigned int offset_in_page, void *buf, + unsigned int len, bool force_8bit); +int nand_read_oob_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, void *buf, unsigned int len); +int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, const void *buf, + unsigned int len); +int nand_prog_page_end_op(struct nand_chip *chip); +int nand_prog_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, const void *buf, + unsigned int len); +int nand_change_write_column_op(struct nand_chip *chip, + unsigned int offset_in_page, const void *buf, + unsigned int len, bool force_8bit); +int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, + bool force_8bit); +int nand_write_data_op(struct nand_chip *chip, const void *buf, + unsigned int len, bool force_8bit); + /* Free resources held by the NAND device */ void nand_cleanup(struct nand_chip *chip); -- cgit v1.2.3 From 25f815f66a141436df8a4c45e5d2765272aea2ac Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 30 Nov 2017 18:01:30 +0100 Subject: mtd: nand: force drivers to explicitly send READ/PROG commands The core currently send the READ0 and SEQIN+PAGEPROG commands in nand_do_read/write_ops(). This is inconsistent with ->read/write_oob[_raw]() hooks behavior which are expected to send these commands. There's already a flag (NAND_ECC_CUSTOM_PAGE_ACCESS) to inform the core that a specific controller wants to send the READ/SEQIN+PAGEPROG commands on its own, but it's an opt-in flag, and existing drivers are unlikely to be updated to pass it. Moreover, some controllers cannot dissociate the READ/PAGEPROG commands from the associated data transfer and ECC engine activation, and developers have to hack things in their ->cmdfunc() implementation to handle such complex cases, or have to accept the perf penalty of sending twice the same command. To address this problem we are planning on adding a new interface which is passed all information about a NAND operation (including the amount of data to transfer) and replacing all calls to ->cmdfunc() to calls to this new ->exec_op() hook. But, in order to do that, we need to have all ->cmdfunc() calls placed near their associated ->read/write_buf/byte() calls. Modify the core and relevant drivers to make NAND_ECC_CUSTOM_PAGE_ACCESS the default case, and remove this flag. Signed-off-by: Boris Brezillon [miquel.raynal@free-electrons.com: tested, fixed and rebased on nand/next] Signed-off-by: Miquel Raynal Acked-by: Masahiro Yamada --- include/linux/mtd/rawnand.h | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index fd99d5137d71..e6810f0b8f9e 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -133,12 +133,6 @@ enum nand_ecc_algo { */ #define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) #define NAND_ECC_MAXIMIZE BIT(1) -/* - * If your controller already sends the required NAND commands when - * reading or writing a page, then the framework is not supposed to - * send READ0 and SEQIN/PAGEPROG respectively. - */ -#define NAND_ECC_CUSTOM_PAGE_ACCESS BIT(2) /* Bit mask for flags passed to do_nand_read_ecc */ #define NAND_GET_DEVICE 0x80 @@ -602,11 +596,6 @@ struct nand_ecc_ctrl { int page); }; -static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc) -{ - return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS); -} - /** * struct nand_buffers - buffer structure for read/write * @ecccalc: buffer pointer for calculated ECC, size is oobsize. -- cgit v1.2.3 From 17fa8044188c152e8a3b9493f8b8054cacbfb9ba Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 30 Nov 2017 18:01:31 +0100 Subject: mtd: nand: provide valid ->data_interface during NAND detection Right now, the chip->data_interface field is populated in nand_scan_tail(), so after the whole NAND detection has taken place. This is fine because these timings are not yet used by the core so early in the probe process, but the situation is about to change with the introduction of ->exec_op(). Also, by convention, nand_scan_ident() is not supposed to allocate resources, only nand_scan_tail() can, so this prevent us from allocating and initializing the data_interface object in nand_scan_ident(). In order to solve this problem, directly embed a data_interface object in nand_chip so that we don't have to allocate it, and initialize it to ONFI SDR mode 0 at the very beginning of nand_scan_ident(). Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- include/linux/mtd/rawnand.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index e6810f0b8f9e..2a72eab286ef 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -917,7 +917,7 @@ struct nand_chip { u16 max_bb_per_die; u32 blocks_per_die; - struct nand_data_interface *data_interface; + struct nand_data_interface data_interface; int read_retries; @@ -1214,8 +1214,7 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); } -int onfi_init_data_interface(struct nand_chip *chip, - struct nand_data_interface *iface, +int onfi_fill_data_interface(struct nand_chip *chip, enum nand_data_interface_type type, int timing_mode); @@ -1258,8 +1257,6 @@ static inline int jedec_feature(struct nand_chip *chip) /* get timing characteristics from ONFI timing mode. */ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); -/* get data interface from ONFI timing mode 0, used after reset. */ -const struct nand_data_interface *nand_get_default_data_interface(void); int nand_check_erased_ecc_chunk(void *data, int datalen, void *ecc, int ecclen, -- cgit v1.2.3 From 8b311ead8bff9b56e512e3e544c488042ad0e7e7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 5 Dec 2017 17:47:15 +0900 Subject: mtd: nand: remove unused NAND_OWN_BUFFERS flag The last/only user of NAND_OWN_BUFFERS (cafe_nand.c) has been reworked. This flag is no longer needed. Suggested-by: Boris Brezillon Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- include/linux/mtd/rawnand.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 2a72eab286ef..fca802ef9af3 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -185,11 +185,6 @@ enum nand_ecc_algo { /* Non chip related options */ /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN 0x00010000 -/* - * This option is defined if the board driver allocates its own buffers - * (e.g. because it needs them DMA-coherent). - */ -#define NAND_OWN_BUFFERS 0x00020000 /* Chip may not exist, so silence any errors in scan */ #define NAND_SCAN_SILENT_NODEV 0x00040000 /* -- cgit v1.2.3 From c0313b966a0942fba934d34c7a76f444641d0b6e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 5 Dec 2017 17:47:16 +0900 Subject: mtd: nand: squash struct nand_buffers into struct nand_chip struct nand_buffers is malloc'ed in nand_scan_tail() just for containing three pointers. Squash this struct into nand_chip. Move and rename as follows: chip->buffers->ecccalc -> chip->ecc.calc_buf chip->buffers->ecccode -> chip->ecc.code_buf chip->buffers->databuf -> chip->data_buf Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- include/linux/mtd/rawnand.h | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index fca802ef9af3..f8f27c6801a6 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -514,6 +514,8 @@ static const struct nand_ecc_caps __name = { \ * @postpad: padding information for syndrome based ECC generators * @options: ECC specific options (see NAND_ECC_XXX flags defined above) * @priv: pointer to private ECC control data + * @calc_buf: buffer for calculated ECC, size is oobsize. + * @code_buf: buffer for ECC read from flash, size is oobsize. * @hwctl: function to control hardware ECC generator. Must only * be provided if an hardware ECC is available * @calculate: function for ECC calculation or readback from ECC hardware @@ -564,6 +566,8 @@ struct nand_ecc_ctrl { int postpad; unsigned int options; void *priv; + u8 *calc_buf; + u8 *code_buf; void (*hwctl)(struct mtd_info *mtd, int mode); int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code); @@ -591,21 +595,6 @@ struct nand_ecc_ctrl { int page); }; -/** - * struct nand_buffers - buffer structure for read/write - * @ecccalc: buffer pointer for calculated ECC, size is oobsize. - * @ecccode: buffer pointer for ECC read from flash, size is oobsize. - * @databuf: buffer pointer for data, size is (page size + oobsize). - * - * Do not change the order of buffers. databuf and oobrbuf must be in - * consecutive order. - */ -struct nand_buffers { - uint8_t *ecccalc; - uint8_t *ecccode; - uint8_t *databuf; -}; - /** * struct nand_sdr_timings - SDR NAND chip timings * @@ -774,7 +763,6 @@ struct nand_manufacturer_ops { * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure - * @buffers: buffer structure for read/write * @buf_align: minimum buffer alignment required by a platform * @hwcontrol: platform-specific hardware control structure * @erase: [REPLACEABLE] erase function @@ -814,6 +802,7 @@ struct nand_manufacturer_ops { * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 + * @data_buf: [INTERN] buffer for data, size is (page size + oobsize). * @pagebuf: [INTERN] holds the pagenumber which is currently in * data_buf. * @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is @@ -892,6 +881,7 @@ struct nand_chip { int numchips; uint64_t chipsize; int pagemask; + u8 *data_buf; int pagebuf; unsigned int pagebuf_bitflips; int subpagesize; @@ -922,7 +912,6 @@ struct nand_chip { struct nand_hw_control *controller; struct nand_ecc_ctrl ecc; - struct nand_buffers *buffers; unsigned long buf_align; struct nand_hw_control hwcontrol; -- cgit v1.2.3 From 8878b126df769831cb2fa4088c3806538e8305f5 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 9 Nov 2017 14:16:45 +0100 Subject: mtd: nand: add ->exec_op() implementation Introduce a new interface to instruct NAND controllers to send specific NAND operations. The new interface takes the form of a single method called ->exec_op(). This method is designed to replace ->cmd_ctrl(), ->cmdfunc() and ->read/write_byte/word/buf() hooks. ->exec_op() is passed a set of instructions describing the operation to execute. Each instruction has a type (ADDR, CMD, DATA, WAITRDY) and delay. The delay is here to help simple controllers wait enough time between each instruction, advanced controllers with integrated timings control can ignore these delays. Controllers that natively support complex operations (operations formed of several instructions) can use the NAND op parser infrastructure. This infrastructure allows controller drivers to describe the sequence of instructions they support (called nand_op_pattern) and a hook for each of these supported sequences. The core then tries to find the best match for a given NAND operation, and calls the associated hook. Various other helpers are also added to ease NAND controller drivers writing. This new interface should ease support of vendor specific operations in that NAND manufacturer drivers now have a way to check if the controller they are connected to supports a specific operation, and complain or refuse to probe the NAND chip when that's not the case. Suggested-by: Boris Brezillon Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- include/linux/mtd/rawnand.h | 368 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 367 insertions(+), 1 deletion(-) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index f8f27c6801a6..469dc724f5df 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -734,6 +734,350 @@ struct nand_manufacturer_ops { void (*cleanup)(struct nand_chip *chip); }; +/** + * struct nand_op_cmd_instr - Definition of a command instruction + * @opcode: the command to issue in one cycle + */ +struct nand_op_cmd_instr { + u8 opcode; +}; + +/** + * struct nand_op_addr_instr - Definition of an address instruction + * @naddrs: length of the @addrs array + * @addrs: array containing the address cycles to issue + */ +struct nand_op_addr_instr { + unsigned int naddrs; + const u8 *addrs; +}; + +/** + * struct nand_op_data_instr - Definition of a data instruction + * @len: number of data bytes to move + * @in: buffer to fill when reading from the NAND chip + * @out: buffer to read from when writing to the NAND chip + * @force_8bit: force 8-bit access + * + * Please note that "in" and "out" are inverted from the ONFI specification + * and are from the controller perspective, so a "in" is a read from the NAND + * chip while a "out" is a write to the NAND chip. + */ +struct nand_op_data_instr { + unsigned int len; + union { + void *in; + const void *out; + } buf; + bool force_8bit; +}; + +/** + * struct nand_op_waitrdy_instr - Definition of a wait ready instruction + * @timeout_ms: maximum delay while waiting for the ready/busy pin in ms + */ +struct nand_op_waitrdy_instr { + unsigned int timeout_ms; +}; + +/** + * enum nand_op_instr_type - Definition of all instruction types + * @NAND_OP_CMD_INSTR: command instruction + * @NAND_OP_ADDR_INSTR: address instruction + * @NAND_OP_DATA_IN_INSTR: data in instruction + * @NAND_OP_DATA_OUT_INSTR: data out instruction + * @NAND_OP_WAITRDY_INSTR: wait ready instruction + */ +enum nand_op_instr_type { + NAND_OP_CMD_INSTR, + NAND_OP_ADDR_INSTR, + NAND_OP_DATA_IN_INSTR, + NAND_OP_DATA_OUT_INSTR, + NAND_OP_WAITRDY_INSTR, +}; + +/** + * struct nand_op_instr - Instruction object + * @type: the instruction type + * @cmd/@addr/@data/@waitrdy: extra data associated to the instruction. + * You'll have to use the appropriate element + * depending on @type + * @delay_ns: delay the controller should apply after the instruction has been + * issued on the bus. Most modern controllers have internal timings + * control logic, and in this case, the controller driver can ignore + * this field. + */ +struct nand_op_instr { + enum nand_op_instr_type type; + union { + struct nand_op_cmd_instr cmd; + struct nand_op_addr_instr addr; + struct nand_op_data_instr data; + struct nand_op_waitrdy_instr waitrdy; + } ctx; + unsigned int delay_ns; +}; + +/* + * Special handling must be done for the WAITRDY timeout parameter as it usually + * is either tPROG (after a prog), tR (before a read), tRST (during a reset) or + * tBERS (during an erase) which all of them are u64 values that cannot be + * divided by usual kernel macros and must be handled with the special + * DIV_ROUND_UP_ULL() macro. + */ +#define __DIVIDE(dividend, divisor) ({ \ + sizeof(dividend) == sizeof(u32) ? \ + DIV_ROUND_UP(dividend, divisor) : \ + DIV_ROUND_UP_ULL(dividend, divisor); \ + }) +#define PSEC_TO_NSEC(x) __DIVIDE(x, 1000) +#define PSEC_TO_MSEC(x) __DIVIDE(x, 1000000000) + +#define NAND_OP_CMD(id, ns) \ + { \ + .type = NAND_OP_CMD_INSTR, \ + .ctx.cmd.opcode = id, \ + .delay_ns = ns, \ + } + +#define NAND_OP_ADDR(ncycles, cycles, ns) \ + { \ + .type = NAND_OP_ADDR_INSTR, \ + .ctx.addr = { \ + .naddrs = ncycles, \ + .addrs = cycles, \ + }, \ + .delay_ns = ns, \ + } + +#define NAND_OP_DATA_IN(l, b, ns) \ + { \ + .type = NAND_OP_DATA_IN_INSTR, \ + .ctx.data = { \ + .len = l, \ + .buf.in = b, \ + .force_8bit = false, \ + }, \ + .delay_ns = ns, \ + } + +#define NAND_OP_DATA_OUT(l, b, ns) \ + { \ + .type = NAND_OP_DATA_OUT_INSTR, \ + .ctx.data = { \ + .len = l, \ + .buf.out = b, \ + .force_8bit = false, \ + }, \ + .delay_ns = ns, \ + } + +#define NAND_OP_8BIT_DATA_IN(l, b, ns) \ + { \ + .type = NAND_OP_DATA_IN_INSTR, \ + .ctx.data = { \ + .len = l, \ + .buf.in = b, \ + .force_8bit = true, \ + }, \ + .delay_ns = ns, \ + } + +#define NAND_OP_8BIT_DATA_OUT(l, b, ns) \ + { \ + .type = NAND_OP_DATA_OUT_INSTR, \ + .ctx.data = { \ + .len = l, \ + .buf.out = b, \ + .force_8bit = true, \ + }, \ + .delay_ns = ns, \ + } + +#define NAND_OP_WAIT_RDY(tout_ms, ns) \ + { \ + .type = NAND_OP_WAITRDY_INSTR, \ + .ctx.waitrdy.timeout_ms = tout_ms, \ + .delay_ns = ns, \ + } + +/** + * struct nand_subop - a sub operation + * @instrs: array of instructions + * @ninstrs: length of the @instrs array + * @first_instr_start_off: offset to start from for the first instruction + * of the sub-operation + * @last_instr_end_off: offset to end at (excluded) for the last instruction + * of the sub-operation + * + * Both @first_instr_start_off and @last_instr_end_off only apply to data or + * address instructions. + * + * When an operation cannot be handled as is by the NAND controller, it will + * be split by the parser into sub-operations which will be passed to the + * controller driver. + */ +struct nand_subop { + const struct nand_op_instr *instrs; + unsigned int ninstrs; + unsigned int first_instr_start_off; + unsigned int last_instr_end_off; +}; + +int nand_subop_get_addr_start_off(const struct nand_subop *subop, + unsigned int op_id); +int nand_subop_get_num_addr_cyc(const struct nand_subop *subop, + unsigned int op_id); +int nand_subop_get_data_start_off(const struct nand_subop *subop, + unsigned int op_id); +int nand_subop_get_data_len(const struct nand_subop *subop, + unsigned int op_id); + +/** + * struct nand_op_parser_addr_constraints - Constraints for address instructions + * @maxcycles: maximum number of address cycles the controller can issue in a + * single step + */ +struct nand_op_parser_addr_constraints { + unsigned int maxcycles; +}; + +/** + * struct nand_op_parser_data_constraints - Constraints for data instructions + * @maxlen: maximum data length that the controller can handle in a single step + */ +struct nand_op_parser_data_constraints { + unsigned int maxlen; +}; + +/** + * struct nand_op_parser_pattern_elem - One element of a pattern + * @type: the instructuction type + * @optional: whether this element of the pattern is optional or mandatory + * @addr/@data: address or data constraint (number of cycles or data length) + */ +struct nand_op_parser_pattern_elem { + enum nand_op_instr_type type; + bool optional; + union { + struct nand_op_parser_addr_constraints addr; + struct nand_op_parser_data_constraints data; + }; +}; + +#define NAND_OP_PARSER_PAT_CMD_ELEM(_opt) \ + { \ + .type = NAND_OP_CMD_INSTR, \ + .optional = _opt, \ + } + +#define NAND_OP_PARSER_PAT_ADDR_ELEM(_opt, _maxcycles) \ + { \ + .type = NAND_OP_ADDR_INSTR, \ + .optional = _opt, \ + .addr.maxcycles = _maxcycles, \ + } + +#define NAND_OP_PARSER_PAT_DATA_IN_ELEM(_opt, _maxlen) \ + { \ + .type = NAND_OP_DATA_IN_INSTR, \ + .optional = _opt, \ + .data.maxlen = _maxlen, \ + } + +#define NAND_OP_PARSER_PAT_DATA_OUT_ELEM(_opt, _maxlen) \ + { \ + .type = NAND_OP_DATA_OUT_INSTR, \ + .optional = _opt, \ + .data.maxlen = _maxlen, \ + } + +#define NAND_OP_PARSER_PAT_WAITRDY_ELEM(_opt) \ + { \ + .type = NAND_OP_WAITRDY_INSTR, \ + .optional = _opt, \ + } + +/** + * struct nand_op_parser_pattern - NAND sub-operation pattern descriptor + * @elems: array of pattern elements + * @nelems: number of pattern elements in @elems array + * @exec: the function that will issue a sub-operation + * + * A pattern is a list of elements, each element reprensenting one instruction + * with its constraints. The pattern itself is used by the core to match NAND + * chip operation with NAND controller operations. + * Once a match between a NAND controller operation pattern and a NAND chip + * operation (or a sub-set of a NAND operation) is found, the pattern ->exec() + * hook is called so that the controller driver can issue the operation on the + * bus. + * + * Controller drivers should declare as many patterns as they support and pass + * this list of patterns (created with the help of the following macro) to + * the nand_op_parser_exec_op() helper. + */ +struct nand_op_parser_pattern { + const struct nand_op_parser_pattern_elem *elems; + unsigned int nelems; + int (*exec)(struct nand_chip *chip, const struct nand_subop *subop); +}; + +#define NAND_OP_PARSER_PATTERN(_exec, ...) \ + { \ + .exec = _exec, \ + .elems = (struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ }, \ + .nelems = sizeof((struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ }) / \ + sizeof(struct nand_op_parser_pattern_elem), \ + } + +/** + * struct nand_op_parser - NAND controller operation parser descriptor + * @patterns: array of supported patterns + * @npatterns: length of the @patterns array + * + * The parser descriptor is just an array of supported patterns which will be + * iterated by nand_op_parser_exec_op() everytime it tries to execute an + * NAND operation (or tries to determine if a specific operation is supported). + * + * It is worth mentioning that patterns will be tested in their declaration + * order, and the first match will be taken, so it's important to order patterns + * appropriately so that simple/inefficient patterns are placed at the end of + * the list. Usually, this is where you put single instruction patterns. + */ +struct nand_op_parser { + const struct nand_op_parser_pattern *patterns; + unsigned int npatterns; +}; + +#define NAND_OP_PARSER(...) \ + { \ + .patterns = (struct nand_op_parser_pattern[]) { __VA_ARGS__ }, \ + .npatterns = sizeof((struct nand_op_parser_pattern[]) { __VA_ARGS__ }) / \ + sizeof(struct nand_op_parser_pattern), \ + } + +/** + * struct nand_operation - NAND operation descriptor + * @instrs: array of instructions to execute + * @ninstrs: length of the @instrs array + * + * The actual operation structure that will be passed to chip->exec_op(). + */ +struct nand_operation { + const struct nand_op_instr *instrs; + unsigned int ninstrs; +}; + +#define NAND_OPERATION(_instrs) \ + { \ + .instrs = _instrs, \ + .ninstrs = ARRAY_SIZE(_instrs), \ + } + +int nand_op_parser_exec_op(struct nand_chip *chip, + const struct nand_op_parser *parser, + const struct nand_operation *op, bool check_only); + /** * struct nand_chip - NAND Private Flash Chip Data * @mtd: MTD device registered to the MTD framework @@ -760,6 +1104,10 @@ struct nand_manufacturer_ops { * commands to the chip. * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * ready. + * @exec_op: controller specific method to execute NAND operations. + * This method replaces ->cmdfunc(), + * ->{read,write}_{buf,byte,word}(), ->dev_ready() and + * ->waifunc(). * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure @@ -859,6 +1207,9 @@ struct nand_chip { void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); + int (*exec_op)(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only); int (*erase)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip, @@ -869,7 +1220,6 @@ struct nand_chip { int (*setup_data_interface)(struct mtd_info *mtd, int chipnr, const struct nand_data_interface *conf); - int chip_delay; unsigned int options; unsigned int bbt_options; @@ -929,6 +1279,15 @@ struct nand_chip { } manufacturer; }; +static inline int nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op) +{ + if (!chip->exec_op) + return -ENOTSUPP; + + return chip->exec_op(chip, op, false); +} + extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops; @@ -1320,4 +1679,11 @@ void nand_cleanup(struct nand_chip *chip); /* Default extended ID decoding function */ void nand_decode_ext_id(struct nand_chip *chip); + +/* + * External helper for controller drivers that have to implement the WAITRDY + * instruction and have no physical pin to check it. + */ +int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms); + #endif /* __LINUX_MTD_RAWNAND_H */ -- cgit v1.2.3 From c1a72e2dbb4abb90bd408480d7c48ba40cb799ce Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 19 Jan 2018 19:11:27 +0100 Subject: mtd: nand: Fix build issues due to an anonymous union GCC-4.4.4 raises errors when assigning a parameter in an anonymous union, leading to this kind of failure: drivers/mtd/nand/marvell_nand.c:1936: warning: missing braces around initializer warning: (near initialization for '(anonymous)[1].') error: unknown field 'data' specified in initializer error: unknown field 'addr' specified in initializer Work around the situation by naming these unions. Fixes: 8878b126df76 ("mtd: nand: add ->exec_op() implementation") Reported-by: Andrew Morton Signed-off-by: Miquel Raynal Tested-by: Andrew Morton Signed-off-by: Boris Brezillon --- include/linux/mtd/rawnand.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux/mtd') diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 469dc724f5df..56c5570aadbe 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -962,7 +962,7 @@ struct nand_op_parser_pattern_elem { union { struct nand_op_parser_addr_constraints addr; struct nand_op_parser_data_constraints data; - }; + } ctx; }; #define NAND_OP_PARSER_PAT_CMD_ELEM(_opt) \ @@ -975,21 +975,21 @@ struct nand_op_parser_pattern_elem { { \ .type = NAND_OP_ADDR_INSTR, \ .optional = _opt, \ - .addr.maxcycles = _maxcycles, \ + .ctx.addr.maxcycles = _maxcycles, \ } #define NAND_OP_PARSER_PAT_DATA_IN_ELEM(_opt, _maxlen) \ { \ .type = NAND_OP_DATA_IN_INSTR, \ .optional = _opt, \ - .data.maxlen = _maxlen, \ + .ctx.data.maxlen = _maxlen, \ } #define NAND_OP_PARSER_PAT_DATA_OUT_ELEM(_opt, _maxlen) \ { \ .type = NAND_OP_DATA_OUT_INSTR, \ .optional = _opt, \ - .data.maxlen = _maxlen, \ + .ctx.data.maxlen = _maxlen, \ } #define NAND_OP_PARSER_PAT_WAITRDY_ELEM(_opt) \ -- cgit v1.2.3