drivers: dma: dma_mcux_smartdma: update interface to support custom FW

The SMARTDMA is a programmable DMA engine, and supports custom firmware
in order to run complex DMA operations. Update the driver to increase
the flexibility users have when configuring the SMARTDMA with
custom firmware, and remove the RT500 display firmware specific
definitions and functionality from the driver.

This display setup is now handled from the MIPI DSI driver, since the
firmware used for this case is specific to the MIPI DSI IP.

This change also requires an update to the RT500 devicetree, as the
register definition for the SMARTDMA has changed, so the base address
must as well.

Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
This commit is contained in:
Daniel DeGrasse 2024-05-15 22:10:40 +00:00 committed by Anas Nashif
parent 97943295e5
commit 126306981d
4 changed files with 28 additions and 136 deletions

View File

@ -19,30 +19,14 @@
LOG_MODULE_REGISTER(dma_mcux_smartdma, CONFIG_DMA_LOG_LEVEL);
/* SMARTDMA peripheral registers, taken from MCUX driver implementation*/
struct smartdma_periph {
volatile uint32_t BOOT;
volatile uint32_t CTRL;
volatile uint32_t PC;
volatile uint32_t SP;
volatile uint32_t BREAK_ADDR;
volatile uint32_t BREAK_VECT;
volatile uint32_t EMER_VECT;
volatile uint32_t EMER_SEL;
volatile uint32_t ARM2SMARTDMA;
volatile uint32_t SMARTDMA2ARM;
volatile uint32_t PENDTRAP;
};
struct dma_mcux_smartdma_config {
struct smartdma_periph *base;
SMARTDMA_Type *base;
void (*irq_config_func)(const struct device *dev);
void (**smartdma_progs)(void);
};
struct dma_mcux_smartdma_data {
uint32_t smartdma_stack[32]; /* Stack for SMARTDMA */
/* Installed DMA callback and user data */
dma_callback_t callback;
void *user_data;
@ -53,22 +37,13 @@ struct dma_mcux_smartdma_data {
/* These bits are set when the SMARTDMA boots, cleared to reset it */
#define SMARTDMA_BOOT 0x11
static inline bool dma_mcux_smartdma_prog_is_mipi(uint32_t prog)
{
return ((prog == kSMARTDMA_MIPI_RGB565_DMA) ||
(prog == kSMARTDMA_MIPI_RGB888_DMA) ||
(prog == kSMARTDMA_MIPI_RGB565_R180_DMA) ||
(prog == kSMARTDMA_MIPI_RGB888_R180_DMA));
}
/* Configure a channel */
static int dma_mcux_smartdma_configure(const struct device *dev,
uint32_t channel, struct dma_config *config)
{
const struct dma_mcux_smartdma_config *dev_config = dev->config;
struct dma_mcux_smartdma_data *data = dev->data;
uint32_t prog_idx;
bool swap_pixels = false;
uint32_t prog_idx = config->dma_slot;
/* SMARTDMA does not have channels */
ARG_UNUSED(channel);
@ -79,68 +54,11 @@ static int dma_mcux_smartdma_configure(const struct device *dev,
/* Reset smartDMA */
SMARTDMA_Reset();
/*
* The dma_slot parameter is used to determine which SMARTDMA program
* to run. First, convert the Zephyr define to a HAL enum.
*/
switch (config->dma_slot) {
case DMA_SMARTDMA_MIPI_RGB565_DMA:
prog_idx = kSMARTDMA_MIPI_RGB565_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB888_DMA:
prog_idx = kSMARTDMA_MIPI_RGB888_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB565_180:
prog_idx = kSMARTDMA_MIPI_RGB565_R180_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB888_180:
prog_idx = kSMARTDMA_MIPI_RGB888_R180_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB565_DMA_SWAP:
swap_pixels = true;
prog_idx = kSMARTDMA_MIPI_RGB565_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB888_DMA_SWAP:
swap_pixels = true;
prog_idx = kSMARTDMA_MIPI_RGB888_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB565_180_SWAP:
swap_pixels = true;
prog_idx = kSMARTDMA_MIPI_RGB565_R180_DMA;
break;
case DMA_SMARTDMA_MIPI_RGB888_180_SWAP:
swap_pixels = true;
prog_idx = kSMARTDMA_MIPI_RGB888_R180_DMA;
break;
default:
prog_idx = config->dma_slot;
break;
}
if (dma_mcux_smartdma_prog_is_mipi(prog_idx)) {
smartdma_dsi_param_t param = {.disablePixelByteSwap = (swap_pixels == false)};
if (config->block_count != 1) {
return -ENOTSUP;
}
/* Setup SMARTDMA */
param.p_buffer = (uint8_t *)config->head_block->source_address;
param.buffersize = config->head_block->block_size;
param.smartdma_stack = data->smartdma_stack;
/* Save configuration to SMARTDMA */
dev_config->base->ARM2SMARTDMA = (uint32_t)(&param);
} else {
/* For other cases, we simply pass the entire DMA config
* struct to the SMARTDMA. The user's application could either
* populate this structure with data, or choose to write
* different configuration data to the SMARTDMA in their
* application
*/
dev_config->base->ARM2SMARTDMA = ((uint32_t)config);
}
/* Write the head block pointer directly to SMARTDMA */
dev_config->base->ARM2EZH = (uint32_t)config->head_block;
/* Save program */
dev_config->base->BOOT = (uint32_t)dev_config->smartdma_progs[prog_idx];
LOG_DBG("Boot address set to 0x%X", dev_config->base->BOOT);
dev_config->base->BOOTADR = (uint32_t)dev_config->smartdma_progs[prog_idx];
LOG_DBG("Boot address set to 0x%X", dev_config->base->BOOTADR);
return 0;
}
@ -175,15 +93,7 @@ static int dma_mcux_smartdma_stop(const struct device *dev, uint32_t channel)
static int dma_mcux_smartdma_init(const struct device *dev)
{
const struct dma_mcux_smartdma_config *config = dev->config;
/*
* Initialize the SMARTDMA with firmware. The default firmware
* from MCUX SDK is a display firmware, which has functions
* implemented above in the dma configuration function. The
* user can install another firmware using `dma_smartdma_install_fw`
*/
SMARTDMA_Init((uint32_t)config->smartdma_progs,
s_smartdmaDisplayFirmware,
SMARTDMA_DISPLAY_FIRMWARE_SIZE);
SMARTDMA_InitWithoutFirmware();
config->irq_config_func(dev);
return 0;
@ -236,7 +146,7 @@ static const struct dma_driver_api dma_mcux_smartdma_api = {
} \
\
static const struct dma_mcux_smartdma_config smartdma_##n##_config = { \
.base = (struct smartdma_periph *)DT_INST_REG_ADDR(n), \
.base = (SMARTDMA_Type *)DT_INST_REG_ADDR(n), \
.smartdma_progs = (void (**)(void))DT_INST_PROP(n, program_mem),\
.irq_config_func = dma_mcux_smartdma_config_func_##n, \
}; \

View File

@ -19,6 +19,9 @@
#include <fsl_inputmux.h>
#include <fsl_mipi_dsi.h>
#include <fsl_clock.h>
#ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
#include <fsl_smartdma.h>
#endif
#include <soc.h>
@ -47,6 +50,8 @@ struct mcux_mipi_dsi_data {
dsi_handle_t mipi_handle;
struct k_sem transfer_sem;
#ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
smartdma_dsi_param_t smartdma_params __aligned(4);
uint32_t smartdma_stack[32];
uint8_t dma_slot;
#endif
};
@ -94,7 +99,6 @@ static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
const struct mcux_mipi_dsi_config *config = dev->config;
struct mcux_mipi_dsi_data *data = dev->data;
struct dma_config dma_cfg = {0};
struct dma_block_config block = {0};
int ret;
if (channel != 0) {
@ -102,12 +106,12 @@ static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
}
/* Configure smartDMA device, and run transfer */
block.source_address = (uint32_t)msg->tx_buf;
block.block_size = msg->tx_len;
data->smartdma_params.p_buffer = msg->tx_buf;
data->smartdma_params.buffersize = msg->tx_len;
dma_cfg.dma_callback = dsi_mcux_dma_cb;
dma_cfg.user_data = (struct device *)dev;
dma_cfg.head_block = &block;
dma_cfg.head_block = (struct dma_block_config *)&data->smartdma_params;
dma_cfg.block_count = 1;
dma_cfg.dma_slot = data->dma_slot;
dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
@ -250,13 +254,15 @@ static int dsi_mcux_attach(const struct device *dev,
switch (mdev->pixfmt) {
case MIPI_DSI_PIXFMT_RGB888:
data->dma_slot = DMA_SMARTDMA_MIPI_RGB888_DMA;
data->dma_slot = kSMARTDMA_MIPI_RGB888_DMA;
data->smartdma_params.disablePixelByteSwap = true;
break;
case MIPI_DSI_PIXFMT_RGB565:
data->dma_slot = kSMARTDMA_MIPI_RGB565_DMA;
if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) {
data->dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA_SWAP;
data->smartdma_params.disablePixelByteSwap = false;
} else {
data->dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA;
data->smartdma_params.disablePixelByteSwap = true;
}
break;
default:
@ -264,6 +270,12 @@ static int dsi_mcux_attach(const struct device *dev,
mdev->pixfmt);
return -ENODEV;
}
data->smartdma_params.smartdma_stack = data->smartdma_stack;
dma_smartdma_install_fw(config->smart_dma,
(uint8_t *)s_smartdmaDisplayFirmware,
s_smartdmaDisplayFirmwareSize);
#else
struct mcux_mipi_dsi_data *data = dev->data;

View File

@ -587,7 +587,7 @@
smartdma: dma@27020 {
compatible = "nxp,smartdma";
reg = <0x27020 0x1000>;
reg = <0x27000 0x1000>;
program-mem = <0x24100000>;
interrupts = <73 0>;
status = "disabled";

View File

@ -7,34 +7,6 @@
#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_SMARTDMA_H_
#define ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_SMARTDMA_H_
/* Write RGB565 data to MIPI DSI via DMA. */
#define DMA_SMARTDMA_MIPI_RGB565_DMA 0
/* Write RGB888 data to MIPI DSI via DMA */
#define DMA_SMARTDMA_MIPI_RGB888_DMA 1
/* Write RGB565 data to MIPI DSI via DMA. Rotate output data by 180 degrees */
#define DMA_SMARTDMA_MIPI_RGB565_180 2
/* Write RGB888 data to MIPI DSI via DMA. Rotate output data by 180 degrees */
#define DMA_SMARTDMA_MIPI_RGB888_180 3
/* Write RGB565 data to MIPI DSI via DMA. Swap data endianness, so that
* little endian RGB565 data will be written big endian style.
*/
#define DMA_SMARTDMA_MIPI_RGB565_DMA_SWAP 4
/* Write RGB888 data to MIPI DSI via DMA. Swap data endianness, so that
* little endian RGB888 data will be written big endian style.
*/
#define DMA_SMARTDMA_MIPI_RGB888_DMA_SWAP 5
/* Write RGB565 data to MIPI DSI via DMA. Rotate output data by 180 degrees,
* and swap data endianness
*/
#define DMA_SMARTDMA_MIPI_RGB565_180_SWAP 6
/* Write RGB888 data to MIPI DSI via DMA. Rotate output data by 180 degrees,
* and swap data endianness
*/
#define DMA_SMARTDMA_MIPI_RGB888_180_SWAP 7
/**
* @brief install SMARTDMA firmware
*
@ -48,6 +20,4 @@
void dma_smartdma_install_fw(const struct device *dev, uint8_t *firmware,
uint32_t len);
#define GD32_DMA_FEATURES_FIFO_THRESHOLD(threshold) (threshold & 0x3)
#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_SMARTDMA_H_ */