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