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