Skip to content

video: st_mipid02: addition of ST MIPID02 CSI bridge #89764

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

Merged
merged 4 commits into from
Jun 2, 2025
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
1 change: 1 addition & 0 deletions drivers/video/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_IMAGER video_emul_imager.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_RX video_emul_rx.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_IMX335 imx335.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_ST_MIPID02 video_st_mipid02.c)

zephyr_linker_sources(DATA_SECTIONS video.ld)
2 changes: 2 additions & 0 deletions drivers/video/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,6 @@ source "drivers/video/Kconfig.emul_rx"

source "drivers/video/Kconfig.imx335"

source "drivers/video/Kconfig.st_mipid02"

endif # VIDEO
24 changes: 24 additions & 0 deletions drivers/video/Kconfig.st_mipid02
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) 2025 ST Microelectronics
# SPDX-License-Identifier: Apache-2.0

menuconfig VIDEO_ST_MIPID02
bool "ST Microelectronics MIPID02 CSI to DVP bridge"
select I2C
depends on DT_HAS_ST_MIPID02_ENABLED
default y
help
Enable driver for ST MIPID02 CSI to DVP bridge.
The ST MIPID02 is a dual lane CSI-2 deserializer allowing
to output up to 200MHz 12-bit parallel.

if VIDEO_ST_MIPID02

config VIDEO_ST_MIPID02_CAPS_HEAP_SIZE
int "Size of a heap reserved to handle caps"
default 512
help
Heap size reserved in order to handle caps. This could be
reduced or increased depending on the amount of formats
supported by the ST_MIPID02 source device.

endif # VIDEO_ST_MIPID02
40 changes: 40 additions & 0 deletions drivers/video/video_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/video.h>
#include <zephyr/drivers/video-controls.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
Expand Down Expand Up @@ -365,3 +366,42 @@ int video_write_cci_multiregs16(const struct i2c_dt_spec *i2c, const struct vide

return 0;
}

int64_t video_get_csi_link_freq(const struct device *dev, uint8_t bpp, uint8_t lane_nb)
{
struct video_control ctrl = {
.id = VIDEO_CID_LINK_FREQ,
};
struct video_ctrl_query ctrl_query = {
.id = VIDEO_CID_LINK_FREQ,
};
int ret;

/* Try to get the LINK_FREQ value from the source device */
ret = video_get_ctrl(dev, &ctrl);
if (ret < 0) {
goto fallback;
}

ret = video_query_ctrl(dev, &ctrl_query);
if (ret < 0) {
return ret;
}

if (!IN_RANGE(ctrl.val, ctrl_query.range.min, ctrl_query.range.max)) {
return -ERANGE;
}

return (int64_t)ctrl_query.int_menu[ctrl.val];

fallback:
/* If VIDEO_CID_LINK_FREQ is not available, approximate from VIDEO_CID_PIXEL_RATE */
ctrl.id = VIDEO_CID_PIXEL_RATE;
ret = video_get_ctrl(dev, &ctrl);
if (ret < 0) {
return ret;
}

/* CSI D-PHY is using a DDR data bus so bitrate is twice the frequency */
return ctrl.val64 * bpp / (2 * lane_nb);
}
44 changes: 42 additions & 2 deletions drivers/video/video_ctrls.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static inline int check_range(enum video_ctrl_type type, struct video_ctrl_range
}
return 0;
case VIDEO_CTRL_TYPE_MENU:
case VIDEO_CTRL_TYPE_INTEGER_MENU:
if (!IN_RANGE(range.min, 0, range.max) ||
!IN_RANGE(range.def, range.min, range.max)) {
return -ERANGE;
Expand Down Expand Up @@ -107,6 +108,9 @@ static inline void set_type_flag(uint32_t id, enum video_ctrl_type *type, uint32
*type = VIDEO_CTRL_TYPE_INTEGER64;
*flags |= VIDEO_CTRL_FLAG_READ_ONLY;
break;
case VIDEO_CID_LINK_FREQ:
*type = VIDEO_CTRL_TYPE_INTEGER_MENU;
break;
default:
*type = VIDEO_CTRL_TYPE_INTEGER;
break;
Expand Down Expand Up @@ -196,6 +200,28 @@ int video_init_menu_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint
return 0;
}

int video_init_int_menu_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t id,
uint8_t def, const int64_t menu[], size_t menu_len)
{
int ret;

if (!menu) {
return -EINVAL;
}

ret = video_init_ctrl(
ctrl, dev, id,
(struct video_ctrl_range){.min = 0, .max = menu_len - 1, .step = 1, .def = def});

if (ret) {
return ret;
}

ctrl->int_menu = menu;

return 0;
}

