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