summaryrefslogtreecommitdiff
path: root/include/linux/mtd/spinand.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/mtd/spinand.h')
-rw-r--r--include/linux/mtd/spinand.h155
1 files changed, 142 insertions, 13 deletions
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 88bacde91e..5c89bd1dcc 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -33,12 +33,25 @@
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
+#define SPINAND_RESET_OP_OCTAL_DTR \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0xffff, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_ADDR, \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_WR_EN_DIS_OP(enable) \
SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1), \
SPI_MEM_OP_NO_ADDR, \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
+#define SPINAND_WR_EN_DIS_OP_OCTAL_DTR(enable) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, (enable) ? 0x0606 : 0x0404, 8, \
+ SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_ADDR, \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_READID_OP(ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
SPI_MEM_OP_NO_ADDR, \
@@ -51,24 +64,48 @@
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_DATA_OUT(1, valptr, 1))
+#define SPINAND_SET_FEATURE_OP_OCTAL_DTR(reg, valptr) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1f1f, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, reg, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_DATA_OUT(2, valptr, 8, SPI_MEM_OP_DTR))
+
#define SPINAND_GET_FEATURE_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_GET_FEATURE_OP_OCTAL_DTR(reg, valptr) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x0f0f, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, reg, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_DUMMY(14, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_DATA_IN(2, valptr, 8, SPI_MEM_OP_DTR))
+
#define SPINAND_BLK_ERASE_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_BLK_ERASE_OP_OCTAL_DTR(addr) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0xd8d8, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, addr, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_PAGE_READ_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_OP_OCTAL_DTR(addr) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1313, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, addr, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
SPI_MEM_OP_ADDR(2, addr, 1), \
@@ -99,18 +136,37 @@
SPI_MEM_OP_DUMMY(ndummy, 4), \
SPI_MEM_OP_DATA_IN(len, buf, 4))
+#define SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(addr, ndummy, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x9d9d, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, addr, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_DUMMY(ndummy, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_DATA_IN(len, buf, 8, SPI_MEM_OP_DTR))
+
#define SPINAND_PROG_EXEC_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_EXEC_OP_OCTAL_DTR(addr) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1010, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, addr, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_PROG_LOAD(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_OCTALIO_DTR(reset, addr, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, reset ? 0x0202 : 0x8484, 8, \
+ SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_ADDR(2, addr, 8, SPI_MEM_OP_DTR), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_DATA_OUT(len, buf, 8, SPI_MEM_OP_DTR))
+
#define SPINAND_PROG_LOAD_X4(reset, addr, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \
SPI_MEM_OP_ADDR(2, addr, 1), \
@@ -118,6 +174,18 @@
SPI_MEM_OP_DATA_OUT(len, buf, 4))
/**
+ * enum spinand_protocol - List of SPI protocols to denote the op protocol and
+ * SPI NAND flash IO modes.
+ */
+enum spinand_protocol {
+ SPINAND_1S,
+ SPINAND_2S,
+ SPINAND_4S,
+ SPINAND_8S,
+ SPINAND_8D,
+};
+
+/**
* Standard SPI NAND flash commands
*/
#define SPINAND_CMD_PROG_LOAD_X4 0x32
@@ -177,6 +245,7 @@ struct spinand_id {
* that properties of the NAND chip (spinand->base.memorg and
* spinand->base.eccreq) have been filled
* @init: initialize a SPI NAND device
+ * @change_protocol: switch the SPI NAND flash to a specific SPI protocol
* @cleanup: cleanup a SPI NAND device
*
* Each SPI NAND manufacturer driver should implement this interface so that
@@ -185,6 +254,8 @@ struct spinand_id {
struct spinand_manufacturer_ops {
int (*detect)(struct spinand_device *spinand);
int (*init)(struct spinand_device *spinand);
+ int (*change_protocol)(struct spinand_device *spinand,
+ const enum spinand_protocol protocol);
void (*cleanup)(struct spinand_device *spinand);
};
@@ -229,6 +300,46 @@ struct spinand_op_variants {
.nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) / \
sizeof(struct spi_mem_op), \
}
+struct spinand_ctrl_ops {
+ const struct {
+ struct spi_mem_op reset;
+ struct spi_mem_op get_feature;
+ struct spi_mem_op set_feature;
+ struct spi_mem_op write_enable;
+ struct spi_mem_op block_erase;
+ struct spi_mem_op page_read;
+ struct spi_mem_op program_execute;
+ } ops;
+ const enum spinand_protocol protocol;
+};
+
+#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature, \
+ __write_enable, __block_erase, __page_read, \
+ __program_execute) \
+ { \
+ .ops = { \
+ .reset = __reset, \
+ .get_feature = __get_feature, \
+ .set_feature = __set_feature, \
+ .write_enable = __write_enable, \
+ .block_erase = __block_erase, \
+ .page_read = __page_read, \
+ .program_execute = __program_execute, \
+ }, \
+ .protocol = __protocol, \
+ }
+
+struct spinand_ctrl_ops_variants {
+ const struct spinand_ctrl_ops *ctrl_ops_list;
+ unsigned int nvariants;
+};
+
+#define SPINAND_CTRL_OPS_VARIANTS(name, ...) \
+ const struct spinand_ctrl_ops_variants name = { \
+ .ctrl_ops_list = (struct spinand_ctrl_ops[]){ __VA_ARGS__ }, \
+ .nvariants = sizeof((struct spinand_ctrl_ops[]){ __VA_ARGS__ })/\
+ sizeof(struct spinand_ctrl_ops), \
+ }
/**
* spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
@@ -247,6 +358,7 @@ struct spinand_ecc_info {
#define SPINAND_HAS_QE_BIT BIT(0)
#define SPINAND_HAS_CR_FEAT_BIT BIT(1)
+#define SPINAND_HAS_OCTAL_DTR_BIT BIT(2)
/**
* struct spinand_info - Structure used to describe SPI NAND chips
@@ -256,10 +368,10 @@ struct spinand_ecc_info {
* @memorg: memory organization
* @eccreq: ECC requirements
* @eccinfo: on-die ECC info
- * @op_variants: operations variants
- * @op_variants.read_cache: variants of the read-cache operation
- * @op_variants.write_cache: variants of the write-cache operation
- * @op_variants.update_cache: variants of the update-cache operation
+ * @data_ops_variants: operations variants for page read/writes
+ * @data_ops_variants.read_cache: variants of the read-cache operation
+ * @data_ops_variants.write_cache: variants of the write-cache operation
+ * @data_ops_variants.update_cache: variants of the update-cache operation
* @select_target: function used to select a target/die. Required only for
* multi-die chips
*
@@ -277,7 +389,9 @@ struct spinand_info {
const struct spinand_op_variants *read_cache;
const struct spinand_op_variants *write_cache;
const struct spinand_op_variants *update_cache;
- } op_variants;
+ } data_ops_variants;
+
+ const struct spinand_ctrl_ops_variants *ctrl_ops_variants;
int (*select_target)(struct spinand_device *spinand,
unsigned int target);
};
@@ -289,6 +403,9 @@ struct spinand_info {
.update_cache = __update, \
}
+#define SPINAND_INFO_CTRL_OPS_VARIANTS(__ctrl_ops_variants) \
+ .ctrl_ops_variants = __ctrl_ops_variants
+
#define SPINAND_ECCINFO(__ooblayout, __get_status) \
.eccinfo = { \
.ooblayout = __ooblayout, \
@@ -298,14 +415,14 @@ struct spinand_info {
#define SPINAND_SELECT_TARGET(__func) \
.select_target = __func,
-#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \
- __flags, ...) \
+#define SPINAND_INFO(__model, __id, __memorg, __eccreq, \
+ __data_ops_variants, __flags, ...) \
{ \
.model = __model, \
.devid = __id, \
.memorg = __memorg, \
.eccreq = __eccreq, \
- .op_variants = __op_variants, \
+ .data_ops_variants = __data_ops_variants, \
.flags = __flags, \
__VA_ARGS__ \
}
@@ -317,15 +434,19 @@ struct spinand_info {
* @lock: lock used to serialize accesses to the NAND
* @id: NAND ID as returned by READ_ID
* @flags: NAND flags
- * @op_templates: various SPI mem op templates
- * @op_templates.read_cache: read cache op template
- * @op_templates.write_cache: write cache op template
- * @op_templates.update_cache: update cache op template
+ * @data_ops: various SPI mem op templates for reading and writing on pages
+ * @data_ops.read_cache: read cache op template
+ * @data_ops.write_cache: write cache op template
+ * @data_ops.update_cache: update cache op template
+ * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
+ * non page-read/write ops.
* @select_target: select a specific target/die. Usually called before sending
* a command addressing a page or an eraseblock embedded in
* this die. Only required if your chip exposes several dies
* @cur_target: currently selected target/die
* @eccinfo: on-die ECC information
+ * @protocol: SPI IO protocol in operation. Update on successful transition into
+ * a different SPI IO protocol.
* @cfg_cache: config register cache. One entry per die
* @databuf: bounce buffer for data
* @oobbuf: bounce buffer for OOB data
@@ -334,6 +455,8 @@ struct spinand_info {
* passed in spi_mem_op be DMA-able, so we can't based the bufs on
* the stack
* @manufacturer: SPI NAND manufacturer information
+ * @desc_entry: pointer to device description entry in the manufacturer's
+ * spinand_info tables
* @priv: manufacturer private data
*/
struct spinand_device {
@@ -351,7 +474,9 @@ struct spinand_device {
const struct spi_mem_op *read_cache;
const struct spi_mem_op *write_cache;
const struct spi_mem_op *update_cache;
- } op_templates;
+ } data_ops;
+
+ const struct spinand_ctrl_ops *ctrl_ops;
int (*select_target)(struct spinand_device *spinand,
unsigned int target);
@@ -359,11 +484,14 @@ struct spinand_device {
struct spinand_ecc_info eccinfo;
+ enum spinand_protocol protocol;
+
u8 *cfg_cache;
u8 *databuf;
u8 *oobbuf;
u8 *scratchbuf;
const struct spinand_manufacturer *manufacturer;
+ const struct spinand_info *desc_entry;
void *priv;
};
@@ -431,5 +559,6 @@ int spinand_match_and_init(struct spinand_device *dev,
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+int spinand_write_enable_op(struct spinand_device *spinand);
#endif /* __LINUX_MTD_SPINAND_H */