diff --git a/boards/madmachine/mm_swiftio/mm_swiftio.dts b/boards/madmachine/mm_swiftio/mm_swiftio.dts index e4212cd8294c6d..7fa2a9cd37cff4 100644 --- a/boards/madmachine/mm_swiftio/mm_swiftio.dts +++ b/boards/madmachine/mm_swiftio/mm_swiftio.dts @@ -115,7 +115,7 @@ port { ov7725_ep_out: endpoint { - remote-endpoint = <&csi_ep_in>; + remote-endpoint-label = "csi_ep_in"; }; }; }; @@ -192,13 +192,12 @@ &csi { status = "okay"; - source = <&ov7725>; pinctrl-0 = <&pinmux_csi>; pinctrl-names = "default"; port { csi_ep_in: endpoint { - remote-endpoint = <&ov7725_ep_out>; + remote-endpoint-label = "ov7725_ep_out"; }; }; }; diff --git a/boards/shields/dvp_fpc24_mt9m114/boards/mimxrt1060_evkb.overlay b/boards/shields/dvp_fpc24_mt9m114/boards/mimxrt1060_evkb.overlay deleted file mode 100644 index a4aa7a273080dd..00000000000000 --- a/boards/shields/dvp_fpc24_mt9m114/boards/mimxrt1060_evkb.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2024 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&dvp_fpc24_interface { - source = <&mt9m114>; -}; diff --git a/boards/shields/dvp_fpc24_mt9m114/boards/mimxrt1064_evk.overlay b/boards/shields/dvp_fpc24_mt9m114/boards/mimxrt1064_evk.overlay deleted file mode 100644 index a4aa7a273080dd..00000000000000 --- a/boards/shields/dvp_fpc24_mt9m114/boards/mimxrt1064_evk.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2024 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&dvp_fpc24_interface { - source = <&mt9m114>; -}; diff --git a/boards/shields/dvp_fpc24_mt9m114/dvp_fpc24_mt9m114.overlay b/boards/shields/dvp_fpc24_mt9m114/dvp_fpc24_mt9m114.overlay index 52988535182d31..49bc018779a8fc 100644 --- a/boards/shields/dvp_fpc24_mt9m114/dvp_fpc24_mt9m114.overlay +++ b/boards/shields/dvp_fpc24_mt9m114/dvp_fpc24_mt9m114.overlay @@ -17,7 +17,7 @@ port { mt9m114_ep_out: endpoint { - remote-endpoint = <&dfi_ep_in>; + remote-endpoint-label = "dfi_ep_in"; }; }; }; @@ -28,7 +28,7 @@ port { dfi_ep_in: endpoint { - remote-endpoint = <&mt9m114_ep_out>; + remote-endpoint-label = "mt9m114_ep_out"; }; }; }; diff --git a/boards/shields/nxp_btb44_ov5640/nxp_btb44_ov5640.overlay b/boards/shields/nxp_btb44_ov5640/nxp_btb44_ov5640.overlay index e7c179f5d2355c..9eca70c27cdebe 100644 --- a/boards/shields/nxp_btb44_ov5640/nxp_btb44_ov5640.overlay +++ b/boards/shields/nxp_btb44_ov5640/nxp_btb44_ov5640.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /{ chosen { zephyr,camera = &nxp_csi; @@ -21,7 +23,9 @@ port { ov5640_ep_out: endpoint { - remote-endpoint = <&mipi_csi2rx_ep_in>; + remote-endpoint-label = "mipi_csi2rx_ep_in"; + bus-type = ; + data-lanes = <1 2>; }; }; }; @@ -30,14 +34,13 @@ &nxp_mipi_csi { status = "okay"; - sensor = <&ov5640>; - ports { port@1 { reg = <1>; mipi_csi2rx_ep_in: endpoint { - remote-endpoint = <&ov5640_ep_out>; + remote-endpoint-label = "ov5640_ep_out"; + data-lanes = <1 2>; }; }; }; diff --git a/drivers/video/Kconfig.mcux_csi b/drivers/video/Kconfig.mcux_csi index 88b57d3b461f17..e9bc48c7bd0915 100644 --- a/drivers/video/Kconfig.mcux_csi +++ b/drivers/video/Kconfig.mcux_csi @@ -11,7 +11,7 @@ config VIDEO_MCUX_CSI config VIDEO_MCUX_CSI_INIT_PRIORITY int "NXP MCUX CSI init priority" - default 61 + default 59 depends on VIDEO_MCUX_CSI help Initialization priority for the CSI interface on an NXP MCUX device. diff --git a/drivers/video/video_mcux_csi.c b/drivers/video/video_mcux_csi.c index c6a82accdb40b2..6fc4e662343957 100644 --- a/drivers/video/video_mcux_csi.c +++ b/drivers/video/video_mcux_csi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, Linaro Limited + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +18,16 @@ #include #endif +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) +#define DEVICE_DT_INST_GET_SOURCE_DEV(n) \ + DEVICE_DT_GET(DT_PARENT(DT_GPARENT(DT_NODELABEL(DT_STRING_TOKEN( \ + DT_CHILD(DT_INST_CHILD(n, port), endpoint), remote_endpoint_label))))) +#else +#define DEVICE_DT_INST_GET_SOURCE_DEV(n) \ + DEVICE_DT_GET(DT_GPARENT(DT_NODELABEL(DT_STRING_TOKEN( \ + DT_CHILD(DT_INST_CHILD(n, port), endpoint), remote_endpoint_label)))) +#endif + struct video_mcux_csi_config { CSI_Type *base; const struct device *source_dev; @@ -32,25 +43,6 @@ struct video_mcux_csi_data { struct k_poll_signal *signal; }; -static inline unsigned int video_pix_fmt_bpp(uint32_t pixelformat) -{ - switch (pixelformat) { - case VIDEO_PIX_FMT_BGGR8: - case VIDEO_PIX_FMT_GBRG8: - case VIDEO_PIX_FMT_GRBG8: - case VIDEO_PIX_FMT_RGGB8: - return 1; - 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; - } -} - static void __frame_done_cb(CSI_Type *base, csi_handle_t *handle, status_t status, void *user_data) { struct video_mcux_csi_data *data = user_data; @@ -217,6 +209,11 @@ static int video_mcux_csi_stream_start(const struct device *dev) const struct video_mcux_csi_config *config = dev->config; struct video_mcux_csi_data *data = dev->data; status_t ret; + struct video_buf *vbuf; + + while ((vbuf = k_fifo_get(&data->fifo_out, K_NO_WAIT))) { + k_fifo_put(&data->fifo_in, vbuf); + }; ret = CSI_TransferStart(config->base, &data->csi_handle); if (ret != kStatus_Success) { @@ -450,6 +447,42 @@ static int video_mcux_csi_set_signal(const struct device *dev, enum video_endpoi } #endif +static int video_mcux_csi_set_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival *frmival) +{ + const struct video_mcux_csi_config *config = dev->config; + + return video_set_frmival(config->source_dev, ep, frmival); +} + +static int video_mcux_csi_get_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival *frmival) +{ + const struct video_mcux_csi_config *config = dev->config; + + return video_get_frmival(config->source_dev, ep, frmival); +} + +static int video_mcux_csi_enum_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival_enum *fie) +{ + const struct video_mcux_csi_config *config = dev->config; + const struct video_format *fie_fmt = fie->format; + int ret; + +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + struct video_format converted_fmt = *fie->format; + + video_pix_fmt_convert(&converted_fmt, false); + fie->format = &converted_fmt; +#endif + + ret = video_enum_frmival(config->source_dev, ep, fie); + fie->format = fie_fmt; + + return ret; +} + static const struct video_driver_api video_mcux_csi_driver_api = { .set_format = video_mcux_csi_set_fmt, .get_format = video_mcux_csi_get_fmt, @@ -461,6 +494,9 @@ static const struct video_driver_api video_mcux_csi_driver_api = { .set_ctrl = video_mcux_csi_set_ctrl, .get_ctrl = video_mcux_csi_get_ctrl, .get_caps = video_mcux_csi_get_caps, + .set_frmival = video_mcux_csi_set_frmival, + .get_frmival = video_mcux_csi_get_frmival, + .enum_frmival = video_mcux_csi_enum_frmival, #ifdef CONFIG_POLL .set_signal = video_mcux_csi_set_signal, #endif @@ -471,7 +507,7 @@ PINCTRL_DT_INST_DEFINE(0); static const struct video_mcux_csi_config video_mcux_csi_config_0 = { .base = (CSI_Type *)DT_INST_REG_ADDR(0), - .source_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, source)), + .source_dev = DEVICE_DT_INST_GET_SOURCE_DEV(0), .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; @@ -490,11 +526,6 @@ static int video_mcux_csi_init_0(const struct device *dev) return video_mcux_csi_init(dev); } -/* CONFIG_KERNEL_INIT_PRIORITY_DEVICE is used to make sure the - * CSI peripheral is initialized before the camera, which is - * necessary since the clock to the camera is provided by the - * CSI peripheral. - */ DEVICE_DT_INST_DEFINE(0, &video_mcux_csi_init_0, NULL, &video_mcux_csi_data_0, &video_mcux_csi_config_0, POST_KERNEL, CONFIG_VIDEO_MCUX_CSI_INIT_PRIORITY, &video_mcux_csi_driver_api); diff --git a/drivers/video/video_mcux_mipi_csi2rx.c b/drivers/video/video_mcux_mipi_csi2rx.c index 5ad56383fda4fe..e52a8d1199045e 100644 --- a/drivers/video/video_mcux_mipi_csi2rx.c +++ b/drivers/video/video_mcux_mipi_csi2rx.c @@ -7,19 +7,22 @@ #define DT_DRV_COMPAT nxp_mipi_csi2rx #include +#include #include #include +#include #include LOG_MODULE_REGISTER(video_mipi_csi2rx, CONFIG_VIDEO_LOG_LEVEL); -/* - * Two data lanes are set by default as 2-lanes camera sensors are - * more common and more performant but single lane is also supported. - */ -#define DEFAULT_MIPI_CSI_NUM_LANES 2 -#define DEFAULT_CAMERA_FRAME_RATE 30 +#define MAX_SUPPORTED_PIXEL_RATE MHZ(96) + +#define ABS(a, b) (a > b ? a - b : b - a) + +#define DEVICE_DT_INST_GET_SENSOR_DEV(n) \ + DEVICE_DT_GET(DT_GPARENT(DT_NODELABEL(DT_STRING_TOKEN( \ + DT_CHILD(DT_CHILD(DT_INST_CHILD(n, ports), port_1), endpoint), remote_endpoint_label)))) struct mipi_csi2rx_config { const MIPI_CSI2RX_Type *base; @@ -30,100 +33,82 @@ struct mipi_csi2rx_data { csi2rx_config_t csi2rxConfig; }; -static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep, - struct video_format *fmt) +struct mipi_csi2rx_tHsSettleEscClk_config { + uint64_t pixel_rate; + uint8_t tHsSettle_EscClk; +}; + +/* Must be in pixel rate ascending order */ +const struct mipi_csi2rx_tHsSettleEscClk_config tHsSettleEscClk_configs[] = { + {MHZ(24), 0x24}, + {MHZ(48), 0x12}, + {MHZ(96), 0x09}, +}; + +static int mipi_csi2rx_update_settings(const struct device *dev, enum video_endpoint_id ep) { const struct mipi_csi2rx_config *config = dev->config; struct mipi_csi2rx_data *drv_data = dev->data; - csi2rx_config_t csi2rxConfig = {0}; - uint8_t i = 0; + uint8_t bpp; + uint64_t sensor_pixel_rate, sensor_lane_rate, sensor_byte_clk; + uint32_t best_match; + int ret, ind = 0; + struct video_format fmt; + + ret = video_get_format(config->sensor_dev, ep, &fmt); + if (ret) { + LOG_ERR("Cannot get sensor_dev pixel format"); + return ret; + } - /* - * Initialize the MIPI CSI2 - * - * From D-PHY specification, the T-HSSETTLE should in the range of 85ns+6*UI to 145ns+10*UI - * UI is Unit Interval, equal to the duration of any HS state on the Clock Lane - * - * T-HSSETTLE = csi2rxConfig.tHsSettle_EscClk * (Tperiod of RxClkInEsc) - * - * csi2rxConfig.tHsSettle_EscClk setting for camera: - * - * Resolution | frame rate | T_HS_SETTLE - * ============================================= - * 720P | 30 | 0x12 - * --------------------------------------------- - * 720P | 15 | 0x17 - * --------------------------------------------- - * VGA | 30 | 0x1F - * --------------------------------------------- - * VGA | 15 | 0x24 - * --------------------------------------------- - * QVGA | 30 | 0x1F - * --------------------------------------------- - * QVGA | 15 | 0x24 - * --------------------------------------------- - */ - static const uint32_t csi2rxHsSettle[][4] = { - { - 1280, - 720, - 30, - 0x12, - }, - { - 1280, - 720, - 15, - 0x17, - }, - { - 640, - 480, - 30, - 0x1F, - }, - { - 640, - 480, - 15, - 0x24, - }, - { - 320, - 240, - 30, - 0x1F, - }, - { - 320, - 240, - 15, - 0x24, - }, - }; - - csi2rxConfig.laneNum = DEFAULT_MIPI_CSI_NUM_LANES; - - for (i = 0; i < ARRAY_SIZE(csi2rxHsSettle); i++) { - if ((fmt->width == csi2rxHsSettle[i][0]) && (fmt->height == csi2rxHsSettle[i][1]) && - (DEFAULT_CAMERA_FRAME_RATE == csi2rxHsSettle[i][2])) { - csi2rxConfig.tHsSettle_EscClk = csi2rxHsSettle[i][3]; - break; - } + ret = video_get_ctrl(config->sensor_dev, VIDEO_CID_PIXEL_RATE, &sensor_pixel_rate); + if (ret) { + LOG_ERR("Can not get sensor_dev pixel rate"); + return ret; } - if (i == ARRAY_SIZE(csi2rxHsSettle)) { - LOG_ERR("Unsupported resolution"); + bpp = video_pix_fmt_bpp(fmt.pixelformat) * 8; + sensor_lane_rate = sensor_pixel_rate * bpp / drv_data->csi2rxConfig.laneNum; + + if (sensor_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) { + LOG_ERR("Sensor pixel rate is not supported"); return -ENOTSUP; } - drv_data->csi2rxConfig = csi2rxConfig; + sensor_byte_clk = sensor_pixel_rate * bpp / drv_data->csi2rxConfig.laneNum / 8; + if (sensor_byte_clk > CLOCK_GetRootClockFreq(kCLOCK_Root_Csi2)) { + mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2, sensor_byte_clk); + } + + if (sensor_pixel_rate > CLOCK_GetRootClockFreq(kCLOCK_Root_Csi2_Ui)) { + mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Ui, sensor_pixel_rate); + } + + /* Find the supported sensor_pixel_rate closest to the desired one */ + best_match = tHsSettleEscClk_configs[ind].pixel_rate; + for (uint8_t i = 0; i < ARRAY_SIZE(tHsSettleEscClk_configs); i++) { + if (ABS(tHsSettleEscClk_configs[i].pixel_rate, sensor_pixel_rate) < + ABS(tHsSettleEscClk_configs[i].pixel_rate, best_match)) { + best_match = tHsSettleEscClk_configs[i].pixel_rate; + ind = i; + } + } + + drv_data->csi2rxConfig.tHsSettle_EscClk = tHsSettleEscClk_configs[ind].tHsSettle_EscClk; + + return ret; +} + +static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + const struct mipi_csi2rx_config *config = dev->config; if (video_set_format(config->sensor_dev, ep, fmt)) { return -EIO; } - return 0; + return mipi_csi2rx_update_settings(dev, ep); } static int mipi_csi2rx_get_fmt(const struct device *dev, enum video_endpoint_id ep, @@ -182,12 +167,136 @@ static int mipi_csi2rx_get_caps(const struct device *dev, enum video_endpoint_id return video_get_caps(config->sensor_dev, ep, caps); } +static inline int mipi_csi2rx_set_ctrl(const struct device *dev, unsigned int cid, void *value) +{ + const struct mipi_csi2rx_config *config = dev->config; + + if (config->sensor_dev) { + return video_set_ctrl(config->sensor_dev, cid, value); + } + + return -ENOTSUP; +} + +static int mipi_csi2rx_set_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival *frmival) +{ + const struct mipi_csi2rx_config *config = dev->config; + int ret; + + ret = video_set_frmival(config->sensor_dev, ep, frmival); + if (ret) { + LOG_ERR("Cannot set sensor_dev frmival"); + return ret; + } + + ret = mipi_csi2rx_update_settings(dev, ep); + + return ret; +} + +static int mipi_csi2rx_get_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival *frmival) +{ + const struct mipi_csi2rx_config *config = dev->config; + + return video_get_frmival(config->sensor_dev, ep, frmival); +} + +static uint64_t mipi_csi2rx_cal_frame_size(const struct video_format *fmt) +{ + return fmt->height * fmt->width * video_pix_fmt_bpp(fmt->pixelformat) * 8; +} + +static uint64_t mipi_csi2rx_estimate_pixel_rate(const struct video_frmival *cur_fmival, + const struct video_frmival *fie_frmival, + const struct video_format *cur_format, + const struct video_format *fie_format, + uint64_t cur_pixel_rate, uint8_t laneNum) +{ + return mipi_csi2rx_cal_frame_size(cur_format) * fie_frmival->denominator * + cur_fmival->numerator * cur_pixel_rate / + (mipi_csi2rx_cal_frame_size(fie_format) * fie_frmival->numerator * + cur_fmival->denominator); +} + +static int mipi_csi2rx_enum_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival_enum *fie) +{ + const struct mipi_csi2rx_config *config = dev->config; + struct mipi_csi2rx_data *drv_data = dev->data; + int ret; + uint64_t cur_pixel_rate, est_pixel_rate; + struct video_frmival cur_frmival; + struct video_format cur_fmt; + + ret = video_enum_frmival(config->sensor_dev, ep, fie); + if (ret) { + return ret; + } + + ret = video_get_ctrl(config->sensor_dev, VIDEO_CID_PIXEL_RATE, &cur_pixel_rate); + if (ret) { + LOG_ERR("Cannot get sensor_dev pixel rate"); + return ret; + } + + ret = video_get_frmival(config->sensor_dev, ep, &cur_frmival); + if (ret) { + LOG_ERR("Cannot get sensor_dev frame rate"); + return ret; + } + + ret = video_get_format(config->sensor_dev, ep, &cur_fmt); + if (ret) { + LOG_ERR("Cannot get sensor_dev format"); + return ret; + } + + if (fie->type == VIDEO_FRMIVAL_TYPE_DISCRETE) { + est_pixel_rate = mipi_csi2rx_estimate_pixel_rate( + &cur_frmival, &fie->discrete, &cur_fmt, fie->format, cur_pixel_rate, + drv_data->csi2rxConfig.laneNum); + if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) { + return -EINVAL; + } + + } else { + /* Check the lane rate of the lower bound framerate */ + est_pixel_rate = mipi_csi2rx_estimate_pixel_rate( + &cur_frmival, &fie->stepwise.min, &cur_fmt, fie->format, cur_pixel_rate, + drv_data->csi2rxConfig.laneNum); + if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) { + return -EINVAL; + } + + /* Check the lane rate of the upper bound framerate */ + est_pixel_rate = mipi_csi2rx_estimate_pixel_rate( + &cur_frmival, &fie->stepwise.max, &cur_fmt, fie->format, cur_pixel_rate, + drv_data->csi2rxConfig.laneNum); + if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) { + fie->stepwise.max.denominator = + (mipi_csi2rx_cal_frame_size(&cur_fmt) * MAX_SUPPORTED_PIXEL_RATE * + cur_frmival.denominator) / + (mipi_csi2rx_cal_frame_size(fie->format) * cur_pixel_rate * + cur_frmival.numerator); + fie->stepwise.max.numerator = 1; + } + } + + return 0; +} + static const struct video_driver_api mipi_csi2rx_driver_api = { .get_caps = mipi_csi2rx_get_caps, .get_format = mipi_csi2rx_get_fmt, .set_format = mipi_csi2rx_set_fmt, .stream_start = mipi_csi2rx_stream_start, .stream_stop = mipi_csi2rx_stream_stop, + .set_ctrl = mipi_csi2rx_set_ctrl, + .set_frmival = mipi_csi2rx_set_frmival, + .get_frmival = mipi_csi2rx_get_frmival, + .enum_frmival = mipi_csi2rx_enum_frmival, }; static int mipi_csi2rx_init(const struct device *dev) @@ -199,15 +308,25 @@ static int mipi_csi2rx_init(const struct device *dev) return -ENODEV; } - return 0; + /* + * CSI2 escape clock should be in the range [60, 80] Mhz. We set it + * to 60 Mhz. + */ + mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Esc, MHZ(60)); + + return mipi_csi2rx_update_settings(dev, VIDEO_EP_ALL); } #define MIPI_CSI2RX_INIT(n) \ - static struct mipi_csi2rx_data mipi_csi2rx_data_##n; \ + static struct mipi_csi2rx_data mipi_csi2rx_data_##n = { \ + .csi2rxConfig.laneNum = \ + DT_PROP_LEN(DT_CHILD(DT_CHILD(DT_INST_CHILD(n, ports), port_1), endpoint), \ + data_lanes), \ + }; \ \ static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \ .base = (MIPI_CSI2RX_Type *)DT_INST_REG_ADDR(n), \ - .sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, sensor)), \ + .sensor_dev = DEVICE_DT_INST_GET_SENSOR_DEV(n), \ }; \ \ DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n, \ diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 5dd41ed398b664..214e35f2a8e3cf 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -888,11 +888,10 @@ reg = <0x40800000 0x4000>; interrupts = <56 1>; status = "disabled"; - source = <&mipi_csi2rx>; port { csi_ep_in: endpoint { - remote-endpoint = <&mipi_csi2rx_ep_out>; + remote-endpoint-label = "mipi_csi2rx_ep_out"; }; }; }; @@ -909,7 +908,7 @@ port@0 { reg = <0>; mipi_csi2rx_ep_out: endpoint { - remote-endpoint = <&csi_ep_in>; + remote-endpoint-label = "csi_ep_in"; }; }; diff --git a/dts/bindings/video/aptina,mt9m114.yaml b/dts/bindings/video/aptina,mt9m114.yaml index 21dbefb5419eee..c233080ae0ca11 100644 --- a/dts/bindings/video/aptina,mt9m114.yaml +++ b/dts/bindings/video/aptina,mt9m114.yaml @@ -6,3 +6,7 @@ description: MT9M114 CMOS video sensor compatible: "aptina,mt9m114" include: i2c-device.yaml + +child-binding: + child-binding: + include: video-interfaces.yaml diff --git a/dts/bindings/video/nxp,imx-csi.yaml b/dts/bindings/video/nxp,imx-csi.yaml index bf7fd01eeaadd3..f8f146c9c425de 100644 --- a/dts/bindings/video/nxp,imx-csi.yaml +++ b/dts/bindings/video/nxp,imx-csi.yaml @@ -14,8 +14,6 @@ properties: interrupts: required: true - source: - required: true - type: phandle - description: the connected source device, - e.g., a mipi csi or a camera sensor +child-binding: + child-binding: + include: video-interfaces.yaml diff --git a/dts/bindings/video/nxp,mipi-csi2rx.yaml b/dts/bindings/video/nxp,mipi-csi2rx.yaml index 1726d63b3299e1..727289e567b3d1 100644 --- a/dts/bindings/video/nxp,mipi-csi2rx.yaml +++ b/dts/bindings/video/nxp,mipi-csi2rx.yaml @@ -10,8 +10,7 @@ compatible: "nxp,mipi-csi2rx" include: [base.yaml] -properties: - sensor: - required: true - type: phandle - description: the connected camera sensor +child-binding: + child-binding: + child-binding: + include: video-interfaces.yaml diff --git a/dts/bindings/video/ovti,ov5640.yaml b/dts/bindings/video/ovti,ov5640.yaml index eecb0e3d3192ba..9b10d9b2d27ffd 100644 --- a/dts/bindings/video/ovti,ov5640.yaml +++ b/dts/bindings/video/ovti,ov5640.yaml @@ -18,3 +18,7 @@ properties: description: | The PWDN pin is asserted to disable the sensor. The sensor receives this as an active-high signal. + +child-binding: + child-binding: + include: video-interfaces.yaml diff --git a/dts/bindings/video/ovti,ov7725.yaml b/dts/bindings/video/ovti,ov7725.yaml index 15b557d78e7409..a3648234d65129 100644 --- a/dts/bindings/video/ovti,ov7725.yaml +++ b/dts/bindings/video/ovti,ov7725.yaml @@ -13,3 +13,7 @@ properties: reset. The sensor receives this as an active-low signal. include: i2c-device.yaml + +child-binding: + child-binding: + include: video-interfaces.yaml diff --git a/include/zephyr/drivers/video.h b/include/zephyr/drivers/video.h index b90707383166a8..fb647cac70fb17 100644 --- a/include/zephyr/drivers/video.h +++ b/include/zephyr/drivers/video.h @@ -827,6 +827,30 @@ void video_buffer_release(struct video_buffer *buf); * @} */ +/** + * @brief Get number of bytes per pixel of a pixel format + * + * @param pixfmt FourCC pixel format value (\ref video_pixel_formats). + */ +static inline unsigned int video_pix_fmt_bpp(uint32_t pixfmt) +{ + switch (pixfmt) { + case VIDEO_PIX_FMT_BGGR8: + case VIDEO_PIX_FMT_GBRG8: + case VIDEO_PIX_FMT_GRBG8: + case VIDEO_PIX_FMT_RGGB8: + return 1; + 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; + } +} + #ifdef __cplusplus } #endif diff --git a/soc/nxp/imxrt/imxrt11xx/soc.c b/soc/nxp/imxrt/imxrt11xx/soc.c index 02e35c2d105e99..62726aafa1fdc2 100644 --- a/soc/nxp/imxrt/imxrt11xx/soc.c +++ b/soc/nxp/imxrt/imxrt11xx/soc.c @@ -474,17 +474,6 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_EnableClock(kCLOCK_Video_Mux); VIDEO_MUX->VID_MUX_CTRL.SET = VIDEO_MUX_VID_MUX_CTRL_CSI_SEL_MASK; - /* Configure MIPI CSI-2 Rx clocks */ - rootCfg.div = 8; - rootCfg.mux = kCLOCK_CSI2_ClockRoot_MuxSysPll3Out; - CLOCK_SetRootClock(kCLOCK_Root_Csi2, &rootCfg); - - rootCfg.mux = kCLOCK_CSI2_ESC_ClockRoot_MuxSysPll3Out; - CLOCK_SetRootClock(kCLOCK_Root_Csi2_Esc, &rootCfg); - - rootCfg.mux = kCLOCK_CSI2_UI_ClockRoot_MuxSysPll3Out; - CLOCK_SetRootClock(kCLOCK_Root_Csi2_Ui, &rootCfg); - /* Enable power domain for MIPI CSI-2 */ PGMC_BPC4->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_ON_SOFT_MASK | PGMC_BPC_BPC_POWER_CTRL_ISO_OFF_SOFT_MASK); @@ -682,6 +671,35 @@ void imxrt_post_init_display_interface(void) #endif +#if CONFIG_VIDEO_MCUX_MIPI_CSI2RX +void mipi_csi2rx_clock_set_freq(clock_root_t clock_root, uint32_t rate) +{ + clock_root_config_t rootCfg = {0}; + uint32_t freq; + clock_name_t clk_source; + + switch (clock_root) { + case kCLOCK_Root_Csi2: + rootCfg.mux = kCLOCK_CSI2_ClockRoot_MuxSysPll3Out; + break; + case kCLOCK_Root_Csi2_Esc: + rootCfg.mux = kCLOCK_CSI2_ESC_ClockRoot_MuxSysPll3Out; + break; + case kCLOCK_Root_Csi2_Ui: + rootCfg.mux = kCLOCK_CSI2_UI_ClockRoot_MuxSysPll3Out; + break; + default: + return; + } + + clk_source = CLOCK_GetRootClockSource(clock_root, rootCfg.mux); + freq = CLOCK_GetFreq(clk_source); + __ASSERT(rate < freq, "Requested rate is higher than the maximum clock frequency"); + rootCfg.div = (uint32_t)freq / rate; + CLOCK_SetRootClock(clock_root, &rootCfg); +} +#endif + /** * * @brief Perform basic hardware initialization diff --git a/soc/nxp/imxrt/imxrt11xx/soc.h b/soc/nxp/imxrt/imxrt11xx/soc.h index 88b344541793c3..c5b7b54a294c45 100644 --- a/soc/nxp/imxrt/imxrt11xx/soc.h +++ b/soc/nxp/imxrt/imxrt11xx/soc.h @@ -32,6 +32,10 @@ void imxrt_pre_init_display_interface(void); void imxrt_post_init_display_interface(void); #endif +#if CONFIG_VIDEO_MCUX_MIPI_CSI2RX +void mipi_csi2rx_clock_set_freq(clock_root_t clock_root, uint32_t rate); +#endif + void flexspi_clock_set_div(uint32_t value); uint32_t flexspi_clock_get_freq(void); diff --git a/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay b/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay index 99542ad4c78255..6d6559e4631546 100644 --- a/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay +++ b/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -8,6 +8,8 @@ * (and be extended to test) real hardware. */ +#include + / { test { #address-cells = <1>; @@ -34,6 +36,14 @@ reg = <0x1>; reset-gpios = <&test_gpio 0 0>; powerdown-gpios = <&test_gpio 1 0>; + + port { + ov5640_ep_out: endpoint { + remote-endpoint-label = "mipi_csi2rx_ep_in"; + bus-type = ; + data-lanes = <1 2>; + }; + }; }; }; @@ -43,14 +53,26 @@ status = "okay"; interrupt-parent = <&nvic>; interrupts = <56 1>; - source = <&test_mipi_csi2rx>; }; test_mipi_csi2rx: mipi_csi2rx@33334444 { compatible = "nxp,mipi-csi2rx"; reg = <0x33334444 0x200>; status = "okay"; - sensor = <&test_i2c_ov5640>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + mipi_csi2rx_ep_in: endpoint { + remote-endpoint-label = "ov5640_ep_out"; + data-lanes = <1 2>; + }; + }; + }; }; }; };