qspi: stm32: Add code to switch flash memory to use 4 SIO pins

For proper operation of QUADSPI IP block, both sides of communication;
NOR flash memory and STM32 controller need to support 4 IO
transmission.

After this change the QSPI stm32 driver is able to program NOR flash
memory to switch itself to use all 4 IO lines (SIO[0123]) to transmit
and receive data.

The QE bit (in SPI-NOR's Status Register) is the non-volatile one, so
setting it is done only once (at first boot of the device).

Signed-off-by: Lukasz Majewski <lukma@denx.de>
This commit is contained in:
Lukasz Majewski 2021-12-01 15:31:00 +01:00 committed by Anas Nashif
commit c1b60e7fb6
2 changed files with 102 additions and 0 deletions

View file

@ -90,6 +90,10 @@ 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;
};
#define DEV_NAME(dev) ((dev)->name)
@ -665,6 +669,101 @@ 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)
{
QSPI_CommandTypeDef cmd = {
.Instruction = SPI_NOR_CMD_RDSR,
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.DataMode = QSPI_DATA_1_LINE,
};
return qspi_read_access(dev, &cmd, reg, sizeof(*reg));
}
static int qspi_write_status_register(const struct device *dev, uint8_t reg)
{
QSPI_CommandTypeDef cmd = {
.Instruction = SPI_NOR_CMD_WRSR,
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.DataMode = QSPI_DATA_1_LINE,
};
return qspi_write_access(dev, &cmd, &reg, sizeof(reg));
}
static int qspi_write_enable(const struct device *dev)
{
uint8_t reg;
int ret;
QSPI_CommandTypeDef cmd_write_en = {
.Instruction = SPI_NOR_CMD_WREN,
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
};
ret = qspi_send_cmd(dev, &cmd_write_en);
if (ret) {
return ret;
}
do {
ret = qspi_read_status_register(dev, &reg);
} while (!ret && !(reg & SPI_NOR_WEL_BIT));
return ret;
}
static int qspi_program_quad_io(const struct device *dev)
{
struct flash_stm32_qspi_data *data = DEV_DATA(dev);
uint8_t reg;
int ret;
/* Check if QE bit setting is required */
ret = qspi_read_status_register(dev, &reg);
if (ret) {
return ret;
}
/* Quit early when QE bit is already set */
if (reg & SPI_NOR_QE_BIT) {
goto out;
}
ret = qspi_write_enable(dev);
if (ret) {
return ret;
}
reg |= SPI_NOR_QE_BIT;
ret = qspi_write_status_register(dev, reg);
if (ret) {
return ret;
}
ret = qspi_wait_until_ready(dev);
if (ret) {
return ret;
}
ret = qspi_read_status_register(dev, &reg);
if (ret) {
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");
return -EIO;
}
out:
LOG_INF("Flash - QUAD mode enabled [SR:0x%02x]", reg);
data->flag_quad_io_en = true;
return ret;
}
static int spi_nor_process_bfp(const struct device *dev,
const struct jesd216_param_header *php,
const struct jesd216_bfp *bfp)
@ -723,6 +822,8 @@ static int spi_nor_process_bfp(const struct device *dev,
}
}
qspi_program_quad_io(dev);
return 0;
}

View file

@ -14,6 +14,7 @@
/* 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 */