1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Medifield PNW Camera Imaging ISP subsystem.
4  *
5  * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License version
9  * 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  *
17  */
18 
19 #include <media/v4l2-event.h>
20 #include <media/v4l2-mediabus.h>
21 #include "atomisp_cmd.h"
22 #include "atomisp_internal.h"
23 #include "atomisp-regs.h"
24 
__csi2_get_format(struct atomisp_mipi_csi2_device * csi2,struct v4l2_subdev_state * sd_state,enum v4l2_subdev_format_whence which,unsigned int pad)25 static struct v4l2_mbus_framefmt *__csi2_get_format(struct
26 	atomisp_mipi_csi2_device
27 	* csi2,
28 	struct v4l2_subdev_state *sd_state,
29 	enum
30 	v4l2_subdev_format_whence
31 	which, unsigned int pad)
32 {
33 	if (which == V4L2_SUBDEV_FORMAT_TRY)
34 		return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
35 						  pad);
36 	else
37 		return &csi2->formats[pad];
38 }
39 
40 /*
41  * csi2_enum_mbus_code - Handle pixel format enumeration
42  * @sd     : pointer to v4l2 subdev structure
43  * @fh     : V4L2 subdev file handle
44  * @code   : pointer to v4l2_subdev_pad_mbus_code_enum structure
45  * return -EINVAL or zero on success
46 */
csi2_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)47 static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
48 			       struct v4l2_subdev_state *sd_state,
49 			       struct v4l2_subdev_mbus_code_enum *code)
50 {
51 	const struct atomisp_in_fmt_conv *ic = atomisp_in_fmt_conv;
52 	unsigned int i = 0;
53 
54 	while (ic->code) {
55 		if (i == code->index) {
56 			code->code = ic->code;
57 			return 0;
58 		}
59 		i++, ic++;
60 	}
61 
62 	return -EINVAL;
63 }
64 
65 /*
66  * csi2_get_format - Handle get format by pads subdev method
67  * @sd : pointer to v4l2 subdev structure
68  * @fh : V4L2 subdev file handle
69  * @pad: pad num
70  * @fmt: pointer to v4l2 format structure
71  * return -EINVAL or zero on success
72 */
csi2_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)73 static int csi2_get_format(struct v4l2_subdev *sd,
74 			   struct v4l2_subdev_state *sd_state,
75 			   struct v4l2_subdev_format *fmt)
76 {
77 	struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
78 	struct v4l2_mbus_framefmt *format;
79 
80 	format = __csi2_get_format(csi2, sd_state, fmt->which, fmt->pad);
81 
82 	fmt->format = *format;
83 
84 	return 0;
85 }
86 
atomisp_csi2_set_ffmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,unsigned int which,uint16_t pad,struct v4l2_mbus_framefmt * ffmt)87 int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
88 			  struct v4l2_subdev_state *sd_state,
89 			  unsigned int which, uint16_t pad,
90 			  struct v4l2_mbus_framefmt *ffmt)
91 {
92 	struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
93 	struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2,
94 								   sd_state,
95 								   which, pad);
96 
97 	if (pad == CSI2_PAD_SINK) {
98 		const struct atomisp_in_fmt_conv *ic;
99 		struct v4l2_mbus_framefmt tmp_ffmt;
100 
101 		ic = atomisp_find_in_fmt_conv(ffmt->code);
102 		if (ic)
103 			actual_ffmt->code = ic->code;
104 		else
105 			actual_ffmt->code = atomisp_in_fmt_conv[0].code;
106 
107 		actual_ffmt->width = clamp_t(
108 					 u32, ffmt->width, ATOM_ISP_MIN_WIDTH,
109 					 ATOM_ISP_MAX_WIDTH);
110 		actual_ffmt->height = clamp_t(
111 					  u32, ffmt->height, ATOM_ISP_MIN_HEIGHT,
112 					  ATOM_ISP_MAX_HEIGHT);
113 
114 		tmp_ffmt = *ffmt = *actual_ffmt;
115 
116 		return atomisp_csi2_set_ffmt(sd, sd_state, which,
117 					     CSI2_PAD_SOURCE,
118 					     &tmp_ffmt);
119 	}
120 
121 	/* FIXME: DPCM decompression */
122 	*actual_ffmt = *ffmt = *__csi2_get_format(csi2, sd_state, which,
123 						  CSI2_PAD_SINK);
124 
125 	return 0;
126 }
127 
128 /*
129  * csi2_set_format - Handle set format by pads subdev method
130  * @sd : pointer to v4l2 subdev structure
131  * @fh : V4L2 subdev file handle
132  * @pad: pad num
133  * @fmt: pointer to v4l2 format structure
134  * return -EINVAL or zero on success
135 */
csi2_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)136 static int csi2_set_format(struct v4l2_subdev *sd,
137 			   struct v4l2_subdev_state *sd_state,
138 			   struct v4l2_subdev_format *fmt)
139 {
140 	return atomisp_csi2_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
141 				     &fmt->format);
142 }
143 
144 /*
145  * csi2_set_stream - Enable/Disable streaming on the CSI2 module
146  * @sd: ISP CSI2 V4L2 subdevice
147  * @enable: Enable/disable stream (1/0)
148  *
149  * Return 0 on success or a negative error code otherwise.
150 */
csi2_set_stream(struct v4l2_subdev * sd,int enable)151 static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
152 {
153 	return 0;
154 }
155 
156 /* subdev core operations */
157 static const struct v4l2_subdev_core_ops csi2_core_ops = {
158 };
159 
160 /* subdev video operations */
161 static const struct v4l2_subdev_video_ops csi2_video_ops = {
162 	.s_stream = csi2_set_stream,
163 };
164 
165 /* subdev pad operations */
166 static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
167 	.enum_mbus_code = csi2_enum_mbus_code,
168 	.get_fmt = csi2_get_format,
169 	.set_fmt = csi2_set_format,
170 	.link_validate = v4l2_subdev_link_validate_default,
171 };
172 
173 /* subdev operations */
174 static const struct v4l2_subdev_ops csi2_ops = {
175 	.core = &csi2_core_ops,
176 	.video = &csi2_video_ops,
177 	.pad = &csi2_pad_ops,
178 };
179 
180 /*
181  * csi2_link_setup - Setup CSI2 connections.
182  * @entity : Pointer to media entity structure
183  * @local  : Pointer to local pad array
184  * @remote : Pointer to remote pad array
185  * @flags  : Link flags
186  * return -EINVAL or zero on success
187 */
csi2_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)188 static int csi2_link_setup(struct media_entity *entity,
189 			   const struct media_pad *local,
190 			   const struct media_pad *remote, u32 flags)
191 {
192 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
193 	struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
194 	u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity);
195 
196 	switch (result) {
197 	case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE:
198 		/* not supported yet */
199 		return -EINVAL;
200 
201 	case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
202 		if (flags & MEDIA_LNK_FL_ENABLED) {
203 			if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV)
204 				return -EBUSY;
205 			csi2->output |= CSI2_OUTPUT_ISP_SUBDEV;
206 		} else {
207 			csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV;
208 		}
209 		break;
210 
211 	default:
212 		/* Link from camera to CSI2 is fixed... */
213 		return -EINVAL;
214 	}
215 	return 0;
216 }
217 
218 /* media operations */
219 static const struct media_entity_operations csi2_media_ops = {
220 	.link_setup = csi2_link_setup,
221 	.link_validate = v4l2_subdev_link_validate,
222 };
223 
224 /*
225 * ispcsi2_init_entities - Initialize subdev and media entity.
226 * @csi2: Pointer to ispcsi2 structure.
227 * return -ENOMEM or zero on success
228 */
mipi_csi2_init_entities(struct atomisp_mipi_csi2_device * csi2,int port)229 static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2,
230 				   int port)
231 {
232 	struct v4l2_subdev *sd = &csi2->subdev;
233 	struct media_pad *pads = csi2->pads;
234 	struct media_entity *me = &sd->entity;
235 	int ret;
236 
237 	v4l2_subdev_init(sd, &csi2_ops);
238 	snprintf(sd->name, sizeof(sd->name), "ATOM ISP CSI2-port%d", port);
239 
240 	v4l2_set_subdevdata(sd, csi2);
241 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
242 
243 	pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
244 	pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
245 
246 	me->ops = &csi2_media_ops;
247 	me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
248 	ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
249 	if (ret < 0)
250 		return ret;
251 
252 	csi2->formats[CSI2_PAD_SINK].code =
253 	    csi2->formats[CSI2_PAD_SOURCE].code =
254 		atomisp_in_fmt_conv[0].code;
255 
256 	return 0;
257 }
258 
259 void
atomisp_mipi_csi2_unregister_entities(struct atomisp_mipi_csi2_device * csi2)260 atomisp_mipi_csi2_unregister_entities(struct atomisp_mipi_csi2_device *csi2)
261 {
262 	media_entity_cleanup(&csi2->subdev.entity);
263 	v4l2_device_unregister_subdev(&csi2->subdev);
264 }
265 
atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device * csi2,struct v4l2_device * vdev)266 int atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device *csi2,
267 					struct v4l2_device *vdev)
268 {
269 	int ret;
270 
271 	/* Register the subdev and video nodes. */
272 	ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
273 	if (ret < 0)
274 		goto error;
275 
276 	return 0;
277 
278 error:
279 	atomisp_mipi_csi2_unregister_entities(csi2);
280 	return ret;
281 }
282 
283 static const int LIMIT_SHIFT = 6;	/* Limit numeric range into 31 bits */
284 
285 static int
atomisp_csi2_configure_calc(const short int coeffs[2],int mipi_freq,int def)286 atomisp_csi2_configure_calc(const short int coeffs[2], int mipi_freq, int def)
287 {
288 	/* Delay counter accuracy, 1/0.0625 for ANN/CHT, 1/0.125 for BXT */
289 	static const int accinv = 16;		/* 1 / COUNT_ACC */
290 	int r;
291 
292 	if (mipi_freq >> LIMIT_SHIFT <= 0)
293 		return def;
294 
295 	r = accinv * coeffs[1] * (500000000 >> LIMIT_SHIFT);
296 	r /= mipi_freq >> LIMIT_SHIFT;
297 	r += accinv * coeffs[0];
298 
299 	return r;
300 }
301 
atomisp_csi2_configure_isp2401(struct atomisp_sub_device * asd)302 static void atomisp_csi2_configure_isp2401(struct atomisp_sub_device *asd)
303 {
304 	/*
305 	 * The ISP2401 new input system CSI2+ receiver has several
306 	 * parameters affecting the receiver timings. These depend
307 	 * on the MIPI bus frequency F in Hz (sensor transmitter rate)
308 	 * as follows:
309 	 *	register value = (A/1e9 + B * UI) / COUNT_ACC
310 	 * where
311 	 *	UI = 1 / (2 * F) in seconds
312 	 *	COUNT_ACC = counter accuracy in seconds
313 	 *	For ANN and CHV, COUNT_ACC = 0.0625 ns
314 	 *	For BXT,  COUNT_ACC = 0.125 ns
315 	 * A and B are coefficients from the table below,
316 	 * depending whether the register minimum or maximum value is
317 	 * calculated.
318 	 *				       Minimum     Maximum
319 	 * Clock lane			       A     B     A     B
320 	 * reg_rx_csi_dly_cnt_termen_clane     0     0    38     0
321 	 * reg_rx_csi_dly_cnt_settle_clane    95    -8   300   -16
322 	 * Data lanes
323 	 * reg_rx_csi_dly_cnt_termen_dlane0    0     0    35     4
324 	 * reg_rx_csi_dly_cnt_settle_dlane0   85    -2   145    -6
325 	 * reg_rx_csi_dly_cnt_termen_dlane1    0     0    35     4
326 	 * reg_rx_csi_dly_cnt_settle_dlane1   85    -2   145    -6
327 	 * reg_rx_csi_dly_cnt_termen_dlane2    0     0    35     4
328 	 * reg_rx_csi_dly_cnt_settle_dlane2   85    -2   145    -6
329 	 * reg_rx_csi_dly_cnt_termen_dlane3    0     0    35     4
330 	 * reg_rx_csi_dly_cnt_settle_dlane3   85    -2   145    -6
331 	 *
332 	 * We use the minimum values in the calculations below.
333 	 */
334 	static const short int coeff_clk_termen[] = { 0, 0 };
335 	static const short int coeff_clk_settle[] = { 95, -8 };
336 	static const short int coeff_dat_termen[] = { 0, 0 };
337 	static const short int coeff_dat_settle[] = { 85, -2 };
338 	static const int TERMEN_DEFAULT		  = 0 * 0;
339 	static const int SETTLE_DEFAULT		  = 0x480;
340 
341 	static const hrt_address csi2_port_base[] = {
342 		[ATOMISP_CAMERA_PORT_PRIMARY]     = CSI2_PORT_A_BASE,
343 		[ATOMISP_CAMERA_PORT_SECONDARY]   = CSI2_PORT_B_BASE,
344 		[ATOMISP_CAMERA_PORT_TERTIARY]    = CSI2_PORT_C_BASE,
345 	};
346 	/* Number of lanes on each port, excluding clock lane */
347 	static const unsigned char csi2_port_lanes[] = {
348 		[ATOMISP_CAMERA_PORT_PRIMARY]     = 4,
349 		[ATOMISP_CAMERA_PORT_SECONDARY]   = 2,
350 		[ATOMISP_CAMERA_PORT_TERTIARY]    = 2,
351 	};
352 	static const hrt_address csi2_lane_base[] = {
353 		CSI2_LANE_CL_BASE,
354 		CSI2_LANE_D0_BASE,
355 		CSI2_LANE_D1_BASE,
356 		CSI2_LANE_D2_BASE,
357 		CSI2_LANE_D3_BASE,
358 	};
359 
360 	int clk_termen;
361 	int clk_settle;
362 	int dat_termen;
363 	int dat_settle;
364 
365 	struct v4l2_control ctrl;
366 	struct atomisp_device *isp = asd->isp;
367 	struct camera_mipi_info *mipi_info;
368 	int mipi_freq = 0;
369 	enum atomisp_camera_port port;
370 
371 	int n;
372 
373 	mipi_info = atomisp_to_sensor_mipi_info(
374 			isp->inputs[asd->input_curr].camera);
375 	port = mipi_info->port;
376 
377 	ctrl.id = V4L2_CID_LINK_FREQ;
378 	if (v4l2_g_ctrl
379 	    (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0)
380 		mipi_freq = ctrl.value;
381 
382 	clk_termen = atomisp_csi2_configure_calc(coeff_clk_termen,
383 		     mipi_freq, TERMEN_DEFAULT);
384 	clk_settle = atomisp_csi2_configure_calc(coeff_clk_settle,
385 		     mipi_freq, SETTLE_DEFAULT);
386 	dat_termen = atomisp_csi2_configure_calc(coeff_dat_termen,
387 		     mipi_freq, TERMEN_DEFAULT);
388 	dat_settle = atomisp_csi2_configure_calc(coeff_dat_settle,
389 		     mipi_freq, SETTLE_DEFAULT);
390 	for (n = 0; n < csi2_port_lanes[port] + 1; n++) {
391 		hrt_address base = csi2_port_base[port] + csi2_lane_base[n];
392 
393 		atomisp_css2_hw_store_32(base + CSI2_REG_RX_CSI_DLY_CNT_TERMEN,
394 				     n == 0 ? clk_termen : dat_termen);
395 		atomisp_css2_hw_store_32(base + CSI2_REG_RX_CSI_DLY_CNT_SETTLE,
396 				     n == 0 ? clk_settle : dat_settle);
397 	}
398 }
399 
atomisp_csi2_configure(struct atomisp_sub_device * asd)400 void atomisp_csi2_configure(struct atomisp_sub_device *asd)
401 {
402 	if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401))
403 		atomisp_csi2_configure_isp2401(asd);
404 }
405 
406 /*
407  * atomisp_mipi_csi2_cleanup - Routine for module driver cleanup
408 */
atomisp_mipi_csi2_cleanup(struct atomisp_device * isp)409 void atomisp_mipi_csi2_cleanup(struct atomisp_device *isp)
410 {
411 }
412 
atomisp_mipi_csi2_init(struct atomisp_device * isp)413 int atomisp_mipi_csi2_init(struct atomisp_device *isp)
414 {
415 	struct atomisp_mipi_csi2_device *csi2_port;
416 	unsigned int i;
417 	int ret;
418 
419 	for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
420 		csi2_port = &isp->csi2_port[i];
421 		csi2_port->isp = isp;
422 		ret = mipi_csi2_init_entities(csi2_port, i);
423 		if (ret < 0)
424 			goto fail;
425 	}
426 
427 	return 0;
428 
429 fail:
430 	atomisp_mipi_csi2_cleanup(isp);
431 	return ret;
432 }
433