Browse Source

drivers: flash: stm32 xspi driver with DMA support

Add the commands to read and write to/from the xSPI with gpDMA
On the stm32h5 device, the one request for xspi instance

Signed-off-by: Francois Ramu <francois.ramu@st.com>
pull/73520/head
Francois Ramu 1 year ago committed by Anas Nashif
parent
commit
ac48369731
  1. 10
      drivers/flash/Kconfig.stm32_xspi
  2. 170
      drivers/flash/flash_stm32_xspi.c
  3. 31
      drivers/flash/flash_stm32_xspi.h

10
drivers/flash/Kconfig.stm32_xspi

@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
# Copyright (c) 2024 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
DT_STM32_XSPI_1_HAS_DMA := $(dt_nodelabel_has_prop,xspi1,dmas)
DT_STM32_XSPI_2_HAS_DMA := $(dt_nodelabel_has_prop,xspi2,dmas)
config FLASH_STM32_XSPI
bool "STM32 XSPI Flash driver"
default y
@ -13,6 +16,11 @@ config FLASH_STM32_XSPI @@ -13,6 +16,11 @@ config FLASH_STM32_XSPI
select FLASH_JESD216
select FLASH_PAGE_LAYOUT
select FLASH_HAS_PAGE_LAYOUT
select DMA if $(DT_STM32_XSPI_1_HAS_DMA) || $(DT_STM32_XSPI_2_HAS_DMA)
select USE_STM32_HAL_DMA if $(DT_STM32_XSPI_1_HAS_DMA) || \
$(DT_STM32_XSPI_2_HAS_DMA)
select USE_STM32_HAL_DMA_EX if SOC_SERIES_STM32H5X && \
($(DT_STM32_XSPI_1_HAS_DMA) || \
$(DT_STM32_XSPI_2_HAS_DMA))
help
Enable XSPI-NOR support on the STM32 family of processors.

170
drivers/flash/flash_stm32_xspi.c

