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 
25 static struct
__csi2_get_format(struct atomisp_mipi_csi2_device * csi2,struct v4l2_subdev_state * sd_state,enum v4l2_subdev_format_whence which,unsigned int pad)26 v4l2_mbus_framefmt *__csi2_get_format(struct atomisp_mipi_csi2_device *csi2,
27 				      struct v4l2_subdev_state *sd_state,
28 				      enum v4l2_subdev_format_whence which,
29 				      unsigned int pad)
30 {
31 	if (which == V4L2_SUBDEV_FORMAT_TRY)
32 		return v4l2_subdev_state_get_format(sd_state, pad);
33 	else
34 		return &csi2->formats[pad];
35 }
36 
37 /*
38  * csi2_enum_mbus_code - Handle pixel format enumeration
39  * @sd     : pointer to v4l2 subdev structure
40  * @fh     : V4L2 subdev file handle
41  * @code   : pointer to v4l2_subdev_pad_mbus_code_enum structure
42  * return -EINVAL or zero on success
43  */
csi2_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)44 static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
45 			       struct v4l2_subdev_state *sd_state,
46 			       struct v4l2_subdev_mbus_code_enum *code)
47 {
48 	const struct atomisp_in_fmt_conv *ic = atomisp_in_fmt_conv;
49 	unsigned int i = 0;
50 
51 	while (ic->code) {
52 		if (i == code->index) {
53 			code->code = ic->code;
54 			return 0;
55 		}
56 		i++, ic++;
57 	}
58 
59 	return -EINVAL;
60 }
61 
62 /*
63  * csi2_get_format - Handle get format by pads subdev method
64  * @sd : pointer to v4l2 subdev structure
65  * @fh : V4L2 subdev file handle
66  * @pad: pad num
67  * @fmt: pointer to v4l2 format structure
68  * return -EINVAL or zero on success
69  */
csi2_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)70 static int csi2_get_format(struct v4l2_subdev *sd,
71 			   struct v4l2_subdev_state *sd_state,
72 			   struct v4l2_subdev_format *fmt)
73 {
74 	struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
75 	struct v4l2_mbus_framefmt *format;
76 
77 	format = __csi2_get_format(csi2, sd_state, fmt->which, fmt->pad);
78 
79 	fmt->format = *format;
80 
81 	return 0;
82 }
83 
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)84 int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
85 			  struct v4l2_subdev_state *sd_state,
86 			  unsigned int which, uint16_t pad,
87 			  struct v4l2_mbus_framefmt *ffmt)
88 {
89 	struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
90 	struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2,
91 								   sd_state,
92 								   which, pad);
93 
94 	if (pad == CSI2_PAD_SINK) {
95 		const struct atomisp_in_fmt_conv *ic;
96 		struct v4l2_mbus_framefmt tmp_ffmt;
97 
98 		ic = atomisp_find_in_fmt_conv(ffmt->code);
99 		if (ic)
100 			actual_ffmt->code = ic->code;
101 		else
102 			actual_ffmt->code = atomisp_in_fmt_conv[0].code;
103 
104 		actual_ffmt->width = clamp_t(u32, ffmt->width,
105 					     ATOM_ISP_MIN_WIDTH,
106 					     ATOM_ISP_MAX_WIDTH);
107 		actual_ffmt->height = clamp_t(u32, ffmt->height,
108 					      ATOM_ISP_MIN_HEIGHT,
109 					      ATOM_ISP_MAX_HEIGHT);
110 		actual_ffmt->field = ffmt->field;
111 
112 		tmp_ffmt = *ffmt = *actual_ffmt;
113 
114 		/* Always use V4L2_FIELD_ANY to match the ISP sink pad */
115 		tmp_ffmt.field = V4L2_FIELD_ANY;
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 /* subdev pad operations */
145 static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
146 	.enum_mbus_code = csi2_enum_mbus_code,
147 	.get_fmt = csi2_get_format,
148 	.set_fmt = csi2_set_format,
149 	.link_validate = v4l2_subdev_link_validate_default,
150 };
151 
152 /* subdev operations */
153 static const struct v4l2_subdev_ops csi2_ops = {
154 	.pad = &csi2_pad_ops,
155 };
156 
157 /* media operations */
158 static const struct media_entity_operations csi2_media_ops = {
159 	.link_validate = v4l2_subdev_link_validate,
160 };
161 
162 /*
163  * ispcsi2_init_entities - Initialize subdev and media entity.
164  * @csi2: Pointer to ispcsi2 structure.
165  * return -ENOMEM or zero on success
166  */
mipi_csi2_init_entities(struct atomisp_mipi_csi2_device * csi2,int port)167 static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2,
168 				   int port)
169 {
170 	struct v4l2_subdev *sd = &csi2->subdev;
171 	struct media_pad *pads = csi2->pads;
172 	struct media_entity *me = &sd->entity;
173 	int ret;
174 
175 	v4l2_subdev_init(sd, &csi2_ops);
176 	snprintf(sd->name, sizeof(sd->name), "ATOM ISP CSI2-port%d", port);
177 
178 	v4l2_set_subdevdata(sd, csi2);
179 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
180 
181 	pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
182 	pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
183 
184 	me->ops = &csi2_media_ops;
185 	me->function = MEDIA_ENT_F_VID_IF_BRIDGE;
186 	ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
187 	if (ret < 0)
188 		return ret;
189 
190 	csi2->formats[CSI2_PAD_SINK].code = atomisp_in_fmt_conv[0].code;
191 	csi2->formats[CSI2_PAD_SOURCE].code = atomisp_in_fmt_conv[0].code;
192 
193 	return 0;
194 }
195 
196 void
atomisp_mipi_csi2_unregister_entities(struct atomisp_mipi_csi2_device * csi2)197 atomisp_mipi_csi2_unregister_entities(struct atomisp_mipi_csi2_device *csi2)
198 {
199 	media_entity_cleanup(&csi2->subdev.entity);
200 	v4l2_device_unregister_subdev(&csi2->subdev);
201 }
202 
atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device * csi2,struct v4l2_device * vdev)203 int atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device *csi2,
204 					struct v4l2_device *vdev)
205 {
206 	int ret;
207 
208 	/* Register the subdev and video nodes. */
209 	ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
210 	if (ret < 0)
211 		goto error;
212 
213 	return 0;
214 
215 error:
216 	atomisp_mipi_csi2_unregister_entities(csi2);
217 	return ret;
218 }
219 
220 static const int LIMIT_SHIFT = 6;	/* Limit numeric range into 31 bits */
221 
222 static int
atomisp_csi2_configure_calc(const short int coeffs[2],int mipi_freq,int def)223 atomisp_csi2_configure_calc(const short int coeffs[2], int mipi_freq, int def)
224 {
225 	/* Delay counter accuracy, 1/0.0625 for ANN/CHT, 1/0.125 for BXT */
226 	static const int accinv = 16;		/* 1 / COUNT_ACC */
227 	int r;
228 
229 	if (mipi_freq >> LIMIT_SHIFT <= 0)
230 		return def;
231 
232 	r = accinv * coeffs[1] * (500000000 >> LIMIT_SHIFT);
233 	r /= mipi_freq >> LIMIT_SHIFT;
234 	r += accinv * coeffs[0];
235 
236 	return r;
237 }
238 
atomisp_csi2_configure_isp2401(struct atomisp_sub_device * asd)239 static void atomisp_csi2_configure_isp2401(struct atomisp_sub_device *asd)
240 {
241 	/*
242 	 * The ISP2401 new input system CSI2+ receiver has several
243 	 * parameters affecting the receiver timings. These depend
244 	 * on the MIPI bus frequency F in Hz (sensor transmitter rate)
245 	 * as follows:
246 	 *	register value = (A/1e9 + B * UI) / COUNT_ACC
247 	 * where
248 	 *	UI = 1 / (2 * F) in seconds
249 	 *	COUNT_ACC = counter accuracy in seconds
250 	 *	For ANN and CHV, COUNT_ACC = 0.0625 ns
251 	 *	For BXT,  COUNT_ACC = 0.125 ns
252 	 * A and B are coefficients from the table below,
253 	 * depending whether the register minimum or maximum value is
254 	 * calculated.
255 	 *				       Minimum     Maximum
256 	 * Clock lane			       A     B     A     B
257 	 * reg_rx_csi_dly_cnt_termen_clane     0     0    38     0
258 	 * reg_rx_csi_dly_cnt_settle_clane    95    -8   300   -16
259 	 * Data lanes
260 	 * reg_rx_csi_dly_cnt_termen_dlane0    0     0    35     4
261 	 * reg_rx_csi_dly_cnt_settle_dlane0   85    -2   145    -6
262 	 * reg_rx_csi_dly_cnt_termen_dlane1    0     0    35     4
263 	 * reg_rx_csi_dly_cnt_settle_dlane1   85    -2   145    -6
264 	 * reg_rx_csi_dly_cnt_termen_dlane2    0     0    35     4
265 	 * reg_rx_csi_dly_cnt_settle_dlane2   85    -2   145    -6
266 	 * reg_rx_csi_dly_cnt_termen_dlane3    0     0    35     4
267 	 * reg_rx_csi_dly_cnt_settle_dlane3   85    -2   145    -6
268 	 *
269 	 * We use the minimum values in the calculations below.
270 	 */
271 	static const short int coeff_clk_termen[] = { 0, 0 };
272 	static const short int coeff_clk_settle[] = { 95, -8 };
273 	static const short int coeff_dat_termen[] = { 0, 0 };
274 	static const short int coeff_dat_settle[] = { 85, -2 };
275 	static const int TERMEN_DEFAULT		  = 0 * 0;
276 	static const int SETTLE_DEFAULT		  = 0x480;
277 
278 	static const hrt_address csi2_port_base[] = {
279 		[ATOMISP_CAMERA_PORT_PRIMARY]     = CSI2_PORT_A_BASE,
280 		[ATOMISP_CAMERA_PORT_SECONDARY]   = CSI2_PORT_B_BASE,
281 		[ATOMISP_CAMERA_PORT_TERTIARY]    = CSI2_PORT_C_BASE,
282 	};
283 	/* Number of lanes on each port, excluding clock lane */
284 	static const unsigned char csi2_port_lanes[] = {
285 		[ATOMISP_CAMERA_PORT_PRIMARY]     = 4,
286 		[ATOMISP_CAMERA_PORT_SECONDARY]   = 2,
287 		[ATOMISP_CAMERA_PORT_TERTIARY]    = 2,
288 	};
289 	static const hrt_address csi2_lane_base[] = {
290 		CSI2_LANE_CL_BASE,
291 		CSI2_LANE_D0_BASE,
292 		CSI2_LANE_D1_BASE,
293 		CSI2_LANE_D2_BASE,
294 		CSI2_LANE_D3_BASE,
295 	};
296 
297 	int clk_termen;
298 	int clk_settle;
299 	int dat_termen;
300 	int dat_settle;
301 
302 	struct v4l2_control ctrl;
303 	struct atomisp_device *isp = asd->isp;
304 	int mipi_freq = 0;
305 	enum atomisp_camera_port port;
306 	int n;
307 
308 	port = isp->inputs[asd->input_curr].port;
309 
310 	ctrl.id = V4L2_CID_LINK_FREQ;
311 	if (v4l2_g_ctrl
312 	    (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0)
313 		mipi_freq = ctrl.value;
314 
315 	clk_termen = atomisp_csi2_configure_calc(coeff_clk_termen, mipi_freq,
316 						 TERMEN_DEFAULT);
317 	clk_settle = atomisp_csi2_configure_calc(coeff_clk_settle, mipi_freq,
318 						 SETTLE_DEFAULT);
319 	dat_termen = atomisp_csi2_configure_calc(coeff_dat_termen, mipi_freq,
320 						 TERMEN_DEFAULT);
321 	dat_settle = atomisp_csi2_configure_calc(coeff_dat_settle, mipi_freq,
322 						 SETTLE_DEFAULT);
323 
324 	for (n = 0; n < csi2_port_lanes[port] + 1; n++) {
325 		hrt_address base = csi2_port_base[port] + csi2_lane_base[n];
326 
327 		atomisp_css2_hw_store_32(base + CSI2_REG_RX_CSI_DLY_CNT_TERMEN,
328 					 n == 0 ? clk_termen : dat_termen);
329 		atomisp_css2_hw_store_32(base + CSI2_REG_RX_CSI_DLY_CNT_SETTLE,
330 					 n == 0 ? clk_settle : dat_settle);
331 	}
332 }
333 
atomisp_csi2_configure(struct atomisp_sub_device * asd)334 void atomisp_csi2_configure(struct atomisp_sub_device *asd)
335 {
336 	if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401))
337 		atomisp_csi2_configure_isp2401(asd);
338 }
339 
340 /*
341  * atomisp_mipi_csi2_cleanup - Routine for module driver cleanup
342  */
atomisp_mipi_csi2_cleanup(struct atomisp_device * isp)343 void atomisp_mipi_csi2_cleanup(struct atomisp_device *isp)
344 {
345 }
346 
atomisp_mipi_csi2_init(struct atomisp_device * isp)347 int atomisp_mipi_csi2_init(struct atomisp_device *isp)
348 {
349 	struct atomisp_mipi_csi2_device *csi2_port;
350 	unsigned int i;
351 	int ret;
352 
353 	ret = atomisp_csi2_bridge_init(isp);
354 	if (ret < 0)
355 		return ret;
356 
357 	for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
358 		csi2_port = &isp->csi2_port[i];
359 		csi2_port->isp = isp;
360 		ret = mipi_csi2_init_entities(csi2_port, i);
361 		if (ret < 0)
362 			goto fail;
363 	}
364 
365 	return 0;
366 
367 fail:
368 	atomisp_mipi_csi2_cleanup(isp);
369 	return ret;
370 }
371