Skip to content

Commit 9e9b4a8

Browse files
committed
drivers: Flash: Enable quad and octal mode in spi_nor.c
Enable quad and octal mode in spi_nor.c Signed-off-by: Daniel Zhang <[email protected]>
1 parent bd254ee commit 9e9b4a8

File tree

3 files changed

+340
-5
lines changed

3 files changed

+340
-5
lines changed

drivers/flash/spi_nor.c

Lines changed: 293 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ struct spi_nor_data {
195195
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
196196
#endif /* CONFIG_SPI_NOR_SFDP_RUNTIME */
197197
#endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */
198+
199+
#ifdef CONFIG_SPI_EXTENDED_MODES
200+
enum spi_nor_protocol nor_protocol;
201+
202+
uint8_t read_cmd;
203+
uint8_t program_cmd;
204+
uint8_t erase_cmd;
205+
#endif
198206
};
199207

200208
#ifdef CONFIG_SPI_NOR_SFDP_MINIMAL
@@ -393,6 +401,7 @@ static int spi_nor_access(const struct device *const dev,
393401
}
394402
};
395403

404+
#ifndef CONFIG_SPI_EXTENDED_MODES
396405
buf[0] = opcode;
397406
if (is_addressed) {
398407
bool access_24bit = (access & NOR_ACCESS_24BIT_ADDR) != 0;
@@ -425,6 +434,131 @@ static int spi_nor_access(const struct device *const dev,
425434
.buffers = spi_buf,
426435
.count = 2,
427436
};
437+
#else
438+
439+
spi_buf[0].spi_mem_op.cmd.opcode = opcode;
440+
spi_buf[0].spi_mem_op.cmd.nbytes = 1;
441+
442+
if (is_addressed) {
443+
bool access_24bit = (access & NOR_ACCESS_24BIT_ADDR) != 0;
444+
bool access_32bit = (access & NOR_ACCESS_32BIT_ADDR) != 0;
445+
bool use_32bit = (access_32bit
446+
|| (!access_24bit
447+
&& driver_data->flag_access_32bit));
448+
449+
spi_buf[0].spi_mem_op.addr.nbytes = use_32bit ? 4 : 3;
450+
};
451+
spi_buf[0].spi_mem_op.addr.val = addr;
452+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_SINGLE;
453+
spi_buf[0].spi_mem_op.addr.dtr = 0;
454+
455+
spi_buf[0].spi_mem_op.data.nbytes = length;
456+
spi_buf[0].spi_mem_op.data.buf = data;
457+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_SINGLE;
458+
spi_buf[0].spi_mem_op.data.dtr = 0;
459+
460+
461+
switch (driver_data->nor_protocol) {
462+
case PROTO_1_1_1:
463+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
464+
spi_buf[0].spi_mem_op.cmd.dtr = 0;
465+
break;
466+
case PROTO_1_1_2:
467+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
468+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_SINGLE;
469+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_DUAL;
470+
break;
471+
case PROTO_1_2_2:
472+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
473+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_DUAL;
474+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_DUAL;
475+
break;
476+
case PROTO_1_1_4:
477+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
478+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_SINGLE;
479+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
480+
break;
481+
case PROTO_1_4_4:
482+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
483+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_QUAD;
484+
spi_buf[0].spi_mem_op.addr.dtr = 1;
485+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
486+
spi_buf[0].spi_mem_op.data.dtr = 1;
487+
break;
488+
case PROTO_1_4D_4D:
489+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
490+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_QUAD;
491+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
492+
break;
493+
case PROTO_4_4_4:
494+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_QUAD;
495+
spi_buf[0].spi_mem_op.cmd.dtr = 0;
496+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_QUAD;
497+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
498+
if (opcode == SPI_NOR_CMD_4READ) {
499+
spi_buf[0].spi_mem_op.dummy.nbytes = 6;
500+
}
501+
break;
502+
case PROTO_8_8_8:
503+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_OCTAL;
504+
spi_buf[0].spi_mem_op.cmd.dtr = 0;
505+
spi_buf[0].spi_mem_op.cmd.opcode = (opcode << 8) | (0xFF - opcode);
506+
spi_buf[0].spi_mem_op.cmd.nbytes = 2;
507+
508+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
509+
spi_buf[0].spi_mem_op.addr.dtr = 0;
510+
511+
if ((opcode == SPI_NOR_CMD_RDID) || (opcode == SPI_NOR_CMD_RDSR)) {
512+
spi_buf[0].spi_mem_op.addr.val = 0;
513+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
514+
spi_buf[0].spi_mem_op.addr.nbytes = 4;
515+
516+
spi_buf[0].spi_mem_op.dummy.nbytes = 4;
517+
}
518+
if (opcode == 0xEC) {
519+
spi_buf[0].spi_mem_op.dummy.nbytes = 20;
520+
}
521+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_OCTAL;
522+
spi_buf[0].spi_mem_op.data.dtr = 0;
523+
break;
524+
case PROTO_8D_8D_8D:
525+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_OCTAL;
526+
spi_buf[0].spi_mem_op.cmd.dtr = 1;
527+
spi_buf[0].spi_mem_op.cmd.opcode = (opcode << 8) | (0xFF - opcode);
528+
spi_buf[0].spi_mem_op.cmd.nbytes = 2;
529+
530+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
531+
spi_buf[0].spi_mem_op.addr.dtr = 1;
532+
533+
spi_buf[0].spi_mem_op.data.dtr = 1;
534+
535+
if ((opcode == SPI_NOR_CMD_RDID) || (opcode == SPI_NOR_CMD_RDSR))
536+
spi_buf[0].spi_mem_op.addr.val = 0;
537+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
538+
spi_buf[0].spi_mem_op.addr.nbytes = 4;
539+
spi_buf[0].spi_mem_op.dummy.nbytes = 6;
540+
spi_buf[0].spi_mem_op.data.dtr = 0;
541+
} else if (opcode == 0xEE) {
542+
spi_buf[0].spi_mem_op.dummy.nbytes = 20;
543+
}
544+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_OCTAL;
545+
546+
break;
547+
default:
548+
break;
549+
};
550+
551+
const struct spi_buf_set tx_set = {
552+
.buffers = spi_buf,
553+
.count = 1,
554+
};
555+
556+
const struct spi_buf_set rx_set = {
557+
.buffers = spi_buf,
558+
.count = 1,
559+
};
560+
561+
#endif
428562

