Skip to content

Commit a182394

Browse files
trunghieulenxphenrikbrixandersen
authored andcommitted
drivers: video: mipi_csi2rx: Set clocks according to pixel rate
Instead of fixing csi2rx clock frequencies, set them according to the pixel rate got from the camera sensor. Signed-off-by: Trung Hieu Le <[email protected]> Signed-off-by: Phi Bang Nguyen <[email protected]>
1 parent a405051 commit a182394

File tree

7 files changed

+179
-91
lines changed

7 files changed

+179
-91
lines changed

drivers/clock_control/clock_control_mcux_ccm_rev2.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,19 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev,
225225
clock_root = kCLOCK_Root_Netc;
226226
break;
227227
#endif
228+
229+
#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX)
230+
case IMX_CCM_MIPI_CSI2RX_ROOT_CLK:
231+
clock_root = kCLOCK_Root_Csi2;
232+
break;
233+
case IMX_CCM_MIPI_CSI2RX_ESC_CLK:
234+
clock_root = kCLOCK_Root_Csi2_Esc;
235+
break;
236+
case IMX_CCM_MIPI_CSI2RX_UI_CLK:
237+
clock_root = kCLOCK_Root_Csi2_Ui;
238+
break;
239+
#endif
240+
228241
default:
229242
return -EINVAL;
230243
}
@@ -264,6 +277,16 @@ static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev,
264277
*/
265278
return flexspi_clock_set_freq(clock_name, clock_rate);
266279
#endif
280+
281+
#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX)
282+
case IMX_CCM_MIPI_CSI2RX_ROOT_CLK:
283+
return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2, clock_rate);
284+
case IMX_CCM_MIPI_CSI2RX_UI_CLK:
285+
return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Ui, clock_rate);
286+
case IMX_CCM_MIPI_CSI2RX_ESC_CLK:
287+
return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Esc, clock_rate);
288+
#endif
289+
267290
default:
268291
/* Silence unused variable warning */
269292
ARG_UNUSED(clock_rate);

drivers/video/video_mcux_mipi_csi2rx.c

Lines changed: 106 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@
66

77
#define DT_DRV_COMPAT nxp_mipi_csi2rx
88

9+
#include <zephyr/drivers/clock_control.h>
910
#include <zephyr/drivers/video.h>
1011
#include <zephyr/kernel.h>
1112
#include <zephyr/logging/log.h>
13+
#include <soc.h>
1214

1315
#include <fsl_mipi_csi2rx.h>
1416

1517
LOG_MODULE_REGISTER(video_mipi_csi2rx, CONFIG_VIDEO_LOG_LEVEL);
1618

17-
#define DEFAULT_CAMERA_FRAME_RATE 30
19+
#define MAX_SUPPORTED_PIXEL_RATE MHZ(96)
20+
21+
#define ABS(a, b) (a > b ? a - b : b - a)
1822

