mtd: spi-nor-core: Add support for DTR protocol
Double Transfer Rate (DTR) is SPI protocol in which data is transferred on each clock edge as opposed to on each clock cycle. Make framework-level changes to allow supporting flashes in DTR mode. Right now, mixed DTR modes are not supported. So, for example a mode like 4S-4D-4D will not work. All phases need to be either DTR or STR. Signed-off-by: Pratyush Yadav <p.yadav@ti.com> Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
This commit is contained in:
committed by
Jagan Teki
parent
6182d15b3e
commit
95954f55e9
@@ -68,6 +68,7 @@ struct flash_info {
|
||||
#define USE_CLSR BIT(14) /* use CLSR command */
|
||||
#define SPI_NOR_HAS_SST26LOCK BIT(15) /* Flash supports lock/unlock via BPR */
|
||||
#define SPI_NOR_OCTAL_READ BIT(16) /* Flash supports Octal Read */
|
||||
#define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */
|
||||
};
|
||||
|
||||
extern const struct flash_info spi_nor_ids[];
|
||||
|
||||
@@ -177,6 +177,76 @@ struct spi_nor_fixups {
|
||||
struct spi_nor_flash_parameter *params);
|
||||
};
|
||||
|
||||
/**
|
||||
* spi_nor_get_cmd_ext() - Get the command opcode extension based on the
|
||||
* extension type.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
* @op: pointer to the 'struct spi_mem_op' whose properties
|
||||
* need to be initialized.
|
||||
*
|
||||
* Right now, only "repeat" and "invert" are supported.
|
||||
*
|
||||
* Return: The opcode extension.
|
||||
*/
|
||||
static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
switch (nor->cmd_ext_type) {
|
||||
case SPI_NOR_EXT_INVERT:
|
||||
return ~op->cmd.opcode;
|
||||
|
||||
case SPI_NOR_EXT_REPEAT:
|
||||
return op->cmd.opcode;
|
||||
|
||||
default:
|
||||
dev_dbg(nor->dev, "Unknown command extension type\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_setup_op() - Set up common properties of a spi-mem op.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
* @op: pointer to the 'struct spi_mem_op' whose properties
|
||||
* need to be initialized.
|
||||
* @proto: the protocol from which the properties need to be set.
|
||||
*/
|
||||
static void spi_nor_setup_op(const struct spi_nor *nor,
|
||||
struct spi_mem_op *op,
|
||||
const enum spi_nor_protocol proto)
|
||||
{
|
||||
u8 ext;
|
||||
|
||||
op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto);
|
||||
|
||||
if (op->addr.nbytes)
|
||||
op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto);
|
||||
|
||||
if (op->dummy.nbytes)
|
||||
op->dummy.buswidth = spi_nor_get_protocol_addr_nbits(proto);
|
||||
|
||||
if (op->data.nbytes)
|
||||
op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
|
||||
|
||||
if (spi_nor_protocol_is_dtr(proto)) {
|
||||
/*
|
||||
* spi-mem supports mixed DTR modes, but right now we can only
|
||||
* have all phases either DTR or STR. IOW, spi-mem can have
|
||||
* something like 4S-4D-4D, but spi-nor can't. So, set all 4
|
||||
* phases to either DTR or STR.
|
||||
*/
|
||||
op->cmd.dtr = op->addr.dtr = op->dummy.dtr =
|
||||
op->data.dtr = true;
|
||||
|
||||
/* 2 bytes per clock cycle in DTR mode. */
|
||||
op->dummy.nbytes *= 2;
|
||||
|
||||
ext = spi_nor_get_cmd_ext(nor, op);
|
||||
op->cmd.opcode = (op->cmd.opcode << 8) | ext;
|
||||
op->cmd.nbytes = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
|
||||
*op, void *buf)
|
||||
{
|
||||
@@ -189,12 +259,14 @@ static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
|
||||
|
||||
static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
|
||||
{
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 0),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_IN(len, NULL, 1));
|
||||
SPI_MEM_OP_DATA_IN(len, NULL, 0));
|
||||
int ret;
|
||||
|
||||
spi_nor_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_nor_read_write_reg(nor, &op, val);
|
||||
if (ret < 0)
|
||||
dev_dbg(nor->dev, "error %d reading %x\n", ret, code);
|
||||
@@ -204,10 +276,12 @@ static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
|
||||
|
||||
static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
{
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(len, NULL, 1));
|
||||
SPI_MEM_OP_DATA_OUT(len, NULL, 0));
|
||||
|
||||
spi_nor_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
if (len == 0)
|
||||
op.data.dir = SPI_MEM_NO_DATA;
|
||||
@@ -219,21 +293,19 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
|
||||
u_char *buf)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
|
||||
SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1));
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, from, 0),
|
||||
SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 0));
|
||||
size_t remaining = len;
|
||||
int ret;
|
||||
|
||||
/* get transfer protocols. */
|
||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
|
||||
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
|
||||
op.dummy.buswidth = op.addr.buswidth;
|
||||
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
|
||||
spi_nor_setup_op(nor, &op, nor->read_proto);
|
||||
|
||||
/* convert the dummy cycles to the number of bytes */
|
||||
op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
|
||||
if (spi_nor_protocol_is_dtr(nor->read_proto))
|
||||
op.dummy.nbytes *= 2;
|
||||
|
||||
while (remaining) {
|
||||
op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
|
||||
@@ -257,20 +329,17 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
|
||||
const u_char *buf)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, to, 0),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 1));
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 0));
|
||||
int ret;
|
||||
|
||||
/* get transfer protocols. */
|
||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
|
||||
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
|
||||
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
|
||||
|
||||
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
|
||||
op.addr.nbytes = 0;
|
||||
|
||||
spi_nor_setup_op(nor, &op, nor->write_proto);
|
||||
|
||||
ret = spi_mem_adjust_op_size(nor->spi, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -668,11 +737,13 @@ static int read_bar(struct spi_nor *nor, const struct flash_info *info)
|
||||
static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, addr, 0),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_NO_DATA);
|
||||
|
||||
spi_nor_setup_op(nor, &op, nor->write_proto);
|
||||
|
||||
if (nor->erase)
|
||||
return nor->erase(nor, addr);
|
||||
|
||||
@@ -2194,11 +2265,25 @@ static int spi_nor_init_params(struct spi_nor *nor,
|
||||
SNOR_PROTO_1_1_8);
|
||||
}
|
||||
|
||||
if (info->flags & SPI_NOR_OCTAL_DTR_READ) {
|
||||
params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
|
||||
spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR],
|
||||
0, 20, SPINOR_OP_READ_FAST,
|
||||
SNOR_PROTO_8_8_8_DTR);
|
||||
}
|
||||
|
||||
/* Page Program settings. */
|
||||
params->hwcaps.mask |= SNOR_HWCAPS_PP;
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP],
|
||||
SPINOR_OP_PP, SNOR_PROTO_1_1_1);
|
||||
|
||||
/*
|
||||
* Since xSPI Page Program opcode is backward compatible with
|
||||
* Legacy SPI, use Legacy SPI opcode there as well.
|
||||
*/
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR],
|
||||
SPINOR_OP_PP, SNOR_PROTO_8_8_8_DTR);
|
||||
|
||||
if (info->flags & SPI_NOR_QUAD_READ) {
|
||||
params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4],
|
||||
@@ -2233,7 +2318,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
|
||||
/* Override the parameters with data read from SFDP tables. */
|
||||
nor->addr_width = 0;
|
||||
nor->mtd.erasesize = 0;
|
||||
if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
|
||||
if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_OCTAL_DTR_READ)) &&
|
||||
!(info->flags & SPI_NOR_SKIP_SFDP)) {
|
||||
struct spi_nor_flash_parameter sfdp_params;
|
||||
|
||||
@@ -2280,6 +2366,7 @@ static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
|
||||
{ SNOR_HWCAPS_READ_1_8_8, SNOR_CMD_READ_1_8_8 },
|
||||
{ SNOR_HWCAPS_READ_8_8_8, SNOR_CMD_READ_8_8_8 },
|
||||
{ SNOR_HWCAPS_READ_1_8_8_DTR, SNOR_CMD_READ_1_8_8_DTR },
|
||||
{ SNOR_HWCAPS_READ_8_8_8_DTR, SNOR_CMD_READ_8_8_8_DTR },
|
||||
};
|
||||
|
||||
return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
|
||||
@@ -2296,6 +2383,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
|
||||
{ SNOR_HWCAPS_PP_1_1_8, SNOR_CMD_PP_1_1_8 },
|
||||
{ SNOR_HWCAPS_PP_1_8_8, SNOR_CMD_PP_1_8_8 },
|
||||
{ SNOR_HWCAPS_PP_8_8_8, SNOR_CMD_PP_8_8_8 },
|
||||
{ SNOR_HWCAPS_PP_8_8_8_DTR, SNOR_CMD_PP_8_8_8_DTR },
|
||||
};
|
||||
|
||||
return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
|
||||
@@ -2342,17 +2430,17 @@ static int spi_nor_check_op(struct spi_nor *nor,
|
||||
static int spi_nor_check_readop(struct spi_nor *nor,
|
||||
const struct spi_nor_read_command *read)
|
||||
{
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1),
|
||||
SPI_MEM_OP_ADDR(3, 0, 1),
|
||||
SPI_MEM_OP_DUMMY(0, 1),
|
||||
SPI_MEM_OP_DATA_IN(0, NULL, 1));
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 0),
|
||||
SPI_MEM_OP_ADDR(3, 0, 0),
|
||||
SPI_MEM_OP_DUMMY(1, 0),
|
||||
SPI_MEM_OP_DATA_IN(2, NULL, 0));
|
||||
|
||||
spi_nor_setup_op(nor, &op, read->proto);
|
||||
|
||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto);
|
||||
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto);
|
||||
op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto);
|
||||
op.dummy.buswidth = op.addr.buswidth;
|
||||
op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
|
||||
op.dummy.buswidth / 8;
|
||||
if (spi_nor_protocol_is_dtr(nor->read_proto))
|
||||
op.dummy.nbytes *= 2;
|
||||
|
||||
return spi_nor_check_op(nor, &op);
|
||||
}
|
||||
@@ -2367,14 +2455,12 @@ static int spi_nor_check_readop(struct spi_nor *nor,
|
||||
static int spi_nor_check_pp(struct spi_nor *nor,
|
||||
const struct spi_nor_pp_command *pp)
|
||||
{
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1),
|
||||
SPI_MEM_OP_ADDR(3, 0, 1),
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 0),
|
||||
SPI_MEM_OP_ADDR(3, 0, 0),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(0, NULL, 1));
|
||||
SPI_MEM_OP_DATA_OUT(2, NULL, 0));
|
||||
|
||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto);
|
||||
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto);
|
||||
op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto);
|
||||
spi_nor_setup_op(nor, &op, pp->proto);
|
||||
|
||||
return spi_nor_check_op(nor, &op);
|
||||
}
|
||||
@@ -2404,12 +2490,16 @@ spi_nor_adjust_hwcaps(struct spi_nor *nor,
|
||||
*/
|
||||
*hwcaps = SNOR_HWCAPS_ALL;
|
||||
|
||||
/* DTR modes are not supported yet, mask them all. */
|
||||
*hwcaps &= ~SNOR_HWCAPS_DTR;
|
||||
|
||||
/* X-X-X modes are not supported yet, mask them all. */
|
||||
*hwcaps &= ~SNOR_HWCAPS_X_X_X;
|
||||
|
||||
/*
|
||||
* If the reset line is broken, we do not want to enter a stateful
|
||||
* mode.
|
||||
*/
|
||||
if (nor->flags & SNOR_F_BROKEN_RESET)
|
||||
*hwcaps &= ~(SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR);
|
||||
|
||||
for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
|
||||
int rdidx, ppidx;
|
||||
|
||||
@@ -2649,6 +2739,7 @@ static int spi_nor_init(struct spi_nor *nor)
|
||||
}
|
||||
|
||||
if (nor->addr_width == 4 &&
|
||||
!(nor->info->flags & SPI_NOR_OCTAL_DTR_READ) &&
|
||||
(JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
|
||||
!(nor->info->flags & SPI_NOR_4B_OPCODES)) {
|
||||
/*
|
||||
@@ -2767,7 +2858,10 @@ int spi_nor_scan(struct spi_nor *nor)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->addr_width) {
|
||||
if (spi_nor_protocol_is_dtr(nor->read_proto)) {
|
||||
/* Always use 4-byte addresses in DTR mode. */
|
||||
nor->addr_width = 4;
|
||||
} else if (nor->addr_width) {
|
||||
/* already configured from SFDP */
|
||||
} else if (info->addr_width) {
|
||||
nor->addr_width = info->addr_width;
|
||||
|
||||
@@ -200,6 +200,7 @@ enum spi_nor_protocol {
|
||||
SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),
|
||||
SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),
|
||||
SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
|
||||
SNOR_PROTO_8_8_8_DTR = SNOR_PROTO_DTR(8, 8, 8),
|
||||
};
|
||||
|
||||
static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
|
||||
@@ -267,7 +268,7 @@ struct spi_nor_hwcaps {
|
||||
* then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
|
||||
* (Slow) Read.
|
||||
*/
|
||||
#define SNOR_HWCAPS_READ_MASK GENMASK(14, 0)
|
||||
#define SNOR_HWCAPS_READ_MASK GENMASK(15, 0)
|
||||
#define SNOR_HWCAPS_READ BIT(0)
|
||||
#define SNOR_HWCAPS_READ_FAST BIT(1)
|
||||
#define SNOR_HWCAPS_READ_1_1_1_DTR BIT(2)
|
||||
@@ -284,11 +285,12 @@ struct spi_nor_hwcaps {
|
||||
#define SNOR_HWCAPS_READ_4_4_4 BIT(9)
|
||||
#define SNOR_HWCAPS_READ_1_4_4_DTR BIT(10)
|
||||
|
||||
#define SNOR_HWCPAS_READ_OCTO GENMASK(14, 11)
|
||||
#define SNOR_HWCPAS_READ_OCTO GENMASK(15, 11)
|
||||
#define SNOR_HWCAPS_READ_1_1_8 BIT(11)
|
||||
#define SNOR_HWCAPS_READ_1_8_8 BIT(12)
|
||||
#define SNOR_HWCAPS_READ_8_8_8 BIT(13)
|
||||
#define SNOR_HWCAPS_READ_1_8_8_DTR BIT(14)
|
||||
#define SNOR_HWCAPS_READ_8_8_8_DTR BIT(15)
|
||||
|
||||
/*
|
||||
* Page Program capabilities.
|
||||
@@ -299,18 +301,19 @@ struct spi_nor_hwcaps {
|
||||
* JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
|
||||
* implements such commands.
|
||||
*/
|
||||
#define SNOR_HWCAPS_PP_MASK GENMASK(22, 16)
|
||||
#define SNOR_HWCAPS_PP BIT(16)
|
||||
#define SNOR_HWCAPS_PP_MASK GENMASK(23, 16)
|
||||
#define SNOR_HWCAPS_PP BIT(16)
|
||||
|
||||
#define SNOR_HWCAPS_PP_QUAD GENMASK(19, 17)
|
||||
#define SNOR_HWCAPS_PP_1_1_4 BIT(17)
|
||||
#define SNOR_HWCAPS_PP_1_4_4 BIT(18)
|
||||
#define SNOR_HWCAPS_PP_4_4_4 BIT(19)
|
||||
#define SNOR_HWCAPS_PP_QUAD GENMASK(19, 17)
|
||||
#define SNOR_HWCAPS_PP_1_1_4 BIT(17)
|
||||
#define SNOR_HWCAPS_PP_1_4_4 BIT(18)
|
||||
#define SNOR_HWCAPS_PP_4_4_4 BIT(19)
|
||||
|
||||
#define SNOR_HWCAPS_PP_OCTO GENMASK(22, 20)
|
||||
#define SNOR_HWCAPS_PP_1_1_8 BIT(20)
|
||||
#define SNOR_HWCAPS_PP_1_8_8 BIT(21)
|
||||
#define SNOR_HWCAPS_PP_8_8_8 BIT(22)
|
||||
#define SNOR_HWCAPS_PP_OCTO GENMASK(23, 20)
|
||||
#define SNOR_HWCAPS_PP_1_1_8 BIT(20)
|
||||
#define SNOR_HWCAPS_PP_1_8_8 BIT(21)
|
||||
#define SNOR_HWCAPS_PP_8_8_8 BIT(22)
|
||||
#define SNOR_HWCAPS_PP_8_8_8_DTR BIT(23)
|
||||
|
||||
#define SNOR_HWCAPS_X_X_X (SNOR_HWCAPS_READ_2_2_2 | \
|
||||
SNOR_HWCAPS_READ_4_4_4 | \
|
||||
@@ -318,6 +321,9 @@ struct spi_nor_hwcaps {
|
||||
SNOR_HWCAPS_PP_4_4_4 | \
|
||||
SNOR_HWCAPS_PP_8_8_8)
|
||||
|
||||
#define SNOR_HWCAPS_X_X_X_DTR (SNOR_HWCAPS_READ_8_8_8_DTR | \
|
||||
SNOR_HWCAPS_PP_8_8_8_DTR)
|
||||
|
||||
#define SNOR_HWCAPS_DTR (SNOR_HWCAPS_READ_1_1_1_DTR | \
|
||||
SNOR_HWCAPS_READ_1_2_2_DTR | \
|
||||
SNOR_HWCAPS_READ_1_4_4_DTR | \
|
||||
@@ -360,6 +366,7 @@ enum spi_nor_read_command_index {
|
||||
SNOR_CMD_READ_1_8_8,
|
||||
SNOR_CMD_READ_8_8_8,
|
||||
SNOR_CMD_READ_1_8_8_DTR,
|
||||
SNOR_CMD_READ_8_8_8_DTR,
|
||||
|
||||
SNOR_CMD_READ_MAX
|
||||
};
|
||||
@@ -376,6 +383,7 @@ enum spi_nor_pp_command_index {
|
||||
SNOR_CMD_PP_1_1_8,
|
||||
SNOR_CMD_PP_1_8_8,
|
||||
SNOR_CMD_PP_8_8_8,
|
||||
SNOR_CMD_PP_8_8_8_DTR,
|
||||
|
||||
SNOR_CMD_PP_MAX
|
||||
};
|
||||
@@ -391,6 +399,22 @@ struct spi_nor_flash_parameter {
|
||||
int (*quad_enable)(struct spi_nor *nor);
|
||||
};
|
||||
|
||||
/**
|
||||
* enum spi_nor_cmd_ext - describes the command opcode extension in DTR mode
|
||||
* @SPI_MEM_NOR_NONE: no extension. This is the default, and is used in Legacy
|
||||
* SPI mode
|
||||
* @SPI_MEM_NOR_REPEAT: the extension is same as the opcode
|
||||
* @SPI_MEM_NOR_INVERT: the extension is the bitwise inverse of the opcode
|
||||
* @SPI_MEM_NOR_HEX: the extension is any hex value. The command and opcode
|
||||
* combine to form a 16-bit opcode.
|
||||
*/
|
||||
enum spi_nor_cmd_ext {
|
||||
SPI_NOR_EXT_NONE = 0,
|
||||
SPI_NOR_EXT_REPEAT,
|
||||
SPI_NOR_EXT_INVERT,
|
||||
SPI_NOR_EXT_HEX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct flash_info - Forward declaration of a structure used internally by
|
||||
* spi_nor_scan()
|
||||
@@ -430,6 +454,7 @@ struct spi_flash {
|
||||
* @write_proto: the SPI protocol for write operations
|
||||
* @reg_proto the SPI protocol for read_reg/write_reg/erase operations
|
||||
* @cmd_buf: used by the write_reg
|
||||
* @cmd_ext_type: the command opcode extension for DTR mode.
|
||||
* @fixups: flash-specific fixup hooks.
|
||||
* @prepare: [OPTIONAL] do some preparations for the
|
||||
* read/write/erase/lock/unlock operations
|
||||
@@ -472,6 +497,7 @@ struct spi_nor {
|
||||
bool sst_write_second;
|
||||
u32 flags;
|
||||
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
|
||||
enum spi_nor_cmd_ext cmd_ext_type;
|
||||
struct spi_nor_fixups *fixups;
|
||||
|
||||
int (*setup)(struct spi_nor *nor, const struct flash_info *info,
|
||||
|
||||
Reference in New Issue
Block a user