Skip to content

Commit 1464b46

Browse files
committed
Enable quad and octal mode in spi_nor.c
Signed-off-by: danielzhang <[email protected]>
1 parent 049b67a commit 1464b46

File tree

10 files changed

+820
-13
lines changed

10 files changed

+820
-13
lines changed

boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,14 @@
137137
status = "okay";
138138

139139
mx25lm51245: ospi-nor-flash@0 {
140-
compatible = "st,stm32-ospi-nor";
140+
compatible = "jedec,spi-nor";
141+
label = "MX25LM51245";
141142
reg = <0>;
142-
ospi-max-frequency = <DT_FREQ_M(50)>;
143-
size = <DT_SIZE_M(512)>; /* 64 MBytes */
144-
spi-bus-width = <OSPI_OPI_MODE>;
145-
data-rate = <OSPI_DTR_TRANSFER>;
146-
four-byte-opcodes;
143+
spi-max-frequency = <DT_FREQ_M(50)>;
144+
size = <DT_SIZE_M(64)>;
145+
jedec-id = [c2 85 3a];
146+
duplex = <0>;
147+
frame-format = <0>;
147148
status = "okay";
148149
sfdp-bfp = [
149150
53 46 44 50 06 01 02 ff

drivers/flash/spi_nor.c

Lines changed: 286 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ struct spi_nor_data {
170170
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
171171
#endif /* CONFIG_SPI_NOR_SFDP_RUNTIME */
172172
#endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */
173+
174+
#ifdef CONFIG_SPI_EXTENDED_MODES
175+
enum spi_nor_protocol nor_protocol;
176+
177+
uint8_t read_cmd;
178+
uint8_t program_cmd;
179+
uint8_t erase_cmd;
180+
#endif
173181
};
174182

175183
#ifdef CONFIG_SPI_NOR_SFDP_MINIMAL
@@ -332,7 +340,7 @@ static int spi_nor_access(const struct device *const dev,
332340
.len = length
333341
}
334342
};
335-
343+
#ifndef CONFIG_SPI_EXTENDED_MODES
336344
buf[0] = opcode;
337345
if (is_addressed) {
338346
bool access_24bit = (access & NOR_ACCESS_24BIT_ADDR) != 0;
@@ -365,7 +373,131 @@ static int spi_nor_access(const struct device *const dev,
365373
.buffers = spi_buf,
366374
.count = 2,
367375
};
376+
#else
377+
378+
spi_buf[0].spi_mem_op.cmd.opcode = opcode;
379+
spi_buf[0].spi_mem_op.cmd.nbytes = 1;
380+
381+
if (is_addressed) {
382+
bool access_24bit = (access & NOR_ACCESS_24BIT_ADDR) != 0;
383+
bool access_32bit = (access & NOR_ACCESS_32BIT_ADDR) != 0;
384+
bool use_32bit = (access_32bit
385+
|| (!access_24bit
386+
&& driver_data->flag_access_32bit));
387+
388+
spi_buf[0].spi_mem_op.addr.nbytes = use_32bit ? 4 : 3;
389+
};
390+
spi_buf[0].spi_mem_op.addr.val = addr;
391+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_SINGLE;
392+
spi_buf[0].spi_mem_op.addr.dtr = 0;
393+
394+
spi_buf[0].spi_mem_op.data.nbytes = length;
395+
spi_buf[0].spi_mem_op.data.buf = data;
396+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_SINGLE;
397+
spi_buf[0].spi_mem_op.data.dtr = 0;
398+
399+
400+
switch(driver_data->nor_protocol) {
401+
case PROTO_1_1_1:
402+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
403+
spi_buf[0].spi_mem_op.cmd.dtr = 0;
404+
break;
405+
case PROTO_1_1_2:
406+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
407+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_SINGLE;
408+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_DUAL;
409+
break;
410+
case PROTO_1_2_2:
411+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
412+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_DUAL;
413+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_DUAL;
414+
break;
415+
case PROTO_1_1_4:
416+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
417+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_SINGLE;
418+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
419+
break;
420+
case PROTO_1_4_4:
421+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
422+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_QUAD;
423+
spi_buf[0].spi_mem_op.addr.dtr = 1;
424+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
425+
spi_buf[0].spi_mem_op.data.dtr = 1;
426+
break;
427+
case PROTO_1_4D_4D:
428+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_SINGLE;
429+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_QUAD;
430+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
431+
break;
432+
case PROTO_4_4_4:
433+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_QUAD;
434+
spi_buf[0].spi_mem_op.cmd.dtr = 0;
435+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_QUAD;
436+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_QUAD;
437+
if (opcode == SPI_NOR_CMD_4READ){
438+
spi_buf[0].spi_mem_op.dummy.nbytes = 6;
439+
}
440+
break;
441+
case PROTO_8_8_8:
442+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_OCTAL;
443+
spi_buf[0].spi_mem_op.cmd.dtr = 0;
444+
spi_buf[0].spi_mem_op.cmd.opcode = (opcode << 8) | (0xFF - opcode);
445+
spi_buf[0].spi_mem_op.cmd.nbytes = 2;
446+
447+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
448+
spi_buf[0].spi_mem_op.addr.dtr = 0;
449+
450+
if ((opcode == SPI_NOR_CMD_RDID) || (opcode == SPI_NOR_CMD_RDSR)){
451+
spi_buf[0].spi_mem_op.addr.val = 0;
452+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
453+
spi_buf[0].spi_mem_op.addr.nbytes = 4;
454+
455+
spi_buf[0].spi_mem_op.dummy.nbytes = 4;
456+
}
457+
if (opcode == 0xEC){
458+
spi_buf[0].spi_mem_op.dummy.nbytes = 20;
459+
}
460+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_OCTAL;
461+
spi_buf[0].spi_mem_op.data.dtr = 0;
462+
break;
463+
case PROTO_8D_8D_8D:
464+
spi_buf[0].spi_mem_op.cmd.buswidth = SPI_LINES_OCTAL;
465+
spi_buf[0].spi_mem_op.cmd.dtr = 1;
466+
spi_buf[0].spi_mem_op.cmd.opcode = (opcode << 8) | (0xFF - opcode);
467+
spi_buf[0].spi_mem_op.cmd.nbytes = 2;
468+
469+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
470+
spi_buf[0].spi_mem_op.addr.dtr = 1;
471+
472+
spi_buf[0].spi_mem_op.data.dtr = 1;
473+
474+
if ((opcode == SPI_NOR_CMD_RDID) || (opcode == SPI_NOR_CMD_RDSR)){
475+
spi_buf[0].spi_mem_op.addr.val = 0;
476+
spi_buf[0].spi_mem_op.addr.buswidth = SPI_LINES_OCTAL;
477+
spi_buf[0].spi_mem_op.addr.nbytes = 4;
478+
spi_buf[0].spi_mem_op.dummy.nbytes = 6;
479+
spi_buf[0].spi_mem_op.data.dtr = 0;
480+
} else if (opcode == 0xEE){
481+
spi_buf[0].spi_mem_op.dummy.nbytes = 20;
482+
}
483+
spi_buf[0].spi_mem_op.data.buswidth = SPI_LINES_OCTAL;
484+
485+
break;
486+
default:
487+
break;
488+
};
368489

490+
const struct spi_buf_set tx_set = {
491+
.buffers = spi_buf,
492+
.count = 1,
493+
};
494+
495+
const struct spi_buf_set rx_set = {
496+
.buffers = spi_buf,
497+
.count = 1,
498+
};
499+
500+
#endif
369501
if (is_write) {
370502
return spi_write_dt(&driver_cfg->spi, &tx_set);
371503
}
@@ -683,9 +815,122 @@ static int mxicy_configure(const struct device *dev, const uint8_t *jedec_id)
683815

684816
#endif /* DT_INST_NODE_HAS_PROP(0, mxicy_mx25r_power_mode) */
685817

818+
819+
#ifdef CONFIG_SPI_EXTENDED_MODES
820+
/**
821+
* @brief Write the configuration register2.
822+
*
823+
* @note The device must be externally acquired before invoking this
824+
* function.
825+
*
826+
* @param dev Device struct
827+
* @param sr The new value of the configuration register2
828+
*
829+
* @return 0 on success or a negative error code.
830+
*/
831+
static int spi_nor_wrcr2(const struct device *dev,
832+
uint8_t cr)
833+
{
834+
int ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_WREN);
835+
836+
if (ret == 0) {
837+
838+
struct spi_nor_data *data = dev->data;
839+
840+
data->flag_access_32bit = true;
841+
842+
ret = spi_nor_cmd_addr_write(dev, SPI_NOR_CMD_WR_CFGREG2, 0, &cr, sizeof(cr));
843+
}
844+
845+
return ret;
846+
}
847+
848+
static int spi_nor_change_protocol(const struct device *dev,
849+
enum spi_nor_protocol nor_protocol)
850+
{
851+
struct spi_nor_data *data = dev->data;
852+
uint8_t cr2;
853+
int ret = 0;
854+
855+
switch(nor_protocol) {
856+
case PROTO_1_1_1:
857+
data->nor_protocol = PROTO_1_1_1;
858+
data->flag_access_32bit = false;
859+
data->read_cmd = SPI_NOR_CMD_READ;
860+
data->program_cmd = SPI_NOR_CMD_PP;
861+
data->erase_cmd = SPI_NOR_CMD_SE;
862+
break;
863+
case PROTO_1_1_2:
864+
data->nor_protocol = PROTO_1_1_2;
865+
data->flag_access_32bit = false;
866+
data->read_cmd = SPI_NOR_CMD_READ;
867+
data->program_cmd = SPI_NOR_CMD_PP;
868+
data->erase_cmd = SPI_NOR_CMD_SE;
869+
break;
870+
case PROTO_1_2_2:
871+
data->nor_protocol = PROTO_1_2_2;
872+
data->flag_access_32bit = false;
873+
data->read_cmd = SPI_NOR_CMD_READ;
874+
data->program_cmd = SPI_NOR_CMD_PP;
875+
data->erase_cmd = SPI_NOR_CMD_SE;
876+
break;
877+
case PROTO_1_1_4:
878+
data->nor_protocol = PROTO_1_1_4;
879+
data->flag_access_32bit = false;
880+
data->read_cmd = SPI_NOR_CMD_READ;
881+
data->program_cmd = SPI_NOR_CMD_PP;
882+
data->erase_cmd = SPI_NOR_CMD_SE;
883+
break;
884+
case PROTO_1_4_4:
885+
data->nor_protocol = PROTO_1_4_4;
886+
data->flag_access_32bit = false;
887+
data->read_cmd = SPI_NOR_CMD_READ;
888+
data->program_cmd = SPI_NOR_CMD_PP;
889+
data->erase_cmd = SPI_NOR_CMD_SE;
890+
break;
891+
case PROTO_1_4D_4D:
892+
data->nor_protocol = PROTO_1_4D_4D;
893+
data->flag_access_32bit = false;
894+
data->read_cmd = SPI_NOR_CMD_READ;
895+
data->program_cmd = SPI_NOR_CMD_PP;
896+
data->erase_cmd = SPI_NOR_CMD_SE;
897+
break;
898+
case PROTO_4_4_4:
899+
ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_EQIO);
900+
data->nor_protocol = PROTO_4_4_4;
901+
data->flag_access_32bit = false;
902+
data->read_cmd = SPI_NOR_CMD_4READ;
903+
data->program_cmd = SPI_NOR_CMD_PP;
904+
data->erase_cmd = SPI_NOR_CMD_SE;
905+
break;
906+
case PROTO_8_8_8:
907+
data->flag_access_32bit = true;
908+
data->read_cmd = SPI_NOR_OCMD_RD;
909+
data->program_cmd = SPI_NOR_CMD_PP_4B;
910+
data->erase_cmd = SPI_NOR_OCMD_SE;
911+
cr2 = 0x01;
912+
ret = spi_nor_wrcr2(dev, cr2);
913+
data->nor_protocol = PROTO_8_8_8;
914+
break;
915+
case PROTO_8D_8D_8D:
916+
data->flag_access_32bit = true;
917+
data->read_cmd = SPI_NOR_OCMD_DTR_RD;
918+
data->program_cmd = SPI_NOR_CMD_PP_4B;
919+
data->erase_cmd = SPI_NOR_OCMD_SE;
920+
cr2 = 0x02;
921+
ret = spi_nor_wrcr2(dev, cr2);
922+
data->nor_protocol = PROTO_8D_8D_8D;
923+
break;
924+
}
925+
926+
return ret;
927+
}
928+
#endif
929+
686930
static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
687931
size_t size)
688932
{
933+
struct spi_nor_data *data = dev->data;
689934
const size_t flash_size = dev_flash_size(dev);
690935
int ret;
691936

@@ -696,7 +941,7 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
696941

697942
acquire_device(dev);
698943

699-
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
944+
ret = spi_nor_cmd_addr_read(dev, data->read_cmd, addr, dest, size);
700945

701946
release_device(dev);
702947
return ret;
@@ -734,6 +979,7 @@ static int spi_nor_write(const struct device *dev, off_t addr,
734979
const void *src,
735980
size_t size)
736981
{
982+
struct spi_nor_data *data = dev->data;
737983
const size_t flash_size = dev_flash_size(dev);
738984
const uint16_t page_size = dev_page_size(dev);
739985
int ret = 0;
@@ -761,7 +1007,7 @@ static int spi_nor_write(const struct device *dev, off_t addr,
7611007
}
7621008

7631009
spi_nor_cmd_write(dev, SPI_NOR_CMD_WREN);
764-
ret = spi_nor_cmd_addr_write(dev, SPI_NOR_CMD_PP, addr,
1010+
ret = spi_nor_cmd_addr_write(dev, data->program_cmd, addr,
7651011
src, to_write);
7661012
if (ret != 0) {
7671013
break;
@@ -1190,6 +1436,32 @@ static int setup_pages_layout(const struct device *dev)
11901436
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
11911437
#endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */
11921438

1439+
#ifdef CONFIG_SPI_EXTENDED_MODES
1440+
static enum spi_nor_protocol spi_config_get_lines(const struct spi_config *config)
1441+
{
1442+
enum spi_nor_protocol nor_protocol;
1443+
1444+
switch (config->operation & SPI_LINES_MASK) {
1445+
case SPI_LINES_SINGLE:
1446+
nor_protocol = PROTO_1_1_1;
1447+
break;
1448+
case SPI_LINES_DUAL:
1449+
nor_protocol = PROTO_1_2_2;
1450+
break;
1451+
case SPI_LINES_QUAD:
1452+
nor_protocol = PROTO_4_4_4;
1453+
break;
1454+
case SPI_LINES_OCTAL:
1455+
nor_protocol = PROTO_8_8_8;
1456+
break;
1457+
default:
1458+
nor_protocol = PROTO_1_1_1;
1459+
}
1460+
1461+
return nor_protocol;
1462+
}
1463+
#endif
1464+
11931465
/**
11941466
* @brief Configure the flash
11951467
*
@@ -1265,6 +1537,17 @@ static int spi_nor_configure(const struct device *dev)
12651537
}
12661538
#endif
12671539

1540+
#ifdef CONFIG_SPI_EXTENDED_MODES
1541+
1542+
rc = spi_nor_change_protocol(dev, spi_config_get_lines(spi_cfg));
1543+
//rc = spi_nor_change_protocol(dev, PROTO_8_8_8);
1544+
//rc = spi_nor_change_protocol(dev, PROTO_8D_8D_8D);
1545+
if (rc != 0) {
1546+
LOG_ERR("Change protocol failed: %d", rc);
1547+
return -ENODEV;
1548+
}
1549+
#endif
1550+
12681551
/* Check for block protect bits that need to be cleared. This
12691552
* information cannot be determined from SFDP content, so the
12701553
* devicetree node property must be set correctly for any device

drivers/flash/spi_nor.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@
5959
#define SPI_NOR_CMD_PP_4B 0x12 /* Page Program 4 Byte Address */
6060
#define SPI_NOR_CMD_PP_1_1_4_4B 0x34 /* Quad Page program (1-1-4) 4 Byte Address */
6161
#define SPI_NOR_CMD_PP_1_4_4_4B 0x3e /* Quad Page program (1-4-4) 4 Byte Address */
62+
#define SPI_NOR_CMD_EQIO 0x35 /* Enable QPI mode */
63+
#define SPI_NOR_CMD_RSTQIO 0xF5 /* Disable QPI mode */
6264

6365
/* Flash octal opcodes */
64-
#define SPI_NOR_OCMD_SE 0x21DE /* Octal Sector erase */
66+
#define SPI_NOR_OCMD_SE 0x21 /* Octal Sector erase */
6567
#define SPI_NOR_OCMD_CE 0xC738 /* Octal Chip erase */
6668
#define SPI_NOR_OCMD_RDSR 0x05FA /* Octal Read status register */
67-
#define SPI_NOR_OCMD_DTR_RD 0xEE11 /* Octal IO DTR read command */
68-
#define SPI_NOR_OCMD_RD 0xEC13 /* Octal IO read command */
69+
#define SPI_NOR_OCMD_DTR_RD 0xEE /* Octal IO DTR read command */
70+
#define SPI_NOR_OCMD_RD 0xEC /* Octal IO read command */
6971
#define SPI_NOR_OCMD_PAGE_PRG 0x12ED /* Octal Page Prog */
7072
#define SPI_NOR_OCMD_WREN 0x06F9 /* Octal Write enable */
7173
#define SPI_NOR_OCMD_NOP 0x00FF /* Octal No operation */

0 commit comments

Comments
 (0)