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_pix_fmt_bpp(fmt.pixelformat) * 8;
77 	sensor_byte_clk = sensor_pixel_rate * bpp / drv_data->csi2rxConfig.laneNum / 8;
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_stream_start(const struct device * dev)149 static int mipi_csi2rx_stream_start(const struct device *dev)
150 {
151 	const struct mipi_csi2rx_config *config = dev->config;
152 	struct mipi_csi2rx_data *drv_data = dev->data;
153 
154 	CSI2RX_Init((MIPI_CSI2RX_Type *)config->base, &drv_data->csi2rxConfig);
155 
156 	if (video_stream_start(config->sensor_dev)) {
157 		return -EIO;
158 	}
159 
160 	return 0;
161 }
162 
mipi_csi2rx_stream_stop(const struct device * dev)163 static int mipi_csi2rx_stream_stop(const struct device *dev)
164 {
165 	const struct mipi_csi2rx_config *config = dev->config;
166 
167 	if (video_stream_stop(config->sensor_dev)) {
168 		return -EIO;
169 	}
170 
171 	CSI2RX_Deinit((MIPI_CSI2RX_Type *)config->base);
172 
173 	return 0;
174 }
175 
mipi_csi2rx_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)176 static int mipi_csi2rx_get_caps(const struct device *dev, enum video_endpoint_id ep,
177 				struct video_caps *caps)
178 {
179 	const struct mipi_csi2rx_config *config = dev->config;
180 
181 	if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
182 		return -EINVAL;
183 	}
184 
185 	/* Just forward to sensor dev for now */
186 	return video_get_caps(config->sensor_dev, ep, caps);
187 }
188 
mipi_csi2rx_set_ctrl(const struct device * dev,unsigned int cid,void * value)189 static inline int mipi_csi2rx_set_ctrl(const struct device *dev, unsigned int cid, void *value)
190 {
191 	const struct mipi_csi2rx_config *config = dev->config;
192 
193 	if (config->sensor_dev) {
194 		return video_set_ctrl(config->sensor_dev, cid, value);
195 	}
196 
197 	return -ENOTSUP;
198 }
199 
mipi_csi2rx_set_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival * frmival)200 static int mipi_csi2rx_set_frmival(const struct device *dev, enum video_endpoint_id ep,
201 				   struct video_frmival *frmival)
202 {
203 	const struct mipi_csi2rx_config *config = dev->config;
204 	int ret;
205 
206 	ret = video_set_frmival(config->sensor_dev, ep, frmival);
207 	if (ret) {
208 		LOG_ERR("Cannot set sensor_dev frmival");
209 		return ret;
210 	}
211 
212 	ret = mipi_csi2rx_update_settings(dev, ep);
213 
214 	return ret;
215 }
216 
mipi_csi2rx_get_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival * frmival)217 static int mipi_csi2rx_get_frmival(const struct device *dev, enum video_endpoint_id ep,
218 				   struct video_frmival *frmival)
219 {
220 	const struct mipi_csi2rx_config *config = dev->config;
221 
222 	return video_get_frmival(config->sensor_dev, ep, frmival);
223 }
224 
mipi_csi2rx_cal_frame_size(const struct video_format * fmt)225 static uint64_t mipi_csi2rx_cal_frame_size(const struct video_format *fmt)
226 {
227 	return fmt->height * fmt->width * video_pix_fmt_bpp(fmt->pixelformat) * 8;
228 }
229 
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)230 static uint64_t mipi_csi2rx_estimate_pixel_rate(const struct video_frmival *cur_fmival,
231 						const struct video_frmival *fie_frmival,
232 						const struct video_format *cur_format,
233 						const struct video_format *fie_format,
234 						uint64_t cur_pixel_rate, uint8_t laneNum)
235 {
236 	return mipi_csi2rx_cal_frame_size(cur_format) * fie_frmival->denominator *
237 	       cur_fmival->numerator * cur_pixel_rate /
238 	       (mipi_csi2rx_cal_frame_size(fie_format) * fie_frmival->numerator *
239 		cur_fmival->denominator);
240 }
241 
mipi_csi2rx_enum_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival_enum * fie)242 static int mipi_csi2rx_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
243 				    struct video_frmival_enum *fie)
244 {
245 	const struct mipi_csi2rx_config *config = dev->config;
246 	struct mipi_csi2rx_data *drv_data = dev->data;
247 	int ret;
248 	uint64_t cur_pixel_rate, est_pixel_rate;
249 	struct video_frmival cur_frmival;
250 	struct video_format cur_fmt;
251 
252 	ret = video_enum_frmival(config->sensor_dev, ep, fie);
253 	if (ret) {
254 		return ret;
255 	}
256 
257 	ret = video_get_ctrl(config->sensor_dev, VIDEO_CID_PIXEL_RATE, &cur_pixel_rate);
258 	if (ret) {
259 		LOG_ERR("Cannot get sensor_dev pixel rate");
260 		return ret;
261 	}
262 
263 	ret = video_get_frmival(config->sensor_dev, ep, &cur_frmival);
264 	if (ret) {
265 		LOG_ERR("Cannot get sensor_dev frame rate");
266 		return ret;
267 	}
268 
269 	ret = video_get_format(config->sensor_dev, ep, &cur_fmt);
270 	if (ret) {
271 		LOG_ERR("Cannot get sensor_dev format");
272 		return ret;
273 	}
274 
275 	if (fie->type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
276 		est_pixel_rate = mipi_csi2rx_estimate_pixel_rate(
277 			&cur_frmival, &fie->discrete, &cur_fmt, fie->format, cur_pixel_rate,
278 			drv_data->csi2rxConfig.laneNum);
279 		if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
280 			return -EINVAL;
281 		}
282 
283 	} else {
284 		/* Check the lane rate of the lower bound framerate */
285 		est_pixel_rate = mipi_csi2rx_estimate_pixel_rate(
286 			&cur_frmival, &fie->stepwise.min, &cur_fmt, fie->format, cur_pixel_rate,
287 			drv_data->csi2rxConfig.laneNum);
288 		if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
289 			return -EINVAL;
290 		}
291 
292 		/* Check the lane rate of the upper bound framerate */
293 		est_pixel_rate = mipi_csi2rx_estimate_pixel_rate(
294 			&cur_frmival, &fie->stepwise.max, &cur_fmt, fie->format, cur_pixel_rate,
295 			drv_data->csi2rxConfig.laneNum);
296 		if (est_pixel_rate > MAX_SUPPORTED_PIXEL_RATE) {
297 			fie->stepwise.max.denominator =
298 				(mipi_csi2rx_cal_frame_size(&cur_fmt) * MAX_SUPPORTED_PIXEL_RATE *
299 				 cur_frmival.denominator) /
300 				(mipi_csi2rx_cal_frame_size(fie->format) * cur_pixel_rate *
301 				 cur_frmival.numerator);
302 			fie->stepwise.max.numerator = 1;
303 		}
304 	}
305 
306 	return 0;
307 }
308 
309 static DEVICE_API(video, mipi_csi2rx_driver_api) = {
310 	.get_caps = mipi_csi2rx_get_caps,
311 	.get_format = mipi_csi2rx_get_fmt,
312 	.set_format = mipi_csi2rx_set_fmt,
313 	.stream_start = mipi_csi2rx_stream_start,
314 	.stream_stop = mipi_csi2rx_stream_stop,
315 	.set_ctrl = mipi_csi2rx_set_ctrl,
316 	.set_frmival = mipi_csi2rx_set_frmival,
317 	.get_frmival = mipi_csi2rx_get_frmival,
318 	.enum_frmival = mipi_csi2rx_enum_frmival,
319 };
320 
mipi_csi2rx_init(const struct device * dev)321 static int mipi_csi2rx_init(const struct device *dev)
322 {
323 	const struct mipi_csi2rx_config *config = dev->config;
324 	struct mipi_csi2rx_data *drv_data = dev->data;
325 	int ret;
326 
327 	/* Check if there is any sensor device */
328 	if (!device_is_ready(config->sensor_dev)) {
329 		return -ENODEV;
330 	}
331 
332 	/*
333 	 * CSI2 escape clock should be in the range [60, 80] Mhz. We set it
334 	 * to 60 Mhz.
335 	 */
336 	ret = clock_control_set_rate(drv_data->clock_dev, drv_data->clock_esc,
337 				     (clock_control_subsys_rate_t)MHZ(60));
338 	if (ret) {
339 		return ret;
340 	}
341 
342 	return mipi_csi2rx_update_settings(dev, VIDEO_EP_ALL);
343 }
344 
345 #define MIPI_CSI2RX_INIT(n)                                                                        \
346 	static struct mipi_csi2rx_data mipi_csi2rx_data_##n = {                                    \
347 		.csi2rxConfig.laneNum = DT_PROP_LEN(DT_INST_ENDPOINT_BY_ID(n, 1, 0), data_lanes),  \
348 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),                                \
349 		.clock_root = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name),      \
350 		.clock_ui = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 1, name),        \
351 		.clock_esc = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 2, name),       \
352 	};                                                                                         \
353                                                                                                    \
354 	static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = {                          \
355 		.base = (MIPI_CSI2RX_Type *)DT_INST_REG_ADDR(n),                                   \
356 		.sensor_dev =                                                                      \
357 			DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 1, 0))),     \
358 	};                                                                                         \
359                                                                                                    \
360 	DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n,                   \
361 			      &mipi_csi2rx_config_##n, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY,    \
362 			      &mipi_csi2rx_driver_api);
363 
364 DT_INST_FOREACH_STATUS_OKAY(MIPI_CSI2RX_INIT)
365