diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index b347b12b70cec..e2d4f43d6d126 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 */ @@ -19,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 @@ -28,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" @@ -42,6 +42,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) @@ -60,7 +62,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; @@ -90,8 +91,11 @@ 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; + uint8_t qspi_write_cmd; uint8_t qspi_read_cmd; uint8_t qspi_read_cmd_latency; /* @@ -99,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) @@ -132,38 +132,40 @@ 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) { - 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; - } + __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; + + return 0; } -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->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; - } + + __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; + + return 0; } /* @@ -323,7 +325,13 @@ 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); + 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); @@ -380,7 +388,13 @@ 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); + 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) { @@ -723,26 +737,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) @@ -761,7 +832,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; @@ -770,51 +841,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; } @@ -875,34 +970,65 @@ 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; + + /* 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); - LOG_INF("Mode: 1-4-4 with instr:[0x%x] supported!", - res.instr); + data->mode = supported_modes[i]; + data->qspi_read_cmd = res.instr; + data->qspi_read_cmd_latency = res.wait_states; - 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; + 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); + + /* 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 */ + rc = qspi_program_quad_io(dev); + if (rc < 0) { + LOG_ERR("Failed to enable Quad mode: %d", rc); + return rc; + } + + LOG_INF("Quad mode enabled"); } return 0; @@ -1108,8 +1234,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; } @@ -1144,6 +1268,17 @@ 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 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); @@ -1173,6 +1308,8 @@ 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) }; 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; diff --git a/drivers/flash/spi_nor.h b/drivers/flash/spi_nor.h index 6fbc62f08d2c2..2e88f278c6e6a 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 */ @@ -24,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) */ @@ -31,7 +32,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 */ 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.