Skip to content

Commit 20e1bcb

Browse files
committed
drivers: video: Add PxP m2m driver
The NXP's PxP is a 2D pixel engine which is capable to do some image transformation such as rotation, flipping, color conversion, etc. Make a driver for it in the video m2m category. Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
1 parent 9c71880 commit 20e1bcb

File tree

5 files changed

+340
-1
lines changed

5 files changed

+340
-1
lines changed

drivers/video/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ zephyr_library_sources(video_device.c)
88

99
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_CSI video_mcux_csi.c)
1010
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX video_mcux_mipi_csi2rx.c)
11+
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_PXP video_mcux_pxp.c)
1112
zephyr_library_sources_ifdef(CONFIG_VIDEO_SHELL video_shell.c)
1213
zephyr_library_sources_ifdef(CONFIG_VIDEO_SW_GENERATOR video_sw_generator.c)
1314
zephyr_library_sources_ifdef(CONFIG_VIDEO_MT9M114 mt9m114.c)

drivers/video/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ source "drivers/video/Kconfig.mcux_csi"
6464

6565
source "drivers/video/Kconfig.mcux_mipi_csi2rx"
6666

67+
source "drivers/video/Kconfig.mcux_pxp"
68+
6769
source "drivers/video/Kconfig.shell"
6870

6971
source "drivers/video/Kconfig.sw_generator"

drivers/video/Kconfig.mcux_pxp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# NXP PxP driver configuration option
2+
3+
# Copyright 2025 NXP
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config VIDEO_MCUX_PXP
7+
bool "NXP MCUX PxP driver"
8+
default y
9+
depends on DT_HAS_NXP_PXP_ENABLED

