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