429563
if (is_write) {
430564
return spi_write_dt(&driver_cfg->spi, &tx_set);
@@ -785,9 +919,121 @@ static int mxicy_configure(const struct device *dev, const uint8_t *jedec_id)
785919

786920
#endif /* ANY_INST_HAS_MXICY_MX25R_POWER_MODE */
787921

922+
#ifdef CONFIG_SPI_EXTENDED_MODES
923+
/**
924+
* @brief Write the configuration register2.
925+
*
926+
* @note The device must be externally acquired before invoking this
927+
* function.
928+
*
929+
* @param dev Device struct
930+
* @param sr The new value of the configuration register2
931+
*
932+
* @return 0 on success or a negative error code.
933+
*/
934+
static int spi_nor_wrcr2(const struct device *dev,
935+
uint8_t cr)
936+
{
937+
int ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_WREN);
938+
939+
if (ret == 0) {
940+
941+
struct spi_nor_data *data = dev->data;
942+
943+
data->flag_access_32bit = true;
944+
945+
ret = spi_nor_cmd_addr_write(dev, SPI_NOR_CMD_WR_CFGREG2, 0, &cr, sizeof(cr));
946+
}
947+
948+
return ret;
949+
}
950+
951+
static int spi_nor_change_protocol(const struct device *dev,
952+
enum spi_nor_protocol nor_protocol)
953+
{
954+
struct spi_nor_data *data = dev->data;
955+
uint8_t cr2;
956+
int ret = 0;
957+
958+
switch (nor_protocol) {
959+
case PROTO_1_1_1:
960+
data->nor_protocol = PROTO_1_1_1;
961+
data->flag_access_32bit = false;
962+
data->read_cmd = SPI_NOR_CMD_READ;
963+
data->program_cmd = SPI_NOR_CMD_PP;
964+
data->erase_cmd = SPI_NOR_CMD_SE;
965+
break;
966+
case PROTO_1_1_2:
967+
data->nor_protocol = PROTO_1_1_2;
968+
data->flag_access_32bit = false;
969+
data->read_cmd = SPI_NOR_CMD_READ;
970+
data->program_cmd = SPI_NOR_CMD_PP;
971+
data->erase_cmd = SPI_NOR_CMD_SE;
972+
break;
973+
case PROTO_1_2_2:
974+
data->nor_protocol = PROTO_1_2_2;
975+
data->flag_access_32bit = false;
976+
data->read_cmd = SPI_NOR_CMD_READ;
977+
data->program_cmd = SPI_NOR_CMD_PP;
978+
data->erase_cmd = SPI_NOR_CMD_SE;
979+
break;
980+
case PROTO_1_1_4:
981+
data->nor_protocol = PROTO_1_1_4;
982+
data->flag_access_32bit = false;
983+
data->read_cmd = SPI_NOR_CMD_READ;
984+
data->program_cmd = SPI_NOR_CMD_PP;
985+
data->erase_cmd = SPI_NOR_CMD_SE;
986+
break;
987+
case PROTO_1_4_4:
988+
data->nor_protocol = PROTO_1_4_4;
989+
data->flag_access_32bit = false;
990+
data->read_cmd = SPI_NOR_CMD_READ;
991+
data->program_cmd = SPI_NOR_CMD_PP;
992+
data->erase_cmd = SPI_NOR_CMD_SE;
993+
break;
994+
case PROTO_1_4D_4D:
995+
data->nor_protocol = PROTO_1_4D_4D;
996+
data->flag_access_32bit = false;
997+
data->read_cmd = SPI_NOR_CMD_READ;
998+
data->program_cmd = SPI_NOR_CMD_PP;
999+
data->erase_cmd = SPI_NOR_CMD_SE;
1000+
break;
1001+
case PROTO_4_4_4:
1002+
ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_EQIO);
1003+
data->nor_protocol = PROTO_4_4_4;
1004+
data->flag_access_32bit = false;
1005+
data->read_cmd = SPI_NOR_CMD_4READ;
1006+
data->program_cmd = SPI_NOR_CMD_PP;
1007+
data->erase_cmd = SPI_NOR_CMD_SE;
1008+
break;
1009+
case PROTO_8_8_8:
1010+
data->flag_access_32bit = true;
1011+
data->read_cmd = SPI_NOR_OCMD_RD;
1012+
data->program_cmd = SPI_NOR_CMD_PP_4B;
1013+
data->erase_cmd = SPI_NOR_OCMD_SE;
1014+
cr2 = 0x01;
1015+
ret = spi_nor_wrcr2(dev, cr2);
1016+
data->nor_protocol = PROTO_8_8_8;
1017+
break;
1018+
case PROTO_8D_8D_8D:
1019+
data->flag_access_32bit = true;
1020+
data->read_cmd = SPI_NOR_OCMD_DTR_RD;
1021+
data->program_cmd = SPI_NOR_CMD_PP_4B;
1022+
data->erase_cmd = SPI_NOR_OCMD_SE;
1023+
cr2 = 0x02;
1024+
ret = spi_nor_wrcr2(dev, cr2);
1025+
data->nor_protocol = PROTO_8D_8D_8D;
1026+
break;
1027+
}
1028+
1029+
return ret;
1030+
}
1031+
#endif
1032+
7881033
static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
7891034
size_t size)
7901035
{
1036+
struct spi_nor_data *data = dev->data;
7911037
const size_t flash_size = dev_flash_size(dev);
7921038
int ret;
7931039

@@ -802,15 +1048,18 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
8021048
}
8031049

