drivers: flash: stm32: qspi: support DTS quad enable requirements
Adds support for DTS quad_enable_requirements property. Signed-off-by: Georgij Cernysiov <geo.cgv@gmail.com>
This commit is contained in:
parent
706697168b
commit
685f2098c4
1 changed files with 118 additions and 25 deletions
|
@ -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)
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue