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