drivers/video/video_mcux_pxp.c

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/*
2+
* Copyright 2025 NXP
3+
* All rights reserved.
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <errno.h>
9+
10+
#include <zephyr/drivers/video.h>
11+
#include <zephyr/drivers/video-controls.h>
12+
#include <zephyr/dt-bindings/video/video-interfaces.h>
13+
#include <zephyr/irq.h>
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/logging/log.h>
16+
17+
#include "video_ctrls.h"
18+
#include "video_device.h"
19+
20+
#include <fsl_pxp.h>
21+
#ifdef CONFIG_HAS_MCUX_CACHE
22+
#include <fsl_cache.h>
23+
#endif
24+
25+
#define DT_DRV_COMPAT nxp_pxp
26+
27+
LOG_MODULE_REGISTER(mcux_pxp, CONFIG_VIDEO_LOG_LEVEL);
28+
29+
struct mcux_pxp_config {
30+
PXP_Type *base;
31+
void (*irq_config_func)(void);
32+
};
33+
34+
struct mcux_pxp_ctrls {
35+
struct {
36+
struct video_ctrl rotation;
37+
struct video_ctrl hflip;
38+
struct video_ctrl vflip;
39+
};
40+
};
41+
42+
struct mcux_pxp_data {
43+
struct mcux_pxp_ctrls ctrls;
44+
pxp_ps_buffer_config_t ps_buffer_cfg;
45+
pxp_output_buffer_config_t output_buffer_cfg;
46+
struct k_fifo fifo_in_queued;
47+
struct k_fifo fifo_in_done;
48+
struct k_fifo fifo_out_queued;
49+
struct k_fifo fifo_out_done;
50+
};
51+
52+
static void mcux_pxp_isr(const struct device *const dev)
53+
{
54+
const struct mcux_pxp_config *config = dev->config;
55+
struct mcux_pxp_data *data = dev->data;
56+
57+
PXP_ClearStatusFlags(config->base, kPXP_CompleteFlag);
58+
59+
struct video_buffer *vbuf_in = k_fifo_get(&data->fifo_in_queued, K_NO_WAIT);
60+
struct video_buffer *vbuf_out = k_fifo_get(&data->fifo_out_queued, K_NO_WAIT);
61+
62+
/* Something went wrong, should never happen */
63+
if ((uint32_t)vbuf_in->buffer != data->ps_buffer_cfg.bufferAddr ||
64+
(uint32_t)vbuf_out->buffer != data->output_buffer_cfg.buffer0Addr) {
65+
return;
66+
}
67+
68+
vbuf_out->timestamp = k_uptime_get_32();
69+
vbuf_out->bytesused = data->output_buffer_cfg.pitchBytes * data->output_buffer_cfg.height;
70+
71+
#ifdef CONFIG_HAS_MCUX_CACHE
72+
DCACHE_InvalidateByRange((uint32_t)vbuf_out->buffer, vbuf_out->bytesused);
73+
#endif
74+
75+
k_fifo_put(&data->fifo_in_done, vbuf_in);
76+
k_fifo_put(&data->fifo_out_done, vbuf_out);
77+
// LOG_ERR("mcux_pxp_isr: OK >>>>>");
78+
}
79+
80+
static int mcux_pxp_set_stream(const struct device *dev, bool enable, enum video_buf_type type)
81+
{
82+
const struct mcux_pxp_config *const config = dev->config;
83+
struct mcux_pxp_data *data = dev->data;
84+
85+
if (enable) {
86+
#ifdef CONFIG_HAS_MCUX_CACHE
87+
DCACHE_CleanByRange((uint32_t)data->ps_buffer_cfg.bufferAddr,
88+
data->output_buffer_cfg.pitchBytes *
89+
data->output_buffer_cfg.height);
90+
#endif
91+
PXP_Start(config->base);
92+
}
93+
94+
return 0;
95+
}
96+
97+
static int mcux_pxp_set_ctrl(const struct device *dev, uint32_t id)
98+
{
99+
const struct mcux_pxp_config *const config = dev->config;
100+
struct mcux_pxp_data *data = dev->data;
101+
struct mcux_pxp_ctrls *ctrls = &data->ctrls;
102+
pxp_flip_mode_t flip = ctrls->hflip.val | ctrls->vflip.val;
103+
pxp_rotate_degree_t rotate = kPXP_Rotate0;
104+
105+
ARG_UNUSED(id);
106+
107+
switch (ctrls->rotation.val) {
108+
case 0:
109+
rotate = kPXP_Rotate0;
110+
break;
111+
case 90:
112+
rotate = kPXP_Rotate90;
113+
break;
114+
case 180:
115+
rotate = kPXP_Rotate180;
116+
break;
117+
case 270:
118+
rotate = kPXP_Rotate270;
119+
break;
120+
}
121+
122+
PXP_SetRotateConfig(config->base, kPXP_RotateProcessSurface, rotate, flip);
123+
124+
return 0;
125+
}
126+
127+
static int mcux_pxp_set_fmt(const struct device *dev, struct video_format *fmt)
128+
{
129+
struct mcux_pxp_data *data = dev->data;
130+
131+
fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE;
132+
133+
switch (fmt->type) {
134+
case VIDEO_BUF_TYPE_INPUT:
135+
data->ps_buffer_cfg.pitchBytes = fmt->pitch;
136+
switch (fmt->pixelformat) {
137+
case VIDEO_PIX_FMT_RGB565:
138+
LOG_ERR("mcux_pxp_set_fmt here 1");
139+
data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB565;
140+
break;
141+
case VIDEO_PIX_FMT_RGB24:
142+
LOG_ERR("mcux_pxp_set_fmt here 2");
143+
#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && \
144+
FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \
145+
(!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3))
146+
data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatARGB8888;
147+
#else
148+
data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB888;
149+
#endif
150+
break;
151+
case VIDEO_PIX_FMT_ARGB32:
152+
LOG_ERR("mcux_pxp_set_fmt here 3");
153+
data->ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatARGB8888;
154+
break;
155+
default:
156+
LOG_ERR("mcux_pxp_set_fmt here 4");
157+
return -ENOTSUP;
158+
}
159+
break;
160+
case VIDEO_BUF_TYPE_OUTPUT:
161+
data->output_buffer_cfg.pitchBytes = fmt->pitch;
162+
data->output_buffer_cfg.height = fmt->height;
163+
switch (fmt->pixelformat) {
164+
case VIDEO_PIX_FMT_RGB565:
165+
LOG_ERR("mcux_pxp_set_fmt out 1");
166+
data->output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB565;
167+
break;
168+
case VIDEO_PIX_FMT_RGB24:
169+
data->output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB888;
170+
break;
171+
case VIDEO_PIX_FMT_ARGB32:
172+
data->output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatARGB8888;
173+
break;
174+
default:
175+
return -ENOTSUP;
176+
}
177+
break;
178+
default:
179+
return -ENOTSUP;
180+
}
181+
182+
LOG_ERR("mcux_pxp_set_fmt OK !!!");
183+
return 0;
184+
}
185+
186+
static int mcux_pxp_enqueue(const struct device *dev, struct video_buffer *vbuf)
187+
{
188+
const struct mcux_pxp_config *const config = dev->config;
189+
struct mcux_pxp_data *data = dev->data;
190+
191+
#ifdef CONFIG_HAS_MCUX_CACHE
192+
DCACHE_CleanByRange((uint32_t)vbuf->buffer, vbuf->size);
193+
#endif
194+
195+
switch (vbuf->type) {
196+
case VIDEO_BUF_TYPE_INPUT:
197+
k_fifo_put(&data->fifo_in_queued, vbuf);
198+
199+
data->ps_buffer_cfg.swapByte = false;
200+
data->ps_buffer_cfg.bufferAddr = (uint32_t)vbuf->buffer;
201+
data->ps_buffer_cfg.bufferAddrU = 0U;
202+
data->ps_buffer_cfg.bufferAddrV = 0U;
203+
204+
PXP_SetProcessSurfaceBufferConfig(config->base, &data->ps_buffer_cfg);
205+
206+
break;
207+
case VIDEO_BUF_TYPE_OUTPUT:
208+
k_fifo_put(&data->fifo_out_queued, vbuf);
209+
210+
data->output_buffer_cfg.interlacedMode = kPXP_OutputProgressive;
211+
data->output_buffer_cfg.buffer0Addr = (uint32_t)vbuf->buffer;
212+
data->output_buffer_cfg.buffer1Addr = 0U;
213+
214+
PXP_SetOutputBufferConfig(config->base, &data->output_buffer_cfg);
215+
/* We only support a process surface that covers the full buffer */
216+
PXP_SetProcessSurfacePosition(config->base, 0U, 0U, data->output_buffer_cfg.width,
217+
data->output_buffer_cfg.height);
218+
219+
break;
220+
default:
221+
return -ENOTSUP;
222+
}
223+
224+
return 0;
225+
}
226+
227+
static int mcux_pxp_dequeue(const struct device *dev, struct video_buffer **vbuf,
228+
k_timeout_t timeout)
229+
{
230+
struct mcux_pxp_data *data = dev->data;
231+
LOG_ERR("mcux_pxp_dequeue here 1");
232+
switch ((*vbuf)->type) {
233+
case VIDEO_BUF_TYPE_INPUT:
234+
*vbuf = k_fifo_get(&data->fifo_in_done, timeout);
235+
break;
236+
case VIDEO_BUF_TYPE_OUTPUT:
237+
*vbuf = k_fifo_get(&data->fifo_out_done, timeout);
238+
break;
239+
default:
240+
return -ENOTSUP;
241+
}
242+
LOG_ERR("mcux_pxp_dequeue here 2");
243+
if (*vbuf == NULL) {
244+
LOG_ERR("mcux_pxp_dequeue here NULL");
245+
return -EAGAIN;
246+
}
247+
LOG_ERR("mcux_pxp_dequeue here ");
248+
return 0;
249+
}
250+
251+
static DEVICE_API(video, mcux_pxp_driver_api) = {
252+
// .get_caps = mcux_pxp_get_caps,
253+
.set_stream = mcux_pxp_set_stream,
254+
.set_format = mcux_pxp_set_fmt,
255+
// .get_format = mcux_pxp_get_fmt,
256+
.set_ctrl = mcux_pxp_set_ctrl,
257+
.enqueue = mcux_pxp_enqueue,
258+
.dequeue = mcux_pxp_dequeue,
259+
};
260+
261+
static int mcux_pxp_init(const struct device *const dev)
262+
{
263+
const struct mcux_pxp_config *const config = dev->config;
264+
struct mcux_pxp_data *data = dev->data;
265+
struct mcux_pxp_ctrls *ctrls = &data->ctrls;
266+
int ret;
267+
268+
k_fifo_init(&data->fifo_in_queued);
269+
k_fifo_init(&data->fifo_out_queued);
270+
k_fifo_init(&data->fifo_in_done);
271+
k_fifo_init(&data->fifo_out_done);
272+
273+
PXP_Init(config->base);
274+
275+
PXP_SetProcessSurfaceBackGroundColor(config->base, 0U);
276+
/* Disable alpha surface and CSC1 */
277+
PXP_SetAlphaSurfacePosition(config->base, 0xFFFFU, 0xFFFFU, 0U, 0U);
278+
PXP_EnableCsc1(config->base, false);
279+
PXP_EnableInterrupts(config->base, kPXP_CompleteInterruptEnable);
280+
281+
config->irq_config_func();
282+
283+
ret = video_init_ctrl(&ctrls->rotation, dev, VIDEO_CID_ROTATE,
284+
(struct video_ctrl_range){.min = 0, .max = 270, .step = 90, .def = 0});
285+
if (ret) {
286+
return ret;
287+
}
288+
289+
ret = video_init_ctrl(&ctrls->hflip, dev, VIDEO_CID_HFLIP,
290+
(struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0});
291+
if (ret) {
292+
return ret;
293+
}
294+
295+
ret = video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP,
296+
(struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0});
297+
if (ret) {
298+
return ret;
299+
}
300+
301+
video_auto_cluster_ctrl(&ctrls->rotation, 3, false);
302+
303+
return 0;
304+
}
305+
306+
#define MCUX_PXP_INIT(inst) \
307+
static void mcux_pxp_irq_config_##inst(void) \
308+
{ \
309+
IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), mcux_pxp_isr, \
310+
DEVICE_DT_INST_GET(inst), 0); \
311+
irq_enable(DT_INST_IRQN(inst)); \
312+
} \
313+
\
314+
static const struct mcux_pxp_config mcux_pxp_config_##inst = { \
315+
.base = (PXP_Type *)DT_INST_REG_ADDR(inst), \
316+
.irq_config_func = mcux_pxp_irq_config_##inst, \
317+
}; \
318+
\
319+
static struct mcux_pxp_data mcux_pxp_data_##inst; \
320+
\
321+
DEVICE_DT_INST_DEFINE(inst, &mcux_pxp_init, NULL, &mcux_pxp_data_##inst, \
322+
&mcux_pxp_config_##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
323+
&mcux_pxp_driver_api); \
324+
\
325+
VIDEO_DEVICE_DEFINE(pxp_##inst, DEVICE_DT_INST_GET(inst), NULL);
326+
327+
DT_INST_FOREACH_STATUS_OKAY(MCUX_PXP_INIT)

modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ set_variable_ifdef(CONFIG_WDT_MCUX_WDOG32 CONFIG_MCUX_COMPONENT_driver.wdo
9191
set_variable_ifdef(CONFIG_COUNTER_MCUX_GPT CONFIG_MCUX_COMPONENT_driver.gpt)
9292
set_variable_ifdef(CONFIG_MCUX_GPT_TIMER CONFIG_MCUX_COMPONENT_driver.gpt)
9393
set_variable_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF CONFIG_MCUX_COMPONENT_driver.elcdif)
94-
set_variable_ifdef(CONFIG_MCUX_PXP CONFIG_MCUX_COMPONENT_driver.pxp)
94+
set_variable_ifdef(CONFIG_VIDEO_MCUX_PXP CONFIG_MCUX_COMPONENT_driver.pxp)
9595
set_variable_ifdef(CONFIG_LV_USE_GPU_NXP_PXP CONFIG_MCUX_COMPONENT_driver.pxp)
9696
set_variable_ifdef(CONFIG_GPIO_MCUX_RGPIO CONFIG_MCUX_COMPONENT_driver.rgpio)
9797
set_variable_ifdef(CONFIG_I2S_MCUX_SAI CONFIG_MCUX_COMPONENT_driver.sai)

0 commit comments

Comments
 (0)