diff --git a/drivers/display/Kconfig.mcux_elcdif b/drivers/display/Kconfig.mcux_elcdif index e9b48f761449e..f0354ee3e67b0 100644 --- a/drivers/display/Kconfig.mcux_elcdif +++ b/drivers/display/Kconfig.mcux_elcdif @@ -43,84 +43,4 @@ config MCUX_ELCDIF_FB_SIZE 4-bytes pixel format, e.g. ARGB8888. Applications should change this value according to the actual used resolution and format to optimize the heap size. -config MCUX_ELCDIF_PXP - bool "Use PXP for display rotation" - depends on MCUX_PXP - depends on (MCUX_ELCDIF_FB_NUM > 0) - help - Use the PXP for display rotation. This requires the LCDIF node - have a "nxp,pxp" devicetree property pointing to the PXP device node. - The ELCDIF will only utilize the PXP to rotate frames if - display_write is called with a framebuffer equal in size to the - display. - -if MCUX_ELCDIF_PXP - -choice MCUX_ELCDIF_PXP_ROTATE_DIRECTION - default MCUX_ELCDIF_PXP_ROTATE_0 - prompt "Rotation angle of PXP" - help - Set rotation angle of PXP. The ELCDIF cannot detect the correct - rotation angle based on the call to display_write, so the user should - configure it here. In order for PXP rotation to work, calls to - display_write MUST supply a framebuffer equal in size to screen width - and height (without rotation applied). Note that the width and - height settings of the screen in devicetree should not be modified - from their values in the default screen orientation when using this - functionality. - -config MCUX_ELCDIF_PXP_ROTATE_0 - bool "Rotate display by 0 degrees" - help - Rotate display by 0 degrees. Primarily useful for testing, - production applications should simply disable the PXP. - -config MCUX_ELCDIF_PXP_ROTATE_90 - bool "Rotate display by 90 degrees" - help - Rotate display counter-clockwise by 90 degrees. - For LVGL, this corresponds to a rotation of 270 degrees - -config MCUX_ELCDIF_PXP_ROTATE_180 - bool "Rotate display by 180 degrees" - help - Rotate display counter-clockwise by 180 degrees - -config MCUX_ELCDIF_PXP_ROTATE_270 - bool "Rotate display by 270 degrees" - help - Rotate display counter-clockwise by 270 degrees - For LVGL, this corresponds to a rotation of 90 degrees - -endchoice - -choice MCUX_ELCDIF_PXP_FLIP_DIRECTION - default MCUX_ELCDIF_PXP_FLIP_DISABLE - prompt "Flip direction of PXP" - help - Set flip direction of PXP. The ELCDIF cannot detect the correct - rotation angle based on the call to display_write, so the user should - configure it here. In order for PXP flip to work, calls to - display_write MUST supply a framebuffer equal in size to screen width - and height (without flip applied). Note that the width and - height settings of the screen in devicetree should not be modified - from their values in the default screen orientation when using this - functionality. - -config MCUX_ELCDIF_PXP_FLIP_DISABLE - bool "Do not flip display" - -config MCUX_ELCDIF_PXP_FLIP_HORIZONTAL - bool "Flip display horizontally" - -config MCUX_ELCDIF_PXP_FLIP_VERTICAL - bool "Flip display vertically" - -config MCUX_ELCDIF_PXP_FLIP_BOTH - bool "Flib display both horizontally and vertically" - -endchoice - -endif # MCUX_ELCDIF_PXP - endif # DISPLAY_MCUX_ELCDIF diff --git a/drivers/display/display_mcux_elcdif.c b/drivers/display/display_mcux_elcdif.c index bdde9f59ed90c..876df33802a42 100644 --- a/drivers/display/display_mcux_elcdif.c +++ b/drivers/display/display_mcux_elcdif.c @@ -17,11 +17,6 @@ #include #endif -#ifdef CONFIG_MCUX_ELCDIF_PXP -#include -#include -#endif - #include #include @@ -39,7 +34,6 @@ struct mcux_elcdif_config { elcdif_rgb_mode_config_t rgb_mode; const struct pinctrl_dev_config *pincfg; const struct gpio_dt_spec backlight_gpio; - const struct device *pxp; }; struct mcux_elcdif_data { @@ -54,22 +48,8 @@ struct mcux_elcdif_data { struct k_sem sem; /* Tracks index of next active driver framebuffer */ uint8_t next_idx; -#ifdef CONFIG_MCUX_ELCDIF_PXP - /* Given to when PXP completes operation */ - struct k_sem pxp_done; -#endif }; -#ifdef CONFIG_MCUX_ELCDIF_PXP -static void mcux_elcdif_pxp_callback(const struct device *dma_dev, void *user_data, - uint32_t channel, int ret) -{ - struct mcux_elcdif_data *data = user_data; - - k_sem_give(&data->pxp_done); -} -#endif /* CONFIG_MCUX_ELCDIF_PXP */ - static int mcux_elcdif_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, const void *buf) { @@ -92,15 +72,6 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, const u LOG_DBG("Setting FB from %p->%p", (void *)dev_data->active_fb, (void *)buf); dev_data->active_fb = buf; full_fb = true; - } else if ((x == 0) && (y == 0) && (desc->width == config->rgb_mode.panelHeight) && - (desc->height == config->rgb_mode.panelWidth) && (desc->pitch == desc->width) && - IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP)) { - /* With the PXP, we can rotate this display buffer to align - * with output dimensions - */ - LOG_DBG("Setting FB from %p->%p", (void *)dev_data->active_fb, (void *)buf); - dev_data->active_fb = buf; - full_fb = true; } else { /* We must use partial framebuffer copy */ if (CONFIG_MCUX_ELCDIF_FB_NUM == 0) { @@ -137,77 +108,6 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, const u DCACHE_CleanByRange((uint32_t)dev_data->active_fb, dev_data->fb_bytes); #endif -#ifdef CONFIG_MCUX_ELCDIF_PXP - if (full_fb) { - /* Configure PXP using DMA API, and rotate/flip frame */ - struct dma_config pxp_dma = {0}; - struct dma_block_config pxp_block = {0}; - - /* Source buffer is input to display_write, we will - * place modified output into a driver framebuffer. - */ - dev_data->active_fb = dev_data->fb[dev_data->next_idx]; - pxp_block.source_address = (uint32_t)buf; - pxp_block.dest_address = (uint32_t)dev_data->active_fb; - pxp_block.block_size = desc->buf_size; - - /* DMA slot sets pixel format and rotation angle */ - if (dev_data->pixel_format == PIXEL_FORMAT_BGR_565) { - pxp_dma.dma_slot = DMA_MCUX_PXP_FMT(DMA_MCUX_PXP_FMT_RGB565); - } else if (dev_data->pixel_format == PIXEL_FORMAT_RGB_888) { - pxp_dma.dma_slot = DMA_MCUX_PXP_FMT(DMA_MCUX_PXP_FMT_RGB888); - } else if (dev_data->pixel_format == PIXEL_FORMAT_ARGB_8888) { - pxp_dma.dma_slot = DMA_MCUX_PXP_FMT(DMA_MCUX_PXP_FMT_ARGB8888); - } else { - /* Cannot rotate */ - return -ENOTSUP; - } - if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_90)) { - pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_90); - } else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_180)) { - pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_180); - } else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_270)) { - pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_270); - } else { - pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_0); - } - - /* DMA linked_channel sets the flip direction */ - if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_FLIP_HORIZONTAL)) { - pxp_dma.linked_channel |= DMA_MCUX_PXP_FLIP(DMA_MCUX_PXP_FLIP_HORIZONTAL); - } else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_FLIP_VERTICAL)) { - pxp_dma.linked_channel |= DMA_MCUX_PXP_FLIP(DMA_MCUX_PXP_FLIP_VERTICAL); - } else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_FLIP_BOTH)) { - pxp_dma.linked_channel |= DMA_MCUX_PXP_FLIP(DMA_MCUX_PXP_FLIP_BOTH); - } else { - pxp_dma.linked_channel |= DMA_MCUX_PXP_FLIP(DMA_MCUX_PXP_FLIP_DISABLE); - } - - pxp_dma.channel_direction = MEMORY_TO_MEMORY; - pxp_dma.source_data_size = desc->width * dev_data->pixel_bytes; - pxp_dma.dest_data_size = config->rgb_mode.panelWidth * dev_data->pixel_bytes; - /* Burst lengths are heights of source/dest buffer in pixels */ - pxp_dma.source_burst_length = desc->height; - pxp_dma.dest_burst_length = config->rgb_mode.panelHeight; - pxp_dma.head_block = &pxp_block; - pxp_dma.dma_callback = mcux_elcdif_pxp_callback; - pxp_dma.user_data = dev_data; - - ret = dma_config(config->pxp, 0, &pxp_dma); - if (ret < 0) { - return ret; - } - ret = dma_start(config->pxp, 0); - if (ret < 0) { - return ret; - } - k_sem_take(&dev_data->pxp_done, K_FOREVER); - } else { - LOG_WRN("PXP rotation/flip will not work correctly unless a full sized " - "framebuffer is provided"); - } -#endif /* CONFIG_MCUX_ELCDIF_PXP */ - /* Queue next framebuffer */ ELCDIF_SetNextBufferAddr(config->base, (uint32_t)dev_data->active_fb); @@ -348,13 +248,6 @@ static int mcux_elcdif_init(const struct device *dev) #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(backlight_gpios) */ k_sem_init(&dev_data->sem, 0, 1); -#ifdef CONFIG_MCUX_ELCDIF_PXP - k_sem_init(&dev_data->pxp_done, 0, 1); - if (!device_is_ready(config->pxp)) { - LOG_ERR("PXP device is not ready"); - return -ENODEV; - } -#endif config->irq_config_func(dev); @@ -413,8 +306,7 @@ static DEVICE_API(display, mcux_elcdif_api) = { }, \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(id, backlight_gpios, {0}), \ - IF_ENABLED(CONFIG_MCUX_ELCDIF_PXP, \ - (.pxp = DEVICE_DT_GET(DT_INST_PHANDLE(id, nxp_pxp)),))}; \ + }; \ static struct mcux_elcdif_data mcux_elcdif_data_##id = { \ .next_idx = 0, \ .pixel_format = DT_INST_PROP(id, pixel_format), \ diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 0c15fffea6fc5..67d8ae2dab207 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -35,7 +35,6 @@ zephyr_library_sources_ifdef(CONFIG_DMA_MCHP_XEC dma_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_DMA_XMC4XXX dma_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_DMA_RPI_PICO dma_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_DMA_RENESAS_RZ dma_renesas_rz.c) -zephyr_library_sources_ifdef(CONFIG_MCUX_PXP dma_mcux_pxp.c) zephyr_library_sources_ifdef(CONFIG_DMA_MAX32 dma_max32.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_SMARTDMA dma_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_ANDES_ATCDMAC300 dma_andes_atcdmac300.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 0bba13fb04f3f..4b6470f2d48a8 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -64,8 +64,6 @@ source "drivers/dma/Kconfig.ifx_cat1" source "drivers/dma/Kconfig.intel_lpss" -source "drivers/dma/Kconfig.mcux_pxp" - source "drivers/dma/Kconfig.max32" source "drivers/dma/Kconfig.mcux_smartdma" diff --git a/drivers/dma/Kconfig.mcux_pxp b/drivers/dma/Kconfig.mcux_pxp deleted file mode 100644 index b00148304cffb..0000000000000 --- a/drivers/dma/Kconfig.mcux_pxp +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -config MCUX_PXP - bool "MCUX PXP DMA driver" - default y - depends on DT_HAS_NXP_PXP_ENABLED - depends on DISPLAY - help - PXP DMA driver for NXP SOCs diff --git a/drivers/dma/dma_mcux_pxp.c b/drivers/dma/dma_mcux_pxp.c deleted file mode 100644 index b0b2df1aa68fe..0000000000000 --- a/drivers/dma/dma_mcux_pxp.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2023-2024 NXP - * All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include -#ifdef CONFIG_HAS_MCUX_CACHE -#include -#endif - -#define DT_DRV_COMPAT nxp_pxp - -#include -LOG_MODULE_REGISTER(dma_mcux_pxp, CONFIG_DMA_LOG_LEVEL); - -struct dma_mcux_pxp_config { - PXP_Type *base; - void (*irq_config_func)(const struct device *dev); -}; - -struct dma_mcux_pxp_data { - void *user_data; - dma_callback_t dma_callback; - uint32_t ps_buf_addr; - uint32_t ps_buf_size; - uint32_t out_buf_addr; - uint32_t out_buf_size; -}; - -static void dma_mcux_pxp_irq_handler(const struct device *dev) -{ - const struct dma_mcux_pxp_config *config = dev->config; - struct dma_mcux_pxp_data *data = dev->data; - - PXP_ClearStatusFlags(config->base, kPXP_CompleteFlag); -#ifdef CONFIG_HAS_MCUX_CACHE - DCACHE_InvalidateByRange((uint32_t)data->out_buf_addr, data->out_buf_size); -#endif - if (data->dma_callback) { - data->dma_callback(dev, data->user_data, 0, 0); - } -} - -/* Configure a channel */ -static int dma_mcux_pxp_configure(const struct device *dev, uint32_t channel, - struct dma_config *config) -{ - const struct dma_mcux_pxp_config *dev_config = dev->config; - struct dma_mcux_pxp_data *dev_data = dev->data; - pxp_ps_buffer_config_t ps_buffer_cfg; - pxp_output_buffer_config_t output_buffer_cfg; - uint8_t bytes_per_pixel; - pxp_rotate_degree_t rotate; - pxp_flip_mode_t flip; - - ARG_UNUSED(channel); - if (config->channel_direction != MEMORY_TO_MEMORY) { - return -ENOTSUP; - } - /* - * Use the DMA slot value to get the pixel format and rotation - * settings - */ - switch ((config->dma_slot & DMA_MCUX_PXP_CMD_MASK) >> DMA_MCUX_PXP_CMD_SHIFT) { - case DMA_MCUX_PXP_CMD_ROTATE_0: - rotate = kPXP_Rotate0; - break; - case DMA_MCUX_PXP_CMD_ROTATE_90: - rotate = kPXP_Rotate90; - break; - case DMA_MCUX_PXP_CMD_ROTATE_180: - rotate = kPXP_Rotate180; - break; - case DMA_MCUX_PXP_CMD_ROTATE_270: - rotate = kPXP_Rotate270; - break; - default: - return -ENOTSUP; - } - switch ((config->dma_slot & DMA_MCUX_PXP_FMT_MASK) >> DMA_MCUX_PXP_FMT_SHIFT) { - case DMA_MCUX_PXP_FMT_RGB565: - ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB565; - output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB565; - bytes_per_pixel = 2; - break; - case DMA_MCUX_PXP_FMT_RGB888: -#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && \ - FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \ - (!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3)) - ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatARGB8888; -#else - ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB888; -#endif - output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB888; - bytes_per_pixel = 3; - break; - case DMA_MCUX_PXP_FMT_ARGB8888: - ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatARGB8888; - output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatARGB8888; - bytes_per_pixel = 4; - break; - default: - return -ENOTSUP; - } - /* - * Use the DMA linked_channel value to get the flip settings. - */ - switch ((config->linked_channel & DMA_MCUX_PXP_FLIP_MASK) >> DMA_MCUX_PXP_FLIP_SHIFT) { - case DMA_MCUX_PXP_FLIP_DISABLE: - flip = kPXP_FlipDisable; - break; - case DMA_MCUX_PXP_FLIP_HORIZONTAL: - flip = kPXP_FlipHorizontal; - break; - case DMA_MCUX_PXP_FLIP_VERTICAL: - flip = kPXP_FlipVertical; - break; - case DMA_MCUX_PXP_FLIP_BOTH: - flip = kPXP_FlipBoth; - break; - default: - return -ENOTSUP; - } - DCACHE_CleanByRange((uint32_t)config->head_block->source_address, - config->head_block->block_size); - - /* - * Some notes on how specific fields of the DMA config are used by - * the PXP: - * head block source address: PS buffer source address - * head block destination address: Output buffer address - * head block block size: size of destination and source buffer - * source data size: width of source buffer in bytes (pitch) - * source burst length: height of source buffer in pixels - * dest data size: width of destination buffer in bytes (pitch) - * dest burst length: height of destination buffer in pixels - */ - ps_buffer_cfg.swapByte = false; - ps_buffer_cfg.bufferAddr = config->head_block->source_address; - ps_buffer_cfg.bufferAddrU = 0U; - ps_buffer_cfg.bufferAddrV = 0U; - ps_buffer_cfg.pitchBytes = config->source_data_size; - PXP_SetProcessSurfaceBufferConfig(dev_config->base, &ps_buffer_cfg); - - output_buffer_cfg.interlacedMode = kPXP_OutputProgressive; - output_buffer_cfg.buffer0Addr = config->head_block->dest_address; - output_buffer_cfg.buffer1Addr = 0U; - output_buffer_cfg.pitchBytes = config->dest_data_size; - output_buffer_cfg.width = (config->dest_data_size / bytes_per_pixel); - output_buffer_cfg.height = config->dest_burst_length; - PXP_SetOutputBufferConfig(dev_config->base, &output_buffer_cfg); - /* We only support a process surface that covers the full buffer */ - PXP_SetProcessSurfacePosition(dev_config->base, 0U, 0U, output_buffer_cfg.width, - output_buffer_cfg.height); - /* Setup rotation */ - PXP_SetRotateConfig(dev_config->base, kPXP_RotateProcessSurface, rotate, flip); - - dev_data->ps_buf_addr = config->head_block->source_address; - dev_data->ps_buf_size = config->head_block->block_size; - dev_data->out_buf_addr = config->head_block->dest_address; - dev_data->out_buf_size = config->head_block->block_size; - dev_data->dma_callback = config->dma_callback; - dev_data->user_data = config->user_data; - return 0; -} - -static int dma_mcux_pxp_start(const struct device *dev, uint32_t channel) -{ - const struct dma_mcux_pxp_config *config = dev->config; - struct dma_mcux_pxp_data *data = dev->data; -#ifdef CONFIG_HAS_MCUX_CACHE - DCACHE_CleanByRange((uint32_t)data->ps_buf_addr, data->ps_buf_size); -#endif - - ARG_UNUSED(channel); - PXP_Start(config->base); - return 0; -} - -static DEVICE_API(dma, dma_mcux_pxp_api) = { - .config = dma_mcux_pxp_configure, - .start = dma_mcux_pxp_start, -}; - -static int dma_mcux_pxp_init(const struct device *dev) -{ - const struct dma_mcux_pxp_config *config = dev->config; - - PXP_Init(config->base); - PXP_SetProcessSurfaceBackGroundColor(config->base, 0U); - /* Disable alpha surface and CSC1 */ - PXP_SetAlphaSurfacePosition(config->base, 0xFFFFU, 0xFFFFU, 0U, 0U); - PXP_EnableCsc1(config->base, false); - PXP_EnableInterrupts(config->base, kPXP_CompleteInterruptEnable); - config->irq_config_func(dev); - return 0; -} - -#define DMA_INIT(n) \ - static void dma_pxp_config_func##n(const struct device *dev) \ - { \ - IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \ - (IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ - dma_mcux_pxp_irq_handler, DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ(n, irq));)) \ - } \ - \ - static const struct dma_mcux_pxp_config dma_config_##n = { \ - .base = (PXP_Type *)DT_INST_REG_ADDR(n), \ - .irq_config_func = dma_pxp_config_func##n, \ - }; \ - \ - static struct dma_mcux_pxp_data dma_data_##n; \ - \ - DEVICE_DT_INST_DEFINE(n, dma_mcux_pxp_init, NULL, &dma_data_##n, &dma_config_##n, \ - PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, &dma_mcux_pxp_api); - -DT_INST_FOREACH_STATUS_OKAY(DMA_INIT) diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index 083df586b0033..fe8268bfa6431 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_library_sources(video_device.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_CSI video_mcux_csi.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX video_mcux_mipi_csi2rx.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_PXP video_mcux_pxp.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_SHELL video_shell.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_SW_GENERATOR video_sw_generator.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MT9M114 mt9m114.c) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 924e2156273c4..93c99e14164ac 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -64,6 +64,8 @@ source "drivers/video/Kconfig.mcux_csi" source "drivers/video/Kconfig.mcux_mipi_csi2rx" +source "drivers/video/Kconfig.mcux_pxp" + source "drivers/video/Kconfig.shell" source "drivers/video/Kconfig.sw_generator" diff --git a/drivers/video/Kconfig.mcux_pxp b/drivers/video/Kconfig.mcux_pxp new file mode 100644 index 0000000000000..c3b57ac73459d --- /dev/null +++ b/drivers/video/Kconfig.mcux_pxp @@ -0,0 +1,9 @@ +# NXP PxP driver configuration option + +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config VIDEO_MCUX_PXP + bool "NXP MCUX PxP driver" + default y + depends on DT_HAS_NXP_PXP_ENABLED diff --git a/drivers/video/video_ctrls.c b/drivers/video/video_ctrls.c index cba92100967c2..93f9e94057644 100644 --- a/drivers/video/video_ctrls.c +++ b/drivers/video/video_ctrls.c @@ -488,6 +488,8 @@ static inline const char *video_get_ctrl_name(uint32_t id) return "Brightness, Automatic"; case VIDEO_CID_BAND_STOP_FILTER: return "Band-Stop Filter"; + case VIDEO_CID_ROTATE: + return "Rotate"; case VIDEO_CID_ALPHA_COMPONENT: return "Alpha Component"; diff --git a/drivers/video/video_mcux_pxp.c b/drivers/video/video_mcux_pxp.c new file mode 100644 index 0000000000000..28259b0dbaa66 --- /dev/null +++ b/drivers/video/video_mcux_pxp.c @@ -0,0 +1,334 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "video_ctrls.h" +#include "video_device.h" + +#include +#ifdef CONFIG_HAS_MCUX_CACHE +#include +#endif + +#define DT_DRV_COMPAT nxp_pxp + +LOG_MODULE_REGISTER(mcux_pxp, CONFIG_VIDEO_LOG_LEVEL); + +struct mcux_pxp_config { + PXP_Type *base; + void (*irq_config_func)(void); +}; + +struct mcux_pxp_ctrls { + struct { + struct video_ctrl rotation; + struct video_ctrl hflip; + struct video_ctrl vflip; + }; +}; + +struct mcux_pxp_data { + struct mcux_pxp_ctrls ctrls; + pxp_ps_buffer_config_t ps_buffer_cfg; + pxp_output_buffer_config_t output_buffer_cfg; + struct k_fifo fifo_in_queued; + struct k_fifo fifo_in_done; + struct k_fifo fifo_out_queued; + struct k_fifo fifo_out_done; +}; + +static void mcux_pxp_isr(const struct device *const dev) +{ + const struct mcux_pxp_config *config = dev->config; + struct mcux_pxp_data *data = dev->data; + + PXP_ClearStatusFlags(config->base, kPXP_CompleteFlag); + + struct video_buffer *vbuf_in = k_fifo_get(&data->fifo_in_queued, K_NO_WAIT); + struct video_buffer *vbuf_out = k_fifo_get(&data->fifo_out_queued, K_NO_WAIT); + + /* Something went wrong, should never happen */ + if ((uint32_t)vbuf_in->buffer != data->ps_buffer_cfg.bufferAddr || + (uint32_t)vbuf_out->buffer != data->output_buffer_cfg.buffer0Addr) { + return; + } + + vbuf_out->timestamp = k_uptime_get_32(); + vbuf_out->bytesused = data->output_buffer_cfg.pitchBytes * data->output_buffer_cfg.height; + +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_InvalidateByRange((uint32_t)vbuf_out->buffer, vbuf_out->bytesused); +#endif + + k_fifo_put(&data->fifo_in_done, vbuf_in); + k_fifo_put(&data->fifo_out_done, vbuf_out); +} + +static int mcux_pxp_get_caps(const struct device *dev, struct video_caps *caps) +{ + /* TODO */ + return 0; +} + +static int mcux_pxp_get_fmt(const struct device *dev, struct video_format *fmt) +{ + /* TODO */ + return 0; +} + +static int mcux_pxp_set_fmt(const struct device *dev, struct video_format *fmt) +{ + struct mcux_pxp_data *data = dev->data; + + fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + + switch (fmt->type) { + case VIDEO_BUF_TYPE_INPUT: + data->ps_buffer_cfg.pitchBytes = fmt->pitch; + switch (fmt->pixelformat) { + case VIDEO_PIX_FMT_RGB565: + data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB565; + break; + case VIDEO_PIX_FMT_RGB24: +#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && \ +FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \ + (!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3)) + data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatARGB8888; +#else + data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB888; +#endif + break; + case VIDEO_PIX_FMT_ARGB32: + case VIDEO_PIX_FMT_XRGB32: + data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatARGB8888; + break; + default: + return -ENOTSUP; + } + break; + case VIDEO_BUF_TYPE_OUTPUT: + data->output_buffer_cfg.pitchBytes = fmt->pitch; + data->output_buffer_cfg.width = fmt->width; + data->output_buffer_cfg.height = fmt->height; + switch (fmt->pixelformat) { + case VIDEO_PIX_FMT_RGB565: + data->output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB565; + break; + case VIDEO_PIX_FMT_RGB24: + data->output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB888; + break; + case VIDEO_PIX_FMT_XRGB32: + case VIDEO_PIX_FMT_ARGB32: + data->output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatARGB8888; + break; + default: + return -ENOTSUP; + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int mcux_pxp_set_ctrl(const struct device *dev, uint32_t id) +{ + const struct mcux_pxp_config *const config = dev->config; + struct mcux_pxp_data *data = dev->data; + struct mcux_pxp_ctrls *ctrls = &data->ctrls; + pxp_flip_mode_t flip = ctrls->hflip.val | ctrls->vflip.val; + pxp_rotate_degree_t rotate = kPXP_Rotate0; + + ARG_UNUSED(id); + + switch (ctrls->rotation.val) { + case 0: + rotate = kPXP_Rotate0; + break; + case 90: + rotate = kPXP_Rotate90; + break; + case 180: + rotate = kPXP_Rotate180; + break; + case 270: + rotate = kPXP_Rotate270; + break; + } + + PXP_SetRotateConfig(config->base, kPXP_RotateProcessSurface, rotate, flip); + + return 0; +} + +static int mcux_pxp_enqueue(const struct device *dev, struct video_buffer *vbuf) +{ + const struct mcux_pxp_config *const config = dev->config; + struct mcux_pxp_data *data = dev->data; + +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_CleanByRange((uint32_t)vbuf->buffer, vbuf->size); +#endif + + switch (vbuf->type) { + case VIDEO_BUF_TYPE_INPUT: + k_fifo_put(&data->fifo_in_queued, vbuf); + + data->ps_buffer_cfg.swapByte = false; + data->ps_buffer_cfg.bufferAddr = (uint32_t)vbuf->buffer; + data->ps_buffer_cfg.bufferAddrU = 0U; + data->ps_buffer_cfg.bufferAddrV = 0U; + + PXP_SetProcessSurfaceBufferConfig(config->base, &data->ps_buffer_cfg); + + break; + case VIDEO_BUF_TYPE_OUTPUT: + k_fifo_put(&data->fifo_out_queued, vbuf); + + data->output_buffer_cfg.interlacedMode = kPXP_OutputProgressive; + data->output_buffer_cfg.buffer0Addr = (uint32_t)vbuf->buffer; + data->output_buffer_cfg.buffer1Addr = 0U; + + PXP_SetOutputBufferConfig(config->base, &data->output_buffer_cfg); + /* We only support a process surface that covers the full buffer */ + PXP_SetProcessSurfacePosition(config->base, 0U, 0U, data->output_buffer_cfg.width, + data->output_buffer_cfg.height); + + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int mcux_pxp_dequeue(const struct device *dev, struct video_buffer **vbuf, + k_timeout_t timeout) +{ + struct mcux_pxp_data *data = dev->data; + + switch ((*vbuf)->type) { + case VIDEO_BUF_TYPE_INPUT: + *vbuf = k_fifo_get(&data->fifo_in_done, timeout); + break; + case VIDEO_BUF_TYPE_OUTPUT: + *vbuf = k_fifo_get(&data->fifo_out_done, timeout); + break; + default: + return -ENOTSUP; + } + + if (*vbuf == NULL) { + return -EAGAIN; + } + + return 0; +} + +static int mcux_pxp_set_stream(const struct device *dev, bool enable, enum video_buf_type type) +{ + const struct mcux_pxp_config *const config = dev->config; + struct mcux_pxp_data *data = dev->data; + + if (enable) { +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_CleanByRange((uint32_t)data->ps_buffer_cfg.bufferAddr, + data->output_buffer_cfg.pitchBytes * + data->output_buffer_cfg.height); +#endif + PXP_Start(config->base); + } + + return 0; +} + +static DEVICE_API(video, mcux_pxp_driver_api) = { + .get_caps = mcux_pxp_get_caps, + .get_format = mcux_pxp_get_fmt, + .set_format = mcux_pxp_set_fmt, + .set_ctrl = mcux_pxp_set_ctrl, + .enqueue = mcux_pxp_enqueue, + .dequeue = mcux_pxp_dequeue, + .set_stream = mcux_pxp_set_stream, +}; + +static int mcux_pxp_init(const struct device *const dev) +{ + const struct mcux_pxp_config *const config = dev->config; + struct mcux_pxp_data *data = dev->data; + struct mcux_pxp_ctrls *ctrls = &data->ctrls; + int ret; + + k_fifo_init(&data->fifo_in_queued); + k_fifo_init(&data->fifo_out_queued); + k_fifo_init(&data->fifo_in_done); + k_fifo_init(&data->fifo_out_done); + + PXP_Init(config->base); + + PXP_SetProcessSurfaceBackGroundColor(config->base, 0U); + /* Disable alpha surface and CSC1 */ + PXP_SetAlphaSurfacePosition(config->base, 0xFFFFU, 0xFFFFU, 0U, 0U); + PXP_EnableCsc1(config->base, false); + PXP_EnableInterrupts(config->base, kPXP_CompleteInterruptEnable); + + config->irq_config_func(); + + ret = video_init_ctrl( + &ctrls->rotation, dev, VIDEO_CID_ROTATE, + (struct video_ctrl_range){.min = 0, .max = 270, .step = 90, .def = 0}); + if (ret) { + return ret; + } + + ret = video_init_ctrl(&ctrls->hflip, dev, VIDEO_CID_HFLIP, + (struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0}); + if (ret) { + return ret; + } + + ret = video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP, + (struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0}); + if (ret) { + return ret; + } + + video_auto_cluster_ctrl(&ctrls->rotation, 3, false); + + return 0; +} + +#define MCUX_PXP_INIT(inst) \ + static void mcux_pxp_irq_config_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), mcux_pxp_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + static const struct mcux_pxp_config mcux_pxp_config_##inst = { \ + .base = (PXP_Type *)DT_INST_REG_ADDR(inst), \ + .irq_config_func = mcux_pxp_irq_config_##inst, \ + }; \ + \ + static struct mcux_pxp_data mcux_pxp_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, &mcux_pxp_init, NULL, &mcux_pxp_data_##inst, \ + &mcux_pxp_config_##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ + &mcux_pxp_driver_api); \ + \ + VIDEO_DEVICE_DEFINE(pxp_##inst, DEVICE_DT_INST_GET(inst), NULL); + +DT_INST_FOREACH_STATUS_OKAY(MCUX_PXP_INIT) diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 80409bcc695e6..c31acd6d8ec08 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -452,7 +452,6 @@ reg = <0x402b8000 0x4000>; interrupts = <42 0>; status = "disabled"; - nxp,pxp = <&pxp>; }; lpspi1: spi@40394000 { @@ -988,7 +987,6 @@ reg = <0x402b4000 0x4000>; interrupts = <44 0>; status = "disabled"; - #dma-cells = <0>; }; sai1: sai@40384000 { diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 96daa91b6adfe..447f6961f41cf 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -371,7 +371,6 @@ reg = <0x40804000 0x4000>; interrupts = <54 0>; status = "disabled"; - nxp,pxp = <&pxp>; }; mipi_dsi: mipi-dsi@4080c000 { @@ -1064,7 +1063,6 @@ reg = <0x40814000 0x4000>; interrupts = <57 0>; status = "disabled"; - #dma-cells = <0>; }; iomuxcgpr: iomuxcgpr@400e4000 { diff --git a/dts/bindings/dma/nxp,pxp.yaml b/dts/bindings/dma/nxp,pxp.yaml deleted file mode 100644 index 92fbc6be795de..0000000000000 --- a/dts/bindings/dma/nxp,pxp.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -description: NXP PXP 2D DMA engine - -compatible: "nxp,pxp" - -include: dma-controller.yaml - -properties: - reg: - required: true - - interrupts: - required: true - - "#dma-cells": - type: int - required: true - const: 0 diff --git a/dts/bindings/video/nxp,pxp.yaml b/dts/bindings/video/nxp,pxp.yaml new file mode 100644 index 0000000000000..97f138215e27f --- /dev/null +++ b/dts/bindings/video/nxp,pxp.yaml @@ -0,0 +1,18 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: NXP MCUX PxP + +compatible: "nxp,pxp" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/include/zephyr/drivers/dma/dma_mcux_pxp.h b/include/zephyr/drivers/dma/dma_mcux_pxp.h deleted file mode 100644 index 47082a947462c..0000000000000 --- a/include/zephyr/drivers/dma/dma_mcux_pxp.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023-2024 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_PXP_H_ -#define ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_PXP_H_ - -#define DMA_MCUX_PXP_CMD_MASK 0xE0 -#define DMA_MCUX_PXP_CMD_SHIFT 0x5 - -#define DMA_MCUX_PXP_FMT_MASK 0x1F -#define DMA_MCUX_PXP_FMT_SHIFT 0x0 - -/* - * In order to configure the PXP for rotation, the user should - * supply a format and command as the DMA slot parameter, like so: - * dma_slot = (DMA_MCUX_PXP_FTM(DMA_MCUX_PXP_FMT_RGB565) | - * DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_90)) - * head block source address: input buffer address - * head block destination address: output buffer address - * source data size: input buffer size in bytes - * source burst length: height of source buffer in pixels - * dest data size: output buffer size in bytes - * dest burst length: height of destination buffer in pixels - */ - -#define DMA_MCUX_PXP_FMT(x) ((x << DMA_MCUX_PXP_FMT_SHIFT) & DMA_MCUX_PXP_FMT_MASK) -#define DMA_MCUX_PXP_CMD(x) ((x << DMA_MCUX_PXP_CMD_SHIFT) & DMA_MCUX_PXP_CMD_MASK) - -#define DMA_MCUX_PXP_CMD_ROTATE_0 0 -#define DMA_MCUX_PXP_CMD_ROTATE_90 1 -#define DMA_MCUX_PXP_CMD_ROTATE_180 2 -#define DMA_MCUX_PXP_CMD_ROTATE_270 3 - -#define DMA_MCUX_PXP_FMT_RGB565 0 -#define DMA_MCUX_PXP_FMT_RGB888 1 -#define DMA_MCUX_PXP_FMT_ARGB8888 2 - -#define DMA_MCUX_PXP_FLIP_MASK 0x3 -#define DMA_MCUX_PXP_FLIP_SHIFT 0x0 - -/* - * In order to configure the PXP to flip, the user should - * supply a flip setting as the DMA linked_channel parameter, like so: - * linked_channel |= DMA_MCUX_PXP_FLIP(DMA_MCUX_PXP_FLIP_HORIZONTAL) - */ - -#define DMA_MCUX_PXP_FLIP(x) ((x << DMA_MCUX_PXP_FLIP_SHIFT) & DMA_MCUX_PXP_FLIP_MASK) - -#define DMA_MCUX_PXP_FLIP_DISABLE 0 -#define DMA_MCUX_PXP_FLIP_HORIZONTAL 1 -#define DMA_MCUX_PXP_FLIP_VERTICAL 2 -#define DMA_MCUX_PXP_FLIP_BOTH 3 - -#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_PXP_H_ */ diff --git a/include/zephyr/drivers/video-controls.h b/include/zephyr/drivers/video-controls.h index 21c173c45980d..abc5abdb9c784 100644 --- a/include/zephyr/drivers/video-controls.h +++ b/include/zephyr/drivers/video-controls.h @@ -134,7 +134,7 @@ enum video_colorfx { VIDEO_COLORFX_ANTIQUE = 14, }; -/* Enable Automatic Brightness. */ +/** Enable Automatic Brightness. */ #define VIDEO_CID_AUTOBRIGHTNESS (VIDEO_CID_BASE + 32) /** Switch the band-stop filter of a camera sensor on or off, or specify its strength. @@ -142,6 +142,11 @@ enum video_colorfx { */ #define VIDEO_CID_BAND_STOP_FILTER (VIDEO_CID_BASE + 33) +/** Rotate the image by a given angle, e.g. 90, 180, 270 degree. The application will be then + * responsible for setting the new width and height of the image using video_set_fmt() if needed. + */ +#define VIDEO_CID_ROTATE (VIDEO_CID_BASE + 34) + /** Sets the alpha color component. * Some devices produce data with a user-controllable alpha component. Set the value applied to * the alpha channel of every pixel produced. diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index b794013ca972c..4cb9d6c185311 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -91,7 +91,7 @@ set_variable_ifdef(CONFIG_WDT_MCUX_WDOG32 CONFIG_MCUX_COMPONENT_driver.wdo set_variable_ifdef(CONFIG_COUNTER_MCUX_GPT CONFIG_MCUX_COMPONENT_driver.gpt) set_variable_ifdef(CONFIG_MCUX_GPT_TIMER CONFIG_MCUX_COMPONENT_driver.gpt) set_variable_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF CONFIG_MCUX_COMPONENT_driver.elcdif) -set_variable_ifdef(CONFIG_MCUX_PXP CONFIG_MCUX_COMPONENT_driver.pxp) +set_variable_ifdef(CONFIG_VIDEO_MCUX_PXP CONFIG_MCUX_COMPONENT_driver.pxp) set_variable_ifdef(CONFIG_LV_USE_GPU_NXP_PXP CONFIG_MCUX_COMPONENT_driver.pxp) set_variable_ifdef(CONFIG_GPIO_MCUX_RGPIO CONFIG_MCUX_COMPONENT_driver.rgpio) set_variable_ifdef(CONFIG_I2S_MCUX_SAI CONFIG_MCUX_COMPONENT_driver.sai) diff --git a/samples/drivers/video/capture/CMakeLists.txt b/samples/drivers/video/capture/CMakeLists.txt index 8863a2350f460..2ccd34a2c0070 100644 --- a/samples/drivers/video/capture/CMakeLists.txt +++ b/samples/drivers/video/capture/CMakeLists.txt @@ -6,3 +6,7 @@ project(video_capture) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) + +if(CONFIG_VIDEO_TRANSFORM) + target_sources(app PRIVATE boards/${BOARD}/transform.c) +endif() diff --git a/samples/drivers/video/capture/Kconfig b/samples/drivers/video/capture/Kconfig index 362a6037a6cf1..0ae1bba09030b 100644 --- a/samples/drivers/video/capture/Kconfig +++ b/samples/drivers/video/capture/Kconfig @@ -58,6 +58,11 @@ config VIDEO_CTRL_VFLIP help If set, mirror the video frame vertically +config VIDEO_TRANSFORM + bool "Perform some m2m transforms on the video frame" + help + If set, the video frame will go through some m2m transforms before being displayed + endmenu source "Kconfig.zephyr" diff --git a/samples/drivers/video/capture/boards/mimxrt1170_evk/transform.c b/samples/drivers/video/capture/boards/mimxrt1170_evk/transform.c new file mode 100644 index 0000000000000..5a51cdb786dfb --- /dev/null +++ b/samples/drivers/video/capture/boards/mimxrt1170_evk/transform.c @@ -0,0 +1,106 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(transform, CONFIG_LOG_DEFAULT_LEVEL); + +static const struct device *transform_dev; +static struct video_buffer *transformed_buffer; + +int video_transform_setup(struct video_format in_fmt, struct video_format *out_fmt) +{ + int ret; + struct video_control ctrl = {.id = VIDEO_CID_ROTATE, .val = 90}; + + transform_dev = DEVICE_DT_GET(DT_NODELABEL(pxp)); + + out_fmt->pixelformat = in_fmt.pixelformat; + out_fmt->width = in_fmt.height; + out_fmt->height = in_fmt.width; + out_fmt->type = VIDEO_BUF_TYPE_OUTPUT; + + /* Set input and output formats */ + in_fmt.type = VIDEO_BUF_TYPE_INPUT; + ret = video_set_format(transform_dev, &in_fmt); + if (ret) { + LOG_ERR("Unable to set input format"); + return ret; + } + + ret = video_set_format(transform_dev, out_fmt); + if (ret) { + LOG_ERR("Unable to set output format"); + return ret; + } + + /* Set controls */ + video_set_ctrl(transform_dev, &ctrl); + + /* Allocate a buffer for output queue */ + transformed_buffer = video_buffer_aligned_alloc(in_fmt.pitch * in_fmt.height, + CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER); + + if (transformed_buffer == NULL) { + LOG_ERR("Unable to alloc video buffer"); + return -ENOMEM; + } + + return 0; +} + +int video_transform_process(struct video_buffer *in_buf, struct video_buffer **out_buf) +{ + int err; + struct video_buffer *transformed_buf = &(struct video_buffer){}; + /* Store the input buffer type to recover later */ + enum video_buf_type in_buf_type = in_buf->type; + + in_buf->type = VIDEO_BUF_TYPE_INPUT; + err = video_enqueue(transform_dev, in_buf); + if (err) { + LOG_ERR("Unable to enqueue input buffer"); + return err; + } + + transformed_buffer->type = VIDEO_BUF_TYPE_OUTPUT; + err = video_enqueue(transform_dev, transformed_buffer); + if (err) { + LOG_ERR("Unable to enqueue output buffer"); + return err; + } + + /* Same start for both input and output */ + if (video_stream_start(transform_dev, VIDEO_BUF_TYPE_INPUT)) { + LOG_ERR("Unable to start PxP"); + return 0; + } + + /* Dequeue input and output buffers */ + err = video_dequeue(transform_dev, &in_buf, K_FOREVER); + if (err) { + LOG_ERR("Unable to dequeue PxP video buf in"); + return err; + } + + transformed_buf->type = VIDEO_BUF_TYPE_OUTPUT; + err = video_dequeue(transform_dev, &transformed_buf, K_FOREVER); + if (err) { + LOG_ERR("Unable to dequeue PxP video buf out"); + return err; + } + + *out_buf = transformed_buf; + + /* Keep the input buffer intact */ + in_buf->type = in_buf_type; + + return 0; +} diff --git a/samples/drivers/video/capture/boards/mimxrt1170_evk_mimxrt1176_cm7.conf b/samples/drivers/video/capture/boards/mimxrt1170_evk_mimxrt1176_cm7.conf index 7252f9e67c5cb..8953c39271efc 100644 --- a/samples/drivers/video/capture/boards/mimxrt1170_evk_mimxrt1176_cm7.conf +++ b/samples/drivers/video/capture/boards/mimxrt1170_evk_mimxrt1176_cm7.conf @@ -1,4 +1,3 @@ -CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=3686800 -CONFIG_DMA=y -CONFIG_MCUX_ELCDIF_PXP=y -CONFIG_MCUX_ELCDIF_PXP_ROTATE_90=y +CONFIG_VIDEO_TRANSFORM=y +CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=6530200 +CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3 diff --git a/samples/drivers/video/capture/src/main.c b/samples/drivers/video/capture/src/main.c index d2131219c5647..a36f5ecf5e76d 100644 --- a/samples/drivers/video/capture/src/main.c +++ b/samples/drivers/video/capture/src/main.c @@ -26,6 +26,22 @@ LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); #error No camera chosen in devicetree. Missing "--shield" or "--snippet video-sw-generator" flag? #endif +#define NUM_BUFS 2 + +int __weak video_transform_setup(struct video_format in_fmt, struct video_format *out_fmt) +{ + *out_fmt = in_fmt; + + return 0; +} + +int __weak video_transform_process(struct video_buffer *in_buf, struct video_buffer **out_buf) +{ + *out_buf = in_buf; + + return 0; +} + #if DT_HAS_CHOSEN(zephyr_display) static inline int display_setup(const struct device *const display_dev, const uint32_t pixfmt) { @@ -91,10 +107,11 @@ static inline void video_display_frame(const struct device *const display_dev, int main(void) { - struct video_buffer *buffers[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX]; struct video_buffer *vbuf = &(struct video_buffer){}; + struct video_buffer *transformed_buf = &(struct video_buffer){}; const struct device *video_dev; struct video_format fmt; + struct video_format transformed_fmt; struct video_caps caps; struct video_frmival frmival; struct video_frmival_enum fie; @@ -262,6 +279,13 @@ int main(void) tp_set_ret = video_set_ctrl(video_dev, &ctrl); } + /* Set up transformation */ + err = video_transform_setup(fmt, &transformed_fmt); + if (err) { + LOG_ERR("Unable to set up transformation"); + return 0; + } + #if DT_HAS_CHOSEN(zephyr_display) const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); @@ -270,7 +294,7 @@ int main(void) return 0; } - err = display_setup(display_dev, fmt.pixelformat); + err = display_setup(display_dev, transformed_fmt.pixelformat); if (err) { LOG_ERR("Unable to set up display"); return err; @@ -285,19 +309,19 @@ int main(void) } /* Alloc video buffers and enqueue for capture */ - for (i = 0; i < ARRAY_SIZE(buffers); i++) { + for (i = 0; i < NUM_BUFS; i++) { /* * For some hardwares, such as the PxP used on i.MX RT1170 to do image rotation, * buffer alignment is needed in order to achieve the best performance */ - buffers[i] = video_buffer_aligned_alloc(bsize, CONFIG_VIDEO_BUFFER_POOL_ALIGN, + vbuf = video_buffer_aligned_alloc(bsize, CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER); - if (buffers[i] == NULL) { + if (vbuf == NULL) { LOG_ERR("Unable to alloc video buffer"); return 0; } - buffers[i]->type = type; - video_enqueue(video_dev, buffers[i]); + vbuf->type = type; + video_enqueue(video_dev, vbuf); } /* Start video capture */ @@ -328,8 +352,15 @@ int main(void) } #endif + /* Do transformation */ + err = video_transform_process(vbuf, &transformed_buf); + if (err) { + LOG_ERR("Unable to transform video frame"); + return 0; + } + #if DT_HAS_CHOSEN(zephyr_display) - video_display_frame(display_dev, vbuf, fmt); + video_display_frame(display_dev, transformed_buf, transformed_fmt); #endif err = video_enqueue(video_dev, vbuf); diff --git a/samples/modules/lvgl/demos/boards/mimxrt1060_evk.conf b/samples/modules/lvgl/demos/boards/mimxrt1060_evk.conf deleted file mode 100644 index 30b4edca85841..0000000000000 --- a/samples/modules/lvgl/demos/boards/mimxrt1060_evk.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2023 Fabian Blatz -# SPDX-License-Identifier: Apache-2.0 - -# Enable PXP DMA engine and set rotation angle to 0 degrees. -# This allows us to verify the DMA driver functions without altering -# the output image -CONFIG_DMA=y -CONFIG_MCUX_ELCDIF_PXP=y diff --git a/samples/modules/lvgl/demos/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf b/samples/modules/lvgl/demos/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf deleted file mode 100644 index 30b4edca85841..0000000000000 --- a/samples/modules/lvgl/demos/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2023 Fabian Blatz -# SPDX-License-Identifier: Apache-2.0 - -# Enable PXP DMA engine and set rotation angle to 0 degrees. -# This allows us to verify the DMA driver functions without altering -# the output image -CONFIG_DMA=y -CONFIG_MCUX_ELCDIF_PXP=y diff --git a/samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf b/samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf deleted file mode 100644 index 33e1d5275a880..0000000000000 --- a/samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -# Enable PXP DMA engine and set rotation angle to 0 degrees. -# This allows us to verify the DMA driver functions without altering -# the output image -CONFIG_DMA=y -CONFIG_MCUX_ELCDIF_PXP=y diff --git a/samples/subsys/display/lvgl/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf b/samples/subsys/display/lvgl/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf deleted file mode 100644 index 33e1d5275a880..0000000000000 --- a/samples/subsys/display/lvgl/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -# Enable PXP DMA engine and set rotation angle to 0 degrees. -# This allows us to verify the DMA driver functions without altering -# the output image -CONFIG_DMA=y -CONFIG_MCUX_ELCDIF_PXP=y