From 685f2098c4555f34a7a2728a058db186e2df421c Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Fri, 6 May 2022 22:58:58 +0200 Subject: [PATCH] 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 a8606edd08c..4e9efec48ae 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) };