@ -44,6 +44,14 @@ LOG_MODULE_REGISTER(flash_stm32_xspi, CONFIG_FLASH_LOG_LEVEL); @@ -44,6 +44,14 @@ LOG_MODULE_REGISTER(flash_stm32_xspi, CONFIG_FLASH_LOG_LEVEL);
#define STM32_XSPI_DLYB_BYPASSED DT_PROP(STM32_XSPI_NODE, dlyb_bypass)
#define STM32_XSPI_USE_DMA DT_NODE_HAS_PROP(STM32_XSPI_NODE, dmas)
#if STM32_XSPI_USE_DMA
#include <zephyr/drivers/dma/dma_stm32.h>
#include <zephyr/drivers/dma.h>
#include <stm32_ll_dma.h>
#endif /* STM32_XSPI_USE_DMA */
#include "flash_stm32_xspi.h"
static inline void xspi_lock_thread(const struct device *dev)
@ -97,7 +105,11 @@ static int xspi_read_access(const struct device *dev, XSPI_RegularCmdTypeDef *cm @@ -97,7 +105,11 @@ static int xspi_read_access(const struct device *dev, XSPI_RegularCmdTypeDef *cm
return -EIO;
}
#if STM32_XSPI_USE_DMA
hal_ret = HAL_XSPI_Receive_DMA(&dev_data->hxspi, data);
#else
hal_ret = HAL_XSPI_Receive_IT(&dev_data->hxspi, data);
#endif
if (hal_ret != HAL_OK) {
LOG_ERR("%d: Failed to read data", hal_ret);
@ -135,7 +147,11 @@ static int xspi_write_access(const struct device *dev, XSPI_RegularCmdTypeDef *c @@ -135,7 +147,11 @@ static int xspi_write_access(const struct device *dev, XSPI_RegularCmdTypeDef *c
return -EIO;
}
#if STM32_XSPI_USE_DMA
hal_ret = HAL_XSPI_Transmit_DMA(&dev_data->hxspi, (uint8_t *)data);
#else
hal_ret = HAL_XSPI_Transmit_IT(&dev_data->hxspi, (uint8_t *)data);
#endif
if (hal_ret != HAL_OK) {
LOG_ERR("%d: Failed to write data", hal_ret);
@ -1220,6 +1236,24 @@ __weak HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma) @@ -1220,6 +1236,24 @@ __weak HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
}
#endif /* !CONFIG_SOC_SERIES_STM32H7X */
/* This function is executed in the interrupt context */
#if STM32_XSPI_USE_DMA
static void xspi_dma_callback(const struct device *dev, void *arg,
uint32_t channel, int status)
{
DMA_HandleTypeDef *hdma = arg;
ARG_UNUSED(dev);
if (status < 0) {
LOG_ERR("DMA callback error with channel %d.", channel);
}
HAL_DMA_IRQHandler(hdma);
}
#endif
/*
* Transfer Error callback.
*/
@ -1707,6 +1741,85 @@ static int spi_nor_process_bfp(const struct device *dev, @@ -1707,6 +1741,85 @@ static int spi_nor_process_bfp(const struct device *dev,
return 0;
}
#if STM32_XSPI_USE_DMA
static int flash_stm32_xspi_dma_init(DMA_HandleTypeDef *hdma, struct stream *dma_stream)
{
int ret;
/*
* DMA configuration
* Due to use of XSPI HAL API in current driver,
* both HAL and Zephyr DMA drivers should be configured.
* The required configuration for Zephyr DMA driver should only provide
* the minimum information to inform the DMA slot will be in used and
* how to route callbacks.
*/
if (!device_is_ready(dma_stream->dev)) {
LOG_ERR("DMA %s device not ready", dma_stream->dev->name);
return -ENODEV;
}
/* Proceed to the minimum Zephyr DMA driver init of the channel */
dma_stream->cfg.user_data = hdma;
/* HACK: This field is used to inform driver that it is overridden */
dma_stream->cfg.linked_channel = STM32_DMA_HAL_OVERRIDE;
/* Because of the STREAM OFFSET, the DMA channel given here is from 1 - 8 */
ret = dma_config(dma_stream->dev,
(dma_stream->channel + STM32_DMA_STREAM_OFFSET), &dma_stream->cfg);
if (ret != 0) {
LOG_ERR("Failed to configure DMA channel %d",
dma_stream->channel + STM32_DMA_STREAM_OFFSET);
return ret;
}
/* Proceed to the HAL DMA driver init */
if (dma_stream->cfg.source_data_size != dma_stream->cfg.dest_data_size) {
LOG_ERR("DMA Source and destination data sizes not aligned");
return -EINVAL;
}
hdma->Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; /* Fixed value */
hdma->Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; /* Fixed value */
hdma->Init.SrcInc = (dma_stream->src_addr_increment)
? DMA_SINC_INCREMENTED
: DMA_SINC_FIXED;
hdma->Init.DestInc = (dma_stream->dst_addr_increment)
? DMA_DINC_INCREMENTED
: DMA_DINC_FIXED;
hdma->Init.SrcBurstLength = 4;
hdma->Init.DestBurstLength = 4;
hdma->Init.Priority = table_priority[dma_stream->cfg.channel_priority];
hdma->Init.Direction = table_direction[dma_stream->cfg.channel_direction];
hdma->Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_SRC_ALLOCATED_PORT1;
hdma->Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
hdma->Init.Mode = DMA_NORMAL;
hdma->Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
hdma->Init.Request = dma_stream->cfg.dma_slot;
/*
* HAL expects a valid DMA channel (not DMAMUX).
* The channel is from 0 to 7 because of the STM32_DMA_STREAM_OFFSET
* in the dma_stm32 driver
*/
hdma->Instance = LL_DMA_GET_CHANNEL_INSTANCE(dma_stream->reg,
dma_stream->channel);
/* Initialize DMA HAL */
if (HAL_DMA_Init(hdma) != HAL_OK) {
LOG_ERR("XSPI DMA Init failed");
return -EIO;
}
if (HAL_DMA_ConfigChannelAttributes(hdma, DMA_CHANNEL_NPRIV) != HAL_OK) {
LOG_ERR("XSPI DMA Init failed");
return -EIO;
}
LOG_DBG("XSPI with DMA transfer");
return 0;
}
#endif /* STM32_XSPI_USE_DMA */
static int flash_stm32_xspi_init(const struct device *dev)
{
const struct flash_stm32_xspi_config *dev_cfg = dev->config;
@ -1859,6 +1972,28 @@ static int flash_stm32_xspi_init(const struct device *dev) @@ -1859,6 +1972,28 @@ static int flash_stm32_xspi_init(const struct device *dev)
#endif /* DLYB_ */
#if STM32_XSPI_USE_DMA
/* Configure and enable the DMA channels after XSPI config */
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_rx;
if (flash_stm32_xspi_dma_init(&hdma_tx, &dev_data->dma_tx) != 0) {
LOG_ERR("XSPI DMA Tx init failed");
return -EIO;
}
/* The dma_tx handle is hold by the dma_stream.cfg.user_data */
__HAL_LINKDMA(&dev_data->hxspi, hdmatx, hdma_tx);
if (flash_stm32_xspi_dma_init(&hdma_rx, &dev_data->dma_rx) != 0) {
LOG_ERR("XSPI DMA Rx init failed");
return -EIO;
}
/* The dma_rx handle is hold by the dma_stream.cfg.user_data */
__HAL_LINKDMA(&dev_data->hxspi, hdmarx, hdma_rx);
#endif /* CONFIG_USE_STM32_HAL_DMA */
/* Initialize semaphores */
k_sem_init(&dev_data->sem, 1, 1);
k_sem_init(&dev_data->sync, 0, 1);
@ -2004,6 +2139,39 @@ static int flash_stm32_xspi_init(const struct device *dev) @@ -2004,6 +2139,39 @@ static int flash_stm32_xspi_init(const struct device *dev)
return 0;
}
#if STM32_XSPI_USE_DMA
#define DMA_CHANNEL_CONFIG(node, dir) \
DT_DMAS_CELL_BY_NAME(node, dir, channel_config)
#define XSPI_DMA_CHANNEL_INIT(node, dir, dir_cap, src_dev, dest_dev) \
.dev = DEVICE_DT_GET(DT_DMAS_CTLR(node)), \
.channel = DT_DMAS_CELL_BY_NAME(node, dir, channel), \
.reg = (DMA_TypeDef *)DT_REG_ADDR( \
DT_PHANDLE_BY_NAME(node, dmas, dir)), \
.cfg = { \
.dma_slot = DT_DMAS_CELL_BY_NAME(node, dir, slot), \
.channel_direction = STM32_DMA_CONFIG_DIRECTION( \
DMA_CHANNEL_CONFIG(node, dir)), \
.channel_priority = STM32_DMA_CONFIG_PRIORITY( \
DMA_CHANNEL_CONFIG(node, dir)), \
.dma_callback = xspi_dma_callback, \
}, \
.src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC( \
DMA_CHANNEL_CONFIG(node, dir)), \
.dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC( \
DMA_CHANNEL_CONFIG(node, dir)),
#define XSPI_DMA_CHANNEL(node, dir, DIR, src, dest) \
.dma_##dir = { \
COND_CODE_1(DT_DMAS_HAS_NAME(node, dir), \
(XSPI_DMA_CHANNEL_INIT(node, dir, DIR, src, dest)), \
(NULL)) \
},
#else
#define XSPI_DMA_CHANNEL(node, dir, DIR, src, dest)
#endif /* CONFIG_USE_STM32_HAL_DMA */
#define XSPI_FLASH_MODULE(drv_id, flash_id) \
(DT_DRV_INST(drv_id), xspi_nor_flash_##flash_id)
@ -2065,6 +2233,8 @@ static struct flash_stm32_xspi_data flash_stm32_xspi_dev_data = { @@ -2065,6 +2233,8 @@ static struct flash_stm32_xspi_data flash_stm32_xspi_dev_data = {
#if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_ospi_nor), jedec_id)
.jedec_id = DT_INST_PROP(0, jedec_id),
#endif /* jedec_id */
XSPI_DMA_CHANNEL(STM32_XSPI_NODE, tx, TX, MEMORY, PERIPHERAL)
XSPI_DMA_CHANNEL(STM32_XSPI_NODE, rx, RX, PERIPHERAL, MEMORY)
};
static void flash_stm32_xspi_irq_config_func(const struct device *dev)

31
drivers/flash/flash_stm32_xspi.h

@ -37,6 +37,33 @@ @@ -37,6 +37,33 @@
/* used as default value for DTS writeoc */
#define SPI_NOR_WRITEOC_NONE 0xFF
#if STM32_XSPI_USE_DMA
/* Lookup table to set dma priority from the DTS */
static const uint32_t table_priority[] = {
DMA_LOW_PRIORITY_LOW_WEIGHT,
DMA_LOW_PRIORITY_MID_WEIGHT,
DMA_LOW_PRIORITY_HIGH_WEIGHT,
DMA_HIGH_PRIORITY,
};
/* Lookup table to set dma channel direction from the DTS */
static const uint32_t table_direction[] = {
DMA_MEMORY_TO_MEMORY,
DMA_MEMORY_TO_PERIPH,
DMA_PERIPH_TO_MEMORY,
};
struct stream {
DMA_TypeDef *reg;
const struct device *dev;
uint32_t channel;
struct dma_config cfg;
uint8_t priority;
bool src_addr_increment;
bool dst_addr_increment;
};
#endif /* STM32_XSPI_USE_DMA */
typedef void (*irq_config_func_t)(const struct device *dev);
struct flash_stm32_xspi_config {
@ -77,6 +104,10 @@ struct flash_stm32_xspi_data { @@ -77,6 +104,10 @@ struct flash_stm32_xspi_data {
uint8_t jedec_id[JESD216_READ_ID_LEN];
#endif /* CONFIG_FLASH_JESD216_API */
int cmd_status;
#if STM32_XSPI_USE_DMA
struct stream dma_tx;
struct stream dma_rx;
#endif /* STM32_XSPI_USE_DMA */
};
#endif /* ZEPHYR_DRIVERS_FLASH_XSPI_STM32_H_ */

Loading…
Cancel
Save