Browse Source

drivers: flash: stm32: add "generic read/write" ex op to QSPI driver

Some external flash modules have extra commands to support, for example,
reading/writing an OTP zone. Given that the commands are highly specific
and difficult to generalize, we add two ex ops that can be used to
transmit a custom command (in the form of a full QSPI_CommandTypeDef) and
then read or write a user-provided buffer.

Signed-off-by: Federico Di Gregorio <fog@dndg.it>
pull/91733/merge
Federico Di Gregorio 1 month ago committed by Benjamin Cabé
parent
commit
3d720bcb73
  1. 21
      drivers/flash/Kconfig.stm32_qspi
  2. 84
      drivers/flash/flash_stm32_qspi.c
  3. 19
      include/zephyr/drivers/flash/stm32_flash_api_extensions.h

21
drivers/flash/Kconfig.stm32_qspi

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
DT_STM32_QUADSPI_HAS_DMA := $(dt_compat_any_has_prop,$(DT_COMPAT_ST_STM32_QSPI),dmas)
config FLASH_STM32_QSPI
menuconfig FLASH_STM32_QSPI
bool "STM32 Quad SPI Flash driver"
default y
depends on DT_HAS_ST_STM32_QSPI_NOR_ENABLED
@ -21,3 +21,22 @@ config FLASH_STM32_QSPI @@ -21,3 +21,22 @@ config FLASH_STM32_QSPI
select USE_STM32_HAL_DMA if $(DT_STM32_QUADSPI_HAS_DMA)
help
Enable QSPI-NOR support on the STM32 family of processors.
if FLASH_STM32_QSPI
config FLASH_STM32_QSPI_GENERIC_READ
bool "Generic read command extended operation"
select FLASH_HAS_EX_OP
help
Enables flash extended operation that can be used to transmit
a custom command and read the result to a user-provided buffer.
config FLASH_STM32_QSPI_GENERIC_WRITE
bool "Generic write command extended operation"
select FLASH_HAS_EX_OP
help
Enables flash extended operation that can be used to transmit
a custom command and write data taken from a user-provided
buffer.
endif # FLASH_STM32_QSPI

84
drivers/flash/flash_stm32_qspi.c

@ -20,10 +20,16 @@ @@ -20,10 +20,16 @@
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_stm32.h>
#include <zephyr/drivers/gpio.h>
#ifdef CONFIG_USERSPACE
#include <zephyr/syscall.h>
#include <zephyr/internal/syscall_handler.h>
#endif
#if DT_INST_NODE_HAS_PROP(0, spi_bus_width) && \
DT_INST_PROP(0, spi_bus_width) == 4
#define STM32_QSPI_USE_QUAD_IO 1
@ -886,6 +892,81 @@ static void flash_stm32_qspi_pages_layout(const struct device *dev, @@ -886,6 +892,81 @@ static void flash_stm32_qspi_pages_layout(const struct device *dev,
}
#endif
#if defined(CONFIG_FLASH_EX_OP_ENABLED)
#if defined(CONFIG_FLASH_STM32_QSPI_GENERIC_READ)
static int flash_stm32_qspi_generic_read(const struct device *dev, QSPI_CommandTypeDef *cmd,
void *out)
{
int ret;
#ifdef CONFIG_USERSPACE
QSPI_CommandTypeDef cmd_copy;
bool syscall_trap = z_syscall_trap();
if (syscall_trap) {
K_OOPS(k_usermode_from_copy(&cmd_copy, cmd, sizeof(cmd_copy)));
cmd = &cmd_copy;
K_OOPS(K_SYSCALL_MEMORY_WRITE(out, cmd->NbData));
}
#endif
qspi_lock_thread(dev);
ret = qspi_read_access(dev, cmd, out, cmd->NbData);
qspi_unlock_thread(dev);
return ret;
}
#endif /* CONFIG_FLASH_STM32_QSPI_GENERIC_READ */
#if defined(CONFIG_FLASH_STM32_QSPI_GENERIC_WRITE)
static int flash_stm32_qspi_generic_write(const struct device *dev, QSPI_CommandTypeDef *cmd,
void *in)
{
int ret;
#ifdef CONFIG_USERSPACE
QSPI_CommandTypeDef cmd_copy;
bool syscall_trap = z_syscall_trap();
if (syscall_trap) {
K_OOPS(k_usermode_from_copy(&cmd_copy, cmd, sizeof(cmd_copy)));
cmd = &cmd_copy;
K_OOPS(K_SYSCALL_MEMORY_READ(in, cmd->NbData));
}
#endif
qspi_lock_thread(dev);
ret = qspi_write_access(dev, cmd, in, cmd->NbData);
qspi_unlock_thread(dev);
return ret;
}
#endif /* CONFIG_FLASH_STM32_QSPI_GENERIC_WRITE */
static int flash_stm32_qspi_ex_op(const struct device *dev, uint16_t code, const uintptr_t cmd,
void *data)
{
switch (code) {
#if defined(CONFIG_FLASH_STM32_QSPI_GENERIC_READ)
case FLASH_STM32_QSPI_EX_OP_GENERIC_READ:
return flash_stm32_qspi_generic_read(dev, (QSPI_CommandTypeDef *)cmd, data);
#endif
#if defined(CONFIG_FLASH_STM32_QSPI_GENERIC_WRITE)
case FLASH_STM32_QSPI_EX_OP_GENERIC_WRITE:
return flash_stm32_qspi_generic_write(dev, (QSPI_CommandTypeDef *)cmd, data);
#endif
default:
return -ENOTSUP;
}
}
#endif /* CONFIG_FLASH_EX_OP_ENABLED */
static DEVICE_API(flash, flash_stm32_qspi_driver_api) = {
.read = flash_stm32_qspi_read,
.write = flash_stm32_qspi_write,
@ -899,6 +980,9 @@ static DEVICE_API(flash, flash_stm32_qspi_driver_api) = { @@ -899,6 +980,9 @@ static DEVICE_API(flash, flash_stm32_qspi_driver_api) = {
.sfdp_read = qspi_read_sfdp,
.read_jedec_id = qspi_read_jedec_id,
#endif /* CONFIG_FLASH_JESD216_API */
#if defined(CONFIG_FLASH_EX_OP_ENABLED)
.ex_op = flash_stm32_qspi_ex_op,
#endif
};
#if defined(CONFIG_FLASH_PAGE_LAYOUT)

19
include/zephyr/drivers/flash/stm32_flash_api_extensions.h

@ -64,6 +64,25 @@ enum stm32_ex_ops { @@ -64,6 +64,25 @@ enum stm32_ex_ops {
FLASH_STM32_EX_OP_OPTB_WRITE,
};
#if defined(CONFIG_FLASH_EX_OP_ENABLED)
enum stm32_qspi_ex_ops {
/*
* QSPI generic read command.
*
* Transmit the custom command and read the result to the user-provided
* buffer.
*/
FLASH_STM32_QSPI_EX_OP_GENERIC_READ,
/*
* QSPI generic write command.
*
* Transmit the custom command and then write data taken from the
* user-provided buffer.
*/
FLASH_STM32_QSPI_EX_OP_GENERIC_WRITE,
};
#endif /* CONFIG_FLASH_EX_OP_ENABLED */
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
struct flash_stm32_ex_op_sector_wp_in {
uint64_t enable_mask;

Loading…
Cancel
Save