8041050
acquire_device(dev);
1051+
1052+
bool use_extended_modes = IS_ENABLED(CONFIG_SPI_EXTENDED_MODES);
1053+
uint8_t read_cmd = use_extended_modes ? data->read_cmd : SPI_NOR_CMD_READ
8051054

8061055
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && DEV_CFG(dev)->use_4b_addr_opcodes) {
8071056
if (addr > SPI_NOR_3B_ADDR_MAX) {
8081057
ret = spi_nor_cmd_addr_read_4b(dev, SPI_NOR_CMD_READ_4B, addr, dest, size);
8091058
} else {
810-
ret = spi_nor_cmd_addr_read_3b(dev, SPI_NOR_CMD_READ, addr, dest, size);
1059+
ret = spi_nor_cmd_addr_read_3b(dev, read_cmd, addr, dest, size);
8111060
}
8121061
} else {
813-
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
1062+
ret = spi_nor_cmd_addr_read(dev, read_cmd, addr, dest, size);
8141063
}
8151064

8161065
release_device(dev);
@@ -857,6 +1106,7 @@ static int spi_nor_write(const struct device *dev, off_t addr,
8571106
const void *src,
8581107
size_t size)
8591108
{
1109+
struct spi_nor_data *data = dev->data;
8601110
const size_t flash_size = dev_flash_size(dev);
8611111
const uint16_t page_size = dev_page_size(dev);
8621112
int ret;
@@ -893,18 +1143,21 @@ static int spi_nor_write(const struct device *dev, off_t addr,
8931143
if (ret != 0) {
8941144
break;
8951145
}
1146+
1147+
bool use_extended_modes = IS_ENABLED(CONFIG_SPI_EXTENDED_MODES);
1148+
uint8_t program_cmd = use_extended_modes ? data->program_cmd : SPI_NOR_CMD_PP
8961149

8971150
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) &&
8981151
DEV_CFG(dev)->use_4b_addr_opcodes) {
8991152
if (addr > SPI_NOR_3B_ADDR_MAX) {
9001153
ret = spi_nor_cmd_addr_write_4b(dev, SPI_NOR_CMD_PP_4B,
9011154
addr, src, to_write);
9021155
} else {
903-
ret = spi_nor_cmd_addr_write_3b(dev, SPI_NOR_CMD_PP, addr,
904-
src, to_write);
1156+
ret = spi_nor_cmd_addr_write_3b(dev, program_cmd,
1157+
addr, src, to_write);
9051158
}
9061159
} else {
907-
ret = spi_nor_cmd_addr_write(dev, SPI_NOR_CMD_PP, addr, src,
1160+
ret = spi_nor_cmd_addr_write(dev, program_cmd, addr, src,
9081161
to_write);
9091162
}
9101163

@@ -1426,6 +1679,32 @@ static int setup_pages_layout(const struct device *dev)
14261679
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
14271680
#endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */
14281681

1682+
#ifdef CONFIG_SPI_EXTENDED_MODES
1683+
static enum spi_nor_protocol spi_config_get_lines(const struct spi_config *config)
1684+
{
1685+
enum spi_nor_protocol nor_protocol;
1686+
1687+
switch (config->operation & SPI_LINES_MASK) {
1688+
case SPI_LINES_SINGLE:
1689+
nor_protocol = PROTO_1_1_1;
1690+
break;
1691+
case SPI_LINES_DUAL:
1692+
nor_protocol = PROTO_1_2_2;
1693+
break;
1694+
case SPI_LINES_QUAD:
1695+
nor_protocol = PROTO_4_4_4;
1696+
break;
1697+
case SPI_LINES_OCTAL:
1698+
nor_protocol = PROTO_8_8_8;
1699+
break;
1700+
default:
1701+
nor_protocol = PROTO_1_1_1;
1702+
}
1703+
1704+
return nor_protocol;
1705+
}
1706+
#endif
1707+
14291708
/**
14301709
* @brief Configure the flash
14311710
*
@@ -1509,6 +1788,15 @@ static int spi_nor_configure(const struct device *dev)
15091788
}
15101789
#endif
15111790

1791+
#ifdef CONFIG_SPI_EXTENDED_MODES
1792+
1793+
rc = spi_nor_change_protocol(dev, spi_config_get_lines(&cfg->spi.config));
1794+
if (rc != 0) {
1795+
LOG_ERR("Change protocol failed: %d", rc);
1796+
return -ENODEV;
1797+
}
1798+
#endif
1799+
15121800
/* Check for block protect bits that need to be cleared. This
15131801
* information cannot be determined from SFDP content, so the
15141802
* devicetree node property must be set correctly for any device

drivers/flash/spi_nor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#define SPI_NOR_CMD_PP_4B 0x12 /* Page Program 4 Byte Address */
6161
#define SPI_NOR_CMD_PP_1_1_4_4B 0x34 /* Quad Page program (1-1-4) 4 Byte Address */
6262
#define SPI_NOR_CMD_PP_1_4_4_4B 0x3e /* Quad Page program (1-4-4) 4 Byte Address */
63+
#define SPI_NOR_CMD_EQIO 0x35 /* Enable QPI mode */
64+
#define SPI_NOR_CMD_RSTQIO 0xF5 /* Disable QPI mode */
6365

6466
/* Flash octal opcodes */
6567
#define SPI_NOR_OCMD_SE 0x21DE /* Octal Sector erase */

0 commit comments

Comments
 (0)