2 * Support for Medifield PNW Camera Imaging ISP subsystem.
4 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include <media/v4l2-event.h>
23 #include <media/v4l2-mediabus.h>
24 #include "atomisp_cmd.h"
25 #include "atomisp_internal.h"
26 #include "atomisp-regs.h"
28 static struct v4l2_mbus_framefmt *__csi2_get_format(struct
29 atomisp_mipi_csi2_device
32 v4l2_subdev_pad_config *cfg,
34 v4l2_subdev_format_whence
35 which, unsigned int pad)
37 if (which == V4L2_SUBDEV_FORMAT_TRY)
38 return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
40 return &csi2->formats[pad];
44 * csi2_enum_mbus_code - Handle pixel format enumeration
45 * @sd : pointer to v4l2 subdev structure
46 * @fh : V4L2 subdev file handle
47 * @code : pointer to v4l2_subdev_pad_mbus_code_enum structure
48 * return -EINVAL or zero on success
50 static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
51 struct v4l2_subdev_pad_config *cfg,
52 struct v4l2_subdev_mbus_code_enum *code)
54 const struct atomisp_in_fmt_conv *ic = atomisp_in_fmt_conv;
58 if (i == code->index) {
59 code->code = ic->code;
69 * csi2_get_format - Handle get format by pads subdev method
70 * @sd : pointer to v4l2 subdev structure
71 * @fh : V4L2 subdev file handle
73 * @fmt: pointer to v4l2 format structure
74 * return -EINVAL or zero on sucess
76 static int csi2_get_format(struct v4l2_subdev *sd,
77 struct v4l2_subdev_pad_config *cfg,
78 struct v4l2_subdev_format *fmt)
80 struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
81 struct v4l2_mbus_framefmt *format;
83 format = __csi2_get_format(csi2, cfg, fmt->which, fmt->pad);
85 fmt->format = *format;
90 int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
91 struct v4l2_subdev_pad_config *cfg,
92 unsigned int which, uint16_t pad,
93 struct v4l2_mbus_framefmt *ffmt)
95 struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
96 struct v4l2_mbus_framefmt *actual_ffmt =
98 __csi2_get_format(csi2, cfg, which, pad);
100 __csi2_get_format(csi2, cfg, which, pad);
103 if (pad == CSI2_PAD_SINK) {
104 const struct atomisp_in_fmt_conv *ic;
105 struct v4l2_mbus_framefmt tmp_ffmt;
107 ic = atomisp_find_in_fmt_conv(ffmt->code);
109 actual_ffmt->code = ic->code;
111 actual_ffmt->code = atomisp_in_fmt_conv[0].code;
113 actual_ffmt->width = clamp_t(
114 u32, ffmt->width, ATOM_ISP_MIN_WIDTH,
116 actual_ffmt->height = clamp_t(
117 u32, ffmt->height, ATOM_ISP_MIN_HEIGHT,
118 ATOM_ISP_MAX_HEIGHT);
120 tmp_ffmt = *ffmt = *actual_ffmt;
122 return atomisp_csi2_set_ffmt(sd, cfg, which, CSI2_PAD_SOURCE,
126 /* FIXME: DPCM decompression */
127 *actual_ffmt = *ffmt =
129 *__csi2_get_format(csi2, cfg, which, CSI2_PAD_SINK);
131 *__csi2_get_format(csi2, cfg, which, CSI2_PAD_SINK);
138 * csi2_set_format - Handle set format by pads subdev method
139 * @sd : pointer to v4l2 subdev structure
140 * @fh : V4L2 subdev file handle
142 * @fmt: pointer to v4l2 format structure
143 * return -EINVAL or zero on success
145 static int csi2_set_format(struct v4l2_subdev *sd,
146 struct v4l2_subdev_pad_config *cfg,
147 struct v4l2_subdev_format *fmt)
149 return atomisp_csi2_set_ffmt(sd, cfg, fmt->which, fmt->pad,
154 * csi2_set_stream - Enable/Disable streaming on the CSI2 module
155 * @sd: ISP CSI2 V4L2 subdevice
156 * @enable: Enable/disable stream (1/0)
158 * Return 0 on success or a negative error code otherwise.
160 static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
165 /* subdev core operations */
166 static const struct v4l2_subdev_core_ops csi2_core_ops = {
169 /* subdev video operations */
170 static const struct v4l2_subdev_video_ops csi2_video_ops = {
171 .s_stream = csi2_set_stream,
174 /* subdev pad operations */
175 static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
176 .enum_mbus_code = csi2_enum_mbus_code,
177 .get_fmt = csi2_get_format,
178 .set_fmt = csi2_set_format,
179 .link_validate = v4l2_subdev_link_validate_default,
182 /* subdev operations */
183 static const struct v4l2_subdev_ops csi2_ops = {
184 .core = &csi2_core_ops,
185 .video = &csi2_video_ops,
186 .pad = &csi2_pad_ops,
193 * csi2_link_setup - Setup CSI2 connections.
194 * @entity : Pointer to media entity structure
195 * @local : Pointer to local pad array
196 * @remote : Pointer to remote pad array
197 * @flags : Link flags
198 * return -EINVAL or zero on success
200 static int csi2_link_setup(struct media_entity *entity,
201 const struct media_pad *local,
202 const struct media_pad *remote, u32 flags)
204 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
205 struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
206 u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity);
209 case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE:
210 /* not supported yet */
213 case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
214 if (flags & MEDIA_LNK_FL_ENABLED) {
215 if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV)
217 csi2->output |= CSI2_OUTPUT_ISP_SUBDEV;
219 csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV;
224 /* Link from camera to CSI2 is fixed... */
230 /* media operations */
231 static const struct media_entity_operations csi2_media_ops = {
232 .link_setup = csi2_link_setup,
233 .link_validate = v4l2_subdev_link_validate,
237 * ispcsi2_init_entities - Initialize subdev and media entity.
238 * @csi2: Pointer to ispcsi2 structure.
239 * return -ENOMEM or zero on success
241 static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2,
244 struct v4l2_subdev *sd = &csi2->subdev;
245 struct media_pad *pads = csi2->pads;
246 struct media_entity *me = &sd->entity;
249 v4l2_subdev_init(sd, &csi2_ops);
250 snprintf(sd->name, sizeof(sd->name), "ATOM ISP CSI2-port%d", port);
252 v4l2_set_subdevdata(sd, csi2);
253 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
255 pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
256 pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
258 me->ops = &csi2_media_ops;
259 me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
260 ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
264 csi2->formats[CSI2_PAD_SINK].code =
265 csi2->formats[CSI2_PAD_SOURCE].code =
266 atomisp_in_fmt_conv[0].code;
272 atomisp_mipi_csi2_unregister_entities(struct atomisp_mipi_csi2_device *csi2)
274 media_entity_cleanup(&csi2->subdev.entity);
275 v4l2_device_unregister_subdev(&csi2->subdev);
278 int atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device *csi2,
279 struct v4l2_device *vdev)
283 /* Register the subdev and video nodes. */
284 ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
291 atomisp_mipi_csi2_unregister_entities(csi2);
295 static const int LIMIT_SHIFT = 6; /* Limit numeric range into 31 bits */
298 atomisp_csi2_configure_calc(const short int coeffs[2], int mipi_freq, int def)
300 /* Delay counter accuracy, 1/0.0625 for ANN/CHT, 1/0.125 for BXT */
301 static const int accinv = 16; /* 1 / COUNT_ACC */
304 if (mipi_freq >> LIMIT_SHIFT <= 0)
307 r = accinv * coeffs[1] * (500000000 >> LIMIT_SHIFT);
308 r /= mipi_freq >> LIMIT_SHIFT;
309 r += accinv * coeffs[0];
314 static void atomisp_csi2_configure_isp2401(struct atomisp_sub_device *asd)
317 * The ISP2401 new input system CSI2+ receiver has several
318 * parameters affecting the receiver timings. These depend
319 * on the MIPI bus frequency F in Hz (sensor transmitter rate)
321 * register value = (A/1e9 + B * UI) / COUNT_ACC
323 * UI = 1 / (2 * F) in seconds
324 * COUNT_ACC = counter accuracy in seconds
325 * For ANN and CHV, COUNT_ACC = 0.0625 ns
326 * For BXT, COUNT_ACC = 0.125 ns
327 * A and B are coefficients from the table below,
328 * depending whether the register minimum or maximum value is
332 * reg_rx_csi_dly_cnt_termen_clane 0 0 38 0
333 * reg_rx_csi_dly_cnt_settle_clane 95 -8 300 -16
335 * reg_rx_csi_dly_cnt_termen_dlane0 0 0 35 4
336 * reg_rx_csi_dly_cnt_settle_dlane0 85 -2 145 -6
337 * reg_rx_csi_dly_cnt_termen_dlane1 0 0 35 4
338 * reg_rx_csi_dly_cnt_settle_dlane1 85 -2 145 -6
339 * reg_rx_csi_dly_cnt_termen_dlane2 0 0 35 4
340 * reg_rx_csi_dly_cnt_settle_dlane2 85 -2 145 -6
341 * reg_rx_csi_dly_cnt_termen_dlane3 0 0 35 4
342 * reg_rx_csi_dly_cnt_settle_dlane3 85 -2 145 -6
344 * We use the minimum values in the calculations below.
346 static const short int coeff_clk_termen[] = { 0, 0 };
347 static const short int coeff_clk_settle[] = { 95, -8 };
348 static const short int coeff_dat_termen[] = { 0, 0 };
349 static const short int coeff_dat_settle[] = { 85, -2 };
350 static const int TERMEN_DEFAULT = 0 * 0;
351 static const int SETTLE_DEFAULT = 0x480;
352 static const hrt_address csi2_port_base[] = {
353 [ATOMISP_CAMERA_PORT_PRIMARY] = CSI2_PORT_A_BASE,
354 [ATOMISP_CAMERA_PORT_SECONDARY] = CSI2_PORT_B_BASE,
355 [ATOMISP_CAMERA_PORT_TERTIARY] = CSI2_PORT_C_BASE,
357 /* Number of lanes on each port, excluding clock lane */
358 static const unsigned char csi2_port_lanes[] = {
359 [ATOMISP_CAMERA_PORT_PRIMARY] = 4,
360 [ATOMISP_CAMERA_PORT_SECONDARY] = 2,
361 [ATOMISP_CAMERA_PORT_TERTIARY] = 2,
363 static const hrt_address csi2_lane_base[] = {
376 struct v4l2_control ctrl;
377 struct atomisp_device *isp = asd->isp;
378 struct camera_mipi_info *mipi_info;
380 enum atomisp_camera_port port;
384 mipi_info = atomisp_to_sensor_mipi_info(
385 isp->inputs[asd->input_curr].camera);
386 port = mipi_info->port;
388 ctrl.id = V4L2_CID_LINK_FREQ;
390 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0)
391 mipi_freq = ctrl.value;
393 clk_termen = atomisp_csi2_configure_calc(coeff_clk_termen,
394 mipi_freq, TERMEN_DEFAULT);
395 clk_settle = atomisp_csi2_configure_calc(coeff_clk_settle,
396 mipi_freq, SETTLE_DEFAULT);
397 dat_termen = atomisp_csi2_configure_calc(coeff_dat_termen,
398 mipi_freq, TERMEN_DEFAULT);
399 dat_settle = atomisp_csi2_configure_calc(coeff_dat_settle,
400 mipi_freq, SETTLE_DEFAULT);
401 for (n = 0; n < csi2_port_lanes[port] + 1; n++) {
402 hrt_address base = csi2_port_base[port] + csi2_lane_base[n];
403 atomisp_store_uint32(base + CSI2_REG_RX_CSI_DLY_CNT_TERMEN,
404 n == 0 ? clk_termen : dat_termen);
405 atomisp_store_uint32(base + CSI2_REG_RX_CSI_DLY_CNT_SETTLE,
406 n == 0 ? clk_settle : dat_settle);
410 void atomisp_csi2_configure(struct atomisp_sub_device *asd)
412 if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401))
413 atomisp_csi2_configure_isp2401(asd);
417 * atomisp_mipi_csi2_cleanup - Routine for module driver cleanup
419 void atomisp_mipi_csi2_cleanup(struct atomisp_device *isp)
426 int atomisp_mipi_csi2_init(struct atomisp_device *isp)
428 struct atomisp_mipi_csi2_device *csi2_port;
432 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
433 csi2_port = &isp->csi2_port[i];
434 csi2_port->isp = isp;
435 ret = mipi_csi2_init_entities(csi2_port, i);
443 atomisp_mipi_csi2_cleanup(isp);