/* By definition, the cluster is in manual mode if the master control value is 0 */
static inline bool is_cluster_manual(const struct video_ctrl *master)
{
Expand Down Expand Up @@ -505,6 +531,8 @@ static inline const char *video_get_ctrl_name(uint32_t id)
return "Pixel Rate";
case VIDEO_CID_TEST_PATTERN:
return "Test Pattern";
case VIDEO_CID_LINK_FREQ:
return "Link Frequency";
default:
return NULL;
}
Expand Down Expand Up @@ -540,7 +568,11 @@ int video_query_ctrl(const struct device *dev, struct video_ctrl_query *cq)
cq->type = ctrl->type;
cq->flags = ctrl->flags;
cq->range = ctrl->range;
cq->menu = ctrl->menu;
if (cq->type == VIDEO_CTRL_TYPE_MENU) {
cq->menu = ctrl->menu;
} else if (cq->type == VIDEO_CTRL_TYPE_INTEGER_MENU) {
cq->int_menu = ctrl->int_menu;
}
cq->name = video_get_ctrl_name(cq->id);

return 0;
Expand Down Expand Up @@ -568,6 +600,9 @@ void video_print_ctrl(const struct device *const dev, const struct video_ctrl_qu
case VIDEO_CTRL_TYPE_MENU:
type = "menu";
break;
case VIDEO_CTRL_TYPE_INTEGER_MENU:
type = "integer menu";
break;
case VIDEO_CTRL_TYPE_STRING:
type = "string";
break;
Expand All @@ -594,10 +629,15 @@ void video_print_ctrl(const struct device *const dev, const struct video_ctrl_qu
cq->range.step, cq->range.def, vc.val);
}

if (cq->menu) {
if (cq->type == VIDEO_CTRL_TYPE_MENU && cq->menu) {
while (cq->menu[i]) {
LOG_INF("%*s %u: %s", 32, "", i, cq->menu[i]);
i++;
}
} else if (cq->type == VIDEO_CTRL_TYPE_INTEGER_MENU && cq->int_menu) {
while (cq->int_menu[i]) {
LOG_INF("%*s %u: %lld", 12, "", i, cq->int_menu[i]);
i++;
}
}
}
12 changes: 10 additions & 2 deletions drivers/video/video_ctrls.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ enum video_ctrl_type {
VIDEO_CTRL_TYPE_INTEGER = 2,
/** 64-bit integer type */
VIDEO_CTRL_TYPE_INTEGER64 = 3,
/** Menu type, standard or driver-defined menu */
/** Menu string type, standard or driver-defined menu */
VIDEO_CTRL_TYPE_MENU = 4,
/** String type */
VIDEO_CTRL_TYPE_STRING = 5,
/** Menu integer type, standard or driver-defined menu */
VIDEO_CTRL_TYPE_INTEGER_MENU = 6,
};

struct video_device;
Expand All @@ -54,7 +56,10 @@ struct video_ctrl {
int32_t val;
int64_t val64;
};
const char *const *menu;
union {
const char *const *menu;
const int64_t *int_menu;
};
sys_dnode_t node;
};

Expand All @@ -64,6 +69,9 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t
int video_init_menu_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t id,
uint8_t def, const char *const menu[]);

int video_init_int_menu_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t id,
uint8_t def, const int64_t menu[], size_t menu_len);

void video_cluster_ctrl(struct video_ctrl *ctrls, uint8_t sz);

void video_auto_cluster_ctrl(struct video_ctrl *ctrls, uint8_t sz, bool set_volatile);
Expand Down
Loading