171414826SSergio Aguirre /* 271414826SSergio Aguirre * TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module 371414826SSergio Aguirre * 471414826SSergio Aguirre * Copyright (C) 2012 Texas Instruments, Inc. 571414826SSergio Aguirre * 671414826SSergio Aguirre * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com> 771414826SSergio Aguirre * 871414826SSergio Aguirre * This program is free software; you can redistribute it and/or modify 971414826SSergio Aguirre * it under the terms of the GNU General Public License as published by 1071414826SSergio Aguirre * the Free Software Foundation; either version 2 of the License, or 1171414826SSergio Aguirre * (at your option) any later version. 1271414826SSergio Aguirre */ 1371414826SSergio Aguirre 1471414826SSergio Aguirre #include <linux/module.h> 1571414826SSergio Aguirre #include <linux/uaccess.h> 1671414826SSergio Aguirre #include <linux/delay.h> 1771414826SSergio Aguirre #include <linux/device.h> 1871414826SSergio Aguirre #include <linux/dma-mapping.h> 1971414826SSergio Aguirre #include <linux/mm.h> 2071414826SSergio Aguirre #include <linux/sched.h> 2171414826SSergio Aguirre 2271414826SSergio Aguirre #include "iss.h" 2371414826SSergio Aguirre #include "iss_regs.h" 2471414826SSergio Aguirre #include "iss_ipipeif.h" 2571414826SSergio Aguirre 2671414826SSergio Aguirre static const unsigned int ipipeif_fmts[] = { 273336f07aSBoris BREZILLON MEDIA_BUS_FMT_SGRBG10_1X10, 283336f07aSBoris BREZILLON MEDIA_BUS_FMT_SRGGB10_1X10, 293336f07aSBoris BREZILLON MEDIA_BUS_FMT_SBGGR10_1X10, 303336f07aSBoris BREZILLON MEDIA_BUS_FMT_SGBRG10_1X10, 313336f07aSBoris BREZILLON MEDIA_BUS_FMT_UYVY8_1X16, 323336f07aSBoris BREZILLON MEDIA_BUS_FMT_YUYV8_1X16, 3371414826SSergio Aguirre }; 3471414826SSergio Aguirre 3571414826SSergio Aguirre /* 3671414826SSergio Aguirre * ipipeif_print_status - Print current IPIPEIF Module register values. 3771414826SSergio Aguirre * @ipipeif: Pointer to ISS ISP IPIPEIF device. 3871414826SSergio Aguirre * 3971414826SSergio Aguirre * Also prints other debug information stored in the IPIPEIF module. 4071414826SSergio Aguirre */ 4171414826SSergio Aguirre #define IPIPEIF_PRINT_REGISTER(iss, name)\ 4271414826SSergio Aguirre dev_dbg(iss->dev, "###IPIPEIF " #name "=0x%08x\n", \ 4311abbfd3SLaurent Pinchart iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_##name)) 4471414826SSergio Aguirre 4571414826SSergio Aguirre #define ISIF_PRINT_REGISTER(iss, name)\ 4671414826SSergio Aguirre dev_dbg(iss->dev, "###ISIF " #name "=0x%08x\n", \ 4711abbfd3SLaurent Pinchart iss_reg_read(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_##name)) 4871414826SSergio Aguirre 4971414826SSergio Aguirre #define ISP5_PRINT_REGISTER(iss, name)\ 5071414826SSergio Aguirre dev_dbg(iss->dev, "###ISP5 " #name "=0x%08x\n", \ 5111abbfd3SLaurent Pinchart iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_##name)) 5271414826SSergio Aguirre 5371414826SSergio Aguirre static void ipipeif_print_status(struct iss_ipipeif_device *ipipeif) 5471414826SSergio Aguirre { 5571414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 5671414826SSergio Aguirre 5771414826SSergio Aguirre dev_dbg(iss->dev, "-------------IPIPEIF Register dump-------------\n"); 5871414826SSergio Aguirre 5971414826SSergio Aguirre IPIPEIF_PRINT_REGISTER(iss, CFG1); 6071414826SSergio Aguirre IPIPEIF_PRINT_REGISTER(iss, CFG2); 6171414826SSergio Aguirre 6271414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, SYNCEN); 6371414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, CADU); 6471414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, CADL); 6571414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, MODESET); 6671414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, CCOLP); 6771414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, SPH); 6871414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, LNH); 6971414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, LNV); 7054d0059cSLaurent Pinchart ISIF_PRINT_REGISTER(iss, VDINT(0)); 7171414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, HSIZE); 7271414826SSergio Aguirre 7371414826SSergio Aguirre ISP5_PRINT_REGISTER(iss, SYSCONFIG); 7471414826SSergio Aguirre ISP5_PRINT_REGISTER(iss, CTRL); 7571414826SSergio Aguirre ISP5_PRINT_REGISTER(iss, IRQSTATUS(0)); 7671414826SSergio Aguirre ISP5_PRINT_REGISTER(iss, IRQENABLE_SET(0)); 7771414826SSergio Aguirre ISP5_PRINT_REGISTER(iss, IRQENABLE_CLR(0)); 7871414826SSergio Aguirre 7971414826SSergio Aguirre dev_dbg(iss->dev, "-----------------------------------------------\n"); 8071414826SSergio Aguirre } 8171414826SSergio Aguirre 8271414826SSergio Aguirre static void ipipeif_write_enable(struct iss_ipipeif_device *ipipeif, u8 enable) 8371414826SSergio Aguirre { 8471414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 8571414826SSergio Aguirre 8611abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, 8711abbfd3SLaurent Pinchart ISIF_SYNCEN_DWEN, enable ? ISIF_SYNCEN_DWEN : 0); 8871414826SSergio Aguirre } 8971414826SSergio Aguirre 9071414826SSergio Aguirre /* 9171414826SSergio Aguirre * ipipeif_enable - Enable/Disable IPIPEIF. 9271414826SSergio Aguirre * @enable: enable flag 9371414826SSergio Aguirre * 9471414826SSergio Aguirre */ 9571414826SSergio Aguirre static void ipipeif_enable(struct iss_ipipeif_device *ipipeif, u8 enable) 9671414826SSergio Aguirre { 9771414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 9871414826SSergio Aguirre 9911abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, 10011abbfd3SLaurent Pinchart ISIF_SYNCEN_SYEN, enable ? ISIF_SYNCEN_SYEN : 0); 10171414826SSergio Aguirre } 10271414826SSergio Aguirre 10371414826SSergio Aguirre /* ----------------------------------------------------------------------------- 10471414826SSergio Aguirre * Format- and pipeline-related configuration helpers 10571414826SSergio Aguirre */ 10671414826SSergio Aguirre 10771414826SSergio Aguirre /* 10871414826SSergio Aguirre * ipipeif_set_outaddr - Set memory address to save output image 10971414826SSergio Aguirre * @ipipeif: Pointer to ISP IPIPEIF device. 11071414826SSergio Aguirre * @addr: 32-bit memory address aligned on 32 byte boundary. 11171414826SSergio Aguirre * 11271414826SSergio Aguirre * Sets the memory address where the output will be saved. 11371414826SSergio Aguirre */ 11471414826SSergio Aguirre static void ipipeif_set_outaddr(struct iss_ipipeif_device *ipipeif, u32 addr) 11571414826SSergio Aguirre { 11671414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 11771414826SSergio Aguirre 118107c59e0SAmarjargal Gundjalam /* Save address split in Base Address H & L */ 11911abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADU, 12011abbfd3SLaurent Pinchart (addr >> (16 + 5)) & ISIF_CADU_MASK); 12111abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADL, 12211abbfd3SLaurent Pinchart (addr >> 5) & ISIF_CADL_MASK); 12371414826SSergio Aguirre } 12471414826SSergio Aguirre 12571414826SSergio Aguirre static void ipipeif_configure(struct iss_ipipeif_device *ipipeif) 12671414826SSergio Aguirre { 12771414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 12886efc504SLaurent Pinchart const struct iss_format_info *info; 12971414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 13071414826SSergio Aguirre u32 isif_ccolp = 0; 13171414826SSergio Aguirre 13271414826SSergio Aguirre omap4iss_configure_bridge(iss, ipipeif->input); 13371414826SSergio Aguirre 13471414826SSergio Aguirre /* IPIPEIF_PAD_SINK */ 13571414826SSergio Aguirre format = &ipipeif->formats[IPIPEIF_PAD_SINK]; 13671414826SSergio Aguirre 13771414826SSergio Aguirre /* IPIPEIF with YUV422 input from ISIF */ 13811abbfd3SLaurent Pinchart iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG1, 13911abbfd3SLaurent Pinchart IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK); 14071414826SSergio Aguirre 14171414826SSergio Aguirre /* Select ISIF/IPIPEIF input format */ 14271414826SSergio Aguirre switch (format->code) { 1433336f07aSBoris BREZILLON case MEDIA_BUS_FMT_UYVY8_1X16: 1443336f07aSBoris BREZILLON case MEDIA_BUS_FMT_YUYV8_1X16: 14511abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, 14611abbfd3SLaurent Pinchart ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | 14711abbfd3SLaurent Pinchart ISIF_MODESET_CCDW_MASK, 14811abbfd3SLaurent Pinchart ISIF_MODESET_INPMOD_YCBCR16); 14971414826SSergio Aguirre 15011abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, 15111abbfd3SLaurent Pinchart IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16); 15271414826SSergio Aguirre 15371414826SSergio Aguirre break; 1543336f07aSBoris BREZILLON case MEDIA_BUS_FMT_SGRBG10_1X10: 15571414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_GR | 15671414826SSergio Aguirre ISIF_CCOLP_CP1_F0_R | 15771414826SSergio Aguirre ISIF_CCOLP_CP2_F0_B | 15871414826SSergio Aguirre ISIF_CCOLP_CP3_F0_GB; 15971414826SSergio Aguirre goto cont_raw; 1603336f07aSBoris BREZILLON case MEDIA_BUS_FMT_SRGGB10_1X10: 16171414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_R | 16271414826SSergio Aguirre ISIF_CCOLP_CP1_F0_GR | 16371414826SSergio Aguirre ISIF_CCOLP_CP2_F0_GB | 16471414826SSergio Aguirre ISIF_CCOLP_CP3_F0_B; 16571414826SSergio Aguirre goto cont_raw; 1663336f07aSBoris BREZILLON case MEDIA_BUS_FMT_SBGGR10_1X10: 16771414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_B | 16871414826SSergio Aguirre ISIF_CCOLP_CP1_F0_GB | 16971414826SSergio Aguirre ISIF_CCOLP_CP2_F0_GR | 17071414826SSergio Aguirre ISIF_CCOLP_CP3_F0_R; 17171414826SSergio Aguirre goto cont_raw; 1723336f07aSBoris BREZILLON case MEDIA_BUS_FMT_SGBRG10_1X10: 17371414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_GB | 17471414826SSergio Aguirre ISIF_CCOLP_CP1_F0_B | 17571414826SSergio Aguirre ISIF_CCOLP_CP2_F0_R | 17671414826SSergio Aguirre ISIF_CCOLP_CP3_F0_GR; 17771414826SSergio Aguirre cont_raw: 17811abbfd3SLaurent Pinchart iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, 17911abbfd3SLaurent Pinchart IPIPEIF_CFG2_YUV16); 18071414826SSergio Aguirre 18111abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, 18211abbfd3SLaurent Pinchart ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | 18311abbfd3SLaurent Pinchart ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_RAW | 18411abbfd3SLaurent Pinchart ISIF_MODESET_CCDW_2BIT); 18571414826SSergio Aguirre 18686efc504SLaurent Pinchart info = omap4iss_video_format_info(format->code); 18711abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CGAMMAWD, 18811abbfd3SLaurent Pinchart ISIF_CGAMMAWD_GWDI_MASK, 18911abbfd3SLaurent Pinchart ISIF_CGAMMAWD_GWDI(info->bpp)); 19071414826SSergio Aguirre 19171414826SSergio Aguirre /* Set RAW Bayer pattern */ 19211abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CCOLP, 19311abbfd3SLaurent Pinchart isif_ccolp); 19471414826SSergio Aguirre break; 19571414826SSergio Aguirre } 19671414826SSergio Aguirre 19711abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SPH, 0 & ISIF_SPH_MASK); 19811abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNH, 19911abbfd3SLaurent Pinchart (format->width - 1) & ISIF_LNH_MASK); 20011abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNV, 20111abbfd3SLaurent Pinchart (format->height - 1) & ISIF_LNV_MASK); 20271414826SSergio Aguirre 20371414826SSergio Aguirre /* Generate ISIF0 on the last line of the image */ 20411abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_VDINT(0), 20511abbfd3SLaurent Pinchart format->height - 1); 20671414826SSergio Aguirre 20771414826SSergio Aguirre /* IPIPEIF_PAD_SOURCE_ISIF_SF */ 20871414826SSergio Aguirre format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF]; 20971414826SSergio Aguirre 21011abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_HSIZE, 21111abbfd3SLaurent Pinchart (ipipeif->video_out.bpl_value >> 5) & 21211abbfd3SLaurent Pinchart ISIF_HSIZE_HSIZE_MASK); 21371414826SSergio Aguirre 21471414826SSergio Aguirre /* IPIPEIF_PAD_SOURCE_VP */ 21571414826SSergio Aguirre /* Do nothing? */ 21671414826SSergio Aguirre } 21771414826SSergio Aguirre 21871414826SSergio Aguirre /* ----------------------------------------------------------------------------- 21971414826SSergio Aguirre * Interrupt handling 22071414826SSergio Aguirre */ 22171414826SSergio Aguirre 22271414826SSergio Aguirre static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif) 22371414826SSergio Aguirre { 22471414826SSergio Aguirre struct iss_buffer *buffer; 22571414826SSergio Aguirre 22674536b2fSLaurent Pinchart /* The ISIF generates VD0 interrupts even when writes are disabled. 22774536b2fSLaurent Pinchart * deal with it anyway). Disabling the ISIF when no buffer is available 22874536b2fSLaurent Pinchart * is thus not be enough, we need to handle the situation explicitly. 22974536b2fSLaurent Pinchart */ 23074536b2fSLaurent Pinchart if (list_empty(&ipipeif->video_out.dmaqueue)) 23174536b2fSLaurent Pinchart return; 23274536b2fSLaurent Pinchart 23371414826SSergio Aguirre ipipeif_write_enable(ipipeif, 0); 23471414826SSergio Aguirre 23571414826SSergio Aguirre buffer = omap4iss_video_buffer_next(&ipipeif->video_out); 2369058fc92SAmarjargal Gundjalam if (!buffer) 23771414826SSergio Aguirre return; 23871414826SSergio Aguirre 23971414826SSergio Aguirre ipipeif_set_outaddr(ipipeif, buffer->iss_addr); 24071414826SSergio Aguirre 24171414826SSergio Aguirre ipipeif_write_enable(ipipeif, 1); 24271414826SSergio Aguirre } 24371414826SSergio Aguirre 24471414826SSergio Aguirre /* 24571414826SSergio Aguirre * omap4iss_ipipeif_isr - Configure ipipeif during interframe time. 24671414826SSergio Aguirre * @ipipeif: Pointer to ISP IPIPEIF device. 24771414826SSergio Aguirre * @events: IPIPEIF events 24871414826SSergio Aguirre */ 24971414826SSergio Aguirre void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events) 25071414826SSergio Aguirre { 251a0fe029cSLaurent Pinchart if (omap4iss_module_sync_is_stopping(&ipipeif->wait, 252a0fe029cSLaurent Pinchart &ipipeif->stopping)) 25371414826SSergio Aguirre return; 25471414826SSergio Aguirre 255dd162547SLaurent Pinchart if ((events & ISP5_IRQ_ISIF_INT(0)) && 256dd162547SLaurent Pinchart (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) 257dd162547SLaurent Pinchart ipipeif_isr_buffer(ipipeif); 25871414826SSergio Aguirre } 25971414826SSergio Aguirre 26071414826SSergio Aguirre /* ----------------------------------------------------------------------------- 26171414826SSergio Aguirre * ISP video operations 26271414826SSergio Aguirre */ 26371414826SSergio Aguirre 264a0fe029cSLaurent Pinchart static int ipipeif_video_queue(struct iss_video *video, 265a0fe029cSLaurent Pinchart struct iss_buffer *buffer) 26671414826SSergio Aguirre { 26771414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = container_of(video, 26871414826SSergio Aguirre struct iss_ipipeif_device, video_out); 26971414826SSergio Aguirre 27071414826SSergio Aguirre if (!(ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) 27171414826SSergio Aguirre return -ENODEV; 27271414826SSergio Aguirre 27371414826SSergio Aguirre ipipeif_set_outaddr(ipipeif, buffer->iss_addr); 27471414826SSergio Aguirre 27571414826SSergio Aguirre /* 27671414826SSergio Aguirre * If streaming was enabled before there was a buffer queued 27771414826SSergio Aguirre * or underrun happened in the ISR, the hardware was not enabled 27871414826SSergio Aguirre * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set. 27971414826SSergio Aguirre * Enable it now. 28071414826SSergio Aguirre */ 28171414826SSergio Aguirre if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { 28271414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 28371414826SSergio Aguirre ipipeif_write_enable(ipipeif, 1); 28471414826SSergio Aguirre ipipeif_enable(ipipeif, 1); 28571414826SSergio Aguirre iss_video_dmaqueue_flags_clr(video); 28671414826SSergio Aguirre } 28771414826SSergio Aguirre 28871414826SSergio Aguirre return 0; 28971414826SSergio Aguirre } 29071414826SSergio Aguirre 29171414826SSergio Aguirre static const struct iss_video_operations ipipeif_video_ops = { 29271414826SSergio Aguirre .queue = ipipeif_video_queue, 29371414826SSergio Aguirre }; 29471414826SSergio Aguirre 29571414826SSergio Aguirre /* ----------------------------------------------------------------------------- 29671414826SSergio Aguirre * V4L2 subdev operations 29771414826SSergio Aguirre */ 29871414826SSergio Aguirre 29971414826SSergio Aguirre #define IPIPEIF_DRV_SUBCLK_MASK (OMAP4_ISS_ISP_SUBCLK_IPIPEIF |\ 30071414826SSergio Aguirre OMAP4_ISS_ISP_SUBCLK_ISIF) 30171414826SSergio Aguirre /* 30271414826SSergio Aguirre * ipipeif_set_stream - Enable/Disable streaming on the IPIPEIF module 30371414826SSergio Aguirre * @sd: ISP IPIPEIF V4L2 subdevice 30471414826SSergio Aguirre * @enable: Enable/disable stream 30571414826SSergio Aguirre */ 30671414826SSergio Aguirre static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) 30771414826SSergio Aguirre { 30871414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 30971414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 31071414826SSergio Aguirre struct iss_video *video_out = &ipipeif->video_out; 31171414826SSergio Aguirre int ret = 0; 31271414826SSergio Aguirre 31371414826SSergio Aguirre if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) { 31471414826SSergio Aguirre if (enable == ISS_PIPELINE_STREAM_STOPPED) 31571414826SSergio Aguirre return 0; 31671414826SSergio Aguirre 31771414826SSergio Aguirre omap4iss_isp_subclk_enable(iss, IPIPEIF_DRV_SUBCLK_MASK); 31871414826SSergio Aguirre } 31971414826SSergio Aguirre 32071414826SSergio Aguirre switch (enable) { 32171414826SSergio Aguirre case ISS_PIPELINE_STREAM_CONTINUOUS: 32271414826SSergio Aguirre 32371414826SSergio Aguirre ipipeif_configure(ipipeif); 32471414826SSergio Aguirre ipipeif_print_status(ipipeif); 32571414826SSergio Aguirre 32671414826SSergio Aguirre /* 32771414826SSergio Aguirre * When outputting to memory with no buffer available, let the 32871414826SSergio Aguirre * buffer queue handler start the hardware. A DMA queue flag 32971414826SSergio Aguirre * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is 33071414826SSergio Aguirre * a buffer available. 33171414826SSergio Aguirre */ 33271414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY && 33371414826SSergio Aguirre !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) 33471414826SSergio Aguirre break; 33571414826SSergio Aguirre 33671414826SSergio Aguirre atomic_set(&ipipeif->stopping, 0); 33771414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 33871414826SSergio Aguirre ipipeif_write_enable(ipipeif, 1); 33971414826SSergio Aguirre ipipeif_enable(ipipeif, 1); 34071414826SSergio Aguirre iss_video_dmaqueue_flags_clr(video_out); 34171414826SSergio Aguirre break; 34271414826SSergio Aguirre 34371414826SSergio Aguirre case ISS_PIPELINE_STREAM_STOPPED: 34471414826SSergio Aguirre if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) 34571414826SSergio Aguirre return 0; 34671414826SSergio Aguirre if (omap4iss_module_sync_idle(&sd->entity, &ipipeif->wait, 34771414826SSergio Aguirre &ipipeif->stopping)) 3486016498fSLaurent Pinchart ret = -ETIMEDOUT; 34971414826SSergio Aguirre 35071414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 35171414826SSergio Aguirre ipipeif_write_enable(ipipeif, 0); 35271414826SSergio Aguirre ipipeif_enable(ipipeif, 0); 35371414826SSergio Aguirre omap4iss_isp_subclk_disable(iss, IPIPEIF_DRV_SUBCLK_MASK); 35471414826SSergio Aguirre iss_video_dmaqueue_flags_clr(video_out); 35571414826SSergio Aguirre break; 35671414826SSergio Aguirre } 35771414826SSergio Aguirre 35871414826SSergio Aguirre ipipeif->state = enable; 35971414826SSergio Aguirre return ret; 36071414826SSergio Aguirre } 36171414826SSergio Aguirre 36271414826SSergio Aguirre static struct v4l2_mbus_framefmt * 363a0fe029cSLaurent Pinchart __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, 364f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, unsigned int pad, 365a0fe029cSLaurent Pinchart enum v4l2_subdev_format_whence which) 36671414826SSergio Aguirre { 36771414826SSergio Aguirre if (which == V4L2_SUBDEV_FORMAT_TRY) 368f7234138SHans Verkuil return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); 36971414826SSergio Aguirre return &ipipeif->formats[pad]; 37071414826SSergio Aguirre } 37171414826SSergio Aguirre 37271414826SSergio Aguirre /* 37371414826SSergio Aguirre * ipipeif_try_format - Try video format on a pad 37471414826SSergio Aguirre * @ipipeif: ISS IPIPEIF device 375f7234138SHans Verkuil * @cfg: V4L2 subdev pad config 37671414826SSergio Aguirre * @pad: Pad number 37771414826SSergio Aguirre * @fmt: Format 37871414826SSergio Aguirre */ 37971414826SSergio Aguirre static void 380a0fe029cSLaurent Pinchart ipipeif_try_format(struct iss_ipipeif_device *ipipeif, 381f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, unsigned int pad, 382a0fe029cSLaurent Pinchart struct v4l2_mbus_framefmt *fmt, 38371414826SSergio Aguirre enum v4l2_subdev_format_whence which) 38471414826SSergio Aguirre { 38571414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 38671414826SSergio Aguirre unsigned int width = fmt->width; 38771414826SSergio Aguirre unsigned int height = fmt->height; 38871414826SSergio Aguirre unsigned int i; 38971414826SSergio Aguirre 39071414826SSergio Aguirre switch (pad) { 39171414826SSergio Aguirre case IPIPEIF_PAD_SINK: 392a0fe029cSLaurent Pinchart /* TODO: If the IPIPEIF output formatter pad is connected 393a0fe029cSLaurent Pinchart * directly to the resizer, only YUV formats can be used. 39471414826SSergio Aguirre */ 39571414826SSergio Aguirre for (i = 0; i < ARRAY_SIZE(ipipeif_fmts); i++) { 39671414826SSergio Aguirre if (fmt->code == ipipeif_fmts[i]) 39771414826SSergio Aguirre break; 39871414826SSergio Aguirre } 39971414826SSergio Aguirre 40071414826SSergio Aguirre /* If not found, use SGRBG10 as default */ 40171414826SSergio Aguirre if (i >= ARRAY_SIZE(ipipeif_fmts)) 4023336f07aSBoris BREZILLON fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 40371414826SSergio Aguirre 40471414826SSergio Aguirre /* Clamp the input size. */ 40571414826SSergio Aguirre fmt->width = clamp_t(u32, width, 1, 8192); 40671414826SSergio Aguirre fmt->height = clamp_t(u32, height, 1, 8192); 40771414826SSergio Aguirre break; 40871414826SSergio Aguirre 40971414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_ISIF_SF: 410f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, 411a0fe029cSLaurent Pinchart which); 41271414826SSergio Aguirre memcpy(fmt, format, sizeof(*fmt)); 41371414826SSergio Aguirre 41471414826SSergio Aguirre /* The data formatter truncates the number of horizontal output 41571414826SSergio Aguirre * pixels to a multiple of 16. To avoid clipping data, allow 41671414826SSergio Aguirre * callers to request an output size bigger than the input size 41771414826SSergio Aguirre * up to the nearest multiple of 16. 41871414826SSergio Aguirre */ 41971414826SSergio Aguirre fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); 42071414826SSergio Aguirre fmt->width &= ~15; 42171414826SSergio Aguirre fmt->height = clamp_t(u32, height, 32, fmt->height); 42271414826SSergio Aguirre break; 42371414826SSergio Aguirre 42471414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_VP: 425f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, 426a0fe029cSLaurent Pinchart which); 42771414826SSergio Aguirre memcpy(fmt, format, sizeof(*fmt)); 42871414826SSergio Aguirre 42971414826SSergio Aguirre fmt->width = clamp_t(u32, width, 32, fmt->width); 43071414826SSergio Aguirre fmt->height = clamp_t(u32, height, 32, fmt->height); 43171414826SSergio Aguirre break; 43271414826SSergio Aguirre } 43371414826SSergio Aguirre 43471414826SSergio Aguirre /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is 43571414826SSergio Aguirre * stored on 2 bytes. 43671414826SSergio Aguirre */ 43771414826SSergio Aguirre fmt->colorspace = V4L2_COLORSPACE_SRGB; 43871414826SSergio Aguirre fmt->field = V4L2_FIELD_NONE; 43971414826SSergio Aguirre } 44071414826SSergio Aguirre 44171414826SSergio Aguirre /* 44271414826SSergio Aguirre * ipipeif_enum_mbus_code - Handle pixel format enumeration 44371414826SSergio Aguirre * @sd : pointer to v4l2 subdev structure 444f7234138SHans Verkuil * @cfg : V4L2 subdev pad config 44571414826SSergio Aguirre * @code : pointer to v4l2_subdev_mbus_code_enum structure 44671414826SSergio Aguirre * return -EINVAL or zero on success 44771414826SSergio Aguirre */ 44871414826SSergio Aguirre static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, 449f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 45071414826SSergio Aguirre struct v4l2_subdev_mbus_code_enum *code) 45171414826SSergio Aguirre { 45271414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 45371414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 45471414826SSergio Aguirre 45571414826SSergio Aguirre switch (code->pad) { 45671414826SSergio Aguirre case IPIPEIF_PAD_SINK: 45771414826SSergio Aguirre if (code->index >= ARRAY_SIZE(ipipeif_fmts)) 45871414826SSergio Aguirre return -EINVAL; 45971414826SSergio Aguirre 46071414826SSergio Aguirre code->code = ipipeif_fmts[code->index]; 46171414826SSergio Aguirre break; 46271414826SSergio Aguirre 46371414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_ISIF_SF: 46471414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_VP: 46571414826SSergio Aguirre /* No format conversion inside IPIPEIF */ 46671414826SSergio Aguirre if (code->index != 0) 46771414826SSergio Aguirre return -EINVAL; 46871414826SSergio Aguirre 469f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, 4703f1ccf16SHans Verkuil code->which); 47171414826SSergio Aguirre 47271414826SSergio Aguirre code->code = format->code; 47371414826SSergio Aguirre break; 47471414826SSergio Aguirre 47571414826SSergio Aguirre default: 47671414826SSergio Aguirre return -EINVAL; 47771414826SSergio Aguirre } 47871414826SSergio Aguirre 47971414826SSergio Aguirre return 0; 48071414826SSergio Aguirre } 48171414826SSergio Aguirre 48271414826SSergio Aguirre static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, 483f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 48471414826SSergio Aguirre struct v4l2_subdev_frame_size_enum *fse) 48571414826SSergio Aguirre { 48671414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 48771414826SSergio Aguirre struct v4l2_mbus_framefmt format; 48871414826SSergio Aguirre 48971414826SSergio Aguirre if (fse->index != 0) 49071414826SSergio Aguirre return -EINVAL; 49171414826SSergio Aguirre 49271414826SSergio Aguirre format.code = fse->code; 49371414826SSergio Aguirre format.width = 1; 49471414826SSergio Aguirre format.height = 1; 4955778e749SHans Verkuil ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); 49671414826SSergio Aguirre fse->min_width = format.width; 49771414826SSergio Aguirre fse->min_height = format.height; 49871414826SSergio Aguirre 49971414826SSergio Aguirre if (format.code != fse->code) 50071414826SSergio Aguirre return -EINVAL; 50171414826SSergio Aguirre 50271414826SSergio Aguirre format.code = fse->code; 50371414826SSergio Aguirre format.width = -1; 50471414826SSergio Aguirre format.height = -1; 5055778e749SHans Verkuil ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); 50671414826SSergio Aguirre fse->max_width = format.width; 50771414826SSergio Aguirre fse->max_height = format.height; 50871414826SSergio Aguirre 50971414826SSergio Aguirre return 0; 51071414826SSergio Aguirre } 51171414826SSergio Aguirre 51271414826SSergio Aguirre /* 51371414826SSergio Aguirre * ipipeif_get_format - Retrieve the video format on a pad 51471414826SSergio Aguirre * @sd : ISP IPIPEIF V4L2 subdevice 515f7234138SHans Verkuil * @cfg: V4L2 subdev pad config 51671414826SSergio Aguirre * @fmt: Format 51771414826SSergio Aguirre * 51871414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 51971414826SSergio Aguirre * to the format type. 52071414826SSergio Aguirre */ 521ee8defecSPiotr S. Staszewski static int ipipeif_get_format(struct v4l2_subdev *sd, 522ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 52371414826SSergio Aguirre struct v4l2_subdev_format *fmt) 52471414826SSergio Aguirre { 52571414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 52671414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 52771414826SSergio Aguirre 528f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); 5299058fc92SAmarjargal Gundjalam if (!format) 53071414826SSergio Aguirre return -EINVAL; 53171414826SSergio Aguirre 53271414826SSergio Aguirre fmt->format = *format; 53371414826SSergio Aguirre return 0; 53471414826SSergio Aguirre } 53571414826SSergio Aguirre 53671414826SSergio Aguirre /* 53771414826SSergio Aguirre * ipipeif_set_format - Set the video format on a pad 53871414826SSergio Aguirre * @sd : ISP IPIPEIF V4L2 subdevice 539f7234138SHans Verkuil * @cfg: V4L2 subdev pad config 54071414826SSergio Aguirre * @fmt: Format 54171414826SSergio Aguirre * 54271414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 54371414826SSergio Aguirre * to the format type. 54471414826SSergio Aguirre */ 545ee8defecSPiotr S. Staszewski static int ipipeif_set_format(struct v4l2_subdev *sd, 546ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 54771414826SSergio Aguirre struct v4l2_subdev_format *fmt) 54871414826SSergio Aguirre { 54971414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 55071414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 55171414826SSergio Aguirre 552f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); 5539058fc92SAmarjargal Gundjalam if (!format) 55471414826SSergio Aguirre return -EINVAL; 55571414826SSergio Aguirre 556f7234138SHans Verkuil ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); 55771414826SSergio Aguirre *format = fmt->format; 55871414826SSergio Aguirre 55971414826SSergio Aguirre /* Propagate the format from sink to source */ 56071414826SSergio Aguirre if (fmt->pad == IPIPEIF_PAD_SINK) { 561f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, 562a0fe029cSLaurent Pinchart IPIPEIF_PAD_SOURCE_ISIF_SF, 56371414826SSergio Aguirre fmt->which); 56471414826SSergio Aguirre *format = fmt->format; 565f7234138SHans Verkuil ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, 566a0fe029cSLaurent Pinchart format, fmt->which); 56771414826SSergio Aguirre 568f7234138SHans Verkuil format = __ipipeif_get_format(ipipeif, cfg, 569a0fe029cSLaurent Pinchart IPIPEIF_PAD_SOURCE_VP, 57071414826SSergio Aguirre fmt->which); 57171414826SSergio Aguirre *format = fmt->format; 572f7234138SHans Verkuil ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format, 57371414826SSergio Aguirre fmt->which); 57471414826SSergio Aguirre } 57571414826SSergio Aguirre 57671414826SSergio Aguirre return 0; 57771414826SSergio Aguirre } 57871414826SSergio Aguirre 579a0fe029cSLaurent Pinchart static int ipipeif_link_validate(struct v4l2_subdev *sd, 580a0fe029cSLaurent Pinchart struct media_link *link, 58171414826SSergio Aguirre struct v4l2_subdev_format *source_fmt, 58271414826SSergio Aguirre struct v4l2_subdev_format *sink_fmt) 58371414826SSergio Aguirre { 58471414826SSergio Aguirre /* Check if the two ends match */ 58571414826SSergio Aguirre if (source_fmt->format.width != sink_fmt->format.width || 58671414826SSergio Aguirre source_fmt->format.height != sink_fmt->format.height) 58771414826SSergio Aguirre return -EPIPE; 58871414826SSergio Aguirre 58971414826SSergio Aguirre if (source_fmt->format.code != sink_fmt->format.code) 59071414826SSergio Aguirre return -EPIPE; 59171414826SSergio Aguirre 59271414826SSergio Aguirre return 0; 59371414826SSergio Aguirre } 59471414826SSergio Aguirre 59571414826SSergio Aguirre /* 59671414826SSergio Aguirre * ipipeif_init_formats - Initialize formats on all pads 59771414826SSergio Aguirre * @sd: ISP IPIPEIF V4L2 subdevice 59871414826SSergio Aguirre * @fh: V4L2 subdev file handle 59971414826SSergio Aguirre * 60071414826SSergio Aguirre * Initialize all pad formats with default values. If fh is not NULL, try 60171414826SSergio Aguirre * formats are initialized on the file handle. Otherwise active formats are 60271414826SSergio Aguirre * initialized on the device. 60371414826SSergio Aguirre */ 604a0fe029cSLaurent Pinchart static int ipipeif_init_formats(struct v4l2_subdev *sd, 605a0fe029cSLaurent Pinchart struct v4l2_subdev_fh *fh) 60671414826SSergio Aguirre { 60771414826SSergio Aguirre struct v4l2_subdev_format format; 60871414826SSergio Aguirre 60971414826SSergio Aguirre memset(&format, 0, sizeof(format)); 61071414826SSergio Aguirre format.pad = IPIPEIF_PAD_SINK; 61171414826SSergio Aguirre format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 6123336f07aSBoris BREZILLON format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 61371414826SSergio Aguirre format.format.width = 4096; 61471414826SSergio Aguirre format.format.height = 4096; 615f7234138SHans Verkuil ipipeif_set_format(sd, fh ? fh->pad : NULL, &format); 61671414826SSergio Aguirre 61771414826SSergio Aguirre return 0; 61871414826SSergio Aguirre } 61971414826SSergio Aguirre 62071414826SSergio Aguirre /* V4L2 subdev video operations */ 62171414826SSergio Aguirre static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { 62271414826SSergio Aguirre .s_stream = ipipeif_set_stream, 62371414826SSergio Aguirre }; 62471414826SSergio Aguirre 62571414826SSergio Aguirre /* V4L2 subdev pad operations */ 62671414826SSergio Aguirre static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { 62771414826SSergio Aguirre .enum_mbus_code = ipipeif_enum_mbus_code, 62871414826SSergio Aguirre .enum_frame_size = ipipeif_enum_frame_size, 62971414826SSergio Aguirre .get_fmt = ipipeif_get_format, 63071414826SSergio Aguirre .set_fmt = ipipeif_set_format, 63171414826SSergio Aguirre .link_validate = ipipeif_link_validate, 63271414826SSergio Aguirre }; 63371414826SSergio Aguirre 63471414826SSergio Aguirre /* V4L2 subdev operations */ 63571414826SSergio Aguirre static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { 63671414826SSergio Aguirre .video = &ipipeif_v4l2_video_ops, 63771414826SSergio Aguirre .pad = &ipipeif_v4l2_pad_ops, 63871414826SSergio Aguirre }; 63971414826SSergio Aguirre 64071414826SSergio Aguirre /* V4L2 subdev internal operations */ 64171414826SSergio Aguirre static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { 64271414826SSergio Aguirre .open = ipipeif_init_formats, 64371414826SSergio Aguirre }; 64471414826SSergio Aguirre 64571414826SSergio Aguirre /* ----------------------------------------------------------------------------- 64671414826SSergio Aguirre * Media entity operations 64771414826SSergio Aguirre */ 64871414826SSergio Aguirre 64971414826SSergio Aguirre /* 65071414826SSergio Aguirre * ipipeif_link_setup - Setup IPIPEIF connections 65171414826SSergio Aguirre * @entity: IPIPEIF media entity 65271414826SSergio Aguirre * @local: Pad at the local end of the link 65371414826SSergio Aguirre * @remote: Pad at the remote end of the link 65471414826SSergio Aguirre * @flags: Link flags 65571414826SSergio Aguirre * 65671414826SSergio Aguirre * return -EINVAL or zero on success 65771414826SSergio Aguirre */ 65871414826SSergio Aguirre static int ipipeif_link_setup(struct media_entity *entity, 65971414826SSergio Aguirre const struct media_pad *local, 66071414826SSergio Aguirre const struct media_pad *remote, u32 flags) 66171414826SSergio Aguirre { 66271414826SSergio Aguirre struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 66371414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 66471414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 665829de29bSMauro Carvalho Chehab unsigned int index = local->index; 66671414826SSergio Aguirre 66759ecd59dSMauro Carvalho Chehab /* FIXME: this is actually a hack! */ 66859ecd59dSMauro Carvalho Chehab if (is_media_entity_v4l2_subdev(remote->entity)) 66959ecd59dSMauro Carvalho Chehab index |= 2 << 16; 67059ecd59dSMauro Carvalho Chehab 67159ecd59dSMauro Carvalho Chehab switch (index) { 67259ecd59dSMauro Carvalho Chehab case IPIPEIF_PAD_SINK | 2 << 16: 67371414826SSergio Aguirre /* Read from the sensor CSI2a or CSI2b. */ 67471414826SSergio Aguirre if (!(flags & MEDIA_LNK_FL_ENABLED)) { 67571414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_NONE; 67671414826SSergio Aguirre break; 67771414826SSergio Aguirre } 67871414826SSergio Aguirre 67971414826SSergio Aguirre if (ipipeif->input != IPIPEIF_INPUT_NONE) 68071414826SSergio Aguirre return -EBUSY; 68171414826SSergio Aguirre 68271414826SSergio Aguirre if (remote->entity == &iss->csi2a.subdev.entity) 68371414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_CSI2A; 68471414826SSergio Aguirre else if (remote->entity == &iss->csi2b.subdev.entity) 68571414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_CSI2B; 68671414826SSergio Aguirre 68771414826SSergio Aguirre break; 68871414826SSergio Aguirre 68959ecd59dSMauro Carvalho Chehab case IPIPEIF_PAD_SOURCE_ISIF_SF: 69071414826SSergio Aguirre /* Write to memory */ 69171414826SSergio Aguirre if (flags & MEDIA_LNK_FL_ENABLED) { 69271414826SSergio Aguirre if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY) 69371414826SSergio Aguirre return -EBUSY; 69471414826SSergio Aguirre ipipeif->output |= IPIPEIF_OUTPUT_MEMORY; 69571414826SSergio Aguirre } else { 69671414826SSergio Aguirre ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY; 69771414826SSergio Aguirre } 69871414826SSergio Aguirre break; 69971414826SSergio Aguirre 70059ecd59dSMauro Carvalho Chehab case IPIPEIF_PAD_SOURCE_VP | 2 << 16: 70171414826SSergio Aguirre /* Send to IPIPE/RESIZER */ 70271414826SSergio Aguirre if (flags & MEDIA_LNK_FL_ENABLED) { 70371414826SSergio Aguirre if (ipipeif->output & ~IPIPEIF_OUTPUT_VP) 70471414826SSergio Aguirre return -EBUSY; 70571414826SSergio Aguirre ipipeif->output |= IPIPEIF_OUTPUT_VP; 70671414826SSergio Aguirre } else { 70771414826SSergio Aguirre ipipeif->output &= ~IPIPEIF_OUTPUT_VP; 70871414826SSergio Aguirre } 70971414826SSergio Aguirre break; 71071414826SSergio Aguirre 71171414826SSergio Aguirre default: 71271414826SSergio Aguirre return -EINVAL; 71371414826SSergio Aguirre } 71471414826SSergio Aguirre 71571414826SSergio Aguirre return 0; 71671414826SSergio Aguirre } 71771414826SSergio Aguirre 71871414826SSergio Aguirre /* media operations */ 71971414826SSergio Aguirre static const struct media_entity_operations ipipeif_media_ops = { 72071414826SSergio Aguirre .link_setup = ipipeif_link_setup, 72171414826SSergio Aguirre .link_validate = v4l2_subdev_link_validate, 72271414826SSergio Aguirre }; 72371414826SSergio Aguirre 72471414826SSergio Aguirre /* 72571414826SSergio Aguirre * ipipeif_init_entities - Initialize V4L2 subdev and media entity 72671414826SSergio Aguirre * @ipipeif: ISS ISP IPIPEIF module 72771414826SSergio Aguirre * 72871414826SSergio Aguirre * Return 0 on success and a negative error code on failure. 72971414826SSergio Aguirre */ 73071414826SSergio Aguirre static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif) 73171414826SSergio Aguirre { 73271414826SSergio Aguirre struct v4l2_subdev *sd = &ipipeif->subdev; 73371414826SSergio Aguirre struct media_pad *pads = ipipeif->pads; 73471414826SSergio Aguirre struct media_entity *me = &sd->entity; 73571414826SSergio Aguirre int ret; 73671414826SSergio Aguirre 73771414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_NONE; 73871414826SSergio Aguirre 73971414826SSergio Aguirre v4l2_subdev_init(sd, &ipipeif_v4l2_ops); 74071414826SSergio Aguirre sd->internal_ops = &ipipeif_v4l2_internal_ops; 74171414826SSergio Aguirre strlcpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name)); 74271414826SSergio Aguirre sd->grp_id = 1 << 16; /* group ID for iss subdevs */ 74371414826SSergio Aguirre v4l2_set_subdevdata(sd, ipipeif); 74471414826SSergio Aguirre sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 74571414826SSergio Aguirre 74671414826SSergio Aguirre pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 74771414826SSergio Aguirre pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE; 74871414826SSergio Aguirre pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; 74971414826SSergio Aguirre 75071414826SSergio Aguirre me->ops = &ipipeif_media_ops; 751ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(me, IPIPEIF_PADS_NUM, pads); 75271414826SSergio Aguirre if (ret < 0) 75371414826SSergio Aguirre return ret; 75471414826SSergio Aguirre 75571414826SSergio Aguirre ipipeif_init_formats(sd, NULL); 75671414826SSergio Aguirre 75771414826SSergio Aguirre ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 75871414826SSergio Aguirre ipipeif->video_out.ops = &ipipeif_video_ops; 75971414826SSergio Aguirre ipipeif->video_out.iss = to_iss_device(ipipeif); 76071414826SSergio Aguirre ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 76171414826SSergio Aguirre ipipeif->video_out.bpl_alignment = 32; 76271414826SSergio Aguirre ipipeif->video_out.bpl_zero_padding = 1; 76371414826SSergio Aguirre ipipeif->video_out.bpl_max = 0x1ffe0; 76471414826SSergio Aguirre 7655837ceeaSJavier Martinez Canillas return omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF"); 76671414826SSergio Aguirre } 76771414826SSergio Aguirre 76871414826SSergio Aguirre void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif) 76971414826SSergio Aguirre { 77071414826SSergio Aguirre v4l2_device_unregister_subdev(&ipipeif->subdev); 77171414826SSergio Aguirre omap4iss_video_unregister(&ipipeif->video_out); 77271414826SSergio Aguirre } 77371414826SSergio Aguirre 77471414826SSergio Aguirre int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif, 77571414826SSergio Aguirre struct v4l2_device *vdev) 77671414826SSergio Aguirre { 77771414826SSergio Aguirre int ret; 77871414826SSergio Aguirre 77971414826SSergio Aguirre /* Register the subdev and video node. */ 78071414826SSergio Aguirre ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); 78171414826SSergio Aguirre if (ret < 0) 78271414826SSergio Aguirre goto error; 78371414826SSergio Aguirre 78471414826SSergio Aguirre ret = omap4iss_video_register(&ipipeif->video_out, vdev); 78571414826SSergio Aguirre if (ret < 0) 78671414826SSergio Aguirre goto error; 78771414826SSergio Aguirre 78871414826SSergio Aguirre return 0; 78971414826SSergio Aguirre 79071414826SSergio Aguirre error: 79171414826SSergio Aguirre omap4iss_ipipeif_unregister_entities(ipipeif); 79271414826SSergio Aguirre return ret; 79371414826SSergio Aguirre } 79471414826SSergio Aguirre 79571414826SSergio Aguirre /* ----------------------------------------------------------------------------- 79671414826SSergio Aguirre * ISP IPIPEIF initialisation and cleanup 79771414826SSergio Aguirre */ 79871414826SSergio Aguirre 79971414826SSergio Aguirre /* 80071414826SSergio Aguirre * omap4iss_ipipeif_init - IPIPEIF module initialization. 80171414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS. 80271414826SSergio Aguirre * 80371414826SSergio Aguirre * TODO: Get the initialisation values from platform data. 80471414826SSergio Aguirre * 80571414826SSergio Aguirre * Return 0 on success or a negative error code otherwise. 80671414826SSergio Aguirre */ 80771414826SSergio Aguirre int omap4iss_ipipeif_init(struct iss_device *iss) 80871414826SSergio Aguirre { 80971414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 81071414826SSergio Aguirre 81171414826SSergio Aguirre ipipeif->state = ISS_PIPELINE_STREAM_STOPPED; 81271414826SSergio Aguirre init_waitqueue_head(&ipipeif->wait); 81371414826SSergio Aguirre 81471414826SSergio Aguirre return ipipeif_init_entities(ipipeif); 81571414826SSergio Aguirre } 81671414826SSergio Aguirre 81771414826SSergio Aguirre /* 8185837ceeaSJavier Martinez Canillas * omap4iss_ipipeif_create_pads_links() - IPIPEIF pads links creation 8195837ceeaSJavier Martinez Canillas * @iss: Pointer to ISS device 8205837ceeaSJavier Martinez Canillas * 8215837ceeaSJavier Martinez Canillas * return negative error code or zero on success 8225837ceeaSJavier Martinez Canillas */ 8235837ceeaSJavier Martinez Canillas int omap4iss_ipipeif_create_pads_links(struct iss_device *iss) 8245837ceeaSJavier Martinez Canillas { 8255837ceeaSJavier Martinez Canillas struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 8265837ceeaSJavier Martinez Canillas 8275837ceeaSJavier Martinez Canillas /* Connect the IPIPEIF subdev to the video node. */ 8285837ceeaSJavier Martinez Canillas return media_create_pad_link(&ipipeif->subdev.entity, 8295837ceeaSJavier Martinez Canillas IPIPEIF_PAD_SOURCE_ISIF_SF, 8305837ceeaSJavier Martinez Canillas &ipipeif->video_out.video.entity, 0, 0); 8315837ceeaSJavier Martinez Canillas } 8325837ceeaSJavier Martinez Canillas 8335837ceeaSJavier Martinez Canillas /* 83471414826SSergio Aguirre * omap4iss_ipipeif_cleanup - IPIPEIF module cleanup. 83571414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS. 83671414826SSergio Aguirre */ 83771414826SSergio Aguirre void omap4iss_ipipeif_cleanup(struct iss_device *iss) 83871414826SSergio Aguirre { 8399d9104fbSLaurent Pinchart struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 8409d9104fbSLaurent Pinchart 8419d9104fbSLaurent Pinchart media_entity_cleanup(&ipipeif->subdev.entity); 84271414826SSergio Aguirre } 843