/* SPDX-License-Identifier: GPL-2.0 *//* * Copyright (c) 2016-2017 Micron Technology, Inc. * * Authors: * Peter Pan <peterpandong@micron.com> */#ifndef __LINUX_MTD_SPINAND_H#define __LINUX_MTD_SPINAND_H #include <linux/mutex.h>#include <linux/bitops.h>#include <linux/device.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/spi/spi.h>#include <linux/spi/spi-mem.h> /** * Standard SPI NAND flash operations */ #define SPINAND_RESET_1S_0_0_OP \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_WR_EN_1S_0_0_OP \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x06, 1), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_WR_DIS_1S_0_0_OP \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x04, 1), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_READID_1S_1S_1S_OP(naddr, ndummy, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \ SPI_MEM_OP_ADDR(naddr, 0, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1)) #define SPINAND_SET_FEATURE_1S_1S_1S_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1), \ SPI_MEM_OP_ADDR(1, reg, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(1, valptr, 1)) #define SPINAND_GET_FEATURE_1S_1S_1S_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1), \ SPI_MEM_OP_ADDR(1, reg, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_IN(1, valptr, 1)) #define SPINAND_BLK_ERASE_1S_1S_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_1S_1S_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ SPI_MEM_OP_ADDR(2, addr, 2), \ SPI_MEM_OP_DUMMY(ndummy, 2), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ SPI_MEM_OP_ADDR(3, addr, 2), \ SPI_MEM_OP_DUMMY(ndummy, 2), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 2), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 2), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ SPI_MEM_OP_ADDR(2, addr, 4), \ SPI_MEM_OP_DUMMY(ndummy, 4), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ SPI_MEM_OP_ADDR(3, addr, 4), \ SPI_MEM_OP_DUMMY(ndummy, 4), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 4), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 4), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \ SPI_MEM_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_DUMMY(ndummy, 8), \ SPI_MEM_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x9d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PROG_EXEC_1S_1S_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PROG_LOAD_1S_1S_1S_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 1)) #define SPINAND_PROG_LOAD_1S_1S_4S_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 4)) #define SPINAND_PROG_LOAD_1S_1S_8S_OP(addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x82, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 8)) #define SPINAND_PROG_LOAD_1S_8S_8S_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0xc2 : 0xc4, 1), \ SPI_MEM_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 8)) /** * Octal DDR SPI NAND flash operations */ #define SPINAND_RESET_8D_0_0_OP \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xff, 8), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_READID_8D_8D_8D_OP(naddr, ndummy, buf, len) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9f, 8), \ SPI_MEM_DTR_OP_ADDR(naddr, 0, 8), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 8)) #define SPINAND_WR_EN_8D_0_0_OP \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x06, 8), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_WR_DIS_8D_0_0_OP \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x04, 8), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_SET_FEATURE_8D_8D_8D_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x1f, 8), \ SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_DTR_OP_DATA_OUT(2, valptr, 8)) #define SPINAND_GET_FEATURE_8D_8D_8D_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x0f, 8), \ SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \ SPI_MEM_DTR_OP_DUMMY(14, 8), \ SPI_MEM_DTR_OP_DATA_IN(2, valptr, 8)) #define SPINAND_BLK_ERASE_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xd8, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x13, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PROG_EXEC_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x10, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PROG_LOAD_8D_8D_8D_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD((reset ? 0xc2 : 0xc4), 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_DTR_OP_DATA_OUT(len, buf, 8)) /* feature register */#define REG_BLOCK_LOCK 0xa0#define BL_ALL_UNLOCKED 0x00 /* configuration register */#define REG_CFG 0xb0#define CFG_OTP_ENABLE BIT(6)#define CFG_ECC_ENABLE BIT(4)#define CFG_QUAD_ENABLE BIT(0) /* status register */#define REG_STATUS 0xc0#define STATUS_BUSY BIT(0)#define STATUS_ERASE_FAILED BIT(2)#define STATUS_PROG_FAILED BIT(3)#define STATUS_ECC_MASK GENMASK(5, 4)#define STATUS_ECC_NO_BITFLIPS (0 << 4)#define STATUS_ECC_HAS_BITFLIPS (1 << 4)#define STATUS_ECC_UNCOR_ERROR (2 << 4) struct spinand_op;struct spinand_device; #define SPINAND_MAX_ID_LEN 6/* * For erase, write and read operation, we got the following timings : * tBERS (erase) 1ms to 4ms * tPROG 300us to 400us * tREAD 25us to 100us * In order to minimize latency, the min value is divided by 4 for the * initial delay, and dividing by 20 for the poll delay. * For reset, 5us/10us/500us if the device is respectively * reading/programming/erasing when the RESET occurs. Since we always * issue a RESET when the device is IDLE, 5us is selected for both initial * and poll delay. */#define SPINAND_READ_INITIAL_DELAY_US 6#define SPINAND_READ_POLL_DELAY_US 5#define SPINAND_RESET_INITIAL_DELAY_US 5#define SPINAND_RESET_POLL_DELAY_US 5#define SPINAND_WRITE_INITIAL_DELAY_US 75#define SPINAND_WRITE_POLL_DELAY_US 15#define SPINAND_ERASE_INITIAL_DELAY_US 250#define SPINAND_ERASE_POLL_DELAY_US 50 #define SPINAND_WAITRDY_TIMEOUT_MS 400 /** * struct spinand_id - SPI NAND id structure * @data: buffer containing the id bytes. Currently 6 bytes large, but can * be extended if required * @len: ID length */struct spinand_id { u8 data[SPINAND_MAX_ID_LEN]; int len;}; enum spinand_readid_method { SPINAND_READID_METHOD_OPCODE, SPINAND_READID_METHOD_OPCODE_ADDR, SPINAND_READID_METHOD_OPCODE_DUMMY,}; /** * struct spinand_devid - SPI NAND device id structure * @id: device id of current chip * @len: number of bytes in device id * @method: method to read chip id * There are 3 possible variants: * SPINAND_READID_METHOD_OPCODE: chip id is returned immediately * after read_id opcode. * SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after * read_id opcode + 1-byte address. * SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after * read_id opcode + 1 dummy byte. */struct spinand_devid { const u8 *id; const u8 len; const enum spinand_readid_method method;}; /** * struct manufacurer_ops - SPI NAND manufacturer specific operations * @init: initialize a SPI NAND device * @cleanup: cleanup a SPI NAND device * * Each SPI NAND manufacturer driver should implement this interface so that * NAND chips coming from this vendor can be initialized properly. */struct spinand_manufacturer_ops { int (*init)(struct spinand_device *spinand); void (*cleanup)(struct spinand_device *spinand);}; /** * struct spinand_manufacturer - SPI NAND manufacturer instance * @id: manufacturer ID * @name: manufacturer name * @devid_len: number of bytes in device ID * @chips: supported SPI NANDs under current manufacturer * @nchips: number of SPI NANDs available in chips array * @ops: manufacturer operations */struct spinand_manufacturer { u8 id; char *name; const struct spinand_info *chips; const size_t nchips; const struct spinand_manufacturer_ops *ops;}; /* SPI NAND manufacturers */extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;extern const struct spinand_manufacturer ato_spinand_manufacturer;extern const struct spinand_manufacturer dosilicon_spinand_manufacturer;extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;extern const struct spinand_manufacturer fmsh_spinand_manufacturer;extern const struct spinand_manufacturer foresee_spinand_manufacturer;extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;extern const struct spinand_manufacturer heyangtek_spinand_manufacturer;extern const struct spinand_manufacturer macronix_spinand_manufacturer;extern const struct spinand_manufacturer micron_spinand_manufacturer;extern const struct spinand_manufacturer paragon_spinand_manufacturer;extern const struct spinand_manufacturer skyhigh_spinand_manufacturer;extern const struct spinand_manufacturer toshiba_spinand_manufacturer;extern const struct spinand_manufacturer winbond_spinand_manufacturer;extern const struct spinand_manufacturer xtx_spinand_manufacturer; /** * struct spinand_op_variants - SPI NAND operation variants * @ops: the list of variants for a given operation * @nops: the number of variants * * Some operations like read-from-cache/write-to-cache have several variants * depending on the number of IO lines you use to transfer data or address * cycles. This structure is a way to describe the different variants supported * by a chip and let the core pick the best one based on the SPI mem controller * capabilities. */struct spinand_op_variants { const struct spi_mem_op *ops; unsigned int nops;}; #define SPINAND_OP_VARIANTS(name, ...) \ const struct spinand_op_variants name = { \ .ops = (struct spi_mem_op[]) { __VA_ARGS__ }, \ .nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) / \ sizeof(struct spi_mem_op), \ } /** * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND * chip * @get_status: get the ECC status. Should return a positive number encoding * the number of corrected bitflips if correction was possible or * -EBADMSG if there are uncorrectable errors. I can also return * other negative error codes if the error is not caused by * uncorrectable bitflips * @ooblayout: the OOB layout used by the on-die ECC implementation */struct spinand_ecc_info { int (*get_status)(struct spinand_device *spinand, u8 status); const struct mtd_ooblayout_ops *ooblayout;}; /* SPI NAND flags */#define SPINAND_HAS_QE_BIT BIT(0)#define SPINAND_HAS_CR_FEAT_BIT BIT(1)#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)#define SPINAND_NO_RAW_ACCESS BIT(4)#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5) /** * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure * @status: status of the last wait operation that will be used in case * ->get_status() is not populated by the spinand device. */struct spinand_ondie_ecc_conf {Lines 1–500 of 927. Load more
/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016-2017 Micron Technology, Inc. * * Authors: * Peter Pan <peterpandong@micron.com> */ #ifndef __LINUX_MTD_SPINAND_H #define __LINUX_MTD_SPINAND_H #include <linux/mutex.h> #include <linux/bitops.h> #include <linux/device.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> /** * Standard SPI NAND flash operations */ #define SPINAND_RESET_1S_0_0_OP \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_WR_EN_1S_0_0_OP \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x06, 1), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_WR_DIS_1S_0_0_OP \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x04, 1), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_READID_1S_1S_1S_OP(naddr, ndummy, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \ SPI_MEM_OP_ADDR(naddr, 0, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1)) #define SPINAND_SET_FEATURE_1S_1S_1S_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1), \ SPI_MEM_OP_ADDR(1, reg, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(1, valptr, 1)) #define SPINAND_GET_FEATURE_1S_1S_1S_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1), \ SPI_MEM_OP_ADDR(1, reg, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_IN(1, valptr, 1)) #define SPINAND_BLK_ERASE_1S_1S_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_1S_1S_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ SPI_MEM_OP_ADDR(2, addr, 2), \ SPI_MEM_OP_DUMMY(ndummy, 2), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ SPI_MEM_OP_ADDR(3, addr, 2), \ SPI_MEM_OP_DUMMY(ndummy, 2), \ SPI_MEM_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 2), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 2), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ SPI_MEM_OP_ADDR(2, addr, 4), \ SPI_MEM_OP_DUMMY(ndummy, 4), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ SPI_MEM_OP_ADDR(3, addr, 4), \ SPI_MEM_OP_DUMMY(ndummy, 4), \ SPI_MEM_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 4), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 4), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_DUMMY(ndummy, 1), \ SPI_MEM_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \ SPI_MEM_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_DUMMY(ndummy, 8), \ SPI_MEM_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x9d, 1), \ SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PROG_EXEC_1S_1S_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PROG_LOAD_1S_1S_1S_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 1)) #define SPINAND_PROG_LOAD_1S_1S_4S_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 4)) #define SPINAND_PROG_LOAD_1S_1S_8S_OP(addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x82, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 8)) #define SPINAND_PROG_LOAD_1S_8S_8S_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0xc2 : 0xc4, 1), \ SPI_MEM_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 8)) /** * Octal DDR SPI NAND flash operations */ #define SPINAND_RESET_8D_0_0_OP \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xff, 8), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_READID_8D_8D_8D_OP(naddr, ndummy, buf, len) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9f, 8), \ SPI_MEM_DTR_OP_ADDR(naddr, 0, 8), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 8)) #define SPINAND_WR_EN_8D_0_0_OP \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x06, 8), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_WR_DIS_8D_0_0_OP \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x04, 8), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_SET_FEATURE_8D_8D_8D_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x1f, 8), \ SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_DTR_OP_DATA_OUT(2, valptr, 8)) #define SPINAND_GET_FEATURE_8D_8D_8D_OP(reg, valptr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x0f, 8), \ SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \ SPI_MEM_DTR_OP_DUMMY(14, 8), \ SPI_MEM_DTR_OP_DATA_IN(2, valptr, 8)) #define SPINAND_BLK_ERASE_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xd8, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x13, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \ SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ SPI_MEM_OP_MAX_FREQ(freq)) #define SPINAND_PROG_EXEC_8D_8D_0_OP(addr) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x10, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) #define SPINAND_PROG_LOAD_8D_8D_8D_OP(reset, addr, buf, len) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD((reset ? 0xc2 : 0xc4), 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_DTR_OP_DATA_OUT(len, buf, 8)) /* feature register */ #define REG_BLOCK_LOCK 0xa0 #define BL_ALL_UNLOCKED 0x00 /* configuration register */ #define REG_CFG 0xb0 #define CFG_OTP_ENABLE BIT(6) #define CFG_ECC_ENABLE BIT(4) #define CFG_QUAD_ENABLE BIT(0) /* status register */ #define REG_STATUS 0xc0 #define STATUS_BUSY BIT(0) #define STATUS_ERASE_FAILED BIT(2) #define STATUS_PROG_FAILED BIT(3) #define STATUS_ECC_MASK GENMASK(5, 4) #define STATUS_ECC_NO_BITFLIPS (0 << 4) #define STATUS_ECC_HAS_BITFLIPS (1 << 4) #define STATUS_ECC_UNCOR_ERROR (2 << 4) struct spinand_op; struct spinand_device; #define SPINAND_MAX_ID_LEN 6 /* * For erase, write and read operation, we got the following timings : * tBERS (erase) 1ms to 4ms * tPROG 300us to 400us * tREAD 25us to 100us * In order to minimize latency, the min value is divided by 4 for the * initial delay, and dividing by 20 for the poll delay. * For reset, 5us/10us/500us if the device is respectively * reading/programming/erasing when the RESET occurs. Since we always * issue a RESET when the device is IDLE, 5us is selected for both initial * and poll delay. */ #define SPINAND_READ_INITIAL_DELAY_US 6 #define SPINAND_READ_POLL_DELAY_US 5 #define SPINAND_RESET_INITIAL_DELAY_US 5 #define SPINAND_RESET_POLL_DELAY_US 5 #define SPINAND_WRITE_INITIAL_DELAY_US 75 #define SPINAND_WRITE_POLL_DELAY_US 15 #define SPINAND_ERASE_INITIAL_DELAY_US 250 #define SPINAND_ERASE_POLL_DELAY_US 50 #define SPINAND_WAITRDY_TIMEOUT_MS 400 /** * struct spinand_id - SPI NAND id structure * @data: buffer containing the id bytes. Currently 6 bytes large, but can * be extended if required * @len: ID length */ struct spinand_id { u8 data[SPINAND_MAX_ID_LEN]; int len; }; enum spinand_readid_method { SPINAND_READID_METHOD_OPCODE, SPINAND_READID_METHOD_OPCODE_ADDR, SPINAND_READID_METHOD_OPCODE_DUMMY, }; /** * struct spinand_devid - SPI NAND device id structure * @id: device id of current chip * @len: number of bytes in device id * @method: method to read chip id * There are 3 possible variants: * SPINAND_READID_METHOD_OPCODE: chip id is returned immediately * after read_id opcode. * SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after * read_id opcode + 1-byte address. * SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after * read_id opcode + 1 dummy byte. */ struct spinand_devid { const u8 *id; const u8 len; const enum spinand_readid_method method; }; /** * struct manufacurer_ops - SPI NAND manufacturer specific operations * @init: initialize a SPI NAND device * @cleanup: cleanup a SPI NAND device * * Each SPI NAND manufacturer driver should implement this interface so that * NAND chips coming from this vendor can be initialized properly. */ struct spinand_manufacturer_ops { int (*init)(struct spinand_device *spinand); void (*cleanup)(struct spinand_device *spinand); }; /** * struct spinand_manufacturer - SPI NAND manufacturer instance * @id: manufacturer ID * @name: manufacturer name * @devid_len: number of bytes in device ID * @chips: supported SPI NANDs under current manufacturer * @nchips: number of SPI NANDs available in chips array * @ops: manufacturer operations */ struct spinand_manufacturer { u8 id; char *name; const struct spinand_info *chips; const size_t nchips; const struct spinand_manufacturer_ops *ops; }; /* SPI NAND manufacturers */ extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer dosilicon_spinand_manufacturer; extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer; extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; extern const struct spinand_manufacturer fmsh_spinand_manufacturer; extern const struct spinand_manufacturer foresee_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer heyangtek_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer micron_spinand_manufacturer; extern const struct spinand_manufacturer paragon_spinand_manufacturer; extern const struct spinand_manufacturer skyhigh_spinand_manufacturer; extern const struct spinand_manufacturer toshiba_spinand_manufacturer; extern const struct spinand_manufacturer winbond_spinand_manufacturer; extern const struct spinand_manufacturer xtx_spinand_manufacturer; /** * struct spinand_op_variants - SPI NAND operation variants * @ops: the list of variants for a given operation * @nops: the number of variants * * Some operations like read-from-cache/write-to-cache have several variants * depending on the number of IO lines you use to transfer data or address * cycles. This structure is a way to describe the different variants supported * by a chip and let the core pick the best one based on the SPI mem controller * capabilities. */ struct spinand_op_variants { const struct spi_mem_op *ops; unsigned int nops; }; #define SPINAND_OP_VARIANTS(name, ...) \ const struct spinand_op_variants name = { \ .ops = (struct spi_mem_op[]) { __VA_ARGS__ }, \ .nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) / \ sizeof(struct spi_mem_op), \ } /** * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND * chip * @get_status: get the ECC status. Should return a positive number encoding * the number of corrected bitflips if correction was possible or * -EBADMSG if there are uncorrectable errors. I can also return * other negative error codes if the error is not caused by * uncorrectable bitflips * @ooblayout: the OOB layout used by the on-die ECC implementation */ struct spinand_ecc_info { int (*get_status)(struct spinand_device *spinand, u8 status); const struct mtd_ooblayout_ops *ooblayout; }; /* SPI NAND flags */ #define SPINAND_HAS_QE_BIT BIT(0) #define SPINAND_HAS_CR_FEAT_BIT BIT(1) #define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) #define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) #define SPINAND_NO_RAW_ACCESS BIT(4) #define SPINAND_ODTR_PACKED_PAGE_READ BIT(5) /** * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure * @status: status of the last wait operation that will be used in case * ->get_status() is not populated by the spinand device. */ struct spinand_ondie_ecc_conf {