171414826SSergio Aguirre /* 271414826SSergio Aguirre * TI OMAP4 ISS V4L2 Driver - ISP IPIPE 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_ipipe.h" 2571414826SSergio Aguirre 2671414826SSergio Aguirre static struct v4l2_mbus_framefmt * 27ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe, 28ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 29ee8defecSPiotr S. Staszewski unsigned int pad, 30ee8defecSPiotr S. Staszewski enum v4l2_subdev_format_whence which); 3171414826SSergio Aguirre 3271414826SSergio Aguirre static const unsigned int ipipe_fmts[] = { 333336f07aSBoris BREZILLON MEDIA_BUS_FMT_SGRBG10_1X10, 343336f07aSBoris BREZILLON MEDIA_BUS_FMT_SRGGB10_1X10, 353336f07aSBoris BREZILLON MEDIA_BUS_FMT_SBGGR10_1X10, 363336f07aSBoris BREZILLON MEDIA_BUS_FMT_SGBRG10_1X10, 3771414826SSergio Aguirre }; 3871414826SSergio Aguirre 3971414826SSergio Aguirre /* 4071414826SSergio Aguirre * ipipe_print_status - Print current IPIPE Module register values. 4171414826SSergio Aguirre * @ipipe: Pointer to ISS ISP IPIPE device. 4271414826SSergio Aguirre * 4371414826SSergio Aguirre * Also prints other debug information stored in the IPIPE module. 4471414826SSergio Aguirre */ 4571414826SSergio Aguirre #define IPIPE_PRINT_REGISTER(iss, name)\ 4671414826SSergio Aguirre dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \ 4711abbfd3SLaurent Pinchart iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name)) 4871414826SSergio Aguirre 4971414826SSergio Aguirre static void ipipe_print_status(struct iss_ipipe_device *ipipe) 5071414826SSergio Aguirre { 5171414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe); 5271414826SSergio Aguirre 5371414826SSergio Aguirre dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n"); 5471414826SSergio Aguirre 5571414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_EN); 5671414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_MODE); 5771414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_FMT); 5871414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_COL); 5971414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_VPS); 6071414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_VSZ); 6171414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_HPS); 6271414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_HSZ); 6371414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, GCK_MMR); 6471414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, YUV_PHS); 6571414826SSergio Aguirre 6671414826SSergio Aguirre dev_dbg(iss->dev, "-----------------------------------------------\n"); 6771414826SSergio Aguirre } 6871414826SSergio Aguirre 6971414826SSergio Aguirre /* 7071414826SSergio Aguirre * ipipe_enable - Enable/Disable IPIPE. 7171414826SSergio Aguirre * @enable: enable flag 7271414826SSergio Aguirre * 7371414826SSergio Aguirre */ 7471414826SSergio Aguirre static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable) 7571414826SSergio Aguirre { 7671414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe); 7771414826SSergio Aguirre 7811abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN, 7911abbfd3SLaurent Pinchart IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0); 8071414826SSergio Aguirre } 8171414826SSergio Aguirre 8271414826SSergio Aguirre /* ----------------------------------------------------------------------------- 8371414826SSergio Aguirre * Format- and pipeline-related configuration helpers 8471414826SSergio Aguirre */ 8571414826SSergio Aguirre 8671414826SSergio Aguirre static void ipipe_configure(struct iss_ipipe_device *ipipe) 8771414826SSergio Aguirre { 8871414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe); 8971414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 9071414826SSergio Aguirre 9171414826SSergio Aguirre /* IPIPE_PAD_SINK */ 9271414826SSergio Aguirre format = &ipipe->formats[IPIPE_PAD_SINK]; 9371414826SSergio Aguirre 9471414826SSergio Aguirre /* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */ 9511abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT, 9611abbfd3SLaurent Pinchart IPIPE_SRC_FMT_RAW2YUV); 9771414826SSergio Aguirre 9871414826SSergio Aguirre /* Enable YUV444 -> YUV422 conversion */ 9911abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS, 10011abbfd3SLaurent Pinchart IPIPE_YUV_PHS_LPF); 10171414826SSergio Aguirre 10211abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0); 10311abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0); 10411abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ, 10511abbfd3SLaurent Pinchart (format->height - 2) & IPIPE_SRC_VSZ_MASK); 10611abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ, 10711abbfd3SLaurent Pinchart (format->width - 1) & IPIPE_SRC_HSZ_MASK); 10871414826SSergio Aguirre 10971414826SSergio Aguirre /* Ignore ipipeif_wrt signal, and operate on-the-fly. */ 11011abbfd3SLaurent Pinchart iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE, 11111abbfd3SLaurent Pinchart IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST); 11271414826SSergio Aguirre 11371414826SSergio Aguirre /* HACK: Values tuned for Ducati SW (OV) */ 11411abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL, 11511abbfd3SLaurent Pinchart IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB | 11611abbfd3SLaurent Pinchart IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R); 11771414826SSergio Aguirre 11871414826SSergio Aguirre /* IPIPE_PAD_SOURCE_VP */ 11971414826SSergio Aguirre format = &ipipe->formats[IPIPE_PAD_SOURCE_VP]; 12071414826SSergio Aguirre /* Do nothing? */ 12171414826SSergio Aguirre } 12271414826SSergio Aguirre 12371414826SSergio Aguirre /* ----------------------------------------------------------------------------- 12471414826SSergio Aguirre * V4L2 subdev operations 12571414826SSergio Aguirre */ 12671414826SSergio Aguirre 12771414826SSergio Aguirre /* 12871414826SSergio Aguirre * ipipe_set_stream - Enable/Disable streaming on the IPIPE module 12971414826SSergio Aguirre * @sd: ISP IPIPE V4L2 subdevice 13071414826SSergio Aguirre * @enable: Enable/disable stream 13171414826SSergio Aguirre */ 13271414826SSergio Aguirre static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) 13371414826SSergio Aguirre { 13471414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); 13571414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe); 13671414826SSergio Aguirre int ret = 0; 13771414826SSergio Aguirre 13871414826SSergio Aguirre if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) { 13971414826SSergio Aguirre if (enable == ISS_PIPELINE_STREAM_STOPPED) 14071414826SSergio Aguirre return 0; 14171414826SSergio Aguirre 14271414826SSergio Aguirre omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); 14371414826SSergio Aguirre 14471414826SSergio Aguirre /* Enable clk_arm_g0 */ 14511abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR, 14611abbfd3SLaurent Pinchart IPIPE_GCK_MMR_REG); 14771414826SSergio Aguirre 14871414826SSergio Aguirre /* Enable clk_pix_g[3:0] */ 14911abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX, 15011abbfd3SLaurent Pinchart IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 | 15111abbfd3SLaurent Pinchart IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0); 15271414826SSergio Aguirre } 15371414826SSergio Aguirre 15471414826SSergio Aguirre switch (enable) { 15571414826SSergio Aguirre case ISS_PIPELINE_STREAM_CONTINUOUS: 15671414826SSergio Aguirre 15771414826SSergio Aguirre ipipe_configure(ipipe); 15871414826SSergio Aguirre ipipe_print_status(ipipe); 15971414826SSergio Aguirre 16071414826SSergio Aguirre atomic_set(&ipipe->stopping, 0); 16171414826SSergio Aguirre ipipe_enable(ipipe, 1); 16271414826SSergio Aguirre break; 16371414826SSergio Aguirre 16471414826SSergio Aguirre case ISS_PIPELINE_STREAM_STOPPED: 16571414826SSergio Aguirre if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) 16671414826SSergio Aguirre return 0; 16771414826SSergio Aguirre if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait, 16871414826SSergio Aguirre &ipipe->stopping)) 1696016498fSLaurent Pinchart ret = -ETIMEDOUT; 17071414826SSergio Aguirre 17171414826SSergio Aguirre ipipe_enable(ipipe, 0); 17271414826SSergio Aguirre omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); 17371414826SSergio Aguirre break; 17471414826SSergio Aguirre } 17571414826SSergio Aguirre 17671414826SSergio Aguirre ipipe->state = enable; 17771414826SSergio Aguirre return ret; 17871414826SSergio Aguirre } 17971414826SSergio Aguirre 18071414826SSergio Aguirre static struct v4l2_mbus_framefmt * 181ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe, 182ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 183ee8defecSPiotr S. Staszewski unsigned int pad, 184ee8defecSPiotr S. Staszewski enum v4l2_subdev_format_whence which) 18571414826SSergio Aguirre { 18671414826SSergio Aguirre if (which == V4L2_SUBDEV_FORMAT_TRY) 187f7234138SHans Verkuil return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); 188ae357388SYeliz Taneroglu 18971414826SSergio Aguirre return &ipipe->formats[pad]; 19071414826SSergio Aguirre } 19171414826SSergio Aguirre 19271414826SSergio Aguirre /* 19371414826SSergio Aguirre * ipipe_try_format - Try video format on a pad 19471414826SSergio Aguirre * @ipipe: ISS IPIPE device 195f7234138SHans Verkuil * @cfg: V4L2 subdev pad config 19671414826SSergio Aguirre * @pad: Pad number 19771414826SSergio Aguirre * @fmt: Format 19871414826SSergio Aguirre */ 19971414826SSergio Aguirre static void 200ee8defecSPiotr S. Staszewski ipipe_try_format(struct iss_ipipe_device *ipipe, 201ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 202ee8defecSPiotr S. Staszewski unsigned int pad, 203ee8defecSPiotr S. Staszewski struct v4l2_mbus_framefmt *fmt, 20471414826SSergio Aguirre enum v4l2_subdev_format_whence which) 20571414826SSergio Aguirre { 20671414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 20771414826SSergio Aguirre unsigned int width = fmt->width; 20871414826SSergio Aguirre unsigned int height = fmt->height; 20971414826SSergio Aguirre unsigned int i; 21071414826SSergio Aguirre 21171414826SSergio Aguirre switch (pad) { 21271414826SSergio Aguirre case IPIPE_PAD_SINK: 21371414826SSergio Aguirre for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) { 21471414826SSergio Aguirre if (fmt->code == ipipe_fmts[i]) 21571414826SSergio Aguirre break; 21671414826SSergio Aguirre } 21771414826SSergio Aguirre 21871414826SSergio Aguirre /* If not found, use SGRBG10 as default */ 21971414826SSergio Aguirre if (i >= ARRAY_SIZE(ipipe_fmts)) 2203336f07aSBoris BREZILLON fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 22171414826SSergio Aguirre 22271414826SSergio Aguirre /* Clamp the input size. */ 22371414826SSergio Aguirre fmt->width = clamp_t(u32, width, 1, 8192); 22471414826SSergio Aguirre fmt->height = clamp_t(u32, height, 1, 8192); 22571414826SSergio Aguirre fmt->colorspace = V4L2_COLORSPACE_SRGB; 22671414826SSergio Aguirre break; 22771414826SSergio Aguirre 22871414826SSergio Aguirre case IPIPE_PAD_SOURCE_VP: 229f7234138SHans Verkuil format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which); 23071414826SSergio Aguirre memcpy(fmt, format, sizeof(*fmt)); 23171414826SSergio Aguirre 2323336f07aSBoris BREZILLON fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; 23371414826SSergio Aguirre fmt->width = clamp_t(u32, width, 32, fmt->width); 23471414826SSergio Aguirre fmt->height = clamp_t(u32, height, 32, fmt->height); 23571414826SSergio Aguirre fmt->colorspace = V4L2_COLORSPACE_JPEG; 23671414826SSergio Aguirre break; 23771414826SSergio Aguirre } 23871414826SSergio Aguirre 23971414826SSergio Aguirre fmt->field = V4L2_FIELD_NONE; 24071414826SSergio Aguirre } 24171414826SSergio Aguirre 24271414826SSergio Aguirre /* 24371414826SSergio Aguirre * ipipe_enum_mbus_code - Handle pixel format enumeration 24471414826SSergio Aguirre * @sd : pointer to v4l2 subdev structure 245f7234138SHans Verkuil * @cfg : V4L2 subdev pad config 24671414826SSergio Aguirre * @code : pointer to v4l2_subdev_mbus_code_enum structure 24771414826SSergio Aguirre * return -EINVAL or zero on success 24871414826SSergio Aguirre */ 24971414826SSergio Aguirre static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, 250f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 25171414826SSergio Aguirre struct v4l2_subdev_mbus_code_enum *code) 25271414826SSergio Aguirre { 25371414826SSergio Aguirre switch (code->pad) { 25471414826SSergio Aguirre case IPIPE_PAD_SINK: 25571414826SSergio Aguirre if (code->index >= ARRAY_SIZE(ipipe_fmts)) 25671414826SSergio Aguirre return -EINVAL; 25771414826SSergio Aguirre 25871414826SSergio Aguirre code->code = ipipe_fmts[code->index]; 25971414826SSergio Aguirre break; 26071414826SSergio Aguirre 26171414826SSergio Aguirre case IPIPE_PAD_SOURCE_VP: 26271414826SSergio Aguirre /* FIXME: Forced format conversion inside IPIPE ? */ 26371414826SSergio Aguirre if (code->index != 0) 26471414826SSergio Aguirre return -EINVAL; 26571414826SSergio Aguirre 2663336f07aSBoris BREZILLON code->code = MEDIA_BUS_FMT_UYVY8_1X16; 26771414826SSergio Aguirre break; 26871414826SSergio Aguirre 26971414826SSergio Aguirre default: 27071414826SSergio Aguirre return -EINVAL; 27171414826SSergio Aguirre } 27271414826SSergio Aguirre 27371414826SSergio Aguirre return 0; 27471414826SSergio Aguirre } 27571414826SSergio Aguirre 27671414826SSergio Aguirre static int ipipe_enum_frame_size(struct v4l2_subdev *sd, 277f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 27871414826SSergio Aguirre struct v4l2_subdev_frame_size_enum *fse) 27971414826SSergio Aguirre { 28071414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); 28171414826SSergio Aguirre struct v4l2_mbus_framefmt format; 28271414826SSergio Aguirre 28371414826SSergio Aguirre if (fse->index != 0) 28471414826SSergio Aguirre return -EINVAL; 28571414826SSergio Aguirre 28671414826SSergio Aguirre format.code = fse->code; 28771414826SSergio Aguirre format.width = 1; 28871414826SSergio Aguirre format.height = 1; 2895778e749SHans Verkuil ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); 29071414826SSergio Aguirre fse->min_width = format.width; 29171414826SSergio Aguirre fse->min_height = format.height; 29271414826SSergio Aguirre 29371414826SSergio Aguirre if (format.code != fse->code) 29471414826SSergio Aguirre return -EINVAL; 29571414826SSergio Aguirre 29671414826SSergio Aguirre format.code = fse->code; 29771414826SSergio Aguirre format.width = -1; 29871414826SSergio Aguirre format.height = -1; 2995778e749SHans Verkuil ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); 30071414826SSergio Aguirre fse->max_width = format.width; 30171414826SSergio Aguirre fse->max_height = format.height; 30271414826SSergio Aguirre 30371414826SSergio Aguirre return 0; 30471414826SSergio Aguirre } 30571414826SSergio Aguirre 30671414826SSergio Aguirre /* 30771414826SSergio Aguirre * ipipe_get_format - Retrieve the video format on a pad 30871414826SSergio Aguirre * @sd : ISP IPIPE V4L2 subdevice 309f7234138SHans Verkuil * @cfg: V4L2 subdev pad config 31071414826SSergio Aguirre * @fmt: Format 31171414826SSergio Aguirre * 31271414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 31371414826SSergio Aguirre * to the format type. 31471414826SSergio Aguirre */ 315ee8defecSPiotr S. Staszewski static int ipipe_get_format(struct v4l2_subdev *sd, 316ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 31771414826SSergio Aguirre struct v4l2_subdev_format *fmt) 31871414826SSergio Aguirre { 31971414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); 32071414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 32171414826SSergio Aguirre 322f7234138SHans Verkuil format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); 32371414826SSergio Aguirre if (format == NULL) 32471414826SSergio Aguirre return -EINVAL; 32571414826SSergio Aguirre 32671414826SSergio Aguirre fmt->format = *format; 32771414826SSergio Aguirre return 0; 32871414826SSergio Aguirre } 32971414826SSergio Aguirre 33071414826SSergio Aguirre /* 33171414826SSergio Aguirre * ipipe_set_format - Set the video format on a pad 33271414826SSergio Aguirre * @sd : ISP IPIPE V4L2 subdevice 333f7234138SHans Verkuil * @cfg: V4L2 subdev pad config 33471414826SSergio Aguirre * @fmt: Format 33571414826SSergio Aguirre * 33671414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 33771414826SSergio Aguirre * to the format type. 33871414826SSergio Aguirre */ 339ee8defecSPiotr S. Staszewski static int ipipe_set_format(struct v4l2_subdev *sd, 340ee8defecSPiotr S. Staszewski struct v4l2_subdev_pad_config *cfg, 34171414826SSergio Aguirre struct v4l2_subdev_format *fmt) 34271414826SSergio Aguirre { 34371414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); 34471414826SSergio Aguirre struct v4l2_mbus_framefmt *format; 34571414826SSergio Aguirre 346f7234138SHans Verkuil format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); 34771414826SSergio Aguirre if (format == NULL) 34871414826SSergio Aguirre return -EINVAL; 34971414826SSergio Aguirre 350f7234138SHans Verkuil ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); 35171414826SSergio Aguirre *format = fmt->format; 35271414826SSergio Aguirre 35371414826SSergio Aguirre /* Propagate the format from sink to source */ 35471414826SSergio Aguirre if (fmt->pad == IPIPE_PAD_SINK) { 355f7234138SHans Verkuil format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, 35671414826SSergio Aguirre fmt->which); 35771414826SSergio Aguirre *format = fmt->format; 358f7234138SHans Verkuil ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format, 35971414826SSergio Aguirre fmt->which); 36071414826SSergio Aguirre } 36171414826SSergio Aguirre 36271414826SSergio Aguirre return 0; 36371414826SSergio Aguirre } 36471414826SSergio Aguirre 36571414826SSergio Aguirre static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link, 36671414826SSergio Aguirre struct v4l2_subdev_format *source_fmt, 36771414826SSergio Aguirre struct v4l2_subdev_format *sink_fmt) 36871414826SSergio Aguirre { 36971414826SSergio Aguirre /* Check if the two ends match */ 37071414826SSergio Aguirre if (source_fmt->format.width != sink_fmt->format.width || 37171414826SSergio Aguirre source_fmt->format.height != sink_fmt->format.height) 37271414826SSergio Aguirre return -EPIPE; 37371414826SSergio Aguirre 37471414826SSergio Aguirre if (source_fmt->format.code != sink_fmt->format.code) 37571414826SSergio Aguirre return -EPIPE; 37671414826SSergio Aguirre 37771414826SSergio Aguirre return 0; 37871414826SSergio Aguirre } 37971414826SSergio Aguirre 38071414826SSergio Aguirre /* 38171414826SSergio Aguirre * ipipe_init_formats - Initialize formats on all pads 38271414826SSergio Aguirre * @sd: ISP IPIPE V4L2 subdevice 38371414826SSergio Aguirre * @fh: V4L2 subdev file handle 38471414826SSergio Aguirre * 38571414826SSergio Aguirre * Initialize all pad formats with default values. If fh is not NULL, try 38671414826SSergio Aguirre * formats are initialized on the file handle. Otherwise active formats are 38771414826SSergio Aguirre * initialized on the device. 38871414826SSergio Aguirre */ 38971414826SSergio Aguirre static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 39071414826SSergio Aguirre { 39171414826SSergio Aguirre struct v4l2_subdev_format format; 39271414826SSergio Aguirre 39371414826SSergio Aguirre memset(&format, 0, sizeof(format)); 39471414826SSergio Aguirre format.pad = IPIPE_PAD_SINK; 39571414826SSergio Aguirre format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 3963336f07aSBoris BREZILLON format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 39771414826SSergio Aguirre format.format.width = 4096; 39871414826SSergio Aguirre format.format.height = 4096; 399f7234138SHans Verkuil ipipe_set_format(sd, fh ? fh->pad : NULL, &format); 40071414826SSergio Aguirre 40171414826SSergio Aguirre return 0; 40271414826SSergio Aguirre } 40371414826SSergio Aguirre 40471414826SSergio Aguirre /* V4L2 subdev video operations */ 40571414826SSergio Aguirre static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = { 40671414826SSergio Aguirre .s_stream = ipipe_set_stream, 40771414826SSergio Aguirre }; 40871414826SSergio Aguirre 40971414826SSergio Aguirre /* V4L2 subdev pad operations */ 41071414826SSergio Aguirre static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = { 41171414826SSergio Aguirre .enum_mbus_code = ipipe_enum_mbus_code, 41271414826SSergio Aguirre .enum_frame_size = ipipe_enum_frame_size, 41371414826SSergio Aguirre .get_fmt = ipipe_get_format, 41471414826SSergio Aguirre .set_fmt = ipipe_set_format, 41571414826SSergio Aguirre .link_validate = ipipe_link_validate, 41671414826SSergio Aguirre }; 41771414826SSergio Aguirre 41871414826SSergio Aguirre /* V4L2 subdev operations */ 41971414826SSergio Aguirre static const struct v4l2_subdev_ops ipipe_v4l2_ops = { 42071414826SSergio Aguirre .video = &ipipe_v4l2_video_ops, 42171414826SSergio Aguirre .pad = &ipipe_v4l2_pad_ops, 42271414826SSergio Aguirre }; 42371414826SSergio Aguirre 42471414826SSergio Aguirre /* V4L2 subdev internal operations */ 42571414826SSergio Aguirre static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = { 42671414826SSergio Aguirre .open = ipipe_init_formats, 42771414826SSergio Aguirre }; 42871414826SSergio Aguirre 42971414826SSergio Aguirre /* ----------------------------------------------------------------------------- 43071414826SSergio Aguirre * Media entity operations 43171414826SSergio Aguirre */ 43271414826SSergio Aguirre 43371414826SSergio Aguirre /* 43471414826SSergio Aguirre * ipipe_link_setup - Setup IPIPE connections 43571414826SSergio Aguirre * @entity: IPIPE media entity 43671414826SSergio Aguirre * @local: Pad at the local end of the link 43771414826SSergio Aguirre * @remote: Pad at the remote end of the link 43871414826SSergio Aguirre * @flags: Link flags 43971414826SSergio Aguirre * 44071414826SSergio Aguirre * return -EINVAL or zero on success 44171414826SSergio Aguirre */ 44271414826SSergio Aguirre static int ipipe_link_setup(struct media_entity *entity, 44371414826SSergio Aguirre const struct media_pad *local, 44471414826SSergio Aguirre const struct media_pad *remote, u32 flags) 44571414826SSergio Aguirre { 44671414826SSergio Aguirre struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 44771414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); 44871414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe); 44971414826SSergio Aguirre 45071414826SSergio Aguirre switch (local->index | media_entity_type(remote->entity)) { 45171414826SSergio Aguirre case IPIPE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: 45271414826SSergio Aguirre /* Read from IPIPEIF. */ 45371414826SSergio Aguirre if (!(flags & MEDIA_LNK_FL_ENABLED)) { 45471414826SSergio Aguirre ipipe->input = IPIPE_INPUT_NONE; 45571414826SSergio Aguirre break; 45671414826SSergio Aguirre } 45771414826SSergio Aguirre 45871414826SSergio Aguirre if (ipipe->input != IPIPE_INPUT_NONE) 45971414826SSergio Aguirre return -EBUSY; 46071414826SSergio Aguirre 46171414826SSergio Aguirre if (remote->entity == &iss->ipipeif.subdev.entity) 46271414826SSergio Aguirre ipipe->input = IPIPE_INPUT_IPIPEIF; 46371414826SSergio Aguirre 46471414826SSergio Aguirre break; 46571414826SSergio Aguirre 46671414826SSergio Aguirre case IPIPE_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV: 46771414826SSergio Aguirre /* Send to RESIZER */ 46871414826SSergio Aguirre if (flags & MEDIA_LNK_FL_ENABLED) { 46971414826SSergio Aguirre if (ipipe->output & ~IPIPE_OUTPUT_VP) 47071414826SSergio Aguirre return -EBUSY; 47171414826SSergio Aguirre ipipe->output |= IPIPE_OUTPUT_VP; 47271414826SSergio Aguirre } else { 47371414826SSergio Aguirre ipipe->output &= ~IPIPE_OUTPUT_VP; 47471414826SSergio Aguirre } 47571414826SSergio Aguirre break; 47671414826SSergio Aguirre 47771414826SSergio Aguirre default: 47871414826SSergio Aguirre return -EINVAL; 47971414826SSergio Aguirre } 48071414826SSergio Aguirre 48171414826SSergio Aguirre return 0; 48271414826SSergio Aguirre } 48371414826SSergio Aguirre 48471414826SSergio Aguirre /* media operations */ 48571414826SSergio Aguirre static const struct media_entity_operations ipipe_media_ops = { 48671414826SSergio Aguirre .link_setup = ipipe_link_setup, 48771414826SSergio Aguirre .link_validate = v4l2_subdev_link_validate, 48871414826SSergio Aguirre }; 48971414826SSergio Aguirre 49071414826SSergio Aguirre /* 49171414826SSergio Aguirre * ipipe_init_entities - Initialize V4L2 subdev and media entity 49271414826SSergio Aguirre * @ipipe: ISS ISP IPIPE module 49371414826SSergio Aguirre * 49471414826SSergio Aguirre * Return 0 on success and a negative error code on failure. 49571414826SSergio Aguirre */ 49671414826SSergio Aguirre static int ipipe_init_entities(struct iss_ipipe_device *ipipe) 49771414826SSergio Aguirre { 49871414826SSergio Aguirre struct v4l2_subdev *sd = &ipipe->subdev; 49971414826SSergio Aguirre struct media_pad *pads = ipipe->pads; 50071414826SSergio Aguirre struct media_entity *me = &sd->entity; 50171414826SSergio Aguirre int ret; 50271414826SSergio Aguirre 50371414826SSergio Aguirre ipipe->input = IPIPE_INPUT_NONE; 50471414826SSergio Aguirre 50571414826SSergio Aguirre v4l2_subdev_init(sd, &ipipe_v4l2_ops); 50671414826SSergio Aguirre sd->internal_ops = &ipipe_v4l2_internal_ops; 50771414826SSergio Aguirre strlcpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name)); 50871414826SSergio Aguirre sd->grp_id = 1 << 16; /* group ID for iss subdevs */ 50971414826SSergio Aguirre v4l2_set_subdevdata(sd, ipipe); 51071414826SSergio Aguirre sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 51171414826SSergio Aguirre 51271414826SSergio Aguirre pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 51371414826SSergio Aguirre pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; 51471414826SSergio Aguirre 51571414826SSergio Aguirre me->ops = &ipipe_media_ops; 51671414826SSergio Aguirre ret = media_entity_init(me, IPIPE_PADS_NUM, pads, 0); 51771414826SSergio Aguirre if (ret < 0) 51871414826SSergio Aguirre return ret; 51971414826SSergio Aguirre 52071414826SSergio Aguirre ipipe_init_formats(sd, NULL); 52171414826SSergio Aguirre 52271414826SSergio Aguirre return 0; 52371414826SSergio Aguirre } 52471414826SSergio Aguirre 52571414826SSergio Aguirre void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe) 52671414826SSergio Aguirre { 52771414826SSergio Aguirre v4l2_device_unregister_subdev(&ipipe->subdev); 52871414826SSergio Aguirre } 52971414826SSergio Aguirre 53071414826SSergio Aguirre int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe, 53171414826SSergio Aguirre struct v4l2_device *vdev) 53271414826SSergio Aguirre { 53371414826SSergio Aguirre int ret; 53471414826SSergio Aguirre 53571414826SSergio Aguirre /* Register the subdev and video node. */ 53671414826SSergio Aguirre ret = v4l2_device_register_subdev(vdev, &ipipe->subdev); 53771414826SSergio Aguirre if (ret < 0) 53871414826SSergio Aguirre goto error; 53971414826SSergio Aguirre 54071414826SSergio Aguirre return 0; 54171414826SSergio Aguirre 54271414826SSergio Aguirre error: 54371414826SSergio Aguirre omap4iss_ipipe_unregister_entities(ipipe); 54471414826SSergio Aguirre return ret; 54571414826SSergio Aguirre } 54671414826SSergio Aguirre 54771414826SSergio Aguirre /* ----------------------------------------------------------------------------- 54871414826SSergio Aguirre * ISP IPIPE initialisation and cleanup 54971414826SSergio Aguirre */ 55071414826SSergio Aguirre 55171414826SSergio Aguirre /* 55271414826SSergio Aguirre * omap4iss_ipipe_init - IPIPE module initialization. 55371414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS. 55471414826SSergio Aguirre * 55571414826SSergio Aguirre * TODO: Get the initialisation values from platform data. 55671414826SSergio Aguirre * 55771414826SSergio Aguirre * Return 0 on success or a negative error code otherwise. 55871414826SSergio Aguirre */ 55971414826SSergio Aguirre int omap4iss_ipipe_init(struct iss_device *iss) 56071414826SSergio Aguirre { 56171414826SSergio Aguirre struct iss_ipipe_device *ipipe = &iss->ipipe; 56271414826SSergio Aguirre 56371414826SSergio Aguirre ipipe->state = ISS_PIPELINE_STREAM_STOPPED; 56471414826SSergio Aguirre init_waitqueue_head(&ipipe->wait); 56571414826SSergio Aguirre 56671414826SSergio Aguirre return ipipe_init_entities(ipipe); 56771414826SSergio Aguirre } 56871414826SSergio Aguirre 56971414826SSergio Aguirre /* 57071414826SSergio Aguirre * omap4iss_ipipe_cleanup - IPIPE module cleanup. 57171414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS. 57271414826SSergio Aguirre */ 57371414826SSergio Aguirre void omap4iss_ipipe_cleanup(struct iss_device *iss) 57471414826SSergio Aguirre { 5759d9104fbSLaurent Pinchart struct iss_ipipe_device *ipipe = &iss->ipipe; 5769d9104fbSLaurent Pinchart 5779d9104fbSLaurent Pinchart media_entity_cleanup(&ipipe->subdev.entity); 57871414826SSergio Aguirre } 579