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[] = { 2771414826SSergio Aguirre V4L2_MBUS_FMT_SGRBG10_1X10, 2871414826SSergio Aguirre V4L2_MBUS_FMT_SRGGB10_1X10, 2971414826SSergio Aguirre V4L2_MBUS_FMT_SBGGR10_1X10, 3071414826SSergio Aguirre V4L2_MBUS_FMT_SGBRG10_1X10, 3171414826SSergio Aguirre V4L2_MBUS_FMT_UYVY8_1X16, 3271414826SSergio Aguirre V4L2_MBUS_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", \ 4371414826SSergio Aguirre readl(iss->regs[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", \ 4771414826SSergio Aguirre readl(iss->regs[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", \ 5171414826SSergio Aguirre readl(iss->regs[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); 7071414826SSergio Aguirre ISIF_PRINT_REGISTER(iss, VDINT0); 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 8671414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_SYNCEN) & 8771414826SSergio Aguirre ~ISIF_SYNCEN_DWEN) | 8871414826SSergio Aguirre enable ? ISIF_SYNCEN_DWEN : 0, 8971414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_SYNCEN); 9071414826SSergio Aguirre } 9171414826SSergio Aguirre 9271414826SSergio Aguirre /* 9371414826SSergio Aguirre * ipipeif_enable - Enable/Disable IPIPEIF. 9471414826SSergio Aguirre * @enable: enable flag 9571414826SSergio Aguirre * 9671414826SSergio Aguirre */ 9771414826SSergio Aguirre static void ipipeif_enable(struct iss_ipipeif_device *ipipeif, u8 enable) 9871414826SSergio Aguirre { 9971414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 10071414826SSergio Aguirre 10171414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_SYNCEN) & 10271414826SSergio Aguirre ~ISIF_SYNCEN_SYEN) | 10371414826SSergio Aguirre enable ? ISIF_SYNCEN_SYEN : 0, 10471414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_SYNCEN); 10571414826SSergio Aguirre } 10671414826SSergio Aguirre 10771414826SSergio Aguirre /* ----------------------------------------------------------------------------- 10871414826SSergio Aguirre * Format- and pipeline-related configuration helpers 10971414826SSergio Aguirre */ 11071414826SSergio Aguirre 11171414826SSergio Aguirre /* 11271414826SSergio Aguirre * ipipeif_set_outaddr - Set memory address to save output image 11371414826SSergio Aguirre * @ipipeif: Pointer to ISP IPIPEIF device. 11471414826SSergio Aguirre * @addr: 32-bit memory address aligned on 32 byte boundary. 11571414826SSergio Aguirre * 11671414826SSergio Aguirre * Sets the memory address where the output will be saved. 11771414826SSergio Aguirre */ 11871414826SSergio Aguirre static void ipipeif_set_outaddr(struct iss_ipipeif_device *ipipeif, u32 addr) 11971414826SSergio Aguirre { 12071414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 12171414826SSergio Aguirre 12271414826SSergio Aguirre /* Save address splitted in Base Address H & L */ 12371414826SSergio Aguirre writel((addr >> (16 + 5)) & ISIF_CADU_MASK, 12471414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_CADU); 12571414826SSergio Aguirre writel((addr >> 5) & ISIF_CADL_MASK, 12671414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_CADL); 12771414826SSergio Aguirre } 12871414826SSergio Aguirre 12971414826SSergio Aguirre static void ipipeif_configure(struct iss_ipipeif_device *ipipeif) 13071414826SSergio Aguirre { 13171414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 13271414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 13371414826SSergio Aguirre u32 isif_ccolp = 0; 13471414826SSergio Aguirre 13571414826SSergio Aguirre omap4iss_configure_bridge(iss, ipipeif->input); 13671414826SSergio Aguirre 13771414826SSergio Aguirre /* IPIPEIF_PAD_SINK */ 13871414826SSergio Aguirre format = &ipipeif->formats[IPIPEIF_PAD_SINK]; 13971414826SSergio Aguirre 14071414826SSergio Aguirre /* IPIPEIF with YUV422 input from ISIF */ 14171414826SSergio Aguirre writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_IPIPEIF] + IPIPEIF_CFG1) & 14271414826SSergio Aguirre ~(IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK), 14371414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_IPIPEIF] + IPIPEIF_CFG1); 14471414826SSergio Aguirre 14571414826SSergio Aguirre /* Select ISIF/IPIPEIF input format */ 14671414826SSergio Aguirre switch (format->code) { 14771414826SSergio Aguirre case V4L2_MBUS_FMT_UYVY8_1X16: 14871414826SSergio Aguirre case V4L2_MBUS_FMT_YUYV8_1X16: 14971414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_MODESET) & 15071414826SSergio Aguirre ~(ISIF_MODESET_CCDMD | 15171414826SSergio Aguirre ISIF_MODESET_INPMOD_MASK | 15271414826SSergio Aguirre ISIF_MODESET_CCDW_MASK)) | 15371414826SSergio Aguirre ISIF_MODESET_INPMOD_YCBCR16, 15471414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_MODESET); 15571414826SSergio Aguirre 15671414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_IPIPEIF] + IPIPEIF_CFG2) & 15771414826SSergio Aguirre ~IPIPEIF_CFG2_YUV8) | 15871414826SSergio Aguirre IPIPEIF_CFG2_YUV16, 15971414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_IPIPEIF] + IPIPEIF_CFG2); 16071414826SSergio Aguirre 16171414826SSergio Aguirre break; 16271414826SSergio Aguirre case V4L2_MBUS_FMT_SGRBG10_1X10: 16371414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_GR | 16471414826SSergio Aguirre ISIF_CCOLP_CP1_F0_R | 16571414826SSergio Aguirre ISIF_CCOLP_CP2_F0_B | 16671414826SSergio Aguirre ISIF_CCOLP_CP3_F0_GB; 16771414826SSergio Aguirre goto cont_raw; 16871414826SSergio Aguirre case V4L2_MBUS_FMT_SRGGB10_1X10: 16971414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_R | 17071414826SSergio Aguirre ISIF_CCOLP_CP1_F0_GR | 17171414826SSergio Aguirre ISIF_CCOLP_CP2_F0_GB | 17271414826SSergio Aguirre ISIF_CCOLP_CP3_F0_B; 17371414826SSergio Aguirre goto cont_raw; 17471414826SSergio Aguirre case V4L2_MBUS_FMT_SBGGR10_1X10: 17571414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_B | 17671414826SSergio Aguirre ISIF_CCOLP_CP1_F0_GB | 17771414826SSergio Aguirre ISIF_CCOLP_CP2_F0_GR | 17871414826SSergio Aguirre ISIF_CCOLP_CP3_F0_R; 17971414826SSergio Aguirre goto cont_raw; 18071414826SSergio Aguirre case V4L2_MBUS_FMT_SGBRG10_1X10: 18171414826SSergio Aguirre isif_ccolp = ISIF_CCOLP_CP0_F0_GB | 18271414826SSergio Aguirre ISIF_CCOLP_CP1_F0_B | 18371414826SSergio Aguirre ISIF_CCOLP_CP2_F0_R | 18471414826SSergio Aguirre ISIF_CCOLP_CP3_F0_GR; 18571414826SSergio Aguirre cont_raw: 18671414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_IPIPEIF] + IPIPEIF_CFG2) & 18771414826SSergio Aguirre ~IPIPEIF_CFG2_YUV16), 18871414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_IPIPEIF] + IPIPEIF_CFG2); 18971414826SSergio Aguirre 19071414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_MODESET) & 19171414826SSergio Aguirre ~(ISIF_MODESET_CCDMD | 19271414826SSergio Aguirre ISIF_MODESET_INPMOD_MASK | 19371414826SSergio Aguirre ISIF_MODESET_CCDW_MASK)) | 19471414826SSergio Aguirre ISIF_MODESET_INPMOD_RAW | ISIF_MODESET_CCDW_2BIT, 19571414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_MODESET); 19671414826SSergio Aguirre 19771414826SSergio Aguirre writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_CGAMMAWD) & 19871414826SSergio Aguirre ~ISIF_CGAMMAWD_GWDI_MASK) | 19971414826SSergio Aguirre ISIF_CGAMMAWD_GWDI_BIT11, 20071414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_CGAMMAWD); 20171414826SSergio Aguirre 20271414826SSergio Aguirre /* Set RAW Bayer pattern */ 20371414826SSergio Aguirre writel(isif_ccolp, 20471414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_CCOLP); 20571414826SSergio Aguirre break; 20671414826SSergio Aguirre } 20771414826SSergio Aguirre 20871414826SSergio Aguirre writel(0 & ISIF_SPH_MASK, iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_SPH); 20971414826SSergio Aguirre writel((format->width - 1) & ISIF_LNH_MASK, 21071414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_LNH); 21171414826SSergio Aguirre writel((format->height - 1) & ISIF_LNV_MASK, 21271414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_LNV); 21371414826SSergio Aguirre 21471414826SSergio Aguirre /* Generate ISIF0 on the last line of the image */ 21571414826SSergio Aguirre writel(format->height - 1, 21671414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_VDINT0); 21771414826SSergio Aguirre 21871414826SSergio Aguirre /* IPIPEIF_PAD_SOURCE_ISIF_SF */ 21971414826SSergio Aguirre format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF]; 22071414826SSergio Aguirre 22171414826SSergio Aguirre writel((ipipeif->video_out.bpl_value >> 5) & ISIF_HSIZE_HSIZE_MASK, 22271414826SSergio Aguirre iss->regs[OMAP4_ISS_MEM_ISP_ISIF] + ISIF_HSIZE); 22371414826SSergio Aguirre 22471414826SSergio Aguirre /* IPIPEIF_PAD_SOURCE_VP */ 22571414826SSergio Aguirre /* Do nothing? */ 22671414826SSergio Aguirre 22771414826SSergio Aguirre omap4iss_isp_enable_interrupts(iss); 22871414826SSergio Aguirre } 22971414826SSergio Aguirre 23071414826SSergio Aguirre /* ----------------------------------------------------------------------------- 23171414826SSergio Aguirre * Interrupt handling 23271414826SSergio Aguirre */ 23371414826SSergio Aguirre 23471414826SSergio Aguirre static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif) 23571414826SSergio Aguirre { 23671414826SSergio Aguirre struct iss_buffer *buffer; 23771414826SSergio Aguirre 23871414826SSergio Aguirre ipipeif_write_enable(ipipeif, 0); 23971414826SSergio Aguirre 24071414826SSergio Aguirre buffer = omap4iss_video_buffer_next(&ipipeif->video_out); 24171414826SSergio Aguirre if (buffer == NULL) 24271414826SSergio Aguirre return; 24371414826SSergio Aguirre 24471414826SSergio Aguirre ipipeif_set_outaddr(ipipeif, buffer->iss_addr); 24571414826SSergio Aguirre 24671414826SSergio Aguirre ipipeif_write_enable(ipipeif, 1); 24771414826SSergio Aguirre } 24871414826SSergio Aguirre 24971414826SSergio Aguirre /* 25071414826SSergio Aguirre * ipipeif_isif0_isr - Handle ISIF0 event 25171414826SSergio Aguirre * @ipipeif: Pointer to ISP IPIPEIF device. 25271414826SSergio Aguirre * 25371414826SSergio Aguirre * Executes LSC deferred enablement before next frame starts. 25471414826SSergio Aguirre */ 25571414826SSergio Aguirre static void ipipeif_isif0_isr(struct iss_ipipeif_device *ipipeif) 25671414826SSergio Aguirre { 25771414826SSergio Aguirre struct iss_pipeline *pipe = 25871414826SSergio Aguirre to_iss_pipeline(&ipipeif->subdev.entity); 25971414826SSergio Aguirre if (pipe->do_propagation) 26071414826SSergio Aguirre atomic_inc(&pipe->frame_number); 26171414826SSergio Aguirre 26271414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 26371414826SSergio Aguirre ipipeif_isr_buffer(ipipeif); 26471414826SSergio Aguirre } 26571414826SSergio Aguirre 26671414826SSergio Aguirre /* 26771414826SSergio Aguirre * omap4iss_ipipeif_isr - Configure ipipeif during interframe time. 26871414826SSergio Aguirre * @ipipeif: Pointer to ISP IPIPEIF device. 26971414826SSergio Aguirre * @events: IPIPEIF events 27071414826SSergio Aguirre */ 27171414826SSergio Aguirre void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events) 27271414826SSergio Aguirre { 273a0fe029cSLaurent Pinchart if (omap4iss_module_sync_is_stopping(&ipipeif->wait, 274a0fe029cSLaurent Pinchart &ipipeif->stopping)) 27571414826SSergio Aguirre return; 27671414826SSergio Aguirre 277ade1ec37SLaurent Pinchart if (events & ISP5_IRQ_ISIF_INT(0)) 27871414826SSergio Aguirre ipipeif_isif0_isr(ipipeif); 27971414826SSergio Aguirre } 28071414826SSergio Aguirre 28171414826SSergio Aguirre /* ----------------------------------------------------------------------------- 28271414826SSergio Aguirre * ISP video operations 28371414826SSergio Aguirre */ 28471414826SSergio Aguirre 285a0fe029cSLaurent Pinchart static int ipipeif_video_queue(struct iss_video *video, 286a0fe029cSLaurent Pinchart struct iss_buffer *buffer) 28771414826SSergio Aguirre { 28871414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = container_of(video, 28971414826SSergio Aguirre struct iss_ipipeif_device, video_out); 29071414826SSergio Aguirre 29171414826SSergio Aguirre if (!(ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) 29271414826SSergio Aguirre return -ENODEV; 29371414826SSergio Aguirre 29471414826SSergio Aguirre ipipeif_set_outaddr(ipipeif, buffer->iss_addr); 29571414826SSergio Aguirre 29671414826SSergio Aguirre /* 29771414826SSergio Aguirre * If streaming was enabled before there was a buffer queued 29871414826SSergio Aguirre * or underrun happened in the ISR, the hardware was not enabled 29971414826SSergio Aguirre * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set. 30071414826SSergio Aguirre * Enable it now. 30171414826SSergio Aguirre */ 30271414826SSergio Aguirre if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { 30371414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 30471414826SSergio Aguirre ipipeif_write_enable(ipipeif, 1); 30571414826SSergio Aguirre ipipeif_enable(ipipeif, 1); 30671414826SSergio Aguirre iss_video_dmaqueue_flags_clr(video); 30771414826SSergio Aguirre } 30871414826SSergio Aguirre 30971414826SSergio Aguirre return 0; 31071414826SSergio Aguirre } 31171414826SSergio Aguirre 31271414826SSergio Aguirre static const struct iss_video_operations ipipeif_video_ops = { 31371414826SSergio Aguirre .queue = ipipeif_video_queue, 31471414826SSergio Aguirre }; 31571414826SSergio Aguirre 31671414826SSergio Aguirre /* ----------------------------------------------------------------------------- 31771414826SSergio Aguirre * V4L2 subdev operations 31871414826SSergio Aguirre */ 31971414826SSergio Aguirre 32071414826SSergio Aguirre #define IPIPEIF_DRV_SUBCLK_MASK (OMAP4_ISS_ISP_SUBCLK_IPIPEIF |\ 32171414826SSergio Aguirre OMAP4_ISS_ISP_SUBCLK_ISIF) 32271414826SSergio Aguirre /* 32371414826SSergio Aguirre * ipipeif_set_stream - Enable/Disable streaming on the IPIPEIF module 32471414826SSergio Aguirre * @sd: ISP IPIPEIF V4L2 subdevice 32571414826SSergio Aguirre * @enable: Enable/disable stream 32671414826SSergio Aguirre */ 32771414826SSergio Aguirre static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) 32871414826SSergio Aguirre { 32971414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 33071414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 33171414826SSergio Aguirre struct iss_video *video_out = &ipipeif->video_out; 33271414826SSergio Aguirre int ret = 0; 33371414826SSergio Aguirre 33471414826SSergio Aguirre if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) { 33571414826SSergio Aguirre if (enable == ISS_PIPELINE_STREAM_STOPPED) 33671414826SSergio Aguirre return 0; 33771414826SSergio Aguirre 33871414826SSergio Aguirre omap4iss_isp_subclk_enable(iss, IPIPEIF_DRV_SUBCLK_MASK); 33971414826SSergio Aguirre } 34071414826SSergio Aguirre 34171414826SSergio Aguirre switch (enable) { 34271414826SSergio Aguirre case ISS_PIPELINE_STREAM_CONTINUOUS: 34371414826SSergio Aguirre 34471414826SSergio Aguirre ipipeif_configure(ipipeif); 34571414826SSergio Aguirre ipipeif_print_status(ipipeif); 34671414826SSergio Aguirre 34771414826SSergio Aguirre /* 34871414826SSergio Aguirre * When outputting to memory with no buffer available, let the 34971414826SSergio Aguirre * buffer queue handler start the hardware. A DMA queue flag 35071414826SSergio Aguirre * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is 35171414826SSergio Aguirre * a buffer available. 35271414826SSergio Aguirre */ 35371414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY && 35471414826SSergio Aguirre !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) 35571414826SSergio Aguirre break; 35671414826SSergio Aguirre 35771414826SSergio Aguirre atomic_set(&ipipeif->stopping, 0); 35871414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 35971414826SSergio Aguirre ipipeif_write_enable(ipipeif, 1); 36071414826SSergio Aguirre ipipeif_enable(ipipeif, 1); 36171414826SSergio Aguirre iss_video_dmaqueue_flags_clr(video_out); 36271414826SSergio Aguirre break; 36371414826SSergio Aguirre 36471414826SSergio Aguirre case ISS_PIPELINE_STREAM_STOPPED: 36571414826SSergio Aguirre if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) 36671414826SSergio Aguirre return 0; 36771414826SSergio Aguirre if (omap4iss_module_sync_idle(&sd->entity, &ipipeif->wait, 36871414826SSergio Aguirre &ipipeif->stopping)) 36971414826SSergio Aguirre dev_dbg(iss->dev, "%s: module stop timeout.\n", 37071414826SSergio Aguirre sd->name); 37171414826SSergio Aguirre 37271414826SSergio Aguirre if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) 37371414826SSergio Aguirre ipipeif_write_enable(ipipeif, 0); 37471414826SSergio Aguirre ipipeif_enable(ipipeif, 0); 37571414826SSergio Aguirre omap4iss_isp_disable_interrupts(iss); 37671414826SSergio Aguirre omap4iss_isp_subclk_disable(iss, IPIPEIF_DRV_SUBCLK_MASK); 37771414826SSergio Aguirre iss_video_dmaqueue_flags_clr(video_out); 37871414826SSergio Aguirre break; 37971414826SSergio Aguirre } 38071414826SSergio Aguirre 38171414826SSergio Aguirre ipipeif->state = enable; 38271414826SSergio Aguirre return ret; 38371414826SSergio Aguirre } 38471414826SSergio Aguirre 38571414826SSergio Aguirre static struct v4l2_mbus_framefmt * 386a0fe029cSLaurent Pinchart __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, 387a0fe029cSLaurent Pinchart struct v4l2_subdev_fh *fh, unsigned int pad, 388a0fe029cSLaurent Pinchart enum v4l2_subdev_format_whence which) 38971414826SSergio Aguirre { 39071414826SSergio Aguirre if (which == V4L2_SUBDEV_FORMAT_TRY) 39171414826SSergio Aguirre return v4l2_subdev_get_try_format(fh, pad); 39271414826SSergio Aguirre else 39371414826SSergio Aguirre return &ipipeif->formats[pad]; 39471414826SSergio Aguirre } 39571414826SSergio Aguirre 39671414826SSergio Aguirre /* 39771414826SSergio Aguirre * ipipeif_try_format - Try video format on a pad 39871414826SSergio Aguirre * @ipipeif: ISS IPIPEIF device 39971414826SSergio Aguirre * @fh : V4L2 subdev file handle 40071414826SSergio Aguirre * @pad: Pad number 40171414826SSergio Aguirre * @fmt: Format 40271414826SSergio Aguirre */ 40371414826SSergio Aguirre static void 404a0fe029cSLaurent Pinchart ipipeif_try_format(struct iss_ipipeif_device *ipipeif, 405a0fe029cSLaurent Pinchart struct v4l2_subdev_fh *fh, unsigned int pad, 406a0fe029cSLaurent Pinchart struct v4l2_mbus_framefmt *fmt, 40771414826SSergio Aguirre enum v4l2_subdev_format_whence which) 40871414826SSergio Aguirre { 40971414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 41071414826SSergio Aguirre unsigned int width = fmt->width; 41171414826SSergio Aguirre unsigned int height = fmt->height; 41271414826SSergio Aguirre unsigned int i; 41371414826SSergio Aguirre 41471414826SSergio Aguirre switch (pad) { 41571414826SSergio Aguirre case IPIPEIF_PAD_SINK: 416a0fe029cSLaurent Pinchart /* TODO: If the IPIPEIF output formatter pad is connected 417a0fe029cSLaurent Pinchart * directly to the resizer, only YUV formats can be used. 41871414826SSergio Aguirre */ 41971414826SSergio Aguirre for (i = 0; i < ARRAY_SIZE(ipipeif_fmts); i++) { 42071414826SSergio Aguirre if (fmt->code == ipipeif_fmts[i]) 42171414826SSergio Aguirre break; 42271414826SSergio Aguirre } 42371414826SSergio Aguirre 42471414826SSergio Aguirre /* If not found, use SGRBG10 as default */ 42571414826SSergio Aguirre if (i >= ARRAY_SIZE(ipipeif_fmts)) 42671414826SSergio Aguirre fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; 42771414826SSergio Aguirre 42871414826SSergio Aguirre /* Clamp the input size. */ 42971414826SSergio Aguirre fmt->width = clamp_t(u32, width, 1, 8192); 43071414826SSergio Aguirre fmt->height = clamp_t(u32, height, 1, 8192); 43171414826SSergio Aguirre break; 43271414826SSergio Aguirre 43371414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_ISIF_SF: 434a0fe029cSLaurent Pinchart format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, 435a0fe029cSLaurent Pinchart which); 43671414826SSergio Aguirre memcpy(fmt, format, sizeof(*fmt)); 43771414826SSergio Aguirre 43871414826SSergio Aguirre /* The data formatter truncates the number of horizontal output 43971414826SSergio Aguirre * pixels to a multiple of 16. To avoid clipping data, allow 44071414826SSergio Aguirre * callers to request an output size bigger than the input size 44171414826SSergio Aguirre * up to the nearest multiple of 16. 44271414826SSergio Aguirre */ 44371414826SSergio Aguirre fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); 44471414826SSergio Aguirre fmt->width &= ~15; 44571414826SSergio Aguirre fmt->height = clamp_t(u32, height, 32, fmt->height); 44671414826SSergio Aguirre break; 44771414826SSergio Aguirre 44871414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_VP: 449a0fe029cSLaurent Pinchart format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, 450a0fe029cSLaurent Pinchart which); 45171414826SSergio Aguirre memcpy(fmt, format, sizeof(*fmt)); 45271414826SSergio Aguirre 45371414826SSergio Aguirre fmt->width = clamp_t(u32, width, 32, fmt->width); 45471414826SSergio Aguirre fmt->height = clamp_t(u32, height, 32, fmt->height); 45571414826SSergio Aguirre break; 45671414826SSergio Aguirre } 45771414826SSergio Aguirre 45871414826SSergio Aguirre /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is 45971414826SSergio Aguirre * stored on 2 bytes. 46071414826SSergio Aguirre */ 46171414826SSergio Aguirre fmt->colorspace = V4L2_COLORSPACE_SRGB; 46271414826SSergio Aguirre fmt->field = V4L2_FIELD_NONE; 46371414826SSergio Aguirre } 46471414826SSergio Aguirre 46571414826SSergio Aguirre /* 46671414826SSergio Aguirre * ipipeif_enum_mbus_code - Handle pixel format enumeration 46771414826SSergio Aguirre * @sd : pointer to v4l2 subdev structure 46871414826SSergio Aguirre * @fh : V4L2 subdev file handle 46971414826SSergio Aguirre * @code : pointer to v4l2_subdev_mbus_code_enum structure 47071414826SSergio Aguirre * return -EINVAL or zero on success 47171414826SSergio Aguirre */ 47271414826SSergio Aguirre static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, 47371414826SSergio Aguirre struct v4l2_subdev_fh *fh, 47471414826SSergio Aguirre struct v4l2_subdev_mbus_code_enum *code) 47571414826SSergio Aguirre { 47671414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 47771414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 47871414826SSergio Aguirre 47971414826SSergio Aguirre switch (code->pad) { 48071414826SSergio Aguirre case IPIPEIF_PAD_SINK: 48171414826SSergio Aguirre if (code->index >= ARRAY_SIZE(ipipeif_fmts)) 48271414826SSergio Aguirre return -EINVAL; 48371414826SSergio Aguirre 48471414826SSergio Aguirre code->code = ipipeif_fmts[code->index]; 48571414826SSergio Aguirre break; 48671414826SSergio Aguirre 48771414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_ISIF_SF: 48871414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_VP: 48971414826SSergio Aguirre /* No format conversion inside IPIPEIF */ 49071414826SSergio Aguirre if (code->index != 0) 49171414826SSergio Aguirre return -EINVAL; 49271414826SSergio Aguirre 49371414826SSergio Aguirre format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, 49471414826SSergio Aguirre V4L2_SUBDEV_FORMAT_TRY); 49571414826SSergio Aguirre 49671414826SSergio Aguirre code->code = format->code; 49771414826SSergio Aguirre break; 49871414826SSergio Aguirre 49971414826SSergio Aguirre default: 50071414826SSergio Aguirre return -EINVAL; 50171414826SSergio Aguirre } 50271414826SSergio Aguirre 50371414826SSergio Aguirre return 0; 50471414826SSergio Aguirre } 50571414826SSergio Aguirre 50671414826SSergio Aguirre static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, 50771414826SSergio Aguirre struct v4l2_subdev_fh *fh, 50871414826SSergio Aguirre struct v4l2_subdev_frame_size_enum *fse) 50971414826SSergio Aguirre { 51071414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 51171414826SSergio Aguirre struct v4l2_mbus_framefmt format; 51271414826SSergio Aguirre 51371414826SSergio Aguirre if (fse->index != 0) 51471414826SSergio Aguirre return -EINVAL; 51571414826SSergio Aguirre 51671414826SSergio Aguirre format.code = fse->code; 51771414826SSergio Aguirre format.width = 1; 51871414826SSergio Aguirre format.height = 1; 519a0fe029cSLaurent Pinchart ipipeif_try_format(ipipeif, fh, fse->pad, &format, 520a0fe029cSLaurent Pinchart V4L2_SUBDEV_FORMAT_TRY); 52171414826SSergio Aguirre fse->min_width = format.width; 52271414826SSergio Aguirre fse->min_height = format.height; 52371414826SSergio Aguirre 52471414826SSergio Aguirre if (format.code != fse->code) 52571414826SSergio Aguirre return -EINVAL; 52671414826SSergio Aguirre 52771414826SSergio Aguirre format.code = fse->code; 52871414826SSergio Aguirre format.width = -1; 52971414826SSergio Aguirre format.height = -1; 530a0fe029cSLaurent Pinchart ipipeif_try_format(ipipeif, fh, fse->pad, &format, 531a0fe029cSLaurent Pinchart V4L2_SUBDEV_FORMAT_TRY); 53271414826SSergio Aguirre fse->max_width = format.width; 53371414826SSergio Aguirre fse->max_height = format.height; 53471414826SSergio Aguirre 53571414826SSergio Aguirre return 0; 53671414826SSergio Aguirre } 53771414826SSergio Aguirre 53871414826SSergio Aguirre /* 53971414826SSergio Aguirre * ipipeif_get_format - Retrieve the video format on a pad 54071414826SSergio Aguirre * @sd : ISP IPIPEIF V4L2 subdevice 54171414826SSergio Aguirre * @fh : V4L2 subdev file handle 54271414826SSergio Aguirre * @fmt: Format 54371414826SSergio Aguirre * 54471414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 54571414826SSergio Aguirre * to the format type. 54671414826SSergio Aguirre */ 54771414826SSergio Aguirre static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 54871414826SSergio Aguirre struct v4l2_subdev_format *fmt) 54971414826SSergio Aguirre { 55071414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 55171414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 55271414826SSergio Aguirre 55371414826SSergio Aguirre format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); 55471414826SSergio Aguirre if (format == NULL) 55571414826SSergio Aguirre return -EINVAL; 55671414826SSergio Aguirre 55771414826SSergio Aguirre fmt->format = *format; 55871414826SSergio Aguirre return 0; 55971414826SSergio Aguirre } 56071414826SSergio Aguirre 56171414826SSergio Aguirre /* 56271414826SSergio Aguirre * ipipeif_set_format - Set the video format on a pad 56371414826SSergio Aguirre * @sd : ISP IPIPEIF V4L2 subdevice 56471414826SSergio Aguirre * @fh : V4L2 subdev file handle 56571414826SSergio Aguirre * @fmt: Format 56671414826SSergio Aguirre * 56771414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 56871414826SSergio Aguirre * to the format type. 56971414826SSergio Aguirre */ 57071414826SSergio Aguirre static int ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 57171414826SSergio Aguirre struct v4l2_subdev_format *fmt) 57271414826SSergio Aguirre { 57371414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 57471414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 57571414826SSergio Aguirre 57671414826SSergio Aguirre format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); 57771414826SSergio Aguirre if (format == NULL) 57871414826SSergio Aguirre return -EINVAL; 57971414826SSergio Aguirre 58071414826SSergio Aguirre ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which); 58171414826SSergio Aguirre *format = fmt->format; 58271414826SSergio Aguirre 58371414826SSergio Aguirre /* Propagate the format from sink to source */ 58471414826SSergio Aguirre if (fmt->pad == IPIPEIF_PAD_SINK) { 585a0fe029cSLaurent Pinchart format = __ipipeif_get_format(ipipeif, fh, 586a0fe029cSLaurent Pinchart IPIPEIF_PAD_SOURCE_ISIF_SF, 58771414826SSergio Aguirre fmt->which); 58871414826SSergio Aguirre *format = fmt->format; 589a0fe029cSLaurent Pinchart ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_ISIF_SF, 590a0fe029cSLaurent Pinchart format, fmt->which); 59171414826SSergio Aguirre 592a0fe029cSLaurent Pinchart format = __ipipeif_get_format(ipipeif, fh, 593a0fe029cSLaurent Pinchart IPIPEIF_PAD_SOURCE_VP, 59471414826SSergio Aguirre fmt->which); 59571414826SSergio Aguirre *format = fmt->format; 59671414826SSergio Aguirre ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_VP, format, 59771414826SSergio Aguirre fmt->which); 59871414826SSergio Aguirre } 59971414826SSergio Aguirre 60071414826SSergio Aguirre return 0; 60171414826SSergio Aguirre } 60271414826SSergio Aguirre 603a0fe029cSLaurent Pinchart static int ipipeif_link_validate(struct v4l2_subdev *sd, 604a0fe029cSLaurent Pinchart struct media_link *link, 60571414826SSergio Aguirre struct v4l2_subdev_format *source_fmt, 60671414826SSergio Aguirre struct v4l2_subdev_format *sink_fmt) 60771414826SSergio Aguirre { 60871414826SSergio Aguirre /* Check if the two ends match */ 60971414826SSergio Aguirre if (source_fmt->format.width != sink_fmt->format.width || 61071414826SSergio Aguirre source_fmt->format.height != sink_fmt->format.height) 61171414826SSergio Aguirre return -EPIPE; 61271414826SSergio Aguirre 61371414826SSergio Aguirre if (source_fmt->format.code != sink_fmt->format.code) 61471414826SSergio Aguirre return -EPIPE; 61571414826SSergio Aguirre 61671414826SSergio Aguirre return 0; 61771414826SSergio Aguirre } 61871414826SSergio Aguirre 61971414826SSergio Aguirre /* 62071414826SSergio Aguirre * ipipeif_init_formats - Initialize formats on all pads 62171414826SSergio Aguirre * @sd: ISP IPIPEIF V4L2 subdevice 62271414826SSergio Aguirre * @fh: V4L2 subdev file handle 62371414826SSergio Aguirre * 62471414826SSergio Aguirre * Initialize all pad formats with default values. If fh is not NULL, try 62571414826SSergio Aguirre * formats are initialized on the file handle. Otherwise active formats are 62671414826SSergio Aguirre * initialized on the device. 62771414826SSergio Aguirre */ 628a0fe029cSLaurent Pinchart static int ipipeif_init_formats(struct v4l2_subdev *sd, 629a0fe029cSLaurent Pinchart struct v4l2_subdev_fh *fh) 63071414826SSergio Aguirre { 63171414826SSergio Aguirre struct v4l2_subdev_format format; 63271414826SSergio Aguirre 63371414826SSergio Aguirre memset(&format, 0, sizeof(format)); 63471414826SSergio Aguirre format.pad = IPIPEIF_PAD_SINK; 63571414826SSergio Aguirre format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 63671414826SSergio Aguirre format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; 63771414826SSergio Aguirre format.format.width = 4096; 63871414826SSergio Aguirre format.format.height = 4096; 63971414826SSergio Aguirre ipipeif_set_format(sd, fh, &format); 64071414826SSergio Aguirre 64171414826SSergio Aguirre return 0; 64271414826SSergio Aguirre } 64371414826SSergio Aguirre 64471414826SSergio Aguirre /* V4L2 subdev video operations */ 64571414826SSergio Aguirre static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { 64671414826SSergio Aguirre .s_stream = ipipeif_set_stream, 64771414826SSergio Aguirre }; 64871414826SSergio Aguirre 64971414826SSergio Aguirre /* V4L2 subdev pad operations */ 65071414826SSergio Aguirre static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { 65171414826SSergio Aguirre .enum_mbus_code = ipipeif_enum_mbus_code, 65271414826SSergio Aguirre .enum_frame_size = ipipeif_enum_frame_size, 65371414826SSergio Aguirre .get_fmt = ipipeif_get_format, 65471414826SSergio Aguirre .set_fmt = ipipeif_set_format, 65571414826SSergio Aguirre .link_validate = ipipeif_link_validate, 65671414826SSergio Aguirre }; 65771414826SSergio Aguirre 65871414826SSergio Aguirre /* V4L2 subdev operations */ 65971414826SSergio Aguirre static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { 66071414826SSergio Aguirre .video = &ipipeif_v4l2_video_ops, 66171414826SSergio Aguirre .pad = &ipipeif_v4l2_pad_ops, 66271414826SSergio Aguirre }; 66371414826SSergio Aguirre 66471414826SSergio Aguirre /* V4L2 subdev internal operations */ 66571414826SSergio Aguirre static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { 66671414826SSergio Aguirre .open = ipipeif_init_formats, 66771414826SSergio Aguirre }; 66871414826SSergio Aguirre 66971414826SSergio Aguirre /* ----------------------------------------------------------------------------- 67071414826SSergio Aguirre * Media entity operations 67171414826SSergio Aguirre */ 67271414826SSergio Aguirre 67371414826SSergio Aguirre /* 67471414826SSergio Aguirre * ipipeif_link_setup - Setup IPIPEIF connections 67571414826SSergio Aguirre * @entity: IPIPEIF media entity 67671414826SSergio Aguirre * @local: Pad at the local end of the link 67771414826SSergio Aguirre * @remote: Pad at the remote end of the link 67871414826SSergio Aguirre * @flags: Link flags 67971414826SSergio Aguirre * 68071414826SSergio Aguirre * return -EINVAL or zero on success 68171414826SSergio Aguirre */ 68271414826SSergio Aguirre static int ipipeif_link_setup(struct media_entity *entity, 68371414826SSergio Aguirre const struct media_pad *local, 68471414826SSergio Aguirre const struct media_pad *remote, u32 flags) 68571414826SSergio Aguirre { 68671414826SSergio Aguirre struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 68771414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); 68871414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipeif); 68971414826SSergio Aguirre 69071414826SSergio Aguirre switch (local->index | media_entity_type(remote->entity)) { 69171414826SSergio Aguirre case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: 69271414826SSergio Aguirre /* Read from the sensor CSI2a or CSI2b. */ 69371414826SSergio Aguirre if (!(flags & MEDIA_LNK_FL_ENABLED)) { 69471414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_NONE; 69571414826SSergio Aguirre break; 69671414826SSergio Aguirre } 69771414826SSergio Aguirre 69871414826SSergio Aguirre if (ipipeif->input != IPIPEIF_INPUT_NONE) 69971414826SSergio Aguirre return -EBUSY; 70071414826SSergio Aguirre 70171414826SSergio Aguirre if (remote->entity == &iss->csi2a.subdev.entity) 70271414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_CSI2A; 70371414826SSergio Aguirre else if (remote->entity == &iss->csi2b.subdev.entity) 70471414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_CSI2B; 70571414826SSergio Aguirre 70671414826SSergio Aguirre break; 70771414826SSergio Aguirre 70871414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_ISIF_SF | MEDIA_ENT_T_DEVNODE: 70971414826SSergio Aguirre /* Write to memory */ 71071414826SSergio Aguirre if (flags & MEDIA_LNK_FL_ENABLED) { 71171414826SSergio Aguirre if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY) 71271414826SSergio Aguirre return -EBUSY; 71371414826SSergio Aguirre ipipeif->output |= IPIPEIF_OUTPUT_MEMORY; 71471414826SSergio Aguirre } else { 71571414826SSergio Aguirre ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY; 71671414826SSergio Aguirre } 71771414826SSergio Aguirre break; 71871414826SSergio Aguirre 71971414826SSergio Aguirre case IPIPEIF_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV: 72071414826SSergio Aguirre /* Send to IPIPE/RESIZER */ 72171414826SSergio Aguirre if (flags & MEDIA_LNK_FL_ENABLED) { 72271414826SSergio Aguirre if (ipipeif->output & ~IPIPEIF_OUTPUT_VP) 72371414826SSergio Aguirre return -EBUSY; 72471414826SSergio Aguirre ipipeif->output |= IPIPEIF_OUTPUT_VP; 72571414826SSergio Aguirre } else { 72671414826SSergio Aguirre ipipeif->output &= ~IPIPEIF_OUTPUT_VP; 72771414826SSergio Aguirre } 72871414826SSergio Aguirre break; 72971414826SSergio Aguirre 73071414826SSergio Aguirre default: 73171414826SSergio Aguirre return -EINVAL; 73271414826SSergio Aguirre } 73371414826SSergio Aguirre 73471414826SSergio Aguirre return 0; 73571414826SSergio Aguirre } 73671414826SSergio Aguirre 73771414826SSergio Aguirre /* media operations */ 73871414826SSergio Aguirre static const struct media_entity_operations ipipeif_media_ops = { 73971414826SSergio Aguirre .link_setup = ipipeif_link_setup, 74071414826SSergio Aguirre .link_validate = v4l2_subdev_link_validate, 74171414826SSergio Aguirre }; 74271414826SSergio Aguirre 74371414826SSergio Aguirre /* 74471414826SSergio Aguirre * ipipeif_init_entities - Initialize V4L2 subdev and media entity 74571414826SSergio Aguirre * @ipipeif: ISS ISP IPIPEIF module 74671414826SSergio Aguirre * 74771414826SSergio Aguirre * Return 0 on success and a negative error code on failure. 74871414826SSergio Aguirre */ 74971414826SSergio Aguirre static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif) 75071414826SSergio Aguirre { 75171414826SSergio Aguirre struct v4l2_subdev *sd = &ipipeif->subdev; 75271414826SSergio Aguirre struct media_pad *pads = ipipeif->pads; 75371414826SSergio Aguirre struct media_entity *me = &sd->entity; 75471414826SSergio Aguirre int ret; 75571414826SSergio Aguirre 75671414826SSergio Aguirre ipipeif->input = IPIPEIF_INPUT_NONE; 75771414826SSergio Aguirre 75871414826SSergio Aguirre v4l2_subdev_init(sd, &ipipeif_v4l2_ops); 75971414826SSergio Aguirre sd->internal_ops = &ipipeif_v4l2_internal_ops; 76071414826SSergio Aguirre strlcpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name)); 76171414826SSergio Aguirre sd->grp_id = 1 << 16; /* group ID for iss subdevs */ 76271414826SSergio Aguirre v4l2_set_subdevdata(sd, ipipeif); 76371414826SSergio Aguirre sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 76471414826SSergio Aguirre 76571414826SSergio Aguirre pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 76671414826SSergio Aguirre pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE; 76771414826SSergio Aguirre pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; 76871414826SSergio Aguirre 76971414826SSergio Aguirre me->ops = &ipipeif_media_ops; 77071414826SSergio Aguirre ret = media_entity_init(me, IPIPEIF_PADS_NUM, pads, 0); 77171414826SSergio Aguirre if (ret < 0) 77271414826SSergio Aguirre return ret; 77371414826SSergio Aguirre 77471414826SSergio Aguirre ipipeif_init_formats(sd, NULL); 77571414826SSergio Aguirre 77671414826SSergio Aguirre ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 77771414826SSergio Aguirre ipipeif->video_out.ops = &ipipeif_video_ops; 77871414826SSergio Aguirre ipipeif->video_out.iss = to_iss_device(ipipeif); 77971414826SSergio Aguirre ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 78071414826SSergio Aguirre ipipeif->video_out.bpl_alignment = 32; 78171414826SSergio Aguirre ipipeif->video_out.bpl_zero_padding = 1; 78271414826SSergio Aguirre ipipeif->video_out.bpl_max = 0x1ffe0; 78371414826SSergio Aguirre 78471414826SSergio Aguirre ret = omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF"); 78571414826SSergio Aguirre if (ret < 0) 78671414826SSergio Aguirre return ret; 78771414826SSergio Aguirre 78871414826SSergio Aguirre /* Connect the IPIPEIF subdev to the video node. */ 789a0fe029cSLaurent Pinchart ret = media_entity_create_link(&ipipeif->subdev.entity, 790a0fe029cSLaurent Pinchart IPIPEIF_PAD_SOURCE_ISIF_SF, 79171414826SSergio Aguirre &ipipeif->video_out.video.entity, 0, 0); 79271414826SSergio Aguirre if (ret < 0) 79371414826SSergio Aguirre return ret; 79471414826SSergio Aguirre 79571414826SSergio Aguirre return 0; 79671414826SSergio Aguirre } 79771414826SSergio Aguirre 79871414826SSergio Aguirre void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif) 79971414826SSergio Aguirre { 80071414826SSergio Aguirre media_entity_cleanup(&ipipeif->subdev.entity); 80171414826SSergio Aguirre 80271414826SSergio Aguirre v4l2_device_unregister_subdev(&ipipeif->subdev); 80371414826SSergio Aguirre omap4iss_video_unregister(&ipipeif->video_out); 80471414826SSergio Aguirre } 80571414826SSergio Aguirre 80671414826SSergio Aguirre int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif, 80771414826SSergio Aguirre struct v4l2_device *vdev) 80871414826SSergio Aguirre { 80971414826SSergio Aguirre int ret; 81071414826SSergio Aguirre 81171414826SSergio Aguirre /* Register the subdev and video node. */ 81271414826SSergio Aguirre ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); 81371414826SSergio Aguirre if (ret < 0) 81471414826SSergio Aguirre goto error; 81571414826SSergio Aguirre 81671414826SSergio Aguirre ret = omap4iss_video_register(&ipipeif->video_out, vdev); 81771414826SSergio Aguirre if (ret < 0) 81871414826SSergio Aguirre goto error; 81971414826SSergio Aguirre 82071414826SSergio Aguirre return 0; 82171414826SSergio Aguirre 82271414826SSergio Aguirre error: 82371414826SSergio Aguirre omap4iss_ipipeif_unregister_entities(ipipeif); 82471414826SSergio Aguirre return ret; 82571414826SSergio Aguirre } 82671414826SSergio Aguirre 82771414826SSergio Aguirre /* ----------------------------------------------------------------------------- 82871414826SSergio Aguirre * ISP IPIPEIF initialisation and cleanup 82971414826SSergio Aguirre */ 83071414826SSergio Aguirre 83171414826SSergio Aguirre /* 83271414826SSergio Aguirre * omap4iss_ipipeif_init - IPIPEIF module initialization. 83371414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS. 83471414826SSergio Aguirre * 83571414826SSergio Aguirre * TODO: Get the initialisation values from platform data. 83671414826SSergio Aguirre * 83771414826SSergio Aguirre * Return 0 on success or a negative error code otherwise. 83871414826SSergio Aguirre */ 83971414826SSergio Aguirre int omap4iss_ipipeif_init(struct iss_device *iss) 84071414826SSergio Aguirre { 84171414826SSergio Aguirre struct iss_ipipeif_device *ipipeif = &iss->ipipeif; 84271414826SSergio Aguirre 84371414826SSergio Aguirre ipipeif->state = ISS_PIPELINE_STREAM_STOPPED; 84471414826SSergio Aguirre init_waitqueue_head(&ipipeif->wait); 84571414826SSergio Aguirre 84671414826SSergio Aguirre return ipipeif_init_entities(ipipeif); 84771414826SSergio Aguirre } 84871414826SSergio Aguirre 84971414826SSergio Aguirre /* 85071414826SSergio Aguirre * omap4iss_ipipeif_cleanup - IPIPEIF module cleanup. 85171414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS. 85271414826SSergio Aguirre */ 85371414826SSergio Aguirre void omap4iss_ipipeif_cleanup(struct iss_device *iss) 85471414826SSergio Aguirre { 85571414826SSergio Aguirre /* FIXME: are you sure there's nothing to do? */ 85671414826SSergio Aguirre } 857