Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: video: video_mcux_smartdma: add SMARTDMA video driver #72827

Merged
merged 14 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions boards/nxp/frdm_mcxn947/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ static int frdm_mcxn947_init(void)
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm7))
CLOCK_SetClkDiv(kCLOCK_DivFlexcom7Clk, 1u);
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM7);
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(os_timer))
CLOCK_AttachClk(kCLK_1M_to_OSTIMER);
#endif
Expand Down Expand Up @@ -260,6 +265,19 @@ static int frdm_mcxn947_init(void)
enable_cache64();
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(smartdma))
CLOCK_EnableClock(kCLOCK_Smartdma);
RESET_PeripheralReset(kSMART_DMA_RST_SHIFT_RSTn);
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(video_sdma))
/* Drive CLKOUT from main clock, divided by 25 to yield 6MHz clock
* The camera will use this clock signal to generate
* PCLK, HSYNC, and VSYNC
*/
CLOCK_AttachClk(kMAIN_CLK_to_CLKOUT);
CLOCK_SetClkDiv(kCLOCK_DivClkOut, 25U);
#endif
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(vref))
CLOCK_EnableClock(kCLOCK_Vref);
SPC_EnableActiveModeAnalogModules(SPC0, kSPC_controlVref);
Expand Down
37 changes: 37 additions & 0 deletions boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
};
};

pinmux_flexcomm7_lpi2c: pimux_flexcomm7_lpi2c {
group0 {
pinmux = <FC7_P0_PIO3_2>,
<FC7_P1_PIO3_3>;
slew-rate = "fast";
drive-strength = "low";
input-enable;
bias-pull-up;
drive-open-drain;
};
};

pinmux_flexcomm2_lpuart: pinmux_flexcomm2_lpuart {
group0 {
pinmux = <FC2_P2_PIO4_2>,
Expand Down Expand Up @@ -129,6 +141,31 @@
};
};

pinmux_smartdma_camera: pinmux_smartdma_camera {
group0 {
/*
* SmartDMA pinmux is not defined by SOC header, so
* we encode it manually
*/
pinmux = <N9X_MUX('1',4,7)>,
<N9X_MUX('1',5,7)>,
<N9X_MUX('1',6,7)>,
<N9X_MUX('1',7,7)>,
<N9X_MUX('3',4,7)>,
<N9X_MUX('3',5,7)>,
<N9X_MUX('1',10,7)>,
<N9X_MUX('1',11,7)>,
<PIO0_4>,
<PIO0_5>,
<PIO0_11>,
<CLKOUT_PIO2_2>,
<CLKOUT_PIO0_6>;
drive-strength = "low";
slew-rate = "fast";
input-enable;
};
};

pinmux_usdhc0: pinmux_usdhc0 {
group0 {
pinmux = <SDHC0_CMD_PIO2_5>,
Expand Down
28 changes: 28 additions & 0 deletions boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,34 @@ nxp_8080_touch_panel_i2c: &flexcomm2_lpi2c2 {
pinctrl-names = "default";
};

&flexcomm7_lpi2c7 {
pinctrl-0 = <&pinmux_flexcomm7_lpi2c>;
pinctrl-names = "default";
clock-frequency = <I2C_BITRATE_STANDARD>;
ov7670: ov7670@21 {
compatible = "ovti,ov7670";
reset-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
reg = <0x21>;
};
};

/* SmartDMA is used for video driver on this board */
&smartdma {
status = "okay";
program-mem = <0x4000000>;
video_sdma: video-sdma {
status = "okay";
compatible = "nxp,video-smartdma";
pinctrl-0 = <&pinmux_smartdma_camera>;
pinctrl-names = "default";
sensor = <&ov7670>;
vsync-pin = <4>;
hsync-pin = <11>;
pclk-pin = <5>;
};
};

/*
* MCXN947 board uses OS timer as the kernel timer
* In case we need to switch to SYSTICK timer, then
Expand Down
8 changes: 8 additions & 0 deletions boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@
status = "okay";
};

&flexcomm7 {
status = "okay";
};

&flexcomm7_lpi2c7 {
status = "okay";
};

&flexspi {
status = "okay";
};
Expand Down
106 changes: 8 additions & 98 deletions drivers/dma/dma_mcux_smartdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -53,22 +37,13 @@
/* 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);
Expand All @@ -79,68 +54,11 @@
/* 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;
}

Expand Down Expand Up @@ -175,15 +93,7 @@
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;
Expand Down Expand Up @@ -236,7 +146,7 @@
} \
\
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, \
}; \
Expand All @@ -248,5 +158,5 @@
&smartdma_##n##_data, &smartdma_##n##_config, \
POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, \
&dma_mcux_smartdma_api);

Check notice on line 161 in drivers/dma/dma_mcux_smartdma.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/dma/dma_mcux_smartdma.c:161 - -#define SMARTDMA_INIT(n) \ - static void dma_mcux_smartdma_config_func_##n(const struct device *dev) \ - { \ - IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ - dma_mcux_smartdma_irq, \ - DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQN(n)); \ - } \ - \ - static const struct dma_mcux_smartdma_config smartdma_##n##_config = { \ - .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, \ - }; \ - static struct dma_mcux_smartdma_data smartdma_##n##_data; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - &dma_mcux_smartdma_init, \ - NULL, \ - &smartdma_##n##_data, &smartdma_##n##_config, \ - POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, \ - &dma_mcux_smartdma_api); +#define SMARTDMA_INIT(n) \ + static void dma_mcux_smartdma_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), dma_mcux_smartdma_irq, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static const struct dma_mcux_smartdma_config smartdma_##n##_config = { \ + .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, \ + }; \ + static struct dma_mcux_smartdma_data smartdma_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &dma_mcux_smartdma_init, NULL, &smartdma_##n##_data, \ + &smartdma_##n##_config, POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, \ + &dma_mcux_smartdma_api);
DT_INST_FOREACH_STATUS_OKAY(SMARTDMA_INIT)
26 changes: 19 additions & 7 deletions drivers/mipi_dsi/dsi_mcux_2l.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -47,6 +50,8 @@
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
};
Expand Down Expand Up @@ -94,20 +99,19 @@
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) {
return -ENOTSUP; /* DMA can only transfer on virtual channel 0 */
}

/* 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;
Expand Down Expand Up @@ -250,20 +254,28 @@

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:
LOG_ERR("SMARTDMA does not support pixel_format %u",
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);

Check notice on line 278 in drivers/mipi_dsi/dsi_mcux_2l.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/mipi_dsi/dsi_mcux_2l.c:278 - dma_smartdma_install_fw(config->smart_dma, - (uint8_t *)s_smartdmaDisplayFirmware, + dma_smartdma_install_fw(config->smart_dma, (uint8_t *)s_smartdmaDisplayFirmware,
#else
struct mcux_mipi_dsi_data *data = dev->data;

Expand Down
1 change: 1 addition & 0 deletions drivers/video/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMI video_stm32_dcmi.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov7670.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32 video_esp32_dvp.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c)
2 changes: 2 additions & 0 deletions drivers/video/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,6 @@ source "drivers/video/Kconfig.ov7670"

source "drivers/video/Kconfig.gc2145"

source "drivers/video/Kconfig.mcux_sdma"

endif # VIDEO
10 changes: 10 additions & 0 deletions drivers/video/Kconfig.mcux_sdma
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# NXP MCUX SDMA driver configuration options

# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0

config VIDEO_MCUX_SDMA
bool "NXP MCUX Video SMARTDMA driver"
default y
select DMA
depends on DT_HAS_NXP_VIDEO_SMARTDMA_ENABLED
Loading
Loading