1923
#define DEVICE_DT_INST_GET_SENSOR_DEV(n) \
2024
DEVICE_DT_GET(DT_GPARENT(DT_NODELABEL( \
@@ -28,100 +32,106 @@ struct mipi_csi2rx_config {
2832

2933
struct mipi_csi2rx_data {
3034
csi2rx_config_t csi2rxConfig;
35+
const struct device *clock_dev;
36+
clock_control_subsys_t clock_root;
37+
clock_control_subsys_t clock_ui;
38+
clock_control_subsys_t clock_esc;
3139
};
3240

33-
static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep,
34-
struct video_format *fmt)
41+
struct mipi_csi2rx_tHsSettleEscClk_config {
42+
uint64_t pixel_rate;
43+
uint8_t tHsSettle_EscClk;
44+
};
45+
46+
/* Must be in pixel rate ascending order */
47+
const struct mipi_csi2rx_tHsSettleEscClk_config tHsSettleEscClk_configs[] = {
48+
{MHZ(24), 0x24},
49+
{MHZ(48), 0x12},
50+
{MHZ(96), 0x09},
51+
};
52+
53+
static int mipi_csi2rx_update_settings(const struct device *dev, enum video_endpoint_id ep)
3554
{
3655
const struct mipi_csi2rx_config *config = dev->config;
3756
struct mipi_csi2rx_data *drv_data = dev->data;
38-
csi2rx_config_t csi2rxConfig = {0};
39-
uint8_t i = 0;
57+
uint8_t bpp;
58+
uint64_t sensor_pixel_rate;
59+
uint32_t root_clk_rate, ui_clk_rate, sensor_byte_clk, best_match;
60+
int ret, ind = 0;
61+
struct video_format fmt;
62+
63+
ret = video_get_format(config->sensor_dev, ep, &fmt);
64+
if (ret) {
65+
LOG_ERR("Cannot get sensor_dev pixel format");
66+
return ret;
67+
}
4068

41-
/*
42-
* Initialize the MIPI CSI2
43-
*
44-
* From D-PHY specification, the T-HSSETTLE should in the range of 85ns+6*UI to 145ns+10*UI
45-
* UI is Unit Interval, equal to the duration of any HS state on the Clock Lane
46-
*
47-
* T-HSSETTLE = csi2rxConfig.tHsSettle_EscClk * (Tperiod of RxClkInEsc)
48-
*
49-
* csi2rxConfig.tHsSettle_EscClk setting for camera:
50-
*
51-
* Resolution | frame rate | T_HS_SETTLE
52-
* =============================================
53-
* 720P | 30 | 0x12
54-
* ---------------------------------------------
55-
* 720P | 15 | 0x17
56-
* ---------------------------------------------
57-
* VGA | 30 | 0x1F
58-
* ---------------------------------------------
59-
* VGA | 15 | 0x24
60-
* ---------------------------------------------
61-
* QVGA | 30 | 0x1F
62-
* ---------------------------------------------
63-
* QVGA | 15 | 0x24
64-
* ---------------------------------------------
65-
*/
66-
static const uint32_t csi2rxHsSettle[][4] = {
67-
{
68-
1280,
69-
720,
70-
30,
71-
0x12,
72-
},
73-
{
74-
1280,
75-
720,
76-
15,
77-
0x17,
78-
},
79-
{
80-
640,
81-
480,
82-
30,
83-
0x1F,
84-
},
85-
{
86-
640,
87-
480,
88-
15,
89-
0x24,
90-
},
91-
{
92-
320,
93-
240,
94-
30,
95-
0x1F,
96-
},
97-
{
98-
320,
99-
240,
100-
15,
101-
0x24,
102-
},
103-
};
104-
105-
for (i = 0; i < ARRAY_SIZE(csi2rxHsSettle); i++) {
106-
if ((fmt->width == csi2rxHsSettle[i][0]) && (fmt->height == csi2rxHsSettle[i][1]) &&
107-
(DEFAULT_CAMERA_FRAME_RATE == csi2rxHsSettle[i][2])) {
108-
csi2rxConfig.tHsSettle_EscClk = csi2rxHsSettle[i][3];
109-
break;
110-
}
69+
ret = video_get_ctrl(config->sensor_dev, VIDEO_CID_PIXEL_RATE, &sensor_pixel_rate);
70+
if (ret) {
71+
LOG_ERR("Can not get sensor_dev pixel rate");
72+
return ret;
11173
}
11274

113-
if (i == ARRAY_SIZE(csi2rxHsSettle)) {
114-
LOG_ERR("Unsupported resolution");
75+
if (sensor_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
76+
LOG_ERR("Sensor pixel rate is not supported");
11577
return -ENOTSUP;
11678
}
11779

118-
drv_data->csi2rxConfig = csi2rxConfig;
80+
bpp = video_pix_fmt_bpp(fmt.pixelformat) * 8;
81+
sensor_byte_clk = sensor_pixel_rate * bpp / drv_data->csi2rxConfig.laneNum / 8;
82+
83+
ret = clock_control_get_rate(drv_data->clock_dev, drv_data->clock_root, &root_clk_rate);
84+
if (ret) {
85+
return ret;
86+
}
87+
88+
if (sensor_byte_clk > root_clk_rate) {
89+
ret = clock_control_set_rate(drv_data->clock_dev, drv_data->clock_root,
90+
(clock_control_subsys_rate_t)sensor_byte_clk);
91+
if (ret) {
92+
return ret;
93+
}
94+
}
95+
96+
ret = clock_control_get_rate(drv_data->clock_dev, drv_data->clock_ui, &ui_clk_rate);
97+
if (ret) {
98+
return ret;
99+
}
100+
101+
if (sensor_pixel_rate > ui_clk_rate) {
102+
ret = clock_control_set_rate(
103+
drv_data->clock_dev, drv_data->clock_ui,
104+
(clock_control_subsys_rate_t)(uint32_t)sensor_pixel_rate);
105+
if (ret) {
106+
return ret;
107+
}
108+
}
109+
110+
/* Find the supported sensor_pixel_rate closest to the desired one */
111+
best_match = tHsSettleEscClk_configs[ind].pixel_rate;
112+
for (uint8_t i = 0; i < ARRAY_SIZE(tHsSettleEscClk_configs); i++) {
113+
if (ABS(tHsSettleEscClk_configs[i].pixel_rate, sensor_pixel_rate) <
114+
ABS(tHsSettleEscClk_configs[i].pixel_rate, best_match)) {
115+
best_match = tHsSettleEscClk_configs[i].pixel_rate;
116+
ind = i;
117+
}
118+
}
119+
120+
drv_data->csi2rxConfig.tHsSettle_EscClk = tHsSettleEscClk_configs[ind].tHsSettle_EscClk;
121+
122+
return ret;
123+
}
124+
125+
static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep,
126+
struct video_format *fmt)
127+
{
128+
const struct mipi_csi2rx_config *config = dev->config;
119129

120130
if (video_set_format(config->sensor_dev, ep, fmt)) {
121131
return -EIO;
122132
}
123133

124-
return 0;
134+
return mipi_csi2rx_update_settings(dev, ep);
125135
}
126136

127137
static int mipi_csi2rx_get_fmt(const struct device *dev, enum video_endpoint_id ep,
@@ -203,20 +213,36 @@ static const struct video_driver_api mipi_csi2rx_driver_api = {
203213
static int mipi_csi2rx_init(const struct device *dev)
204214
{
205215
const struct mipi_csi2rx_config *config = dev->config;
216+
struct mipi_csi2rx_data *drv_data = dev->data;
217+
int ret;
206218

207219
/* Check if there is any sensor device */
208220
if (!device_is_ready(config->sensor_dev)) {
209221
return -ENODEV;
210222
}
211223

212-
return 0;
224+
/*
225+
* CSI2 escape clock should be in the range [60, 80] Mhz. We set it
226+
* to 60 Mhz.
227+
*/
228+
ret = clock_control_set_rate(drv_data->clock_dev, drv_data->clock_esc,
229+
(clock_control_subsys_rate_t)MHZ(60));
230+
if (ret) {
231+
return ret;
232+
}
233+
234+
return mipi_csi2rx_update_settings(dev, VIDEO_EP_ALL);
213235
}
214236

215237
#define MIPI_CSI2RX_INIT(n) \
216238
static struct mipi_csi2rx_data mipi_csi2rx_data_##n = { \
217239
.csi2rxConfig.laneNum = \
218240
DT_PROP_LEN(DT_CHILD(DT_CHILD(DT_INST_CHILD(n, ports), port_1), endpoint), \
219241
data_lanes), \
242+
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
243+
.clock_root = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \
244+
.clock_ui = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 1, name), \
245+
.clock_esc = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 2, name), \
220246
}; \
221247
\
222248
static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \

dts/arm/nxp/nxp_rt11xx.dtsi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,9 @@
901901
compatible = "nxp,mipi-csi2rx";
902902
reg = <0x40810000 0x200>;
903903
status = "disabled";
904+
clocks = <&ccm IMX_CCM_MIPI_CSI2RX_ROOT_CLK 0 0>,
905+
<&ccm IMX_CCM_MIPI_CSI2RX_UI_CLK 0 0>,
906+
<&ccm IMX_CCM_MIPI_CSI2RX_ESC_CLK 0 0>;
904907

905908
ports {
906909
#address-cells = <1>;

include/zephyr/dt-bindings/clock/imx_ccm_rev2.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@
134134
/* NETC */
135135
#define IMX_CCM_NETC_CLK 0x1800UL
136136

137+
/* MIPI CSI2RX */
138+
#define IMX_CCM_MIPI_CSI2RX_ROOT_CLK 0x1900UL
139+
#define IMX_CCM_MIPI_CSI2RX_UI_CLK 0x2000UL
140+
#define IMX_CCM_MIPI_CSI2RX_ESC_CLK 0x2100UL
141+
137142
/* QTMR */
138143
#define IMX_CCM_QTMR_CLK 0x6000UL
139144
#define IMX_CCM_QTMR1_CLK 0x6000UL

soc/nxp/imxrt/imxrt11xx/soc.c

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -474,17 +474,6 @@ static ALWAYS_INLINE void clock_init(void)
474474
CLOCK_EnableClock(kCLOCK_Video_Mux);
475475
VIDEO_MUX->VID_MUX_CTRL.SET = VIDEO_MUX_VID_MUX_CTRL_CSI_SEL_MASK;
476476

477-
/* Configure MIPI CSI-2 Rx clocks */
478-
rootCfg.div = 8;
479-
rootCfg.mux = kCLOCK_CSI2_ClockRoot_MuxSysPll3Out;
480-
CLOCK_SetRootClock(kCLOCK_Root_Csi2, &rootCfg);
481-
482-
rootCfg.mux = kCLOCK_CSI2_ESC_ClockRoot_MuxSysPll3Out;
483-
CLOCK_SetRootClock(kCLOCK_Root_Csi2_Esc, &rootCfg);
484-
485-
rootCfg.mux = kCLOCK_CSI2_UI_ClockRoot_MuxSysPll3Out;
486-
CLOCK_SetRootClock(kCLOCK_Root_Csi2_Ui, &rootCfg);
487-
488477
/* Enable power domain for MIPI CSI-2 */
489478
PGMC_BPC4->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_ON_SOFT_MASK |
490479
PGMC_BPC_BPC_POWER_CTRL_ISO_OFF_SOFT_MASK);
@@ -682,6 +671,41 @@ void imxrt_post_init_display_interface(void)
682671

683672
#endif
684673

674+
#if CONFIG_VIDEO_MCUX_MIPI_CSI2RX
675+
int mipi_csi2rx_clock_set_freq(clock_root_t clock_root, uint32_t rate)
676+
{
677+
clock_root_config_t rootCfg = {0};
678+
uint32_t freq;
679+
clock_name_t clk_source;
680+
681+
switch (clock_root) {
682+
case kCLOCK_Root_Csi2:
683+
rootCfg.mux = kCLOCK_CSI2_ClockRoot_MuxSysPll3Out;
684+
break;
685+
case kCLOCK_Root_Csi2_Esc:
686+
rootCfg.mux = kCLOCK_CSI2_ESC_ClockRoot_MuxSysPll3Out;
687+
break;
688+
case kCLOCK_Root_Csi2_Ui:
689+
rootCfg.mux = kCLOCK_CSI2_UI_ClockRoot_MuxSysPll3Out;
690+
break;
691+
default:
692+
return -EINVAL;
693+
}
694+
695+
clk_source = CLOCK_GetRootClockSource(clock_root, rootCfg.mux);
696+
freq = CLOCK_GetFreq(clk_source);
697+
if (rate > freq) {
698+
LOG_ERR("Requested rate is higher than the maximum clock frequency");
699+
return -EINVAL;
700+
}
701+
702+
rootCfg.div = (uint32_t)freq / rate;
703+
CLOCK_SetRootClock(clock_root, &rootCfg);
704+
705+
return 0;
706+
}
707+
#endif
708+
685709
/**
686710
*
687711
* @brief Perform basic hardware initialization

soc/nxp/imxrt/imxrt11xx/soc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ void imxrt_pre_init_display_interface(void);
3232
void imxrt_post_init_display_interface(void);
3333
#endif
3434

35+
#if CONFIG_VIDEO_MCUX_MIPI_CSI2RX
36+
int mipi_csi2rx_clock_set_freq(clock_root_t clock_root, uint32_t rate);
37+
#endif
38+
3539
void flexspi_clock_set_div(uint32_t value);
3640
uint32_t flexspi_clock_get_freq(void);
3741

tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
compatible = "nxp,mipi-csi2rx";
6161
reg = <0x33334444 0x200>;
6262
status = "okay";
63+
clocks = <&ccm IMX_CCM_MIPI_CSI2RX_ROOT_CLK 0 0>,
64+
<&ccm IMX_CCM_MIPI_CSI2RX_UI_CLK 0 0>,
65+
<&ccm IMX_CCM_MIPI_CSI2RX_ESC_CLK 0 0>;
6366

6467
ports {
6568
#address-cells = <1>;

0 commit comments

Comments
 (0)