From 619f4e98048ce1696dfba651fbec3b13c8899cf5 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:42:06 +0200 Subject: [PATCH 01/14] drivers: flash: spi_nor: remove not used QE bit define Removes unused QE bit define. Signed-off-by: Georgij Cernysiov --- drivers/flash/spi_nor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/flash/spi_nor.h b/drivers/flash/spi_nor.h index 6fbc62f08d2c2..931675ef202ae 100644 --- a/drivers/flash/spi_nor.h +++ b/drivers/flash/spi_nor.h @@ -14,7 +14,6 @@ /* Status register bits */ #define SPI_NOR_WIP_BIT BIT(0) /* Write in progress */ #define SPI_NOR_WEL_BIT BIT(1) /* Write enable latch */ -#define SPI_NOR_QE_BIT BIT(6) /* Enable quad mode */ /* Control register bits */ #define SPI_NOR_4BYTE_BIT BIT(5) /* 4B addressing */ From 67ffd4da28d4a060b8ef4e61ae65178352d155b6 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:44:02 +0200 Subject: [PATCH 02/14] drivers: falsh: spi_nor: add PP_1_1_4 and rename 4PP * Renames 4PP define to PP_1_4_4 * Adds PP_1_1_4 define That matches linux kernel defines a bit more. Signed-off-by: Georgij Cernysiov --- drivers/flash/spi_nor.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/flash/spi_nor.h b/drivers/flash/spi_nor.h index 931675ef202ae..5d43fc7998f4b 100644 --- a/drivers/flash/spi_nor.h +++ b/drivers/flash/spi_nor.h @@ -30,7 +30,8 @@ #define SPI_NOR_CMD_WREN 0x06 /* Write enable */ #define SPI_NOR_CMD_WRDI 0x04 /* Write disable */ #define SPI_NOR_CMD_PP 0x02 /* Page program */ -#define SPI_NOR_CMD_4PP 0x38 /* Page program (1-4-4) */ +#define SPI_NOR_CMD_PP_1_1_4 0x32 /* Quad Page program (1-1-4) */ +#define SPI_NOR_CMD_PP_1_4_4 0x38 /* Quad Page program (1-4-4) */ #define SPI_NOR_CMD_RDCR 0x15 /* Read control register */ #define SPI_NOR_CMD_SE 0x20 /* Sector erase */ #define SPI_NOR_CMD_BE_32K 0x52 /* Block erase 32KB */ From 414894092983af55ce0e89b559c29289cca192e8 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:44:46 +0200 Subject: [PATCH 03/14] drivers: flash: spi_nor: add SR3 read and write defines Adds Status Register 3 read and write opcode defines. Signed-off-by: Georgij Cernysiov --- drivers/flash/spi_nor.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/flash/spi_nor.h b/drivers/flash/spi_nor.h index 5d43fc7998f4b..2e88f278c6e6a 100644 --- a/drivers/flash/spi_nor.h +++ b/drivers/flash/spi_nor.h @@ -23,6 +23,8 @@ #define SPI_NOR_CMD_RDSR 0x05 /* Read status register */ #define SPI_NOR_CMD_WRSR2 0x31 /* Write status register 2 */ #define SPI_NOR_CMD_RDSR2 0x35 /* Read status register 2 */ +#define SPI_NOR_CMD_RDSR3 0x15 /* Read status register 3 */ +#define SPI_NOR_CMD_WRSR3 0x11 /* Write status register 3 */ #define SPI_NOR_CMD_READ 0x03 /* Read data */ #define SPI_NOR_CMD_DREAD 0x3B /* Read data (1-1-2) */ #define SPI_NOR_CMD_QREAD 0x6B /* Read data (1-1-4) */ From aba7b408163aa6364b7b745fb151d6b492ab45ce Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:45:34 +0200 Subject: [PATCH 04/14] drivers: flash: jesd216: correct comment mistake Corrects type name in the comment for the DW15 QER field. Signed-off-by: Georgij Cernysiov --- drivers/flash/jesd216.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/flash/jesd216.h b/drivers/flash/jesd216.h index 582856436a603..64367d673a002 100644 --- a/drivers/flash/jesd216.h +++ b/drivers/flash/jesd216.h @@ -457,7 +457,7 @@ enum jesd216_dw15_qer_type { struct jesd216_bfp_dw15 { /* If true clear NVECR bit 4 to disable HOLD/RESET */ bool hold_reset_disable: 1; - /* Encoded jesd216_qer_type */ + /* Encoded jesd216_dw15_qer_type */ unsigned int qer: 3; /* 0-4-4 mode entry method */ unsigned int entry_044: 4; From d9cac022cea60338ef498559a5fb1da7dc913e3d Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:47:38 +0200 Subject: [PATCH 05/14] dts: bindings: flash_controller: stm32-qspi-nor: add writeoc property Adds writeoc property to allow quad write opcode selection. Signed-off-by: Georgij Cernysiov --- .../flash_controller/st,stm32-qspi-nor.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml b/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml index c5728ba5eb996..8498c31998645 100644 --- a/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml @@ -49,3 +49,18 @@ properties: required: false description: The width of (Q)SPI bus to which flash memory is connected. Now only value of 4 (when using SIO[0123]) is supported. + writeoc: + type: string + required: false + enum: + - "PP_1_1_4" # Quad data line SPI, PP 1-1-4 (0x32) + - "PP_1_4_4" # Quad data line SPI, PP 1-4-4 (0x38) + description: | + The value encodes number of I/O lines used for the opcode, + address, and data. + + There is no info about quad page program opcodes in the SFDP + tables, hence it has been assumed that NOR flash memory + supporting 1-4-4 mode also would support fast page programming. + + If absent, then 1-4-4 program page is used in quad mode. From d3238d16d436893a0ebacd49c8c80ab10dddf8f3 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:49:41 +0200 Subject: [PATCH 06/14] drivers: flash: stm32: qspi: minor cleanup Removes double line and log output regarding device initialization. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index b347b12b70cec..00bc65c1ff1b1 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -60,7 +60,6 @@ uint32_t table_p_size[] = { typedef void (*irq_config_func_t)(const struct device *dev); - struct stream { DMA_TypeDef *reg; const struct device *dev; @@ -1108,8 +1107,6 @@ static int flash_stm32_qspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ - LOG_INF("Device %s initialized", dev->name); - return 0; } From 7a65dc28d013a408f8988e85021b5278f3177736 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 13:54:01 +0200 Subject: [PATCH 07/14] drivers: flash: stm32: qspi: support DTS writeoc Adds support for DTS writeoc. Uses 1-4-4 mode by default (as the original driver). Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 42 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 00bc65c1ff1b1..4411cc22c17a6 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2020 Piotr Mienkowski * Copyright (c) 2020 Linaro Limited + * Copyright (c) 2022 Georgij Cernysiov * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,6 +92,7 @@ struct flash_stm32_qspi_data { uint16_t page_size; int cmd_status; struct stream dma; + uint8_t qspi_write_cmd; uint8_t qspi_read_cmd; uint8_t qspi_read_cmd_latency; /* @@ -144,25 +146,30 @@ static inline void qspi_prepare_quad_read(const struct device *dev, } } -static inline void qspi_prepare_quad_program(const struct device *dev, +static inline int qspi_prepare_quad_program(const struct device *dev, QSPI_CommandTypeDef *cmd) { struct flash_stm32_qspi_data *dev_data = dev->data; - /* - * There is no info about PP/4PP command in the SFDP tables, - * hence it has been assumed that NOR flash memory supporting - * 1-4-4 mode also would support fast page programming. - */ + if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO) && dev_data->flag_quad_io_en) { - cmd->Instruction = SPI_NOR_CMD_4PP; - cmd->AddressMode = QSPI_ADDRESS_4_LINES; + cmd->Instruction = dev_data->qspi_write_cmd; + + switch (cmd->Instruction) { + case SPI_NOR_CMD_PP_1_1_4: + cmd->AddressMode = QSPI_ADDRESS_1_LINE; + break; + case SPI_NOR_CMD_PP_1_4_4: + cmd->AddressMode = QSPI_ADDRESS_4_LINES; + break; + default: + return -ENOTSUP; + } + cmd->DataMode = QSPI_DATA_4_LINES; - /* - * Dummy cycles are not required for 4PP command - - * data to be programmed are sent just after address. - */ cmd->DummyCycles = 0; } + + return 0; } /* @@ -379,7 +386,10 @@ static int flash_stm32_qspi_write(const struct device *dev, off_t addr, }; qspi_set_address_size(dev, &cmd_pp); - qspi_prepare_quad_program(dev, &cmd_pp); + ret = qspi_prepare_quad_program(dev, &cmd_pp); + if (ret < 0) { + return ret; + } qspi_lock_thread(dev); while (size > 0) { @@ -1141,6 +1151,11 @@ static int flash_stm32_qspi_init(const struct device *dev) static void flash_stm32_qspi_irq_config_func(const struct device *dev); +#define DT_WRITEOC_PROP_OR(inst, default_value) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, writeoc), \ + (_CONCAT(SPI_NOR_CMD_, DT_STRING_TOKEN(DT_DRV_INST(inst), writeoc))), \ + ((default_value))) + #define STM32_QSPI_NODE DT_INST_PARENT(0) PINCTRL_DT_DEFINE(STM32_QSPI_NODE); @@ -1170,6 +1185,7 @@ static struct flash_stm32_qspi_data flash_stm32_qspi_dev_data = { .ClockMode = QSPI_CLOCK_MODE_0, }, }, + .qspi_write_cmd = DT_WRITEOC_PROP_OR(0, SPI_NOR_CMD_PP_1_4_4), QSPI_DMA_CHANNEL(STM32_QSPI_NODE, tx_rx) }; From 767fd62d636bdd8d2e2ece8ae56077c02878ab7c Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 14:03:01 +0200 Subject: [PATCH 08/14] drivers: flash: stm32: qspi: support 1-4-4 and 1-1-4 quad read modes Adds support for 1-4-4 and 1-1-4 read modes. SFDP is used to query for available read instructions, then the fastest one is used. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 80 +++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 22 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 4411cc22c17a6..1c8c980efe26a 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -43,6 +43,8 @@ LOG_MODULE_REGISTER(flash_stm32_qspi, CONFIG_FLASH_LOG_LEVEL); #define STM32_QSPI_FIFO_THRESHOLD 8 #define STM32_QSPI_CLOCK_PRESCALER_MAX 255 +#define STM32_QSPI_UNKNOWN_MODE (0xFF) + #define STM32_QSPI_USE_DMA DT_NODE_HAS_PROP(DT_INST_PARENT(0), dmas) #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_qspi_nor) @@ -90,6 +92,7 @@ struct flash_stm32_qspi_data { struct jesd216_erase_type erase_types[JESD216_NUM_ERASE_TYPES]; /* Number of bytes per page */ uint16_t page_size; + enum jesd216_mode_type mode; int cmd_status; struct stream dma; uint8_t qspi_write_cmd; @@ -133,17 +136,29 @@ static inline void qspi_set_address_size(const struct device *dev, cmd->AddressSize = QSPI_ADDRESS_24_BITS; } -static inline void qspi_prepare_quad_read(const struct device *dev, +static inline int qspi_prepare_quad_read(const struct device *dev, QSPI_CommandTypeDef *cmd) { struct flash_stm32_qspi_data *dev_data = dev->data; if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO) && dev_data->flag_quad_io_en) { + switch (dev_data->mode) { + case JESD216_MODE_114: + cmd->AddressMode = QSPI_ADDRESS_1_LINE; + break; + case JESD216_MODE_144: + cmd->AddressMode = QSPI_ADDRESS_4_LINES; + break; + default: + return -ENOTSUP; + } + cmd->Instruction = dev_data->qspi_read_cmd; - cmd->AddressMode = QSPI_ADDRESS_4_LINES; cmd->DataMode = QSPI_DATA_4_LINES; cmd->DummyCycles = dev_data->qspi_read_cmd_latency; } + + return 0; } static inline int qspi_prepare_quad_program(const struct device *dev, @@ -329,7 +344,10 @@ static int flash_stm32_qspi_read(const struct device *dev, off_t addr, }; qspi_set_address_size(dev, &cmd); - qspi_prepare_quad_read(dev, &cmd); + ret = qspi_prepare_quad_read(dev, &cmd); + if (ret < 0) { + return ret; + } qspi_lock_thread(dev); ret = qspi_read_access(dev, &cmd, data, size); @@ -884,34 +902,52 @@ static int spi_nor_process_bfp(const struct device *dev, } } } + /* - * Only check if the 1-4-4 (i.e. 4READ) fast read operation is - * supported - other modes - e.g. 1-1-4 (QREAD) or 1-1-2 (DREAD) are - * not. + * Only check if the 1-4-4 (i.e. 4READ) or 1-1-4 (QREAD) + * is supported - other modes are not. */ if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO)) { + const enum jesd216_mode_type supported_modes[] = { JESD216_MODE_114, + JESD216_MODE_144 }; + struct jesd216_bfp_dw15 dw15; struct jesd216_instr res; - rc = jesd216_bfp_read_support(php, bfp, JESD216_MODE_144, &res); - if (rc > 0) { - /* Program flash memory to use SIO[0123] */ - rc = qspi_program_quad_io(dev); - if (rc) { - LOG_ERR("Unable to enable QUAD IO mode: %d\n", - rc); - return rc; - } + /* reset active mode */ + data->mode = STM32_QSPI_UNKNOWN_MODE; - LOG_INF("Mode: 1-4-4 with instr:[0x%x] supported!", - res.instr); + /* query supported read modes, begin from the slowest */ + for (size_t i = 0; i < ARRAY_SIZE(supported_modes); ++i) { + rc = jesd216_bfp_read_support(php, bfp, supported_modes[i], &res); + if (rc >= 0) { + LOG_INF("Quad read mode %d instr [0x%x] supported", + supported_modes[i], res.instr); - data->qspi_read_cmd = res.instr; - data->qspi_read_cmd_latency = res.wait_states; - if (res.mode_clocks) { - data->qspi_read_cmd_latency += - res.mode_clocks; + data->mode = supported_modes[i]; + data->qspi_read_cmd = res.instr; + data->qspi_read_cmd_latency = res.wait_states; + + if (res.mode_clocks) { + data->qspi_read_cmd_latency += res.mode_clocks; + } } } + + /* don't continue when there is no supported mode */ + if (data->mode == STM32_QSPI_UNKNOWN_MODE) { + LOG_ERR("No supported flash read mode found"); + return -ENOTSUP; + } + + LOG_INF("Quad read mode %d instr [0x%x] will be used", data->mode, res.instr); + + /* enable QE */ + rc = qspi_program_quad_io(dev); + if (rc < 0) { + LOG_ERR("Failed to enable Quad mode: %d", rc); + return rc; + } + } return 0; From 90769b3285d0545c8c5a5effe5df1d0e5efee891 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 22:52:02 +0200 Subject: [PATCH 09/14] drivers: flash: stm32: qspi: move prepare cmd is enable check Moves IS_ENABLE check from prepare program and read to the caller. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 1c8c980efe26a..a8606edd08c84 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -141,7 +141,7 @@ static inline int qspi_prepare_quad_read(const struct device *dev, { struct flash_stm32_qspi_data *dev_data = dev->data; - if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO) && dev_data->flag_quad_io_en) { + if (dev_data->flag_quad_io_en) { switch (dev_data->mode) { case JESD216_MODE_114: cmd->AddressMode = QSPI_ADDRESS_1_LINE; @@ -166,7 +166,7 @@ static inline int qspi_prepare_quad_program(const struct device *dev, { struct flash_stm32_qspi_data *dev_data = dev->data; - if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO) && dev_data->flag_quad_io_en) { + if (dev_data->flag_quad_io_en) { cmd->Instruction = dev_data->qspi_write_cmd; switch (cmd->Instruction) { @@ -344,10 +344,13 @@ static int flash_stm32_qspi_read(const struct device *dev, off_t addr, }; qspi_set_address_size(dev, &cmd); - ret = qspi_prepare_quad_read(dev, &cmd); - if (ret < 0) { - return ret; + if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO)) { + ret = qspi_prepare_quad_read(dev, &cmd); + if (ret < 0) { + return ret; + } } + qspi_lock_thread(dev); ret = qspi_read_access(dev, &cmd, data, size); @@ -404,10 +407,13 @@ static int flash_stm32_qspi_write(const struct device *dev, off_t addr, }; qspi_set_address_size(dev, &cmd_pp); - ret = qspi_prepare_quad_program(dev, &cmd_pp); - if (ret < 0) { - return ret; + if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO)) { + ret = qspi_prepare_quad_program(dev, &cmd_pp); + if (ret < 0) { + return ret; + } } + qspi_lock_thread(dev); while (size > 0) { From 213ec26383783828e043fe61d87205eaad7a8abb Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 22:58:58 +0200 Subject: [PATCH 10/14] drivers: flash: stm32: qspi: support DTS quad enable requirements Adds support for DTS quad_enable_requirements property. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 143 +++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 25 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index a8606edd08c84..4e9efec48ae3d 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -92,6 +92,7 @@ struct flash_stm32_qspi_data { struct jesd216_erase_type erase_types[JESD216_NUM_ERASE_TYPES]; /* Number of bytes per page */ uint16_t page_size; + enum jesd216_dw15_qer_type qer_type; enum jesd216_mode_type mode; int cmd_status; struct stream dma; @@ -756,26 +757,83 @@ static int qspi_program_addr_4b(const struct device *dev) return ret; } -static int qspi_read_status_register(const struct device *dev, uint8_t *reg) +static int qspi_read_status_register(const struct device *dev, uint8_t reg_num, uint8_t *reg) { QSPI_CommandTypeDef cmd = { - .Instruction = SPI_NOR_CMD_RDSR, .InstructionMode = QSPI_INSTRUCTION_1_LINE, .DataMode = QSPI_DATA_1_LINE, }; + switch (reg_num) { + case 1U: + cmd.Instruction = SPI_NOR_CMD_RDSR; + break; + case 2U: + cmd.Instruction = SPI_NOR_CMD_RDSR2; + break; + case 3U: + cmd.Instruction = SPI_NOR_CMD_RDSR3; + break; + default: + return -EINVAL; + } + return qspi_read_access(dev, &cmd, reg, sizeof(*reg)); } -static int qspi_write_status_register(const struct device *dev, uint8_t reg) +static int qspi_write_status_register(const struct device *dev, uint8_t reg_num, uint8_t reg) { + struct flash_stm32_qspi_data *dev_data = dev->data; + size_t size; + uint8_t regs[4] = { 0 }; + uint8_t *regs_p; + int ret; + QSPI_CommandTypeDef cmd = { .Instruction = SPI_NOR_CMD_WRSR, .InstructionMode = QSPI_INSTRUCTION_1_LINE, .DataMode = QSPI_DATA_1_LINE, }; - return qspi_write_access(dev, &cmd, ®, sizeof(reg)); + if (reg_num == 1) { + size = 1U; + regs[0] = reg; + regs_p = ®s[0]; + /* 1 byte write clears SR2, write SR2 as well */ + if (dev_data->qer_type == JESD216_DW15_QER_S2B1v1) { + ret = qspi_read_status_register(dev, 2, ®s[1]); + if (ret < 0) { + return ret; + } + size = 2U; + } + } else if (reg_num == 2) { + cmd.Instruction = SPI_NOR_CMD_WRSR2; + size = 1U; + regs[1] = reg; + regs_p = ®s[1]; + /* if SR2 write needs SR1 */ + if ((dev_data->qer_type == JESD216_DW15_QER_VAL_S2B1v1) || + (dev_data->qer_type == JESD216_DW15_QER_VAL_S2B1v4) || + (dev_data->qer_type == JESD216_DW15_QER_VAL_S2B1v5)) { + ret = qspi_read_status_register(dev, 1, ®s[0]); + if (ret < 0) { + return ret; + } + cmd.Instruction = SPI_NOR_CMD_WRSR; + size = 2U; + regs_p = ®s[0]; + } + } else if (reg_num == 3) { + cmd.Instruction = SPI_NOR_CMD_WRSR3; + size = 1U; + regs[2] = reg; + regs_p = ®s[2]; + } else { + return -EINVAL; + } + + return qspi_write_access(dev, &cmd, regs_p, size); } static int qspi_write_enable(const struct device *dev) @@ -794,7 +852,7 @@ static int qspi_write_enable(const struct device *dev) } do { - ret = qspi_read_status_register(dev, ®); + ret = qspi_read_status_register(dev, 1U, ®); } while (!ret && !(reg & SPI_NOR_WEL_BIT)); return ret; @@ -803,51 +861,75 @@ static int qspi_write_enable(const struct device *dev) static int qspi_program_quad_io(const struct device *dev) { struct flash_stm32_qspi_data *data = dev->data; + uint8_t qe_reg_num; + uint8_t qe_bit; uint8_t reg; int ret; - /* Check if QE bit setting is required */ - ret = qspi_read_status_register(dev, ®); - if (ret) { + switch (data->qer_type) { + case JESD216_DW15_QER_NONE: + /* no QE bit, device detects reads based on opcode */ + return 0; + case JESD216_DW15_QER_S1B6: + qe_reg_num = 1U; + qe_bit = BIT(6U); + break; + case JESD216_DW15_QER_S2B7: + qe_reg_num = 2U; + qe_bit = BIT(7U); + break; + case JESD216_DW15_QER_S2B1v1: + __fallthrough; + case JESD216_DW15_QER_S2B1v4: + __fallthrough; + case JESD216_DW15_QER_S2B1v5: + __fallthrough; + case JESD216_DW15_QER_S2B1v6: + qe_reg_num = 2U; + qe_bit = BIT(1U); + break; + default: + return -ENOTSUP; + } + + ret = qspi_read_status_register(dev, qe_reg_num, ®); + if (ret < 0) { return ret; } - /* Quit early when QE bit is already set */ - if (reg & SPI_NOR_QE_BIT) { - goto out; + /* exit early if QE bit is already set */ + if ((reg & qe_bit) != 0U) { + return 0; } + reg |= qe_bit; + ret = qspi_write_enable(dev); - if (ret) { + if (ret < 0) { return ret; } - reg |= SPI_NOR_QE_BIT; - ret = qspi_write_status_register(dev, reg); - if (ret) { + ret = qspi_write_status_register(dev, qe_reg_num, reg); + if (ret < 0) { return ret; } ret = qspi_wait_until_ready(dev); - if (ret) { + if (ret < 0) { return ret; } - ret = qspi_read_status_register(dev, ®); - if (ret) { + /* validate that QE bit is set */ + ret = qspi_read_status_register(dev, qe_reg_num, ®); + if (ret < 0) { return ret; } - /* Check if QE bit programming is finished */ - if (!(reg & SPI_NOR_QE_BIT)) { - LOG_ERR("Quad Enable [QE] bit in status reg not set"); + if ((reg & qe_bit) == 0U) { + LOG_ERR("Status Register %u [0x%02x] not set", qe_reg_num, reg); return -EIO; } - out: - LOG_INF("Flash - QUAD mode enabled [SR:0x%02x]", reg); - data->flag_quad_io_en = true; - return ret; } @@ -947,6 +1029,8 @@ static int spi_nor_process_bfp(const struct device *dev, LOG_INF("Quad read mode %d instr [0x%x] will be used", data->mode, res.instr); + LOG_INF("QE requirement mode: %x", data->qer_type); + /* enable QE */ rc = qspi_program_quad_io(dev); if (rc < 0) { @@ -954,6 +1038,8 @@ static int spi_nor_process_bfp(const struct device *dev, return rc; } + data->flag_quad_io_en = true; + LOG_INF("Quad mode enabled"); } return 0; @@ -1198,6 +1284,12 @@ static void flash_stm32_qspi_irq_config_func(const struct device *dev); (_CONCAT(SPI_NOR_CMD_, DT_STRING_TOKEN(DT_DRV_INST(inst), writeoc))), \ ((default_value))) +#define DT_QER_PROP_OR(inst, default_value) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, quad_enable_requirements), \ + (_CONCAT(JESD216_DW15_QER_VAL_, \ + DT_STRING_TOKEN(DT_DRV_INST(inst), quad_enable_requirements))), \ + ((default_value))) + #define STM32_QSPI_NODE DT_INST_PARENT(0) PINCTRL_DT_DEFINE(STM32_QSPI_NODE); @@ -1227,6 +1319,7 @@ static struct flash_stm32_qspi_data flash_stm32_qspi_dev_data = { .ClockMode = QSPI_CLOCK_MODE_0, }, }, + .qer_type = DT_QER_PROP_OR(0, JESD216_DW15_QER_VAL_S1B6), .qspi_write_cmd = DT_WRITEOC_PROP_OR(0, SPI_NOR_CMD_PP_1_4_4), QSPI_DMA_CHANNEL(STM32_QSPI_NODE, tx_rx) }; From 283d5fa284465e16515ba83beb10e6547cbc2f80 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 23:05:38 +0200 Subject: [PATCH 11/14] drivers: flash: stm32: qspi: support SFDP quad enable requirements Parses SFDP QER related DW15 to use as the source for QER. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 4e9efec48ae3d..b3f2c487e439e 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -1029,6 +1029,16 @@ static int spi_nor_process_bfp(const struct device *dev, LOG_INF("Quad read mode %d instr [0x%x] will be used", data->mode, res.instr); + /* try to decode QE requirement type */ + rc = jesd216_bfp_decode_dw15(php, bfp, &dw15); + if (rc < 0) { + /* will use QER from DTS or default (refer to device data) */ + LOG_WRN("Unable to decode QE requirement [DW15]: %d", rc); + } else { + /* bypass DTS QER value */ + data->qer_type = dw15.qer; + } + LOG_INF("QE requirement mode: %x", data->qer_type); /* enable QE */ From 8b7b012408aef61dea5070bb646369c2ded6e639 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 23:06:17 +0200 Subject: [PATCH 12/14] drivers: flash: stm32: qspi: always include gpio header Always include gpio header. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index b3f2c487e439e..67e9faa5b6468 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -20,6 +20,7 @@ #include #include #include +#include #if DT_INST_NODE_HAS_PROP(0, spi_bus_width) && \ DT_INST_PROP(0, spi_bus_width) == 4 @@ -29,9 +30,7 @@ #endif #define STM32_QSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) -#if STM32_QSPI_RESET_GPIO -#include -#endif + #include #include "spi_nor.h" From 8358837b89b131dd0983ba207464d9891f102f01 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 13 May 2022 10:14:03 +0200 Subject: [PATCH 13/14] drivers: flash: stm32: qspi: remove flag_quad_io_en field There is no need in the `flag_quad_io_en` field. When QE enabling failed, then the driver `init` fails as well. There is no way to use qspi in quad mode if qe is not enabled. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 61 ++++++++++++++------------------ 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 67e9faa5b6468..0d9832c1078af 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -103,10 +103,6 @@ struct flash_stm32_qspi_data { * 24-bit addresses. */ bool flag_access_32bit: 1; - /* - * If set IO operations will be perfromed on SIO[0123] pins - */ - bool flag_quad_io_en: 1; }; static inline void qspi_lock_thread(const struct device *dev) @@ -141,23 +137,21 @@ static inline int qspi_prepare_quad_read(const struct device *dev, { struct flash_stm32_qspi_data *dev_data = dev->data; - if (dev_data->flag_quad_io_en) { - switch (dev_data->mode) { - case JESD216_MODE_114: - cmd->AddressMode = QSPI_ADDRESS_1_LINE; - break; - case JESD216_MODE_144: - cmd->AddressMode = QSPI_ADDRESS_4_LINES; - break; - default: - return -ENOTSUP; - } - - cmd->Instruction = dev_data->qspi_read_cmd; - cmd->DataMode = QSPI_DATA_4_LINES; - cmd->DummyCycles = dev_data->qspi_read_cmd_latency; + switch (dev_data->mode) { + case JESD216_MODE_114: + cmd->AddressMode = QSPI_ADDRESS_1_LINE; + break; + case JESD216_MODE_144: + cmd->AddressMode = QSPI_ADDRESS_4_LINES; + break; + default: + return -ENOTSUP; } + cmd->Instruction = dev_data->qspi_read_cmd; + cmd->DataMode = QSPI_DATA_4_LINES; + cmd->DummyCycles = dev_data->qspi_read_cmd_latency; + return 0; } @@ -166,24 +160,22 @@ static inline int qspi_prepare_quad_program(const struct device *dev, { struct flash_stm32_qspi_data *dev_data = dev->data; - if (dev_data->flag_quad_io_en) { - cmd->Instruction = dev_data->qspi_write_cmd; - - switch (cmd->Instruction) { - case SPI_NOR_CMD_PP_1_1_4: - cmd->AddressMode = QSPI_ADDRESS_1_LINE; - break; - case SPI_NOR_CMD_PP_1_4_4: - cmd->AddressMode = QSPI_ADDRESS_4_LINES; - break; - default: - return -ENOTSUP; - } + cmd->Instruction = dev_data->qspi_write_cmd; - cmd->DataMode = QSPI_DATA_4_LINES; - cmd->DummyCycles = 0; + switch (cmd->Instruction) { + case SPI_NOR_CMD_PP_1_1_4: + cmd->AddressMode = QSPI_ADDRESS_1_LINE; + break; + case SPI_NOR_CMD_PP_1_4_4: + cmd->AddressMode = QSPI_ADDRESS_4_LINES; + break; + default: + return -ENOTSUP; } + cmd->DataMode = QSPI_DATA_4_LINES; + cmd->DummyCycles = 0; + return 0; } @@ -1047,7 +1039,6 @@ static int spi_nor_process_bfp(const struct device *dev, return rc; } - data->flag_quad_io_en = true; LOG_INF("Quad mode enabled"); } From 689528bfd54d64e61d1521e21ce0049822e3a052 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 13 May 2022 10:19:43 +0200 Subject: [PATCH 14/14] drivers: flash: stm32: qspi: use ternary and asserts in quad prepare Use ternary operation and asserts to reduce the footprint and code size. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_qspi.c | 33 +++++++++++--------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 0d9832c1078af..e2d4f43d6d126 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -137,18 +137,13 @@ static inline int qspi_prepare_quad_read(const struct device *dev, { struct flash_stm32_qspi_data *dev_data = dev->data; - switch (dev_data->mode) { - case JESD216_MODE_114: - cmd->AddressMode = QSPI_ADDRESS_1_LINE; - break; - case JESD216_MODE_144: - cmd->AddressMode = QSPI_ADDRESS_4_LINES; - break; - default: - return -ENOTSUP; - } + __ASSERT_NO_MSG(dev_data->mode == JESD216_MODE_114 || + dev_data->mode == JESD216_MODE_144); cmd->Instruction = dev_data->qspi_read_cmd; + cmd->AddressMode = ((dev_data->mode == JESD216_MODE_114) + ? QSPI_ADDRESS_1_LINE + : QSPI_ADDRESS_4_LINES); cmd->DataMode = QSPI_DATA_4_LINES; cmd->DummyCycles = dev_data->qspi_read_cmd_latency; @@ -160,19 +155,13 @@ static inline int qspi_prepare_quad_program(const struct device *dev, { struct flash_stm32_qspi_data *dev_data = dev->data; - cmd->Instruction = dev_data->qspi_write_cmd; - - switch (cmd->Instruction) { - case SPI_NOR_CMD_PP_1_1_4: - cmd->AddressMode = QSPI_ADDRESS_1_LINE; - break; - case SPI_NOR_CMD_PP_1_4_4: - cmd->AddressMode = QSPI_ADDRESS_4_LINES; - break; - default: - return -ENOTSUP; - } + __ASSERT_NO_MSG(dev_data->qspi_write_cmd == SPI_NOR_CMD_PP_1_1_4 || + dev_data->qspi_write_cmd == SPI_NOR_CMD_PP_1_4_4); + cmd->Instruction = dev_data->qspi_write_cmd; + cmd->AddressMode = ((cmd->Instruction == SPI_NOR_CMD_PP_1_1_4) + ? QSPI_ADDRESS_1_LINE + : QSPI_ADDRESS_4_LINES); cmd->DataMode = QSPI_DATA_4_LINES; cmd->DummyCycles = 0;