1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module 4 * 5 * Copyright (C) 2012 Texas Instruments, Inc. 6 * 7 * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/uaccess.h> 12 #include <linux/delay.h> 13 #include <linux/device.h> 14 #include <linux/dma-mapping.h> 15 #include <linux/mm.h> 16 #include <linux/sched.h> 17 18 #include "iss.h" 19 #include "iss_regs.h" 20 #include "iss_ipipeif.h" 21 22 static const unsigned int ipipeif_fmts[] = { 23 MEDIA_BUS_FMT_SGRBG10_1X10, 24 MEDIA_BUS_FMT_SRGGB10_1X10, 25 MEDIA_BUS_FMT_SBGGR10_1X10, 26 MEDIA_BUS_FMT_SGBRG10_1X10, 27 MEDIA_BUS_FMT_UYVY8_1X16, 28 MEDIA_BUS_FMT_YUYV8_1X16, 29 }; 30 31 /* 32 * ipipeif_print_status - Print current IPIPEIF Module register values. 33 * @ipipeif: Pointer to ISS ISP IPIPEIF device. 34 * 35 * Also prints other debug information stored in the IPIPEIF module. 36 */ 37 #define IPIPEIF_PRINT_REGISTER(iss, name)\ 38 dev_dbg(iss->dev, "###IPIPEIF " #name "=0x%08x\n", \ 39 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_##name)) 40 41 #define ISIF_PRINT_REGISTER(iss, name)\ 42 dev_dbg(iss->dev, "###ISIF " #name "=0x%08x\n", \ 43 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_##name)) 44 45 #define ISP5_PRINT_REGISTER(iss, name)\ 46 dev_dbg(iss->dev, "###ISP5 " #name "=0x%08x\n", \ 47 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_##name)) 48 49 static void ipipeif_print_status(struct iss_ipipeif_device *ipipeif) 50 { 51 struct iss_device *iss = to_iss_device(ipipeif); 52 53 dev_dbg(iss->dev, "-------------IPIPEIF Register dump-------------\n"); 54 55 IPIPEIF_PRINT_REGISTER(iss, CFG1); 56 IPIPEIF_PRINT_REGISTER(iss, CFG2); 57 58 ISIF_PRINT_REGISTER(iss, SYNCEN); 59 ISIF_PRINT_REGISTER(iss, CADU); 60 ISIF_PRINT_REGISTER(iss, CADL); 61 ISIF_PRINT_REGISTER(iss, MODESET); 62 ISIF_PRINT_REGISTER(iss, CCOLP); 63 ISIF_PRINT_REGISTER(iss, SPH); 64 ISIF_PRINT_REGISTER(iss, LNH); 65 ISIF_PRINT_REGISTER(iss, LNV); 66 ISIF_PRINT_REGISTER(iss, VDINT(0)); 67 ISIF_PRINT_REGISTER(iss, HSIZE); 68 69 ISP5_PRINT_REGISTER(iss, SYSCONFIG); 70 ISP5_PRINT_REGISTER(iss, CTRL); 71 ISP5_PRINT_REGISTER(iss, IRQSTATUS(0)); 72 ISP5_PRINT_REGISTER(iss, IRQENABLE_SET(0)); 73 ISP5_PRINT_REGISTER(iss, IRQENABLE_CLR(0)); 74 75 dev_dbg(iss->dev, "-----------------------------------------------\n"); 76 } 77 78 static void ipipeif_write_enable(struct iss_ipipeif_device *ipipeif, u8 enable) 79 { 80 struct iss_device *iss = to_iss_device(ipipeif); 81 82 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, 83 ISIF_SYNCEN_DWEN, enable ? ISIF_SYNCEN_DWEN : 0); 84 } 85 86 /* 87 * ipipeif_enable - Enable/Disable IPIPEIF. 88 * @enable: enable flag 89 * 90 */ 91 static void ipipeif_enable(struct iss_ipipeif_device *ipipeif, u8 enable) 92 { 93 struct iss_device *iss = to_iss_device(ipipeif); 94 95 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, 96 ISIF_SYNCEN_SYEN, enable ? ISIF_SYNCEN_SYEN : 0); 97 } 98 99 /* ----------------------------------------------------------------------------- 100 * Format- and pipeline-related configuration helpers 101 */ 102 103 /* 104 * ipipeif_set_outaddr - Set memory address to save output image 105 * @ipipeif: Pointer to ISP IPIPEIF device. 106 * @addr: 32-bit memory address aligned on 32 byte boundary. 107 * 108 * Sets the memory address where the output will be saved. 109 */ 110 static void ipipeif_set_outaddr(struct iss_ipipeif_device *ipipeif, u32 addr) 111 { 112 struct iss_device *iss = to_iss_device(ipipeif); 113 114 /* Save address split in Base Address H & L */ 115 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADU, 116 (addr >> (16 + 5)) & ISIF_CADU_MASK); 117 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADL, 118 (addr >> 5) & ISIF_CADL_MASK); 119 } 120 121 static void ipipeif_configure(struct iss_ipipeif_device *ipipeif) 122 { 123 struct iss_device *iss = to_iss_device(ipipeif); 124 const struct iss_format_info *info; 125 struct v4l2_mbus_framefmt *format; 126 u32 isif_ccolp = 0; 127 128 omap4iss_configure_bridge(iss, ipipeif->input); 129 130 /* IPIPEIF_PAD_SINK */ 131 format = &ipipeif->formats[IPIPEIF_PAD_SINK]; 132 133 /* IPIPEIF with YUV422 input from ISIF */ 134 iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG1, 135 IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK); 136 137 /* Select ISIF/IPIPEIF input format */ 138 switch (format->code) { 139 case MEDIA_BUS_FMT_UYVY8_1X16: 140 case MEDIA_BUS_FMT_YUYV8_1X16: 141 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, 142 ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | 143 ISIF_MODESET_CCDW_MASK, 144 ISIF_MODESET_INPMOD_YCBCR16); 145 146 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, 147 IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16); 148 149 break; 150 case MEDIA_BUS_FMT_SGRBG10_1X10: 151 isif_ccolp = ISIF_CCOLP_CP0_F0_GR | 152 ISIF_CCOLP_CP1_F0_R | 153 ISIF_CCOLP_CP2_F0_B | 154 ISIF_CCOLP_CP3_F0_GB; 155 goto cont_raw; 156 case MEDIA_BUS_FMT_SRGGB10_1X10: 157 isif_ccolp = ISIF_CCOLP_CP0_F0_R | 158 ISIF_CCOLP_CP1_F0_GR | 159 ISIF_CCOLP_CP2_F0_GB | 160 ISIF_CCOLP_CP3_F0_B; 161 goto cont_raw; 162 case MEDIA_BUS_FMT_SBGGR10_1X10: 163 isif_ccolp = ISIF_CCOLP_CP0_F0_B | 164 ISIF_CCOLP_CP1_F0_GB | 165 ISIF_CCOLP_CP2_F0_GR | 166 ISIF_CCOLP_CP3_F0_R; 167 goto cont_raw; 168 case MEDIA_BUS_FMT_SGBRG10_1X10: 169 isif_ccolp = ISIF_CCOLP_CP0_F0_GB | 170 ISIF_CCOLP_CP1_F0_B | 171 ISIF_CCOLP_CP2_F0_R | 172 ISIF_CCOLP_CP3_F0_GR; 173 cont_raw: 174 iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, 175 IPIPEIF_CFG2_YUV16); 176 177 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, 178 ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | 179 ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_RAW | 180 ISIF_MODESET_CCDW_2BIT); 181 182 info = omap4iss_video_format_info(format->code); 183 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CGAMMAWD, 184 ISIF_CGAMMAWD_GWDI_MASK, 185 ISIF_CGAMMAWD_GWDI(info->bpp)); 186 187 /* Set RAW Bayer pattern */ 188 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CCOLP, 189 isif_ccolp); 190 break; 191 } 192 193 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SPH, 0 & ISIF_SPH_MASK); 194 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNH, 195 (format->width - 1) & ISIF_LNH_MASK); 196 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNV, 197 (format->height - 1) & ISIF_LNV_MASK); 198 199 /* Generate ISIF0 on the last line of the image */ 200 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_VDINT(0), 201 format->height - 1); 202 203 /* IPIPEIF_PAD_SOURCE_ISIF_SF */ 204 format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF]; 205 206 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_HSIZE, 207 (ipipeif->video_out.bpl_value >> 5) & 208 ISIF_HSIZE_HSIZE_MASK); 209 210 /* IPIPEIF_PAD_SOURCE_VP */ 211 /* Do nothing? */ 212 } 213 214 /* ----------------------------------------------------------------------------- 215 * Interrupt handling 216 */ 217 218 static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif) 219 { 220 struct iss_buffer *buffer; 221 222 /* The ISIF generates VD0 interrupts even when writes are disabled. 223 * deal with it anyway). Disabling the ISIF when no buffer is available 224 * is thus not be enough, we need to handle the situation explicitly. 225 */ 226 if (list_empty(&ipipeif->video_out.dmaqueue)) 227 return; 228 229 ipipeif_write_enable(ipipeif, 0); 230 231 buffer = omap4iss_video_buffer_next(&ipipeif->video_out); 232 if (!buffer) 233 return; 234 235 ipipeif_set_outaddr(ipipeif, buffer->iss_addr); 236 237 ipipeif_write_enable(ipipeif, 1); 238 } 239 240 /* 241 * omap4iss_ipipeif_isr - Configure ipipeif during interframe time. 242 * @ipipeif: Pointer to ISP IPIPEIF device. 243 * @events: IPIPEIF events 244 */ 245 void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events) 246 { 247 if (omap4iss_module_sync_is_stopping(&ipipeif->wait, 248 &ipipeif->stopping)) 249 return; 250 251 if ((events & ISP5_IRQ_ISIF_INT(0)) && 252 (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) 253 ipipeif_isr_buffer(ipipeif); 254 } 255 256 /* ----------------------------------------------------------------------------- 257 * ISP video operations 258 */ 259 260 static int ipipeif_video_queue(struct iss_video *video, 261 struct iss_buffer *buffer) 262 { 263 struct iss_ipipeif_device *ipipeif = container_of(video, 264 struct iss_ipipeif_device, video_out); 265 266 if (!(ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) 267 return -ENODEV; 268 269 ipipeif_set_outaddr(ipipeif, buffer->iss_addr); 270 271 /* 272 * If streaming was enabled before there was a buffer queued 273 * or underrun happened in the ISR, the hardware was not enabled 274 * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set. 275 * Enable it now. 276 */ 277 if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { 278 if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 279 ipipeif_write_enable(ipipeif, 1); 280 ipipeif_enable(ipipeif, 1); 281 iss_video_dmaqueue_flags_clr(video); 282 } 283 284 return 0; 285 } 286 287 static const struct iss_video_operations ipipeif_video_ops = { 288 .queue = ipipeif_video_queue, 289 }; 290 291 /* ----------------------------------------------------------------------------- 292 * V4L2 subdev operations 293 */ 294 295 #define IPIPEIF_DRV_SUBCLK_MASK (OMAP4_ISS_ISP_SUBCLK_IPIPEIF |\ 296 OMAP4_ISS_ISP_SUBCLK_ISIF) 297 /* 298 * ipipeif_set_stream - Enable/Disable streaming on the IPIPEIF module 299 * @sd: ISP IPIPEIF V4L2 subdevice 300 * @enable: Enable/disable stream 301 */ 302 static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) 303 { 304 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 305 struct iss_device *iss = to_iss_device(ipipeif); 306 struct iss_video *video_out = &ipipeif->video_out; 307 int ret = 0; 308 309 if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) { 310 if (enable == ISS_PIPELINE_STREAM_STOPPED) 311 return 0; 312 313 omap4iss_isp_subclk_enable(iss, IPIPEIF_DRV_SUBCLK_MASK); 314 } 315 316 switch (enable) { 317 case ISS_PIPELINE_STREAM_CONTINUOUS: 318 319 ipipeif_configure(ipipeif); 320 ipipeif_print_status(ipipeif); 321 322 /* 323 * When outputting to memory with no buffer available, let the 324 * buffer queue handler start the hardware. A DMA queue flag 325 * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is 326 * a buffer available. 327 */ 328 if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY && 329 !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) 330 break; 331 332 atomic_set(&ipipeif->stopping, 0); 333 if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 334 ipipeif_write_enable(ipipeif, 1); 335 ipipeif_enable(ipipeif, 1); 336 iss_video_dmaqueue_flags_clr(video_out); 337 break; 338 339 case ISS_PIPELINE_STREAM_STOPPED: 340 if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) 341 return 0; 342 if (omap4iss_module_sync_idle(&sd->entity, &ipipeif->wait, 343 &ipipeif->stopping)) 344 ret = -ETIMEDOUT; 345 346 if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 347 ipipeif_write_enable(ipipeif, 0); 348 ipipeif_enable(ipipeif, 0); 349 omap4iss_isp_subclk_disable(iss, IPIPEIF_DRV_SUBCLK_MASK); 350 iss_video_dmaqueue_flags_clr(video_out); 351 break; 352 } 353 354 ipipeif->state = enable; 355 return ret; 356 } 357 358 static struct v4l2_mbus_framefmt * 359 __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, 360 struct v4l2_subdev_state *sd_state, unsigned int pad, 361 enum v4l2_subdev_format_whence which) 362 { 363 if (which == V4L2_SUBDEV_FORMAT_TRY) 364 return v4l2_subdev_get_try_format(&ipipeif->subdev, sd_state, 365 pad); 366 return &ipipeif->formats[pad]; 367 } 368 369 /* 370 * ipipeif_try_format - Try video format on a pad 371 * @ipipeif: ISS IPIPEIF device 372 * @cfg: V4L2 subdev pad config 373 * @pad: Pad number 374 * @fmt: Format 375 */ 376 static void 377 ipipeif_try_format(struct iss_ipipeif_device *ipipeif, 378 struct v4l2_subdev_state *sd_state, unsigned int pad, 379 struct v4l2_mbus_framefmt *fmt, 380 enum v4l2_subdev_format_whence which) 381 { 382 struct v4l2_mbus_framefmt *format; 383 unsigned int width = fmt->width; 384 unsigned int height = fmt->height; 385 unsigned int i; 386 387 switch (pad) { 388 case IPIPEIF_PAD_SINK: 389 /* TODO: If the IPIPEIF output formatter pad is connected 390 * directly to the resizer, only YUV formats can be used. 391 */ 392 for (i = 0; i < ARRAY_SIZE(ipipeif_fmts); i++) { 393 if (fmt->code == ipipeif_fmts[i]) 394 break; 395 } 396 397 /* If not found, use SGRBG10 as default */ 398 if (i >= ARRAY_SIZE(ipipeif_fmts)) 399 fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 400 401 /* Clamp the input size. */ 402 fmt->width = clamp_t(u32, width, 1, 8192); 403 fmt->height = clamp_t(u32, height, 1, 8192); 404 break; 405 406 case IPIPEIF_PAD_SOURCE_ISIF_SF: 407 format = __ipipeif_get_format(ipipeif, sd_state, 408 IPIPEIF_PAD_SINK, 409 which); 410 memcpy(fmt, format, sizeof(*fmt)); 411 412 /* The data formatter truncates the number of horizontal output 413 * pixels to a multiple of 16. To avoid clipping data, allow 414 * callers to request an output size bigger than the input size 415 * up to the nearest multiple of 16. 416 */ 417 fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); 418 fmt->width &= ~15; 419 fmt->height = clamp_t(u32, height, 32, fmt->height); 420 break; 421 422 case IPIPEIF_PAD_SOURCE_VP: 423 format = __ipipeif_get_format(ipipeif, sd_state, 424 IPIPEIF_PAD_SINK, 425 which); 426 memcpy(fmt, format, sizeof(*fmt)); 427 428 fmt->width = clamp_t(u32, width, 32, fmt->width); 429 fmt->height = clamp_t(u32, height, 32, fmt->height); 430 break; 431 } 432 433 /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is 434 * stored on 2 bytes. 435 */ 436 fmt->colorspace = V4L2_COLORSPACE_SRGB; 437 fmt->field = V4L2_FIELD_NONE; 438 } 439 440 /* 441 * ipipeif_enum_mbus_code - Handle pixel format enumeration 442 * @sd : pointer to v4l2 subdev structure 443 * @cfg : V4L2 subdev pad config 444 * @code : pointer to v4l2_subdev_mbus_code_enum structure 445 * return -EINVAL or zero on success 446 */ 447 static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, 448 struct v4l2_subdev_state *sd_state, 449 struct v4l2_subdev_mbus_code_enum *code) 450 { 451 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 452 struct v4l2_mbus_framefmt *format; 453 454 switch (code->pad) { 455 case IPIPEIF_PAD_SINK: 456 if (code->index >= ARRAY_SIZE(ipipeif_fmts)) 457 return -EINVAL; 458 459 code->code = ipipeif_fmts[code->index]; 460 break; 461 462 case IPIPEIF_PAD_SOURCE_ISIF_SF: 463 case IPIPEIF_PAD_SOURCE_VP: 464 /* No format conversion inside IPIPEIF */ 465 if (code->index != 0) 466 return -EINVAL; 467 468 format = __ipipeif_get_format(ipipeif, sd_state, 469 IPIPEIF_PAD_SINK, 470 code->which); 471 472 code->code = format->code; 473 break; 474 475 default: 476 return -EINVAL; 477 } 478 479 return 0; 480 } 481 482 static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, 483 struct v4l2_subdev_state *sd_state, 484 struct v4l2_subdev_frame_size_enum *fse) 485 { 486 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 487 struct v4l2_mbus_framefmt format; 488 489 if (fse->index != 0) 490 return -EINVAL; 491 492 format.code = fse->code; 493 format.width = 1; 494 format.height = 1; 495 ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which); 496 fse->min_width = format.width; 497 fse->min_height = format.height; 498 499 if (format.code != fse->code) 500 return -EINVAL; 501 502 format.code = fse->code; 503 format.width = -1; 504 format.height = -1; 505 ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which); 506 fse->max_width = format.width; 507 fse->max_height = format.height; 508 509 return 0; 510 } 511 512 /* 513 * ipipeif_get_format - Retrieve the video format on a pad 514 * @sd : ISP IPIPEIF V4L2 subdevice 515 * @cfg: V4L2 subdev pad config 516 * @fmt: Format 517 * 518 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 519 * to the format type. 520 */ 521 static int ipipeif_get_format(struct v4l2_subdev *sd, 522 struct v4l2_subdev_state *sd_state, 523 struct v4l2_subdev_format *fmt) 524 { 525 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 526 struct v4l2_mbus_framefmt *format; 527 528 format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which); 529 if (!format) 530 return -EINVAL; 531 532 fmt->format = *format; 533 return 0; 534 } 535 536 /* 537 * ipipeif_set_format - Set the video format on a pad 538 * @sd : ISP IPIPEIF V4L2 subdevice 539 * @cfg: V4L2 subdev pad config 540 * @fmt: Format 541 * 542 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 543 * to the format type. 544 */ 545 static int ipipeif_set_format(struct v4l2_subdev *sd, 546 struct v4l2_subdev_state *sd_state, 547 struct v4l2_subdev_format *fmt) 548 { 549 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 550 struct v4l2_mbus_framefmt *format; 551 552 format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which); 553 if (!format) 554 return -EINVAL; 555 556 ipipeif_try_format(ipipeif, sd_state, fmt->pad, &fmt->format, 557 fmt->which); 558 *format = fmt->format; 559 560 /* Propagate the format from sink to source */ 561 if (fmt->pad == IPIPEIF_PAD_SINK) { 562 format = __ipipeif_get_format(ipipeif, sd_state, 563 IPIPEIF_PAD_SOURCE_ISIF_SF, 564 fmt->which); 565 *format = fmt->format; 566 ipipeif_try_format(ipipeif, sd_state, 567 IPIPEIF_PAD_SOURCE_ISIF_SF, 568 format, fmt->which); 569 570 format = __ipipeif_get_format(ipipeif, sd_state, 571 IPIPEIF_PAD_SOURCE_VP, 572 fmt->which); 573 *format = fmt->format; 574 ipipeif_try_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_VP, 575 format, 576 fmt->which); 577 } 578 579 return 0; 580 } 581 582 static int ipipeif_link_validate(struct v4l2_subdev *sd, 583 struct media_link *link, 584 struct v4l2_subdev_format *source_fmt, 585 struct v4l2_subdev_format *sink_fmt) 586 { 587 /* Check if the two ends match */ 588 if (source_fmt->format.width != sink_fmt->format.width || 589 source_fmt->format.height != sink_fmt->format.height) 590 return -EPIPE; 591 592 if (source_fmt->format.code != sink_fmt->format.code) 593 return -EPIPE; 594 595 return 0; 596 } 597 598 /* 599 * ipipeif_init_formats - Initialize formats on all pads 600 * @sd: ISP IPIPEIF V4L2 subdevice 601 * @fh: V4L2 subdev file handle 602 * 603 * Initialize all pad formats with default values. If fh is not NULL, try 604 * formats are initialized on the file handle. Otherwise active formats are 605 * initialized on the device. 606 */ 607 static int ipipeif_init_formats(struct v4l2_subdev *sd, 608 struct v4l2_subdev_fh *fh) 609 { 610 struct v4l2_subdev_format format; 611 612 memset(&format, 0, sizeof(format)); 613 format.pad = IPIPEIF_PAD_SINK; 614 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 615 format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 616 format.format.width = 4096; 617 format.format.height = 4096; 618 ipipeif_set_format(sd, fh ? fh->state : NULL, &format); 619 620 return 0; 621 } 622 623 /* V4L2 subdev video operations */ 624 static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { 625 .s_stream = ipipeif_set_stream, 626 }; 627 628 /* V4L2 subdev pad operations */ 629 static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { 630 .enum_mbus_code = ipipeif_enum_mbus_code, 631 .enum_frame_size = ipipeif_enum_frame_size, 632 .get_fmt = ipipeif_get_format, 633 .set_fmt = ipipeif_set_format, 634 .link_validate = ipipeif_link_validate, 635 }; 636 637 /* V4L2 subdev operations */ 638 static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { 639 .video = &ipipeif_v4l2_video_ops, 640 .pad = &ipipeif_v4l2_pad_ops, 641 }; 642 643 /* V4L2 subdev internal operations */ 644 static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { 645 .open = ipipeif_init_formats, 646 }; 647 648 /* ----------------------------------------------------------------------------- 649 * Media entity operations 650 */ 651 652 /* 653 * ipipeif_link_setup - Setup IPIPEIF connections 654 * @entity: IPIPEIF media entity 655 * @local: Pad at the local end of the link 656 * @remote: Pad at the remote end of the link 657 * @flags: Link flags 658 * 659 * return -EINVAL or zero on success 660 */ 661 static int ipipeif_link_setup(struct media_entity *entity, 662 const struct media_pad *local, 663 const struct media_pad *remote, u32 flags) 664 { 665 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 666 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 667 struct iss_device *iss = to_iss_device(ipipeif); 668 unsigned int index = local->index; 669 670 /* FIXME: this is actually a hack! */ 671 if (is_media_entity_v4l2_subdev(remote->entity)) 672 index |= 2 << 16; 673 674 switch (index) { 675 case IPIPEIF_PAD_SINK | 2 << 16: 676 /* Read from the sensor CSI2a or CSI2b. */ 677 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 678 ipipeif->input = IPIPEIF_INPUT_NONE; 679 break; 680 } 681 682 if (ipipeif->input != IPIPEIF_INPUT_NONE) 683 return -EBUSY; 684 685 if (remote->entity == &iss->csi2a.subdev.entity) 686 ipipeif->input = IPIPEIF_INPUT_CSI2A; 687 else if (remote->entity == &iss->csi2b.subdev.entity) 688 ipipeif->input = IPIPEIF_INPUT_CSI2B; 689 690 break; 691 692 case IPIPEIF_PAD_SOURCE_ISIF_SF: 693 /* Write to memory */ 694 if (flags & MEDIA_LNK_FL_ENABLED) { 695 if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY) 696 return -EBUSY; 697 ipipeif->output |= IPIPEIF_OUTPUT_MEMORY; 698 } else { 699 ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY; 700 } 701 break; 702 703 case IPIPEIF_PAD_SOURCE_VP | 2 << 16: 704 /* Send to IPIPE/RESIZER */ 705 if (flags & MEDIA_LNK_FL_ENABLED) { 706 if (ipipeif->output & ~IPIPEIF_OUTPUT_VP) 707 return -EBUSY; 708 ipipeif->output |= IPIPEIF_OUTPUT_VP; 709 } else { 710 ipipeif->output &= ~IPIPEIF_OUTPUT_VP; 711 } 712 break; 713 714 default: 715 return -EINVAL; 716 } 717 718 return 0; 719 } 720 721 /* media operations */ 722 static const struct media_entity_operations ipipeif_media_ops = { 723 .link_setup = ipipeif_link_setup, 724 .link_validate = v4l2_subdev_link_validate, 725 }; 726 727 /* 728 * ipipeif_init_entities - Initialize V4L2 subdev and media entity 729 * @ipipeif: ISS ISP IPIPEIF module 730 * 731 * Return 0 on success and a negative error code on failure. 732 */ 733 static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif) 734 { 735 struct v4l2_subdev *sd = &ipipeif->subdev; 736 struct media_pad *pads = ipipeif->pads; 737 struct media_entity *me = &sd->entity; 738 int ret; 739 740 ipipeif->input = IPIPEIF_INPUT_NONE; 741 742 v4l2_subdev_init(sd, &ipipeif_v4l2_ops); 743 sd->internal_ops = &ipipeif_v4l2_internal_ops; 744 strscpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name)); 745 sd->grp_id = BIT(16); /* group ID for iss subdevs */ 746 v4l2_set_subdevdata(sd, ipipeif); 747 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 748 749 pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 750 pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE; 751 pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; 752 753 me->ops = &ipipeif_media_ops; 754 ret = media_entity_pads_init(me, IPIPEIF_PADS_NUM, pads); 755 if (ret < 0) 756 return ret; 757 758 ipipeif_init_formats(sd, NULL); 759 760 ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 761 ipipeif->video_out.ops = &ipipeif_video_ops; 762 ipipeif->video_out.iss = to_iss_device(ipipeif); 763 ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 764 ipipeif->video_out.bpl_alignment = 32; 765 ipipeif->video_out.bpl_zero_padding = 1; 766 ipipeif->video_out.bpl_max = 0x1ffe0; 767 768 return omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF"); 769 } 770 771 void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif) 772 { 773 v4l2_device_unregister_subdev(&ipipeif->subdev); 774 omap4iss_video_unregister(&ipipeif->video_out); 775 } 776 777 int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif, 778 struct v4l2_device *vdev) 779 { 780 int ret; 781 782 /* Register the subdev and video node. */ 783 ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); 784 if (ret < 0) 785 goto error; 786 787 ret = omap4iss_video_register(&ipipeif->video_out, vdev); 788 if (ret < 0) 789 goto error; 790 791 return 0; 792 793 error: 794 omap4iss_ipipeif_unregister_entities(ipipeif); 795 return ret; 796 } 797 798 /* ----------------------------------------------------------------------------- 799 * ISP IPIPEIF initialisation and cleanup 800 */ 801 802 /* 803 * omap4iss_ipipeif_init - IPIPEIF module initialization. 804 * @iss: Device pointer specific to the OMAP4 ISS. 805 * 806 * TODO: Get the initialisation values from platform data. 807 * 808 * Return 0 on success or a negative error code otherwise. 809 */ 810 int omap4iss_ipipeif_init(struct iss_device *iss) 811 { 812 struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 813 814 ipipeif->state = ISS_PIPELINE_STREAM_STOPPED; 815 init_waitqueue_head(&ipipeif->wait); 816 817 return ipipeif_init_entities(ipipeif); 818 } 819 820 /* 821 * omap4iss_ipipeif_create_links() - IPIPEIF pads links creation 822 * @iss: Pointer to ISS device 823 * 824 * return negative error code or zero on success 825 */ 826 int omap4iss_ipipeif_create_links(struct iss_device *iss) 827 { 828 struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 829 830 /* Connect the IPIPEIF subdev to the video node. */ 831 return media_create_pad_link(&ipipeif->subdev.entity, 832 IPIPEIF_PAD_SOURCE_ISIF_SF, 833 &ipipeif->video_out.video.entity, 0, 0); 834 } 835 836 /* 837 * omap4iss_ipipeif_cleanup - IPIPEIF module cleanup. 838 * @iss: Device pointer specific to the OMAP4 ISS. 839 */ 840 void omap4iss_ipipeif_cleanup(struct iss_device *iss) 841 { 842 struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 843 844 media_entity_cleanup(&ipipeif->subdev.entity); 845 } 846