1 /*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_mipi_csi2rx
8
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/drivers/video.h>
11 #include <zephyr/drivers/video-controls.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/logging/log.h>
14 #include <soc.h>
15
16 #include <fsl_mipi_csi2rx.h>
17
18 LOG_MODULE_REGISTER(video_mipi_csi2rx, CONFIG_VIDEO_LOG_LEVEL);
19
20 #define MAX_SUPPORTED_PIXEL_RATE MHZ(96)
21
22 #define ABS(a, b) (a > b ? a - b : b - a)
23
24 struct mipi_csi2rx_config {
25 const MIPI_CSI2RX_Type *base;
26 const struct device *sensor_dev;
27 };
28
29 struct mipi_csi2rx_data {
30 csi2rx_config_t csi2rxConfig;
31 const struct device *clock_dev;
32 clock_control_subsys_t clock_root;
33 clock_control_subsys_t clock_ui;
34 clock_control_subsys_t clock_esc;
35 };
36
37 struct mipi_csi2rx_tHsSettleEscClk_config {
38 uint64_t pixel_rate;
39 uint8_t tHsSettle_EscClk;
40 };
41
42 /* Must be in pixel rate ascending order */
43 const struct mipi_csi2rx_tHsSettleEscClk_config tHsSettleEscClk_configs[] = {
44 {MHZ(24), 0x24},
45 {MHZ(48), 0x12},
46 {MHZ(96), 0x09},
47 };
48
mipi_csi2rx_update_settings(const struct device * dev,enum video_endpoint_id ep)49 static int mipi_csi2rx_update_settings(const struct device *dev, enum video_endpoint_id ep)
50 {
51 const struct mipi_csi2rx_config *config = dev->config;
52 struct mipi_csi2rx_data *drv_data = dev->data;
53 uint8_t bpp;
54 uint64_t sensor_pixel_rate;
55 uint32_t root_clk_rate, ui_clk_rate, sensor_byte_clk, best_match;
56 int ret, ind = 0;
57 struct video_format fmt;
58
59 ret = video_get_format(config->sensor_dev, ep, &fmt);
60 if (ret) {
61 LOG_ERR("Cannot get sensor_dev pixel format");
62 return ret;
63 }
64
65 ret = video_get_ctrl(config->sensor_dev, VIDEO_CID_PIXEL_RATE, &sensor_pixel_rate);
66 if (ret) {
67 LOG_ERR("Can not get sensor_dev pixel rate");
68 return ret;
69 }
70
71 if (sensor_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
72 LOG_ERR("Sensor pixel rate is not supported");
73 return -ENOTSUP;
74 }
75
76 bpp = video_bits_per_pixel(fmt.pixelformat);
77 sensor_byte_clk = sensor_pixel_rate * bpp / drv_data->csi2rxConfig.laneNum / BITS_PER_BYTE;
78
79 ret = clock_control_get_rate(drv_data->clock_dev, drv_data->clock_root, &root_clk_rate);
80 if (ret) {
81 return ret;
82 }
83
84 if (sensor_byte_clk > root_clk_rate) {
85 ret = clock_control_set_rate(drv_data->clock_dev, drv_data->clock_root,
86 (clock_control_subsys_rate_t)sensor_byte_clk);
87 if (ret) {
88 return ret;
89 }
90 }
91
92 ret = clock_control_get_rate(drv_data->clock_dev, drv_data->clock_ui, &ui_clk_rate);
93 if (ret) {
94 return ret;
95 }
96
97 if (sensor_pixel_rate > ui_clk_rate) {
98 ret = clock_control_set_rate(
99 drv_data->clock_dev, drv_data->clock_ui,
100 (clock_control_subsys_rate_t)(uint32_t)sensor_pixel_rate);
101 if (ret) {
102 return ret;
103 }
104 }
105
106 /* Find the supported sensor_pixel_rate closest to the desired one */
107 best_match = tHsSettleEscClk_configs[ind].pixel_rate;
108 for (uint8_t i = 0; i < ARRAY_SIZE(tHsSettleEscClk_configs); i++) {
109 if (ABS(tHsSettleEscClk_configs[i].pixel_rate, sensor_pixel_rate) <
110 ABS(tHsSettleEscClk_configs[i].pixel_rate, best_match)) {
111 best_match = tHsSettleEscClk_configs[i].pixel_rate;
112 ind = i;
113 }
114 }
115
116 drv_data->csi2rxConfig.tHsSettle_EscClk = tHsSettleEscClk_configs[ind].tHsSettle_EscClk;
117
118 return ret;
119 }
120
mipi_csi2rx_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)121 static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep,
122 struct video_format *fmt)
123 {
124 const struct mipi_csi2rx_config *config = dev->config;
125
126 if (video_set_format(config->sensor_dev, ep, fmt)) {
127 return -EIO;
128 }
129
130 return mipi_csi2rx_update_settings(dev, ep);
131 }
132
mipi_csi2rx_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)133 static int mipi_csi2rx_get_fmt(const struct device *dev, enum video_endpoint_id ep,
134 struct video_format *fmt)
135 {
136 const struct mipi_csi2rx_config *config = dev->config;
137
138 if (fmt == NULL || (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL)) {
139 return -EINVAL;
140 }
141
142 if (video_get_format(config->sensor_dev, ep, fmt)) {
143 return -EIO;
144 }
145
146 return 0;
147 }
148
mipi_csi2rx_set_stream(const struct device * dev,bool enable)149 static int mipi_csi2rx_set_stream(const struct device *dev, bool enable)
150 {
151 const struct mipi_csi2rx_config *config = dev->config;
152
153 if (enable) {
154 struct mipi_csi2rx_data *drv_data = dev->data;
155
156 CSI2RX_Init((MIPI_CSI2RX_Type *)config->base, &drv_data->csi2rxConfig);
157 if (video_stream_start(config->sensor_dev)) {
158 return -EIO;
159 }
160 } else {
161 if (video_stream_stop(config->sensor_dev)) {
162 return -EIO;
163 }
164 CSI2RX_Deinit((MIPI_CSI2RX_Type *)config->base);
165 }
166
167 return 0;
168 }
169
mipi_csi2rx_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)170 static int mipi_csi2rx_get_caps(const struct device *dev, enum video_endpoint_id ep,
171 struct video_caps *caps)
172 {
173 const struct mipi_csi2rx_config *config = dev->config;
174
175 if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
176 return -EINVAL;
177 }
178
179 /* Just forward to sensor dev for now */
180 return video_get_caps(config->sensor_dev, ep, caps);
181 }
182
mipi_csi2rx_set_ctrl(const struct device * dev,unsigned int cid,void * value)183 static inline int mipi_csi2rx_set_ctrl(const struct device *dev, unsigned int cid, void *value)
184 {
185 const struct mipi_csi2rx_config *config = dev->config;
186
187 if (config->sensor_dev) {
188 return video_set_ctrl(config->sensor_dev, cid, value);
189 }
190
191 return -ENOTSUP;
192 }
193
mipi_csi2rx_set_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival * frmival)194 static int mipi_csi2rx_set_frmival(const struct device *dev, enum video_endpoint_id ep,
195 struct video_frmival *frmival)
196 {
197 const struct mipi_csi2rx_config *config = dev->config;
198 int ret;
199
200 ret = video_set_frmival(config->sensor_dev, ep, frmival);
201 if (ret) {
202 LOG_ERR("Cannot set sensor_dev frmival");
203 return ret;
204 }
205
206 ret = mipi_csi2rx_update_settings(dev, ep);
207
208 return ret;
209 }
210
mipi_csi2rx_get_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival * frmival)211 static int mipi_csi2rx_get_frmival(const struct device *dev, enum video_endpoint_id ep,
212 struct video_frmival *frmival)
213 {
214 const struct mipi_csi2rx_config *config = dev->config;
215
216 return video_get_frmival(config->sensor_dev, ep, frmival);
217 }
218
mipi_csi2rx_cal_frame_size(const struct video_format * fmt)219 static uint64_t mipi_csi2rx_cal_frame_size(const struct video_format *fmt)
220 {
221 return fmt->height * fmt->width * video_bits_per_pixel(fmt->pixelformat);
222 }
223
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)224 static uint64_t mipi_csi2rx_estimate_pixel_rate(const struct video_frmival *cur_fmival,
225 const struct video_frmival *fie_frmival,
226 const struct video_format *cur_format,
227 const struct video_format *fie_format,
228 uint64_t cur_pixel_rate, uint8_t laneNum)
229 {
230 return mipi_csi2rx_cal_frame_size(cur_format) * fie_frmival->denominator *
231 cur_fmival->numerator * cur_pixel_rate /
232 (mipi_csi2rx_cal_frame_size(fie_format) * fie_frmival->numerator *
233 cur_fmival->denominator);
234 }
235
mipi_csi2rx_enum_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival_enum * fie)236 static int mipi_csi2rx_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
237 struct video_frmival_enum *fie)
238 {
239 const struct mipi_csi2rx_config *config = dev->config;
240 struct mipi_csi2rx_data *drv_data = dev->data;
241 int ret;
242 uint64_t cur_pixel_rate, est_pixel_rate;
243 struct video_frmival cur_frmival;
244 struct video_format cur_fmt;
245
246 ret = video_enum_frmival(config->sensor_dev, ep, fie);
247 if (ret) {
248 return ret;
249 }
250
251 ret = video_get_ctrl(config->sensor_dev, VIDEO_CID_PIXEL_RATE, &cur_pixel_rate);
252 if (ret) {
253 LOG_ERR("Cannot get sensor_dev pixel rate");
254 return ret;
255 }
256
257 ret = video_get_frmival(config->sensor_dev, ep, &cur_frmival);
258 if (ret) {
259 LOG_ERR("Cannot get sensor_dev frame rate");
260 return ret;
261 }
262
263 ret = video_get_format(config->sensor_dev, ep, &cur_fmt);
264 if (ret) {
265 LOG_ERR("Cannot get sensor_dev format");
266 return ret;
267 }
268
269 if (fie->type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
270 est_pixel_rate = mipi_csi2rx_estimate_pixel_rate(
271 &cur_frmival, &fie->discrete, &cur_fmt, fie->format, cur_pixel_rate,
272 drv_data->csi2rxConfig.laneNum);
273 if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
274 return -EINVAL;
275 }
276
277 } else {
278 /* Check the lane rate of the lower bound framerate */
279 est_pixel_rate = mipi_csi2rx_estimate_pixel_rate(
280 &cur_frmival, &fie->stepwise.min, &cur_fmt, fie->format, cur_pixel_rate,
281 drv_data->csi2rxConfig.laneNum);
282 if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
283 return -EINVAL;
284 }
285
286 /* Check the lane rate of the upper bound framerate */
287 est_pixel_rate = mipi_csi2rx_estimate_pixel_rate(
288 &cur_frmival, &fie->stepwise.max, &cur_fmt, fie->format, cur_pixel_rate,
289 drv_data->csi2rxConfig.laneNum);
290 if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
291 fie->stepwise.max.denominator =
292 (mipi_csi2rx_cal_frame_size(&cur_fmt) * MAX_SUPPORTED_PIXEL_RATE *
293 cur_frmival.denominator) /
294 (mipi_csi2rx_cal_frame_size(fie->format) * cur_pixel_rate *
295 cur_frmival.numerator);
296 fie->stepwise.max.numerator = 1;
297 }
298 }
299
300 return 0;
301 }
302
303 static DEVICE_API(video, mipi_csi2rx_driver_api) = {
304 .get_caps = mipi_csi2rx_get_caps,
305 .get_format = mipi_csi2rx_get_fmt,
306 .set_format = mipi_csi2rx_set_fmt,
307 .set_stream = mipi_csi2rx_set_stream,
308 .set_ctrl = mipi_csi2rx_set_ctrl,
309 .set_frmival = mipi_csi2rx_set_frmival,
310 .get_frmival = mipi_csi2rx_get_frmival,
311 .enum_frmival = mipi_csi2rx_enum_frmival,
312 };
313
mipi_csi2rx_init(const struct device * dev)314 static int mipi_csi2rx_init(const struct device *dev)
315 {
316 const struct mipi_csi2rx_config *config = dev->config;
317 struct mipi_csi2rx_data *drv_data = dev->data;
318 int ret;
319
320 /* Check if there is any sensor device */
321 if (!device_is_ready(config->sensor_dev)) {
322 return -ENODEV;
323 }
324
325 /*
326 * CSI2 escape clock should be in the range [60, 80] Mhz. We set it
327 * to 60 Mhz.
328 */
329 ret = clock_control_set_rate(drv_data->clock_dev, drv_data->clock_esc,
330 (clock_control_subsys_rate_t)MHZ(60));
331 if (ret) {
332 return ret;
333 }
334
335 return mipi_csi2rx_update_settings(dev, VIDEO_EP_ALL);
336 }
337
338 #define MIPI_CSI2RX_INIT(n) \
339 static struct mipi_csi2rx_data mipi_csi2rx_data_##n = { \
340 .csi2rxConfig.laneNum = DT_PROP_LEN(DT_INST_ENDPOINT_BY_ID(n, 1, 0), data_lanes), \
341 .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
342 .clock_root = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \
343 .clock_ui = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 1, name), \
344 .clock_esc = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 2, name), \
345 }; \
346 \
347 static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \
348 .base = (MIPI_CSI2RX_Type *)DT_INST_REG_ADDR(n), \
349 .sensor_dev = \
350 DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 1, 0))), \
351 }; \
352 \
353 DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n, \
354 &mipi_csi2rx_config_##n, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
355 &mipi_csi2rx_driver_api);
356
357 DT_INST_FOREACH_STATUS_OKAY(MIPI_CSI2RX_INIT)
358