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>
This commit is contained in:
parent
9cef24bc62
commit
3d720bcb73
3 changed files with 123 additions and 1 deletions
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
DT_STM32_QUADSPI_HAS_DMA := $(dt_compat_any_has_prop,$(DT_COMPAT_ST_STM32_QSPI),dmas)
|
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"
|
bool "STM32 Quad SPI Flash driver"
|
||||||
default y
|
default y
|
||||||
depends on DT_HAS_ST_STM32_QSPI_NOR_ENABLED
|
depends on DT_HAS_ST_STM32_QSPI_NOR_ENABLED
|
||||||
|
@ -21,3 +21,22 @@ config FLASH_STM32_QSPI
|
||||||
select USE_STM32_HAL_DMA if $(DT_STM32_QUADSPI_HAS_DMA)
|
select USE_STM32_HAL_DMA if $(DT_STM32_QUADSPI_HAS_DMA)
|
||||||
help
|
help
|
||||||
Enable QSPI-NOR support on the STM32 family of processors.
|
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
|
||||||
|
|
|
@ -20,10 +20,16 @@
|
||||||
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
|
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
|
||||||
#include <zephyr/drivers/clock_control.h>
|
#include <zephyr/drivers/clock_control.h>
|
||||||
#include <zephyr/drivers/flash.h>
|
#include <zephyr/drivers/flash.h>
|
||||||
|
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
|
||||||
#include <zephyr/drivers/dma.h>
|
#include <zephyr/drivers/dma.h>
|
||||||
#include <zephyr/drivers/dma/dma_stm32.h>
|
#include <zephyr/drivers/dma/dma_stm32.h>
|
||||||
#include <zephyr/drivers/gpio.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) && \
|
#if DT_INST_NODE_HAS_PROP(0, spi_bus_width) && \
|
||||||
DT_INST_PROP(0, spi_bus_width) == 4
|
DT_INST_PROP(0, spi_bus_width) == 4
|
||||||
#define STM32_QSPI_USE_QUAD_IO 1
|
#define STM32_QSPI_USE_QUAD_IO 1
|
||||||
|
@ -886,6 +892,81 @@ static void flash_stm32_qspi_pages_layout(const struct device *dev,
|
||||||
}
|
}
|
||||||
#endif
|
#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) = {
|
static DEVICE_API(flash, flash_stm32_qspi_driver_api) = {
|
||||||
.read = flash_stm32_qspi_read,
|
.read = flash_stm32_qspi_read,
|
||||||
.write = flash_stm32_qspi_write,
|
.write = flash_stm32_qspi_write,
|
||||||
|
@ -899,6 +980,9 @@ static DEVICE_API(flash, flash_stm32_qspi_driver_api) = {
|
||||||
.sfdp_read = qspi_read_sfdp,
|
.sfdp_read = qspi_read_sfdp,
|
||||||
.read_jedec_id = qspi_read_jedec_id,
|
.read_jedec_id = qspi_read_jedec_id,
|
||||||
#endif /* CONFIG_FLASH_JESD216_API */
|
#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)
|
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||||
|
|
|
@ -64,6 +64,25 @@ enum stm32_ex_ops {
|
||||||
FLASH_STM32_EX_OP_OPTB_WRITE,
|
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)
|
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
|
||||||
struct flash_stm32_ex_op_sector_wp_in {
|
struct flash_stm32_ex_op_sector_wp_in {
|
||||||
uint64_t enable_mask;
|
uint64_t enable_mask;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue