1730b0ac3SDaniel Graefe // SPDX-License-Identifier: GPL-2.0+
271414826SSergio Aguirre /*
371414826SSergio Aguirre * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
471414826SSergio Aguirre *
571414826SSergio Aguirre * Copyright (C) 2012 Texas Instruments, Inc.
671414826SSergio Aguirre *
771414826SSergio Aguirre * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
871414826SSergio Aguirre */
971414826SSergio Aguirre
1071414826SSergio Aguirre #include <linux/module.h>
1171414826SSergio Aguirre #include <linux/uaccess.h>
1271414826SSergio Aguirre #include <linux/delay.h>
1371414826SSergio Aguirre #include <linux/device.h>
1471414826SSergio Aguirre #include <linux/dma-mapping.h>
1571414826SSergio Aguirre #include <linux/mm.h>
1671414826SSergio Aguirre #include <linux/sched.h>
1771414826SSergio Aguirre
1871414826SSergio Aguirre #include "iss.h"
1971414826SSergio Aguirre #include "iss_regs.h"
2071414826SSergio Aguirre #include "iss_ipipe.h"
2171414826SSergio Aguirre
2271414826SSergio Aguirre static struct v4l2_mbus_framefmt *
23ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe,
24*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
25ee8defecSPiotr S. Staszewski unsigned int pad,
26ee8defecSPiotr S. Staszewski enum v4l2_subdev_format_whence which);
2771414826SSergio Aguirre
2871414826SSergio Aguirre static const unsigned int ipipe_fmts[] = {
293336f07aSBoris BREZILLON MEDIA_BUS_FMT_SGRBG10_1X10,
303336f07aSBoris BREZILLON MEDIA_BUS_FMT_SRGGB10_1X10,
313336f07aSBoris BREZILLON MEDIA_BUS_FMT_SBGGR10_1X10,
323336f07aSBoris BREZILLON MEDIA_BUS_FMT_SGBRG10_1X10,
3371414826SSergio Aguirre };
3471414826SSergio Aguirre
3571414826SSergio Aguirre /*
3671414826SSergio Aguirre * ipipe_print_status - Print current IPIPE Module register values.
3771414826SSergio Aguirre * @ipipe: Pointer to ISS ISP IPIPE device.
3871414826SSergio Aguirre *
3971414826SSergio Aguirre * Also prints other debug information stored in the IPIPE module.
4071414826SSergio Aguirre */
4171414826SSergio Aguirre #define IPIPE_PRINT_REGISTER(iss, name)\
4271414826SSergio Aguirre dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \
4311abbfd3SLaurent Pinchart iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name))
4471414826SSergio Aguirre
ipipe_print_status(struct iss_ipipe_device * ipipe)4571414826SSergio Aguirre static void ipipe_print_status(struct iss_ipipe_device *ipipe)
4671414826SSergio Aguirre {
4771414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe);
4871414826SSergio Aguirre
4971414826SSergio Aguirre dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n");
5071414826SSergio Aguirre
5171414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_EN);
5271414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_MODE);
5371414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_FMT);
5471414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_COL);
5571414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_VPS);
5671414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_VSZ);
5771414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_HPS);
5871414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, SRC_HSZ);
5971414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, GCK_MMR);
6071414826SSergio Aguirre IPIPE_PRINT_REGISTER(iss, YUV_PHS);
6171414826SSergio Aguirre
6271414826SSergio Aguirre dev_dbg(iss->dev, "-----------------------------------------------\n");
6371414826SSergio Aguirre }
6471414826SSergio Aguirre
6571414826SSergio Aguirre /*
6671414826SSergio Aguirre * ipipe_enable - Enable/Disable IPIPE.
6771414826SSergio Aguirre * @enable: enable flag
6871414826SSergio Aguirre *
6971414826SSergio Aguirre */
ipipe_enable(struct iss_ipipe_device * ipipe,u8 enable)7071414826SSergio Aguirre static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable)
7171414826SSergio Aguirre {
7271414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe);
7371414826SSergio Aguirre
7411abbfd3SLaurent Pinchart iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN,
7511abbfd3SLaurent Pinchart IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0);
7671414826SSergio Aguirre }
7771414826SSergio Aguirre
7871414826SSergio Aguirre /* -----------------------------------------------------------------------------
7971414826SSergio Aguirre * Format- and pipeline-related configuration helpers
8071414826SSergio Aguirre */
8171414826SSergio Aguirre
ipipe_configure(struct iss_ipipe_device * ipipe)8271414826SSergio Aguirre static void ipipe_configure(struct iss_ipipe_device *ipipe)
8371414826SSergio Aguirre {
8471414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe);
8571414826SSergio Aguirre struct v4l2_mbus_framefmt *format;
8671414826SSergio Aguirre
8771414826SSergio Aguirre /* IPIPE_PAD_SINK */
8871414826SSergio Aguirre format = &ipipe->formats[IPIPE_PAD_SINK];
8971414826SSergio Aguirre
9071414826SSergio Aguirre /* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */
9111abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT,
9211abbfd3SLaurent Pinchart IPIPE_SRC_FMT_RAW2YUV);
9371414826SSergio Aguirre
9471414826SSergio Aguirre /* Enable YUV444 -> YUV422 conversion */
9511abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS,
9611abbfd3SLaurent Pinchart IPIPE_YUV_PHS_LPF);
9771414826SSergio Aguirre
9811abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0);
9911abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0);
10011abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ,
10111abbfd3SLaurent Pinchart (format->height - 2) & IPIPE_SRC_VSZ_MASK);
10211abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ,
10311abbfd3SLaurent Pinchart (format->width - 1) & IPIPE_SRC_HSZ_MASK);
10471414826SSergio Aguirre
10571414826SSergio Aguirre /* Ignore ipipeif_wrt signal, and operate on-the-fly. */
10611abbfd3SLaurent Pinchart iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE,
10711abbfd3SLaurent Pinchart IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST);
10871414826SSergio Aguirre
10971414826SSergio Aguirre /* HACK: Values tuned for Ducati SW (OV) */
11011abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL,
11111abbfd3SLaurent Pinchart IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB |
11211abbfd3SLaurent Pinchart IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R);
11371414826SSergio Aguirre
11471414826SSergio Aguirre /* IPIPE_PAD_SOURCE_VP */
11571414826SSergio Aguirre format = &ipipe->formats[IPIPE_PAD_SOURCE_VP];
11671414826SSergio Aguirre /* Do nothing? */
11771414826SSergio Aguirre }
11871414826SSergio Aguirre
11971414826SSergio Aguirre /* -----------------------------------------------------------------------------
12071414826SSergio Aguirre * V4L2 subdev operations
12171414826SSergio Aguirre */
12271414826SSergio Aguirre
12371414826SSergio Aguirre /*
12471414826SSergio Aguirre * ipipe_set_stream - Enable/Disable streaming on the IPIPE module
12571414826SSergio Aguirre * @sd: ISP IPIPE V4L2 subdevice
12671414826SSergio Aguirre * @enable: Enable/disable stream
12771414826SSergio Aguirre */
ipipe_set_stream(struct v4l2_subdev * sd,int enable)12871414826SSergio Aguirre static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
12971414826SSergio Aguirre {
13071414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
13171414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe);
13271414826SSergio Aguirre int ret = 0;
13371414826SSergio Aguirre
13471414826SSergio Aguirre if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) {
13571414826SSergio Aguirre if (enable == ISS_PIPELINE_STREAM_STOPPED)
13671414826SSergio Aguirre return 0;
13771414826SSergio Aguirre
13871414826SSergio Aguirre omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
13971414826SSergio Aguirre
14071414826SSergio Aguirre /* Enable clk_arm_g0 */
14111abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR,
14211abbfd3SLaurent Pinchart IPIPE_GCK_MMR_REG);
14371414826SSergio Aguirre
14471414826SSergio Aguirre /* Enable clk_pix_g[3:0] */
14511abbfd3SLaurent Pinchart iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX,
14611abbfd3SLaurent Pinchart IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 |
14711abbfd3SLaurent Pinchart IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0);
14871414826SSergio Aguirre }
14971414826SSergio Aguirre
15071414826SSergio Aguirre switch (enable) {
15171414826SSergio Aguirre case ISS_PIPELINE_STREAM_CONTINUOUS:
15271414826SSergio Aguirre
15371414826SSergio Aguirre ipipe_configure(ipipe);
15471414826SSergio Aguirre ipipe_print_status(ipipe);
15571414826SSergio Aguirre
15671414826SSergio Aguirre atomic_set(&ipipe->stopping, 0);
15771414826SSergio Aguirre ipipe_enable(ipipe, 1);
15871414826SSergio Aguirre break;
15971414826SSergio Aguirre
16071414826SSergio Aguirre case ISS_PIPELINE_STREAM_STOPPED:
16171414826SSergio Aguirre if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED)
16271414826SSergio Aguirre return 0;
16371414826SSergio Aguirre if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait,
16471414826SSergio Aguirre &ipipe->stopping))
1656016498fSLaurent Pinchart ret = -ETIMEDOUT;
16671414826SSergio Aguirre
16771414826SSergio Aguirre ipipe_enable(ipipe, 0);
16871414826SSergio Aguirre omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
16971414826SSergio Aguirre break;
17071414826SSergio Aguirre }
17171414826SSergio Aguirre
17271414826SSergio Aguirre ipipe->state = enable;
17371414826SSergio Aguirre return ret;
17471414826SSergio Aguirre }
17571414826SSergio Aguirre
17671414826SSergio Aguirre static struct v4l2_mbus_framefmt *
__ipipe_get_format(struct iss_ipipe_device * ipipe,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)177ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe,
178*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
179ee8defecSPiotr S. Staszewski unsigned int pad,
180ee8defecSPiotr S. Staszewski enum v4l2_subdev_format_whence which)
18171414826SSergio Aguirre {
18271414826SSergio Aguirre if (which == V4L2_SUBDEV_FORMAT_TRY)
183*0d346d2aSTomi Valkeinen return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state,
184*0d346d2aSTomi Valkeinen pad);
185ae357388SYeliz Taneroglu
18671414826SSergio Aguirre return &ipipe->formats[pad];
18771414826SSergio Aguirre }
18871414826SSergio Aguirre
18971414826SSergio Aguirre /*
19071414826SSergio Aguirre * ipipe_try_format - Try video format on a pad
19171414826SSergio Aguirre * @ipipe: ISS IPIPE device
192f7234138SHans Verkuil * @cfg: V4L2 subdev pad config
19371414826SSergio Aguirre * @pad: Pad number
19471414826SSergio Aguirre * @fmt: Format
19571414826SSergio Aguirre */
19671414826SSergio Aguirre static void
ipipe_try_format(struct iss_ipipe_device * ipipe,struct v4l2_subdev_state * sd_state,unsigned int pad,struct v4l2_mbus_framefmt * fmt,enum v4l2_subdev_format_whence which)197ee8defecSPiotr S. Staszewski ipipe_try_format(struct iss_ipipe_device *ipipe,
198*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
199ee8defecSPiotr S. Staszewski unsigned int pad,
200ee8defecSPiotr S. Staszewski struct v4l2_mbus_framefmt *fmt,
20171414826SSergio Aguirre enum v4l2_subdev_format_whence which)
20271414826SSergio Aguirre {
20371414826SSergio Aguirre struct v4l2_mbus_framefmt *format;
20471414826SSergio Aguirre unsigned int width = fmt->width;
20571414826SSergio Aguirre unsigned int height = fmt->height;
20671414826SSergio Aguirre unsigned int i;
20771414826SSergio Aguirre
20871414826SSergio Aguirre switch (pad) {
20971414826SSergio Aguirre case IPIPE_PAD_SINK:
21071414826SSergio Aguirre for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) {
21171414826SSergio Aguirre if (fmt->code == ipipe_fmts[i])
21271414826SSergio Aguirre break;
21371414826SSergio Aguirre }
21471414826SSergio Aguirre
21571414826SSergio Aguirre /* If not found, use SGRBG10 as default */
21671414826SSergio Aguirre if (i >= ARRAY_SIZE(ipipe_fmts))
2173336f07aSBoris BREZILLON fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
21871414826SSergio Aguirre
21971414826SSergio Aguirre /* Clamp the input size. */
22071414826SSergio Aguirre fmt->width = clamp_t(u32, width, 1, 8192);
22171414826SSergio Aguirre fmt->height = clamp_t(u32, height, 1, 8192);
22271414826SSergio Aguirre fmt->colorspace = V4L2_COLORSPACE_SRGB;
22371414826SSergio Aguirre break;
22471414826SSergio Aguirre
22571414826SSergio Aguirre case IPIPE_PAD_SOURCE_VP:
226*0d346d2aSTomi Valkeinen format = __ipipe_get_format(ipipe, sd_state, IPIPE_PAD_SINK,
227*0d346d2aSTomi Valkeinen which);
22871414826SSergio Aguirre memcpy(fmt, format, sizeof(*fmt));
22971414826SSergio Aguirre
2303336f07aSBoris BREZILLON fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
23171414826SSergio Aguirre fmt->width = clamp_t(u32, width, 32, fmt->width);
23271414826SSergio Aguirre fmt->height = clamp_t(u32, height, 32, fmt->height);
23371414826SSergio Aguirre fmt->colorspace = V4L2_COLORSPACE_JPEG;
23471414826SSergio Aguirre break;
23571414826SSergio Aguirre }
23671414826SSergio Aguirre
23771414826SSergio Aguirre fmt->field = V4L2_FIELD_NONE;
23871414826SSergio Aguirre }
23971414826SSergio Aguirre
24071414826SSergio Aguirre /*
24171414826SSergio Aguirre * ipipe_enum_mbus_code - Handle pixel format enumeration
24271414826SSergio Aguirre * @sd : pointer to v4l2 subdev structure
243f7234138SHans Verkuil * @cfg : V4L2 subdev pad config
24471414826SSergio Aguirre * @code : pointer to v4l2_subdev_mbus_code_enum structure
24571414826SSergio Aguirre * return -EINVAL or zero on success
24671414826SSergio Aguirre */
ipipe_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)24771414826SSergio Aguirre static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
248*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
24971414826SSergio Aguirre struct v4l2_subdev_mbus_code_enum *code)
25071414826SSergio Aguirre {
25171414826SSergio Aguirre switch (code->pad) {
25271414826SSergio Aguirre case IPIPE_PAD_SINK:
25371414826SSergio Aguirre if (code->index >= ARRAY_SIZE(ipipe_fmts))
25471414826SSergio Aguirre return -EINVAL;
25571414826SSergio Aguirre
25671414826SSergio Aguirre code->code = ipipe_fmts[code->index];
25771414826SSergio Aguirre break;
25871414826SSergio Aguirre
25971414826SSergio Aguirre case IPIPE_PAD_SOURCE_VP:
26071414826SSergio Aguirre /* FIXME: Forced format conversion inside IPIPE ? */
26171414826SSergio Aguirre if (code->index != 0)
26271414826SSergio Aguirre return -EINVAL;
26371414826SSergio Aguirre
2643336f07aSBoris BREZILLON code->code = MEDIA_BUS_FMT_UYVY8_1X16;
26571414826SSergio Aguirre break;
26671414826SSergio Aguirre
26771414826SSergio Aguirre default:
26871414826SSergio Aguirre return -EINVAL;
26971414826SSergio Aguirre }
27071414826SSergio Aguirre
27171414826SSergio Aguirre return 0;
27271414826SSergio Aguirre }
27371414826SSergio Aguirre
ipipe_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)27471414826SSergio Aguirre static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
275*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
27671414826SSergio Aguirre struct v4l2_subdev_frame_size_enum *fse)
27771414826SSergio Aguirre {
27871414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
27971414826SSergio Aguirre struct v4l2_mbus_framefmt format;
28071414826SSergio Aguirre
28171414826SSergio Aguirre if (fse->index != 0)
28271414826SSergio Aguirre return -EINVAL;
28371414826SSergio Aguirre
28471414826SSergio Aguirre format.code = fse->code;
28571414826SSergio Aguirre format.width = 1;
28671414826SSergio Aguirre format.height = 1;
287*0d346d2aSTomi Valkeinen ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
28871414826SSergio Aguirre fse->min_width = format.width;
28971414826SSergio Aguirre fse->min_height = format.height;
29071414826SSergio Aguirre
29171414826SSergio Aguirre if (format.code != fse->code)
29271414826SSergio Aguirre return -EINVAL;
29371414826SSergio Aguirre
29471414826SSergio Aguirre format.code = fse->code;
29571414826SSergio Aguirre format.width = -1;
29671414826SSergio Aguirre format.height = -1;
297*0d346d2aSTomi Valkeinen ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
29871414826SSergio Aguirre fse->max_width = format.width;
29971414826SSergio Aguirre fse->max_height = format.height;
30071414826SSergio Aguirre
30171414826SSergio Aguirre return 0;
30271414826SSergio Aguirre }
30371414826SSergio Aguirre
30471414826SSergio Aguirre /*
30571414826SSergio Aguirre * ipipe_get_format - Retrieve the video format on a pad
30671414826SSergio Aguirre * @sd : ISP IPIPE V4L2 subdevice
307f7234138SHans Verkuil * @cfg: V4L2 subdev pad config
30871414826SSergio Aguirre * @fmt: Format
30971414826SSergio Aguirre *
31071414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
31171414826SSergio Aguirre * to the format type.
31271414826SSergio Aguirre */
ipipe_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)313ee8defecSPiotr S. Staszewski static int ipipe_get_format(struct v4l2_subdev *sd,
314*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
31571414826SSergio Aguirre struct v4l2_subdev_format *fmt)
31671414826SSergio Aguirre {
31771414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
31871414826SSergio Aguirre struct v4l2_mbus_framefmt *format;
31971414826SSergio Aguirre
320*0d346d2aSTomi Valkeinen format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
3219058fc92SAmarjargal Gundjalam if (!format)
32271414826SSergio Aguirre return -EINVAL;
32371414826SSergio Aguirre
32471414826SSergio Aguirre fmt->format = *format;
32571414826SSergio Aguirre return 0;
32671414826SSergio Aguirre }
32771414826SSergio Aguirre
32871414826SSergio Aguirre /*
32971414826SSergio Aguirre * ipipe_set_format - Set the video format on a pad
33071414826SSergio Aguirre * @sd : ISP IPIPE V4L2 subdevice
331f7234138SHans Verkuil * @cfg: V4L2 subdev pad config
33271414826SSergio Aguirre * @fmt: Format
33371414826SSergio Aguirre *
33471414826SSergio Aguirre * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
33571414826SSergio Aguirre * to the format type.
33671414826SSergio Aguirre */
ipipe_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)337ee8defecSPiotr S. Staszewski static int ipipe_set_format(struct v4l2_subdev *sd,
338*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
33971414826SSergio Aguirre struct v4l2_subdev_format *fmt)
34071414826SSergio Aguirre {
34171414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
34271414826SSergio Aguirre struct v4l2_mbus_framefmt *format;
34371414826SSergio Aguirre
344*0d346d2aSTomi Valkeinen format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
3459058fc92SAmarjargal Gundjalam if (!format)
34671414826SSergio Aguirre return -EINVAL;
34771414826SSergio Aguirre
348*0d346d2aSTomi Valkeinen ipipe_try_format(ipipe, sd_state, fmt->pad, &fmt->format, fmt->which);
34971414826SSergio Aguirre *format = fmt->format;
35071414826SSergio Aguirre
35171414826SSergio Aguirre /* Propagate the format from sink to source */
35271414826SSergio Aguirre if (fmt->pad == IPIPE_PAD_SINK) {
353*0d346d2aSTomi Valkeinen format = __ipipe_get_format(ipipe, sd_state,
354*0d346d2aSTomi Valkeinen IPIPE_PAD_SOURCE_VP,
35571414826SSergio Aguirre fmt->which);
35671414826SSergio Aguirre *format = fmt->format;
357*0d346d2aSTomi Valkeinen ipipe_try_format(ipipe, sd_state, IPIPE_PAD_SOURCE_VP, format,
35871414826SSergio Aguirre fmt->which);
35971414826SSergio Aguirre }
36071414826SSergio Aguirre
36171414826SSergio Aguirre return 0;
36271414826SSergio Aguirre }
36371414826SSergio Aguirre
ipipe_link_validate(struct v4l2_subdev * sd,struct media_link * link,struct v4l2_subdev_format * source_fmt,struct v4l2_subdev_format * sink_fmt)36471414826SSergio Aguirre static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link,
36571414826SSergio Aguirre struct v4l2_subdev_format *source_fmt,
36671414826SSergio Aguirre struct v4l2_subdev_format *sink_fmt)
36771414826SSergio Aguirre {
36871414826SSergio Aguirre /* Check if the two ends match */
36971414826SSergio Aguirre if (source_fmt->format.width != sink_fmt->format.width ||
37071414826SSergio Aguirre source_fmt->format.height != sink_fmt->format.height)
37171414826SSergio Aguirre return -EPIPE;
37271414826SSergio Aguirre
37371414826SSergio Aguirre if (source_fmt->format.code != sink_fmt->format.code)
37471414826SSergio Aguirre return -EPIPE;
37571414826SSergio Aguirre
37671414826SSergio Aguirre return 0;
37771414826SSergio Aguirre }
37871414826SSergio Aguirre
37971414826SSergio Aguirre /*
38071414826SSergio Aguirre * ipipe_init_formats - Initialize formats on all pads
38171414826SSergio Aguirre * @sd: ISP IPIPE V4L2 subdevice
38271414826SSergio Aguirre * @fh: V4L2 subdev file handle
38371414826SSergio Aguirre *
38471414826SSergio Aguirre * Initialize all pad formats with default values. If fh is not NULL, try
38571414826SSergio Aguirre * formats are initialized on the file handle. Otherwise active formats are
38671414826SSergio Aguirre * initialized on the device.
38771414826SSergio Aguirre */
ipipe_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)38871414826SSergio Aguirre static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
38971414826SSergio Aguirre {
39071414826SSergio Aguirre struct v4l2_subdev_format format;
39171414826SSergio Aguirre
39271414826SSergio Aguirre memset(&format, 0, sizeof(format));
39371414826SSergio Aguirre format.pad = IPIPE_PAD_SINK;
39471414826SSergio Aguirre format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
3953336f07aSBoris BREZILLON format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
39671414826SSergio Aguirre format.format.width = 4096;
39771414826SSergio Aguirre format.format.height = 4096;
398*0d346d2aSTomi Valkeinen ipipe_set_format(sd, fh ? fh->state : NULL, &format);
39971414826SSergio Aguirre
40071414826SSergio Aguirre return 0;
40171414826SSergio Aguirre }
40271414826SSergio Aguirre
40371414826SSergio Aguirre /* V4L2 subdev video operations */
40471414826SSergio Aguirre static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
40571414826SSergio Aguirre .s_stream = ipipe_set_stream,
40671414826SSergio Aguirre };
40771414826SSergio Aguirre
40871414826SSergio Aguirre /* V4L2 subdev pad operations */
40971414826SSergio Aguirre static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = {
41071414826SSergio Aguirre .enum_mbus_code = ipipe_enum_mbus_code,
41171414826SSergio Aguirre .enum_frame_size = ipipe_enum_frame_size,
41271414826SSergio Aguirre .get_fmt = ipipe_get_format,
41371414826SSergio Aguirre .set_fmt = ipipe_set_format,
41471414826SSergio Aguirre .link_validate = ipipe_link_validate,
41571414826SSergio Aguirre };
41671414826SSergio Aguirre
41771414826SSergio Aguirre /* V4L2 subdev operations */
41871414826SSergio Aguirre static const struct v4l2_subdev_ops ipipe_v4l2_ops = {
41971414826SSergio Aguirre .video = &ipipe_v4l2_video_ops,
42071414826SSergio Aguirre .pad = &ipipe_v4l2_pad_ops,
42171414826SSergio Aguirre };
42271414826SSergio Aguirre
42371414826SSergio Aguirre /* V4L2 subdev internal operations */
42471414826SSergio Aguirre static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = {
42571414826SSergio Aguirre .open = ipipe_init_formats,
42671414826SSergio Aguirre };
42771414826SSergio Aguirre
42871414826SSergio Aguirre /* -----------------------------------------------------------------------------
42971414826SSergio Aguirre * Media entity operations
43071414826SSergio Aguirre */
43171414826SSergio Aguirre
43271414826SSergio Aguirre /*
43371414826SSergio Aguirre * ipipe_link_setup - Setup IPIPE connections
43471414826SSergio Aguirre * @entity: IPIPE media entity
43571414826SSergio Aguirre * @local: Pad at the local end of the link
43671414826SSergio Aguirre * @remote: Pad at the remote end of the link
43771414826SSergio Aguirre * @flags: Link flags
43871414826SSergio Aguirre *
43971414826SSergio Aguirre * return -EINVAL or zero on success
44071414826SSergio Aguirre */
ipipe_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)44171414826SSergio Aguirre static int ipipe_link_setup(struct media_entity *entity,
44271414826SSergio Aguirre const struct media_pad *local,
44371414826SSergio Aguirre const struct media_pad *remote, u32 flags)
44471414826SSergio Aguirre {
44571414826SSergio Aguirre struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
44671414826SSergio Aguirre struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
44771414826SSergio Aguirre struct iss_device *iss = to_iss_device(ipipe);
44871414826SSergio Aguirre
449bf4178a4SMauro Carvalho Chehab if (!is_media_entity_v4l2_subdev(remote->entity))
450bf4178a4SMauro Carvalho Chehab return -EINVAL;
451bf4178a4SMauro Carvalho Chehab
452bf4178a4SMauro Carvalho Chehab switch (local->index) {
453bf4178a4SMauro Carvalho Chehab case IPIPE_PAD_SINK:
45471414826SSergio Aguirre /* Read from IPIPEIF. */
45571414826SSergio Aguirre if (!(flags & MEDIA_LNK_FL_ENABLED)) {
45671414826SSergio Aguirre ipipe->input = IPIPE_INPUT_NONE;
45771414826SSergio Aguirre break;
45871414826SSergio Aguirre }
45971414826SSergio Aguirre
46071414826SSergio Aguirre if (ipipe->input != IPIPE_INPUT_NONE)
46171414826SSergio Aguirre return -EBUSY;
46271414826SSergio Aguirre
46371414826SSergio Aguirre if (remote->entity == &iss->ipipeif.subdev.entity)
46471414826SSergio Aguirre ipipe->input = IPIPE_INPUT_IPIPEIF;
46571414826SSergio Aguirre
46671414826SSergio Aguirre break;
46771414826SSergio Aguirre
468bf4178a4SMauro Carvalho Chehab case IPIPE_PAD_SOURCE_VP:
46971414826SSergio Aguirre /* Send to RESIZER */
47071414826SSergio Aguirre if (flags & MEDIA_LNK_FL_ENABLED) {
47171414826SSergio Aguirre if (ipipe->output & ~IPIPE_OUTPUT_VP)
47271414826SSergio Aguirre return -EBUSY;
47371414826SSergio Aguirre ipipe->output |= IPIPE_OUTPUT_VP;
47471414826SSergio Aguirre } else {
47571414826SSergio Aguirre ipipe->output &= ~IPIPE_OUTPUT_VP;
47671414826SSergio Aguirre }
47771414826SSergio Aguirre break;
47871414826SSergio Aguirre
47971414826SSergio Aguirre default:
48071414826SSergio Aguirre return -EINVAL;
48171414826SSergio Aguirre }
48271414826SSergio Aguirre
48371414826SSergio Aguirre return 0;
48471414826SSergio Aguirre }
48571414826SSergio Aguirre
48671414826SSergio Aguirre /* media operations */
48771414826SSergio Aguirre static const struct media_entity_operations ipipe_media_ops = {
48871414826SSergio Aguirre .link_setup = ipipe_link_setup,
48971414826SSergio Aguirre .link_validate = v4l2_subdev_link_validate,
49071414826SSergio Aguirre };
49171414826SSergio Aguirre
49271414826SSergio Aguirre /*
49371414826SSergio Aguirre * ipipe_init_entities - Initialize V4L2 subdev and media entity
49471414826SSergio Aguirre * @ipipe: ISS ISP IPIPE module
49571414826SSergio Aguirre *
49671414826SSergio Aguirre * Return 0 on success and a negative error code on failure.
49771414826SSergio Aguirre */
ipipe_init_entities(struct iss_ipipe_device * ipipe)49871414826SSergio Aguirre static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
49971414826SSergio Aguirre {
50071414826SSergio Aguirre struct v4l2_subdev *sd = &ipipe->subdev;
50171414826SSergio Aguirre struct media_pad *pads = ipipe->pads;
50271414826SSergio Aguirre struct media_entity *me = &sd->entity;
50371414826SSergio Aguirre int ret;
50471414826SSergio Aguirre
50571414826SSergio Aguirre ipipe->input = IPIPE_INPUT_NONE;
50671414826SSergio Aguirre
50771414826SSergio Aguirre v4l2_subdev_init(sd, &ipipe_v4l2_ops);
50871414826SSergio Aguirre sd->internal_ops = &ipipe_v4l2_internal_ops;
509c0decac1SMauro Carvalho Chehab strscpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
510c762efd3SArushi Singhal sd->grp_id = BIT(16); /* group ID for iss subdevs */
51171414826SSergio Aguirre v4l2_set_subdevdata(sd, ipipe);
51271414826SSergio Aguirre sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
51371414826SSergio Aguirre
51471414826SSergio Aguirre pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
51571414826SSergio Aguirre pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
51671414826SSergio Aguirre
51771414826SSergio Aguirre me->ops = &ipipe_media_ops;
518ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(me, IPIPE_PADS_NUM, pads);
51971414826SSergio Aguirre if (ret < 0)
52071414826SSergio Aguirre return ret;
52171414826SSergio Aguirre
52271414826SSergio Aguirre ipipe_init_formats(sd, NULL);
52371414826SSergio Aguirre
52471414826SSergio Aguirre return 0;
52571414826SSergio Aguirre }
52671414826SSergio Aguirre
omap4iss_ipipe_unregister_entities(struct iss_ipipe_device * ipipe)52771414826SSergio Aguirre void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe)
52871414826SSergio Aguirre {
52971414826SSergio Aguirre v4l2_device_unregister_subdev(&ipipe->subdev);
53071414826SSergio Aguirre }
53171414826SSergio Aguirre
omap4iss_ipipe_register_entities(struct iss_ipipe_device * ipipe,struct v4l2_device * vdev)53271414826SSergio Aguirre int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe,
53371414826SSergio Aguirre struct v4l2_device *vdev)
53471414826SSergio Aguirre {
53571414826SSergio Aguirre int ret;
53671414826SSergio Aguirre
53771414826SSergio Aguirre /* Register the subdev and video node. */
53871414826SSergio Aguirre ret = v4l2_device_register_subdev(vdev, &ipipe->subdev);
53971414826SSergio Aguirre if (ret < 0)
54071414826SSergio Aguirre goto error;
54171414826SSergio Aguirre
54271414826SSergio Aguirre return 0;
54371414826SSergio Aguirre
54471414826SSergio Aguirre error:
54571414826SSergio Aguirre omap4iss_ipipe_unregister_entities(ipipe);
54671414826SSergio Aguirre return ret;
54771414826SSergio Aguirre }
54871414826SSergio Aguirre
54971414826SSergio Aguirre /* -----------------------------------------------------------------------------
55071414826SSergio Aguirre * ISP IPIPE initialisation and cleanup
55171414826SSergio Aguirre */
55271414826SSergio Aguirre
55371414826SSergio Aguirre /*
55471414826SSergio Aguirre * omap4iss_ipipe_init - IPIPE module initialization.
55571414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS.
55671414826SSergio Aguirre *
55771414826SSergio Aguirre * TODO: Get the initialisation values from platform data.
55871414826SSergio Aguirre *
55971414826SSergio Aguirre * Return 0 on success or a negative error code otherwise.
56071414826SSergio Aguirre */
omap4iss_ipipe_init(struct iss_device * iss)56171414826SSergio Aguirre int omap4iss_ipipe_init(struct iss_device *iss)
56271414826SSergio Aguirre {
56371414826SSergio Aguirre struct iss_ipipe_device *ipipe = &iss->ipipe;
56471414826SSergio Aguirre
56571414826SSergio Aguirre ipipe->state = ISS_PIPELINE_STREAM_STOPPED;
56671414826SSergio Aguirre init_waitqueue_head(&ipipe->wait);
56771414826SSergio Aguirre
56871414826SSergio Aguirre return ipipe_init_entities(ipipe);
56971414826SSergio Aguirre }
57071414826SSergio Aguirre
57171414826SSergio Aguirre /*
57271414826SSergio Aguirre * omap4iss_ipipe_cleanup - IPIPE module cleanup.
57371414826SSergio Aguirre * @iss: Device pointer specific to the OMAP4 ISS.
57471414826SSergio Aguirre */
omap4iss_ipipe_cleanup(struct iss_device * iss)57571414826SSergio Aguirre void omap4iss_ipipe_cleanup(struct iss_device *iss)
57671414826SSergio Aguirre {
5779d9104fbSLaurent Pinchart struct iss_ipipe_device *ipipe = &iss->ipipe;
5789d9104fbSLaurent Pinchart
5799d9104fbSLaurent Pinchart media_entity_cleanup(&ipipe->subdev.entity);
58071414826SSergio Aguirre }
581