From de2be86101e7ad6ec6528919e3501202f0f0757f Mon Sep 17 00:00:00 2001 From: Phi Bang Nguyen Date: Sat, 11 May 2024 21:07:24 +0200 Subject: [PATCH 1/2] include: video: Add XYUV32 pixel format Add XYUV32 pixel format Signed-off-by: Phi Bang Nguyen --- include/zephyr/drivers/video.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/zephyr/drivers/video.h b/include/zephyr/drivers/video.h index 85f08920119fa..84b5558390e85 100644 --- a/include/zephyr/drivers/video.h +++ b/include/zephyr/drivers/video.h @@ -638,6 +638,9 @@ void video_buffer_release(struct video_buffer *buf); /** YUYV pixel format */ #define VIDEO_PIX_FMT_YUYV video_fourcc('Y', 'U', 'Y', 'V') /* 16 Y0-Cb0 Y1-Cr0 */ +/** XYUV32 pixel format */ +#define VIDEO_PIX_FMT_XYUV32 video_fourcc('X', 'Y', 'U', 'V') /* 32 XYUV-8-8-8-8 */ + /** * * @} From 668b5c66914acae84bccd9726f4ab684d531e121 Mon Sep 17 00:00:00 2001 From: Phi Bang Nguyen Date: Sat, 11 May 2024 21:08:41 +0200 Subject: [PATCH 2/2] drivers: video: csi: Add support for i.MX RT11XX On i.MX RT11XX which has MIPI CSI-2 Rx, image data from the camera sensor after passing through the camera pipeline (MIPI CSI-2 Rx --> Video Mux --> CSI) will be implicitly converted to a 32-bits pixel formats. For example, an input in RGB565 / YUYV (2-bytes format) will become an XRGB32 / XYUV32 (4-bytes format), respectively. Make changes to support this. Signed-off-by: Phi Bang Nguyen --- drivers/video/video_mcux_csi.c | 77 +++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/video/video_mcux_csi.c b/drivers/video/video_mcux_csi.c index 77022d037d898..2e8e4d505084a 100644 --- a/drivers/video/video_mcux_csi.c +++ b/drivers/video/video_mcux_csi.c @@ -44,6 +44,9 @@ static inline unsigned int video_pix_fmt_bpp(uint32_t pixelformat) case VIDEO_PIX_FMT_RGB565: case VIDEO_PIX_FMT_YUYV: return 2; + case VIDEO_PIX_FMT_XRGB32: + case VIDEO_PIX_FMT_XYUV32: + return 4; default: return 0; } @@ -113,6 +116,36 @@ static void __frame_done_cb(CSI_Type *base, csi_handle_t *handle, status_t statu return; } +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) +K_HEAP_DEFINE(csi_heap, 1000); +static struct video_format_cap *fmts; +/* + * On i.MX RT11xx SoCs which have MIPI CSI-2 Rx, image data from the camera sensor after passing + * through the pipeline (MIPI CSI-2 Rx --> Video Mux --> CSI) will be implicitly converted to a + * 32-bits pixel format. For example, an input in RGB565 or YUYV (2-bytes format) will become a + * XRGB32 or XYUV32 (4-bytes format) respectively, at the output of the CSI. + */ +static inline void video_pix_fmt_convert(struct video_format *fmt, bool isGetFmt) +{ + switch (fmt->pixelformat) { + case VIDEO_PIX_FMT_XRGB32: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XRGB32 : VIDEO_PIX_FMT_RGB565; + break; + case VIDEO_PIX_FMT_XYUV32: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XYUV32 : VIDEO_PIX_FMT_YUYV; + break; + case VIDEO_PIX_FMT_RGB565: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XRGB32 : VIDEO_PIX_FMT_RGB565; + break; + case VIDEO_PIX_FMT_YUYV: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XYUV32 : VIDEO_PIX_FMT_YUYV; + break; + } + + fmt->pitch = fmt->width * video_pix_fmt_bpp(fmt->pixelformat); +} +#endif + static int video_mcux_csi_set_fmt(const struct device *dev, enum video_endpoint_id ep, struct video_format *fmt) { @@ -120,6 +153,7 @@ static int video_mcux_csi_set_fmt(const struct device *dev, enum video_endpoint_ struct video_mcux_csi_data *data = dev->data; unsigned int bpp = video_pix_fmt_bpp(fmt->pixelformat); status_t ret; + struct video_format format = *fmt; if (!bpp || ep != VIDEO_EP_OUT) { return -EINVAL; @@ -127,9 +161,17 @@ static int video_mcux_csi_set_fmt(const struct device *dev, enum video_endpoint_ data->csi_config.bytesPerPixel = bpp; data->csi_config.linePitch_Bytes = fmt->pitch; +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + if (fmt->pixelformat != VIDEO_PIX_FMT_XRGB32 && fmt->pixelformat != VIDEO_PIX_FMT_XYUV32) { + return -ENOTSUP; + } + video_pix_fmt_convert(&format, false); + data->csi_config.dataBus = kCSI_DataBus24Bit; +#else + data->csi_config.dataBus = kCSI_DataBus8Bit; +#endif data->csi_config.polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge; data->csi_config.workMode = kCSI_GatedClockMode; /* use VSYNC, HSYNC, and PIXCLK */ - data->csi_config.dataBus = kCSI_DataBus8Bit; data->csi_config.useExtVsync = true; data->csi_config.height = fmt->height; data->csi_config.width = fmt->width; @@ -144,7 +186,7 @@ static int video_mcux_csi_set_fmt(const struct device *dev, enum video_endpoint_ return -EIO; } - if (config->source_dev && video_set_format(config->source_dev, ep, fmt)) { + if (config->source_dev && video_set_format(config->source_dev, ep, &format)) { return -EIO; } @@ -161,6 +203,9 @@ static int video_mcux_csi_get_fmt(const struct device *dev, enum video_endpoint_ } if (config->source_dev && !video_get_format(config->source_dev, ep, fmt)) { +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + video_pix_fmt_convert(fmt, true); +#endif /* align CSI with source fmt */ return video_mcux_csi_set_fmt(dev, ep, fmt); } @@ -317,6 +362,34 @@ static int video_mcux_csi_get_caps(const struct device *dev, enum video_endpoint /* Just forward to source dev for now */ if (config->source_dev) { err = video_get_caps(config->source_dev, ep, caps); +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + /* + * On i.MX RT11xx SoCs which have MIPI CSI-2 Rx, image data from the camera sensor + * after passing through the pipeline (MIPI CSI-2 Rx --> Video Mux --> CSI) will be + * implicitly converted to a 32-bits pixel format. For example, an input in RGB565 + * or YUYV (2-bytes format) will become an XRGB32 or XYUV32 (4-bytes format) + * respectively, at the output of the CSI. So, we change the pixel formats of the + * source caps to reflect this. + */ + int ind = 0; + + while (caps->format_caps[ind].pixelformat) { + ind++; + } + k_heap_free(&csi_heap, fmts); + fmts = k_heap_alloc(&csi_heap, (ind + 1) * sizeof(struct video_format_cap), + K_FOREVER); + + for (int i = 0; i <= ind; i++) { + memcpy(&fmts[i], &caps->format_caps[i], sizeof(fmts[i])); + if (fmts[i].pixelformat == VIDEO_PIX_FMT_RGB565) { + fmts[i].pixelformat = VIDEO_PIX_FMT_XRGB32; + } else if (fmts[i].pixelformat == VIDEO_PIX_FMT_YUYV) { + fmts[i].pixelformat = VIDEO_PIX_FMT_XYUV32; + } + } + caps->format_caps = fmts; +#endif } /* NXP MCUX CSI request at least 2 buffer before starting */