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_pad_config *cfg, 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, cfg, pad); 365 return &ipipeif->formats[pad]; 366 } 367 368 /* 369 * ipipeif_try_format - Try video format on a pad 370 * @ipipeif: ISS IPIPEIF device 371 * @cfg: V4L2 subdev pad config 372 * @pad: Pad number 373 * @fmt: Format 374 */ 375 static void 376 ipipeif_try_format(struct iss_ipipeif_device *ipipeif, 377 struct v4l2_subdev_pad_config *cfg, unsigned int pad, 378 struct v4l2_mbus_framefmt *fmt, 379 enum v4l2_subdev_format_whence which) 380 { 381 struct v4l2_mbus_framefmt *format; 382 unsigned int width = fmt->width; 383 unsigned int height = fmt->height; 384 unsigned int i; 385 386 switch (pad) { 387 case IPIPEIF_PAD_SINK: 388 /* TODO: If the IPIPEIF output formatter pad is connected 389 * directly to the resizer, only YUV formats can be used. 390 */ 391 for (i = 0; i < ARRAY_SIZE(ipipeif_fmts); i++) { 392 if (fmt->code == ipipeif_fmts[i]) 393 break; 394 } 395 396 /* If not found, use SGRBG10 as default */ 397 if (i >= ARRAY_SIZE(ipipeif_fmts)) 398 fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 399 400 /* Clamp the input size. */ 401 fmt->width = clamp_t(u32, width, 1, 8192); 402 fmt->height = clamp_t(u32, height, 1, 8192); 403 break; 404 405 case IPIPEIF_PAD_SOURCE_ISIF_SF: 406 format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, 407 which); 408 memcpy(fmt, format, sizeof(*fmt)); 409 410 /* The data formatter truncates the number of horizontal output 411 * pixels to a multiple of 16. To avoid clipping data, allow 412 * callers to request an output size bigger than the input size 413 * up to the nearest multiple of 16. 414 */ 415 fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); 416 fmt->width &= ~15; 417 fmt->height = clamp_t(u32, height, 32, fmt->height); 418 break; 419 420 case IPIPEIF_PAD_SOURCE_VP: 421 format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, 422 which); 423 memcpy(fmt, format, sizeof(*fmt)); 424 425 fmt->width = clamp_t(u32, width, 32, fmt->width); 426 fmt->height = clamp_t(u32, height, 32, fmt->height); 427 break; 428 } 429 430 /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is 431 * stored on 2 bytes. 432 */ 433 fmt->colorspace = V4L2_COLORSPACE_SRGB; 434 fmt->field = V4L2_FIELD_NONE; 435 } 436 437 /* 438 * ipipeif_enum_mbus_code - Handle pixel format enumeration 439 * @sd : pointer to v4l2 subdev structure 440 * @cfg : V4L2 subdev pad config 441 * @code : pointer to v4l2_subdev_mbus_code_enum structure 442 * return -EINVAL or zero on success 443 */ 444 static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, 445 struct v4l2_subdev_pad_config *cfg, 446 struct v4l2_subdev_mbus_code_enum *code) 447 { 448 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 449 struct v4l2_mbus_framefmt *format; 450 451 switch (code->pad) { 452 case IPIPEIF_PAD_SINK: 453 if (code->index >= ARRAY_SIZE(ipipeif_fmts)) 454 return -EINVAL; 455 456 code->code = ipipeif_fmts[code->index]; 457 break; 458 459 case IPIPEIF_PAD_SOURCE_ISIF_SF: 460 case IPIPEIF_PAD_SOURCE_VP: 461 /* No format conversion inside IPIPEIF */ 462 if (code->index != 0) 463 return -EINVAL; 464 465 format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, 466 code->which); 467 468 code->code = format->code; 469 break; 470 471 default: 472 return -EINVAL; 473 } 474 475 return 0; 476 } 477 478 static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, 479 struct v4l2_subdev_pad_config *cfg, 480 struct v4l2_subdev_frame_size_enum *fse) 481 { 482 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 483 struct v4l2_mbus_framefmt format; 484 485 if (fse->index != 0) 486 return -EINVAL; 487 488 format.code = fse->code; 489 format.width = 1; 490 format.height = 1; 491 ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); 492 fse->min_width = format.width; 493 fse->min_height = format.height; 494 495 if (format.code != fse->code) 496 return -EINVAL; 497 498 format.code = fse->code; 499 format.width = -1; 500 format.height = -1; 501 ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); 502 fse->max_width = format.width; 503 fse->max_height = format.height; 504 505 return 0; 506 } 507 508 /* 509 * ipipeif_get_format - Retrieve the video format on a pad 510 * @sd : ISP IPIPEIF V4L2 subdevice 511 * @cfg: V4L2 subdev pad config 512 * @fmt: Format 513 * 514 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 515 * to the format type. 516 */ 517 static int ipipeif_get_format(struct v4l2_subdev *sd, 518 struct v4l2_subdev_pad_config *cfg, 519 struct v4l2_subdev_format *fmt) 520 { 521 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 522 struct v4l2_mbus_framefmt *format; 523 524 format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); 525 if (!format) 526 return -EINVAL; 527 528 fmt->format = *format; 529 return 0; 530 } 531 532 /* 533 * ipipeif_set_format - Set the video format on a pad 534 * @sd : ISP IPIPEIF V4L2 subdevice 535 * @cfg: V4L2 subdev pad config 536 * @fmt: Format 537 * 538 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 539 * to the format type. 540 */ 541 static int ipipeif_set_format(struct v4l2_subdev *sd, 542 struct v4l2_subdev_pad_config *cfg, 543 struct v4l2_subdev_format *fmt) 544 { 545 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 546 struct v4l2_mbus_framefmt *format; 547 548 format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); 549 if (!format) 550 return -EINVAL; 551 552 ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); 553 *format = fmt->format; 554 555 /* Propagate the format from sink to source */ 556 if (fmt->pad == IPIPEIF_PAD_SINK) { 557 format = __ipipeif_get_format(ipipeif, cfg, 558 IPIPEIF_PAD_SOURCE_ISIF_SF, 559 fmt->which); 560 *format = fmt->format; 561 ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, 562 format, fmt->which); 563 564 format = __ipipeif_get_format(ipipeif, cfg, 565 IPIPEIF_PAD_SOURCE_VP, 566 fmt->which); 567 *format = fmt->format; 568 ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format, 569 fmt->which); 570 } 571 572 return 0; 573 } 574 575 static int ipipeif_link_validate(struct v4l2_subdev *sd, 576 struct media_link *link, 577 struct v4l2_subdev_format *source_fmt, 578 struct v4l2_subdev_format *sink_fmt) 579 { 580 /* Check if the two ends match */ 581 if (source_fmt->format.width != sink_fmt->format.width || 582 source_fmt->format.height != sink_fmt->format.height) 583 return -EPIPE; 584 585 if (source_fmt->format.code != sink_fmt->format.code) 586 return -EPIPE; 587 588 return 0; 589 } 590 591 /* 592 * ipipeif_init_formats - Initialize formats on all pads 593 * @sd: ISP IPIPEIF V4L2 subdevice 594 * @fh: V4L2 subdev file handle 595 * 596 * Initialize all pad formats with default values. If fh is not NULL, try 597 * formats are initialized on the file handle. Otherwise active formats are 598 * initialized on the device. 599 */ 600 static int ipipeif_init_formats(struct v4l2_subdev *sd, 601 struct v4l2_subdev_fh *fh) 602 { 603 struct v4l2_subdev_format format; 604 605 memset(&format, 0, sizeof(format)); 606 format.pad = IPIPEIF_PAD_SINK; 607 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 608 format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 609 format.format.width = 4096; 610 format.format.height = 4096; 611 ipipeif_set_format(sd, fh ? fh->pad : NULL, &format); 612 613 return 0; 614 } 615 616 /* V4L2 subdev video operations */ 617 static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { 618 .s_stream = ipipeif_set_stream, 619 }; 620 621 /* V4L2 subdev pad operations */ 622 static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { 623 .enum_mbus_code = ipipeif_enum_mbus_code, 624 .enum_frame_size = ipipeif_enum_frame_size, 625 .get_fmt = ipipeif_get_format, 626 .set_fmt = ipipeif_set_format, 627 .link_validate = ipipeif_link_validate, 628 }; 629 630 /* V4L2 subdev operations */ 631 static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { 632 .video = &ipipeif_v4l2_video_ops, 633 .pad = &ipipeif_v4l2_pad_ops, 634 }; 635 636 /* V4L2 subdev internal operations */ 637 static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { 638 .open = ipipeif_init_formats, 639 }; 640 641 /* ----------------------------------------------------------------------------- 642 * Media entity operations 643 */ 644 645 /* 646 * ipipeif_link_setup - Setup IPIPEIF connections 647 * @entity: IPIPEIF media entity 648 * @local: Pad at the local end of the link 649 * @remote: Pad at the remote end of the link 650 * @flags: Link flags 651 * 652 * return -EINVAL or zero on success 653 */ 654 static int ipipeif_link_setup(struct media_entity *entity, 655 const struct media_pad *local, 656 const struct media_pad *remote, u32 flags) 657 { 658 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 659 struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 660 struct iss_device *iss = to_iss_device(ipipeif); 661 unsigned int index = local->index; 662 663 /* FIXME: this is actually a hack! */ 664 if (is_media_entity_v4l2_subdev(remote->entity)) 665 index |= 2 << 16; 666 667 switch (index) { 668 case IPIPEIF_PAD_SINK | 2 << 16: 669 /* Read from the sensor CSI2a or CSI2b. */ 670 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 671 ipipeif->input = IPIPEIF_INPUT_NONE; 672 break; 673 } 674 675 if (ipipeif->input != IPIPEIF_INPUT_NONE) 676 return -EBUSY; 677 678 if (remote->entity == &iss->csi2a.subdev.entity) 679 ipipeif->input = IPIPEIF_INPUT_CSI2A; 680 else if (remote->entity == &iss->csi2b.subdev.entity) 681 ipipeif->input = IPIPEIF_INPUT_CSI2B; 682 683 break; 684 685 case IPIPEIF_PAD_SOURCE_ISIF_SF: 686 /* Write to memory */ 687 if (flags & MEDIA_LNK_FL_ENABLED) { 688 if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY) 689 return -EBUSY; 690 ipipeif->output |= IPIPEIF_OUTPUT_MEMORY; 691 } else { 692 ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY; 693 } 694 break; 695 696 case IPIPEIF_PAD_SOURCE_VP | 2 << 16: 697 /* Send to IPIPE/RESIZER */ 698 if (flags & MEDIA_LNK_FL_ENABLED) { 699 if (ipipeif->output & ~IPIPEIF_OUTPUT_VP) 700 return -EBUSY; 701 ipipeif->output |= IPIPEIF_OUTPUT_VP; 702 } else { 703 ipipeif->output &= ~IPIPEIF_OUTPUT_VP; 704 } 705 break; 706 707 default: 708 return -EINVAL; 709 } 710 711 return 0; 712 } 713 714 /* media operations */ 715 static const struct media_entity_operations ipipeif_media_ops = { 716 .link_setup = ipipeif_link_setup, 717 .link_validate = v4l2_subdev_link_validate, 718 }; 719 720 /* 721 * ipipeif_init_entities - Initialize V4L2 subdev and media entity 722 * @ipipeif: ISS ISP IPIPEIF module 723 * 724 * Return 0 on success and a negative error code on failure. 725 */ 726 static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif) 727 { 728 struct v4l2_subdev *sd = &ipipeif->subdev; 729 struct media_pad *pads = ipipeif->pads; 730 struct media_entity *me = &sd->entity; 731 int ret; 732 733 ipipeif->input = IPIPEIF_INPUT_NONE; 734 735 v4l2_subdev_init(sd, &ipipeif_v4l2_ops); 736 sd->internal_ops = &ipipeif_v4l2_internal_ops; 737 strscpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name)); 738 sd->grp_id = BIT(16); /* group ID for iss subdevs */ 739 v4l2_set_subdevdata(sd, ipipeif); 740 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 741 742 pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 743 pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE; 744 pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; 745 746 me->ops = &ipipeif_media_ops; 747 ret = media_entity_pads_init(me, IPIPEIF_PADS_NUM, pads); 748 if (ret < 0) 749 return ret; 750 751 ipipeif_init_formats(sd, NULL); 752 753 ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 754 ipipeif->video_out.ops = &ipipeif_video_ops; 755 ipipeif->video_out.iss = to_iss_device(ipipeif); 756 ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 757 ipipeif->video_out.bpl_alignment = 32; 758 ipipeif->video_out.bpl_zero_padding = 1; 759 ipipeif->video_out.bpl_max = 0x1ffe0; 760 761 return omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF"); 762 } 763 764 void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif) 765 { 766 v4l2_device_unregister_subdev(&ipipeif->subdev); 767 omap4iss_video_unregister(&ipipeif->video_out); 768 } 769 770 int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif, 771 struct v4l2_device *vdev) 772 { 773 int ret; 774 775 /* Register the subdev and video node. */ 776 ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); 777 if (ret < 0) 778 goto error; 779 780 ret = omap4iss_video_register(&ipipeif->video_out, vdev); 781 if (ret < 0) 782 goto error; 783 784 return 0; 785 786 error: 787 omap4iss_ipipeif_unregister_entities(ipipeif); 788 return ret; 789 } 790 791 /* ----------------------------------------------------------------------------- 792 * ISP IPIPEIF initialisation and cleanup 793 */ 794 795 /* 796 * omap4iss_ipipeif_init - IPIPEIF module initialization. 797 * @iss: Device pointer specific to the OMAP4 ISS. 798 * 799 * TODO: Get the initialisation values from platform data. 800 * 801 * Return 0 on success or a negative error code otherwise. 802 */ 803 int omap4iss_ipipeif_init(struct iss_device *iss) 804 { 805 struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 806 807 ipipeif->state = ISS_PIPELINE_STREAM_STOPPED; 808 init_waitqueue_head(&ipipeif->wait); 809 810 return ipipeif_init_entities(ipipeif); 811 } 812 813 /* 814 * omap4iss_ipipeif_create_links() - IPIPEIF pads links creation 815 * @iss: Pointer to ISS device 816 * 817 * return negative error code or zero on success 818 */ 819 int omap4iss_ipipeif_create_links(struct iss_device *iss) 820 { 821 struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 822 823 /* Connect the IPIPEIF subdev to the video node. */ 824 return media_create_pad_link(&ipipeif->subdev.entity, 825 IPIPEIF_PAD_SOURCE_ISIF_SF, 826 &ipipeif->video_out.video.entity, 0, 0); 827 } 828 829 /* 830 * omap4iss_ipipeif_cleanup - IPIPEIF module cleanup. 831 * @iss: Device pointer specific to the OMAP4 ISS. 832 */ 833 void omap4iss_ipipeif_cleanup(struct iss_device *iss) 834 { 835 struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 836 837 media_entity_cleanup(&ipipeif->subdev.entity); 838 } 839