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:
parent
97943295e5
commit
126306981d
|
@ -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)(¶m);
|
||||
} 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, \
|
||||
}; \
|
||||
|
|
|
@ -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 = █
|
||||
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;
|
||||
|
||||
|
|
|
@ -587,7 +587,7 @@
|
|||
|
||||
smartdma: dma@27020 {
|
||||
compatible = "nxp,smartdma";
|
||||
reg = <0x27020 0x1000>;
|
||||
reg = <0x27000 0x1000>;
|
||||
program-mem = <0x24100000>;
|
||||
interrupts = <73 0>;
|
||||
status = "disabled";
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Reference in New Issue