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