-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Add mipi csi2 rx driver #71859
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
Add mipi csi2 rx driver #71859
Changes from all commits
e31e28d
0328e92
dafbdbd
bcd21fc
3d13f14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # NXP MIPI CSI-2 Rx driver configuration option | ||
|
|
||
| # Copyright 2024 NXP | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| config VIDEO_MCUX_MIPI_CSI2RX | ||
| bool "NXP MIPI CSI-2 Rx driver" | ||
| default y | ||
| depends on DT_HAS_NXP_MIPI_CSI2RX_ENABLED | ||
| select VIDEO_MCUX_CSI | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| /* | ||
| * Copyright 2024 NXP | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #define DT_DRV_COMPAT nxp_mipi_csi2rx | ||
|
|
||
| #include <fsl_mipi_csi2rx.h> | ||
|
|
||
| #include <zephyr/drivers/video.h> | ||
| #include <zephyr/kernel.h> | ||
|
|
||
| #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL | ||
| #include <zephyr/logging/log.h> | ||
| LOG_MODULE_REGISTER(mipi_csi); | ||
|
|
||
| /* | ||
| * 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 | ||
ngphibang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #define DEFAULT_CAMERA_FRAME_RATE 30 | ||
|
||
|
|
||
| struct mipi_csi2rx_config { | ||
| const MIPI_CSI2RX_Type *base; | ||
| const struct device *sensor_dev; | ||
| }; | ||
|
|
||
| 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) | ||
| { | ||
| 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; | ||
|
|
||
| /* | ||
| * 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; | ||
| } | ||
| } | ||
|
|
||
| if (i == ARRAY_SIZE(csi2rxHsSettle)) { | ||
| LOG_ERR("Unsupported resolution"); | ||
| return -ENOTSUP; | ||
| } | ||
|
|
||
| drv_data->csi2rxConfig = csi2rxConfig; | ||
|
|
||
| if (video_set_format(config->sensor_dev, ep, fmt)) { | ||
| return -EIO; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int mipi_csi2rx_get_fmt(const struct device *dev, enum video_endpoint_id ep, | ||
| struct video_format *fmt) | ||
| { | ||
| const struct mipi_csi2rx_config *config = dev->config; | ||
|
|
||
| if (fmt == NULL || ep != VIDEO_EP_OUT) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| if (video_get_format(config->sensor_dev, ep, fmt)) { | ||
| return -EIO; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int mipi_csi2rx_stream_start(const struct device *dev) | ||
| { | ||
| const struct mipi_csi2rx_config *config = dev->config; | ||
| struct mipi_csi2rx_data *drv_data = dev->data; | ||
|
|
||
| CSI2RX_Init((MIPI_CSI2RX_Type *)config->base, &drv_data->csi2rxConfig); | ||
|
|
||
| if (video_stream_start(config->sensor_dev)) { | ||
| return -EIO; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int mipi_csi2rx_stream_stop(const struct device *dev) | ||
| { | ||
| const struct mipi_csi2rx_config *config = dev->config; | ||
|
|
||
| if (video_stream_stop(config->sensor_dev)) { | ||
| return -EIO; | ||
| } | ||
|
|
||
| CSI2RX_Deinit((MIPI_CSI2RX_Type *)config->base); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int mipi_csi2rx_get_caps(const struct device *dev, enum video_endpoint_id ep, | ||
| struct video_caps *caps) | ||
| { | ||
| const struct mipi_csi2rx_config *config = dev->config; | ||
|
|
||
| if (ep != VIDEO_EP_OUT) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| /* Just forward to sensor dev for now */ | ||
| return video_get_caps(config->sensor_dev, ep, caps); | ||
| } | ||
|
|
||
| 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, | ||
| }; | ||
|
|
||
| static int mipi_csi2rx_init(const struct device *dev) | ||
| { | ||
| const struct mipi_csi2rx_config *config = dev->config; | ||
|
|
||
| /* Check if there is any sensor device */ | ||
| if (!device_is_ready(config->sensor_dev)) { | ||
| return -ENODEV; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| #define MIPI_CSI2RX_INIT(n) \ | ||
| static struct mipi_csi2rx_data mipi_csi2rx_data_##n; \ | ||
| \ | ||
| 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)), \ | ||
| }; \ | ||
| \ | ||
| DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n, \ | ||
| &mipi_csi2rx_config_##n, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ | ||
| &mipi_csi2rx_driver_api); | ||
|
|
||
| DT_INST_FOREACH_STATUS_OKAY(MIPI_CSI2RX_INIT) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # | ||
| # Copyright 2024 NXP | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
|
|
||
| description: NXP MIPI CSI-2 Rx interface | ||
|
|
||
| compatible: "nxp,mipi-csi2rx" | ||
|
|
||
| include: [base.yaml] | ||
|
|
||
| properties: | ||
| sensor: | ||
| required: true | ||
| type: phandle | ||
| description: the connected camera sensor |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /* | ||
| * Copyright 2024 NXP | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * Names in this file should be chosen in a way that won't conflict | ||
| * with real-world devicetree nodes, to allow these tests to run on | ||
| * (and be extended to test) real hardware. | ||
| */ | ||
|
|
||
| / { | ||
| test { | ||
| #address-cells = <1>; | ||
| #size-cells = <1>; | ||
|
|
||
| test_gpio: gpio@deadbeef { | ||
| compatible = "vnd,gpio"; | ||
| gpio-controller; | ||
| reg = <0xdeadbeef 0x1000>; | ||
| #gpio-cells = <0x2>; | ||
| status = "okay"; | ||
| }; | ||
|
|
||
| test_i2c: i2c@11112222 { | ||
| #address-cells = <1>; | ||
| #size-cells = <0>; | ||
| compatible = "vnd,i2c"; | ||
| reg = <0x11112222 0x1000>; | ||
| status = "okay"; | ||
| clock-frequency = <100000>; | ||
|
|
||
| test_i2c_ov5640: ov5640@1 { | ||
| compatible = "ovti,ov5640"; | ||
| reg = <0x1>; | ||
| reset-gpios = <&test_gpio 0 0>; | ||
| powerdown-gpios = <&test_gpio 1 0>; | ||
| }; | ||
| }; | ||
|
|
||
| test_csi: csi@22223333 { | ||
| compatible = "nxp,imx-csi"; | ||
| reg = <0x22223333 0x4000>; | ||
| 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>; | ||
| }; | ||
| }; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VIDEO_MCUX_CSIcurrently depends onHAS_MCUX_CSI, which we don't select for the RT11xx. Perhaps the best choice is to remove the dependency onHAS_MCUX_CSIin #72420?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is already done in #71860 as a "misc fix".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise, this does not relate to this PR, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I missed that PR- it does relate, because the
select VIDEO_MCUX_CSIstatement here will trigger a Kconfig error on the RT11xx series when building the CSI2X driver, becauseVIDEO_MCUX_CSIcurrently has a dependency onHAS_MCUX_CSI. All this means is that this PR is dependent on #71860, as far as I can tellUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this CSI2Rx driver doesn't build. Both CSI and CSI2Rx will build only when there is a camera sensor connected to them and the build is triggered in the camera sensor overlay (another PR). By default, CSI2Rx and CSI nodes are disabled.
BTW, this PR is dependent on #72420 because of the change from "sensor" to "sdev".
So, there is a mutual dependency here ...
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danieldegrasse : So, is it better to move the commit b226ded to #71860 or make it a standalone PR ? I think the first option is better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine to move b226dedfbc2c4cbcf37dd1c86e85895a4660afa3 into #71860.
Maybe I'm not following here- are you saying that since the CSI2Rx driver does not build as part of this PR, there is no dependency on #71860? Generally, we want to be able to build code that is introduced with a PR as part of that PR. Finding out there is a build error later on means we have to fix something in the tree, which is less clean than getting it right the first time around
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay ...
This PR is now dependent on #72623 and #71854 as #71860 is merged.
Is it ok for you now ?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think this is ok. To make sure I understand the dependency chain here:
#72623: no dependencies
#71854: no dependencies
#71859: dependent on #72623 and #71854
#72420: dependent on #71859 (and its dependencies)
#72434: dependent on #72420 (and its dependencies)
#72632: dependent on #72434 (and its dependencies)
Is this all accurate? I'm not clear why this PR depends on #71854, but you know this code best
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danieldegrasse It's nearly correct. The dependency chain are:
#72435: no dependencies
#71854: no dependencies
#72623: no dependencies (merged)
#72631: no dependencies (merged)
#71859: dependent on #72623 (merged) and #71854
#72420: dependent on #71859 (and its dependencies)
#72434: dependent on #71859 (and its dependencies)
#72633: dependent on #72434 (and its dependencies)