146fb9995SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+
246fb9995SMauro Carvalho Chehab /*
346fb9995SMauro Carvalho Chehab * i.MX Pixel Pipeline (PXP) mem-to-mem scaler/CSC/rotator driver
446fb9995SMauro Carvalho Chehab *
546fb9995SMauro Carvalho Chehab * Copyright (c) 2018 Pengutronix, Philipp Zabel
646fb9995SMauro Carvalho Chehab *
746fb9995SMauro Carvalho Chehab * based on vim2m
846fb9995SMauro Carvalho Chehab *
946fb9995SMauro Carvalho Chehab * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
1046fb9995SMauro Carvalho Chehab * Pawel Osciak, <pawel@osciak.com>
1146fb9995SMauro Carvalho Chehab * Marek Szyprowski, <m.szyprowski@samsung.com>
1246fb9995SMauro Carvalho Chehab */
13a4a69d13SMichael Tretter #include <linux/bitfield.h>
1446fb9995SMauro Carvalho Chehab #include <linux/clk.h>
1546fb9995SMauro Carvalho Chehab #include <linux/delay.h>
1646fb9995SMauro Carvalho Chehab #include <linux/dma-mapping.h>
1746fb9995SMauro Carvalho Chehab #include <linux/interrupt.h>
1846fb9995SMauro Carvalho Chehab #include <linux/io.h>
1946fb9995SMauro Carvalho Chehab #include <linux/iopoll.h>
2046fb9995SMauro Carvalho Chehab #include <linux/module.h>
2146fb9995SMauro Carvalho Chehab #include <linux/of.h>
22371ab9c4SLaurent Pinchart #include <linux/platform_device.h>
234e5bd3fdSMichael Tretter #include <linux/regmap.h>
2446fb9995SMauro Carvalho Chehab #include <linux/sched.h>
2546fb9995SMauro Carvalho Chehab #include <linux/slab.h>
2646fb9995SMauro Carvalho Chehab
27ff89b9b4SLaurent Pinchart #include <media/media-device.h>
2846fb9995SMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
29371ab9c4SLaurent Pinchart #include <media/v4l2-device.h>
3046fb9995SMauro Carvalho Chehab #include <media/v4l2-event.h>
31371ab9c4SLaurent Pinchart #include <media/v4l2-ioctl.h>
32371ab9c4SLaurent Pinchart #include <media/v4l2-mem2mem.h>
3346fb9995SMauro Carvalho Chehab #include <media/videobuf2-dma-contig.h>
3446fb9995SMauro Carvalho Chehab
3546fb9995SMauro Carvalho Chehab #include "imx-pxp.h"
3646fb9995SMauro Carvalho Chehab
3746fb9995SMauro Carvalho Chehab static unsigned int debug;
3846fb9995SMauro Carvalho Chehab module_param(debug, uint, 0644);
3946fb9995SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "activates debug info");
4046fb9995SMauro Carvalho Chehab
4146fb9995SMauro Carvalho Chehab #define MIN_W 8
4246fb9995SMauro Carvalho Chehab #define MIN_H 8
4346fb9995SMauro Carvalho Chehab #define MAX_W 4096
4446fb9995SMauro Carvalho Chehab #define MAX_H 4096
4546fb9995SMauro Carvalho Chehab #define ALIGN_W 3 /* 8x8 pixel blocks */
4646fb9995SMauro Carvalho Chehab #define ALIGN_H 3
4746fb9995SMauro Carvalho Chehab
4846fb9995SMauro Carvalho Chehab /* Flags that indicate a format can be used for capture/output */
4946fb9995SMauro Carvalho Chehab #define MEM2MEM_CAPTURE (1 << 0)
5046fb9995SMauro Carvalho Chehab #define MEM2MEM_OUTPUT (1 << 1)
5146fb9995SMauro Carvalho Chehab
5246fb9995SMauro Carvalho Chehab #define MEM2MEM_NAME "pxp"
5346fb9995SMauro Carvalho Chehab
5446fb9995SMauro Carvalho Chehab /* Flags that indicate processing mode */
5546fb9995SMauro Carvalho Chehab #define MEM2MEM_HFLIP (1 << 0)
5646fb9995SMauro Carvalho Chehab #define MEM2MEM_VFLIP (1 << 1)
5746fb9995SMauro Carvalho Chehab
58a4a69d13SMichael Tretter #define PXP_VERSION_MAJOR(version) \
59a4a69d13SMichael Tretter FIELD_GET(BM_PXP_VERSION_MAJOR, version)
60a4a69d13SMichael Tretter #define PXP_VERSION_MINOR(version) \
61a4a69d13SMichael Tretter FIELD_GET(BM_PXP_VERSION_MINOR, version)
62a4a69d13SMichael Tretter
6346fb9995SMauro Carvalho Chehab #define dprintk(dev, fmt, arg...) \
6446fb9995SMauro Carvalho Chehab v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
6546fb9995SMauro Carvalho Chehab
6646fb9995SMauro Carvalho Chehab struct pxp_fmt {
6746fb9995SMauro Carvalho Chehab u32 fourcc;
6846fb9995SMauro Carvalho Chehab int depth;
6946fb9995SMauro Carvalho Chehab /* Types the format can be used for */
7046fb9995SMauro Carvalho Chehab u32 types;
7146fb9995SMauro Carvalho Chehab };
7246fb9995SMauro Carvalho Chehab
7346fb9995SMauro Carvalho Chehab static struct pxp_fmt formats[] = {
7446fb9995SMauro Carvalho Chehab {
7546fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_XBGR32,
7646fb9995SMauro Carvalho Chehab .depth = 32,
7746fb9995SMauro Carvalho Chehab /* Both capture and output format */
7846fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
7946fb9995SMauro Carvalho Chehab }, {
8046fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_ABGR32,
8146fb9995SMauro Carvalho Chehab .depth = 32,
8246fb9995SMauro Carvalho Chehab /* Capture-only format */
8346fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE,
8446fb9995SMauro Carvalho Chehab }, {
8546fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_BGR24,
8646fb9995SMauro Carvalho Chehab .depth = 24,
8746fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE,
8846fb9995SMauro Carvalho Chehab }, {
8946fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_RGB565,
9046fb9995SMauro Carvalho Chehab .depth = 16,
9146fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
9246fb9995SMauro Carvalho Chehab }, {
9346fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_RGB555,
9446fb9995SMauro Carvalho Chehab .depth = 16,
9546fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
9646fb9995SMauro Carvalho Chehab }, {
9746fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_RGB444,
9846fb9995SMauro Carvalho Chehab .depth = 16,
9946fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
10046fb9995SMauro Carvalho Chehab }, {
10146fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_VUYA32,
10246fb9995SMauro Carvalho Chehab .depth = 32,
10346fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE,
10446fb9995SMauro Carvalho Chehab }, {
10546fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_VUYX32,
10646fb9995SMauro Carvalho Chehab .depth = 32,
10746fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
10846fb9995SMauro Carvalho Chehab }, {
10946fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_UYVY,
11046fb9995SMauro Carvalho Chehab .depth = 16,
11146fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
11246fb9995SMauro Carvalho Chehab }, {
11346fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YUYV,
11446fb9995SMauro Carvalho Chehab .depth = 16,
11546fb9995SMauro Carvalho Chehab /* Output-only format */
11646fb9995SMauro Carvalho Chehab .types = MEM2MEM_OUTPUT,
11746fb9995SMauro Carvalho Chehab }, {
11846fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_VYUY,
11946fb9995SMauro Carvalho Chehab .depth = 16,
12046fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
12146fb9995SMauro Carvalho Chehab }, {
12246fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YVYU,
12346fb9995SMauro Carvalho Chehab .depth = 16,
12446fb9995SMauro Carvalho Chehab .types = MEM2MEM_OUTPUT,
12546fb9995SMauro Carvalho Chehab }, {
12646fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_GREY,
12746fb9995SMauro Carvalho Chehab .depth = 8,
12846fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
12946fb9995SMauro Carvalho Chehab }, {
13046fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_Y4,
13146fb9995SMauro Carvalho Chehab .depth = 4,
13246fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
13346fb9995SMauro Carvalho Chehab }, {
13446fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_NV16,
13546fb9995SMauro Carvalho Chehab .depth = 16,
13646fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
13746fb9995SMauro Carvalho Chehab }, {
13846fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_NV12,
13946fb9995SMauro Carvalho Chehab .depth = 12,
14046fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
14146fb9995SMauro Carvalho Chehab }, {
14246fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_NV21,
14346fb9995SMauro Carvalho Chehab .depth = 12,
14446fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
14546fb9995SMauro Carvalho Chehab }, {
14646fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_NV61,
14746fb9995SMauro Carvalho Chehab .depth = 16,
14846fb9995SMauro Carvalho Chehab .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
14946fb9995SMauro Carvalho Chehab }, {
15046fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YUV422P,
15146fb9995SMauro Carvalho Chehab .depth = 16,
15246fb9995SMauro Carvalho Chehab .types = MEM2MEM_OUTPUT,
15346fb9995SMauro Carvalho Chehab }, {
15446fb9995SMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YUV420,
15546fb9995SMauro Carvalho Chehab .depth = 12,
15646fb9995SMauro Carvalho Chehab .types = MEM2MEM_OUTPUT,
15746fb9995SMauro Carvalho Chehab },
15846fb9995SMauro Carvalho Chehab };
15946fb9995SMauro Carvalho Chehab
16046fb9995SMauro Carvalho Chehab #define NUM_FORMATS ARRAY_SIZE(formats)
16146fb9995SMauro Carvalho Chehab
16246fb9995SMauro Carvalho Chehab /* Per-queue, driver-specific private data */
16346fb9995SMauro Carvalho Chehab struct pxp_q_data {
16446fb9995SMauro Carvalho Chehab unsigned int width;
16546fb9995SMauro Carvalho Chehab unsigned int height;
16646fb9995SMauro Carvalho Chehab unsigned int bytesperline;
16746fb9995SMauro Carvalho Chehab unsigned int sizeimage;
16846fb9995SMauro Carvalho Chehab unsigned int sequence;
16946fb9995SMauro Carvalho Chehab struct pxp_fmt *fmt;
17046fb9995SMauro Carvalho Chehab enum v4l2_ycbcr_encoding ycbcr_enc;
17146fb9995SMauro Carvalho Chehab enum v4l2_quantization quant;
17246fb9995SMauro Carvalho Chehab };
17346fb9995SMauro Carvalho Chehab
17446fb9995SMauro Carvalho Chehab enum {
17546fb9995SMauro Carvalho Chehab V4L2_M2M_SRC = 0,
17646fb9995SMauro Carvalho Chehab V4L2_M2M_DST = 1,
17746fb9995SMauro Carvalho Chehab };
17846fb9995SMauro Carvalho Chehab
1794e5bd3fdSMichael Tretter static const struct regmap_config pxp_regmap_config = {
1804e5bd3fdSMichael Tretter .reg_bits = 32,
1814e5bd3fdSMichael Tretter .reg_stride = 4,
1824e5bd3fdSMichael Tretter .val_bits = 32,
1834e5bd3fdSMichael Tretter .max_register = HW_PXP_VERSION,
1844e5bd3fdSMichael Tretter };
1854e5bd3fdSMichael Tretter
find_format(unsigned int pixelformat)1868b57a21aSLaurent Pinchart static struct pxp_fmt *find_format(unsigned int pixelformat)
18746fb9995SMauro Carvalho Chehab {
18846fb9995SMauro Carvalho Chehab struct pxp_fmt *fmt;
18946fb9995SMauro Carvalho Chehab unsigned int k;
19046fb9995SMauro Carvalho Chehab
19146fb9995SMauro Carvalho Chehab for (k = 0; k < NUM_FORMATS; k++) {
19246fb9995SMauro Carvalho Chehab fmt = &formats[k];
1938b57a21aSLaurent Pinchart if (fmt->fourcc == pixelformat)
19446fb9995SMauro Carvalho Chehab break;
19546fb9995SMauro Carvalho Chehab }
19646fb9995SMauro Carvalho Chehab
19746fb9995SMauro Carvalho Chehab if (k == NUM_FORMATS)
19846fb9995SMauro Carvalho Chehab return NULL;
19946fb9995SMauro Carvalho Chehab
20046fb9995SMauro Carvalho Chehab return &formats[k];
20146fb9995SMauro Carvalho Chehab }
20246fb9995SMauro Carvalho Chehab
20376985f4eSMichael Tretter struct pxp_ctx;
20476985f4eSMichael Tretter
20576985f4eSMichael Tretter struct pxp_pdata {
20676985f4eSMichael Tretter u32 (*data_path_ctrl0)(struct pxp_ctx *ctx);
20776985f4eSMichael Tretter };
20876985f4eSMichael Tretter
20946fb9995SMauro Carvalho Chehab struct pxp_dev {
21046fb9995SMauro Carvalho Chehab struct v4l2_device v4l2_dev;
21146fb9995SMauro Carvalho Chehab struct video_device vfd;
212ff89b9b4SLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER
213ff89b9b4SLaurent Pinchart struct media_device mdev;
214ff89b9b4SLaurent Pinchart #endif
21546fb9995SMauro Carvalho Chehab
21646fb9995SMauro Carvalho Chehab struct clk *clk;
2174e5bd3fdSMichael Tretter struct regmap *regmap;
21846fb9995SMauro Carvalho Chehab
21976985f4eSMichael Tretter const struct pxp_pdata *pdata;
22076985f4eSMichael Tretter
22146fb9995SMauro Carvalho Chehab atomic_t num_inst;
22246fb9995SMauro Carvalho Chehab struct mutex dev_mutex;
22346fb9995SMauro Carvalho Chehab spinlock_t irqlock;
22446fb9995SMauro Carvalho Chehab
22546fb9995SMauro Carvalho Chehab struct v4l2_m2m_dev *m2m_dev;
22646fb9995SMauro Carvalho Chehab };
22746fb9995SMauro Carvalho Chehab
22846fb9995SMauro Carvalho Chehab struct pxp_ctx {
22946fb9995SMauro Carvalho Chehab struct v4l2_fh fh;
23046fb9995SMauro Carvalho Chehab struct pxp_dev *dev;
23146fb9995SMauro Carvalho Chehab
23246fb9995SMauro Carvalho Chehab struct v4l2_ctrl_handler hdl;
23346fb9995SMauro Carvalho Chehab
23446fb9995SMauro Carvalho Chehab /* Abort requested by m2m */
23546fb9995SMauro Carvalho Chehab int aborting;
23646fb9995SMauro Carvalho Chehab
23746fb9995SMauro Carvalho Chehab /* Processing mode */
23846fb9995SMauro Carvalho Chehab int mode;
23946fb9995SMauro Carvalho Chehab u8 alpha_component;
24046fb9995SMauro Carvalho Chehab u8 rotation;
24146fb9995SMauro Carvalho Chehab
24246fb9995SMauro Carvalho Chehab enum v4l2_colorspace colorspace;
24346fb9995SMauro Carvalho Chehab enum v4l2_xfer_func xfer_func;
24446fb9995SMauro Carvalho Chehab
24546fb9995SMauro Carvalho Chehab /* Source and destination queue data */
24646fb9995SMauro Carvalho Chehab struct pxp_q_data q_data[2];
24746fb9995SMauro Carvalho Chehab };
24846fb9995SMauro Carvalho Chehab
file2ctx(struct file * file)24946fb9995SMauro Carvalho Chehab static inline struct pxp_ctx *file2ctx(struct file *file)
25046fb9995SMauro Carvalho Chehab {
25146fb9995SMauro Carvalho Chehab return container_of(file->private_data, struct pxp_ctx, fh);
25246fb9995SMauro Carvalho Chehab }
25346fb9995SMauro Carvalho Chehab
get_q_data(struct pxp_ctx * ctx,enum v4l2_buf_type type)25446fb9995SMauro Carvalho Chehab static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
25546fb9995SMauro Carvalho Chehab enum v4l2_buf_type type)
25646fb9995SMauro Carvalho Chehab {
25746fb9995SMauro Carvalho Chehab if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
25846fb9995SMauro Carvalho Chehab return &ctx->q_data[V4L2_M2M_SRC];
25946fb9995SMauro Carvalho Chehab else
26046fb9995SMauro Carvalho Chehab return &ctx->q_data[V4L2_M2M_DST];
26146fb9995SMauro Carvalho Chehab }
26246fb9995SMauro Carvalho Chehab
pxp_read(struct pxp_dev * dev,u32 reg)26336e5c362SLaurent Pinchart static inline u32 pxp_read(struct pxp_dev *dev, u32 reg)
26436e5c362SLaurent Pinchart {
2654e5bd3fdSMichael Tretter u32 value;
2664e5bd3fdSMichael Tretter
2674e5bd3fdSMichael Tretter regmap_read(dev->regmap, reg, &value);
2684e5bd3fdSMichael Tretter
2694e5bd3fdSMichael Tretter return value;
27036e5c362SLaurent Pinchart }
27136e5c362SLaurent Pinchart
pxp_write(struct pxp_dev * dev,u32 reg,u32 value)27236e5c362SLaurent Pinchart static inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value)
27336e5c362SLaurent Pinchart {
2744e5bd3fdSMichael Tretter regmap_write(dev->regmap, reg, value);
27536e5c362SLaurent Pinchart }
27636e5c362SLaurent Pinchart
pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)27746fb9995SMauro Carvalho Chehab static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)
27846fb9995SMauro Carvalho Chehab {
27946fb9995SMauro Carvalho Chehab switch (v4l2_pix_fmt) {
28046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_XBGR32: return BV_PXP_PS_CTRL_FORMAT__RGB888;
28146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_RGB555: return BV_PXP_PS_CTRL_FORMAT__RGB555;
28246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_RGB444: return BV_PXP_PS_CTRL_FORMAT__RGB444;
28346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_RGB565: return BV_PXP_PS_CTRL_FORMAT__RGB565;
28446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VUYX32: return BV_PXP_PS_CTRL_FORMAT__YUV1P444;
28546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_UYVY: return BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
28646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUYV: return BM_PXP_PS_CTRL_WB_SWAP |
28746fb9995SMauro Carvalho Chehab BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
28846fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VYUY: return BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
28946fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YVYU: return BM_PXP_PS_CTRL_WB_SWAP |
29046fb9995SMauro Carvalho Chehab BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
29146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_GREY: return BV_PXP_PS_CTRL_FORMAT__Y8;
29246fb9995SMauro Carvalho Chehab default:
29346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_Y4: return BV_PXP_PS_CTRL_FORMAT__Y4;
29446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16: return BV_PXP_PS_CTRL_FORMAT__YUV2P422;
29546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12: return BV_PXP_PS_CTRL_FORMAT__YUV2P420;
29646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21: return BV_PXP_PS_CTRL_FORMAT__YVU2P420;
29746fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61: return BV_PXP_PS_CTRL_FORMAT__YVU2P422;
29846fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P: return BV_PXP_PS_CTRL_FORMAT__YUV422;
29946fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV420: return BV_PXP_PS_CTRL_FORMAT__YUV420;
30046fb9995SMauro Carvalho Chehab }
30146fb9995SMauro Carvalho Chehab }
30246fb9995SMauro Carvalho Chehab
pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt)30346fb9995SMauro Carvalho Chehab static u32 pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt)
30446fb9995SMauro Carvalho Chehab {
30546fb9995SMauro Carvalho Chehab switch (v4l2_pix_fmt) {
30646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_XBGR32: return BV_PXP_OUT_CTRL_FORMAT__RGB888;
30746fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_ABGR32: return BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
30846fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_BGR24: return BV_PXP_OUT_CTRL_FORMAT__RGB888P;
30946fb9995SMauro Carvalho Chehab /* Missing V4L2 pixel formats for ARGB1555 and ARGB4444 */
31046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_RGB555: return BV_PXP_OUT_CTRL_FORMAT__RGB555;
31146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_RGB444: return BV_PXP_OUT_CTRL_FORMAT__RGB444;
31246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_RGB565: return BV_PXP_OUT_CTRL_FORMAT__RGB565;
31346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VUYA32:
31446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VUYX32: return BV_PXP_OUT_CTRL_FORMAT__YUV1P444;
31546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_UYVY: return BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
31646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VYUY: return BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
31746fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_GREY: return BV_PXP_OUT_CTRL_FORMAT__Y8;
31846fb9995SMauro Carvalho Chehab default:
31946fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_Y4: return BV_PXP_OUT_CTRL_FORMAT__Y4;
32046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16: return BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
32146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12: return BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
32246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61: return BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
32346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21: return BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
32446fb9995SMauro Carvalho Chehab }
32546fb9995SMauro Carvalho Chehab }
32646fb9995SMauro Carvalho Chehab
pxp_v4l2_pix_fmt_is_yuv(u32 v4l2_pix_fmt)32746fb9995SMauro Carvalho Chehab static bool pxp_v4l2_pix_fmt_is_yuv(u32 v4l2_pix_fmt)
32846fb9995SMauro Carvalho Chehab {
32946fb9995SMauro Carvalho Chehab switch (v4l2_pix_fmt) {
33046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VUYA32:
33146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VUYX32:
33246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_UYVY:
33346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUYV:
33446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VYUY:
33546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YVYU:
33646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16:
33746fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12:
33846fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61:
33946fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21:
34046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV420:
34146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P:
34246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_GREY:
34346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_Y4:
34446fb9995SMauro Carvalho Chehab return true;
34546fb9995SMauro Carvalho Chehab default:
34646fb9995SMauro Carvalho Chehab return false;
34746fb9995SMauro Carvalho Chehab }
34846fb9995SMauro Carvalho Chehab }
34946fb9995SMauro Carvalho Chehab
pxp_setup_csc(struct pxp_ctx * ctx)35046fb9995SMauro Carvalho Chehab static void pxp_setup_csc(struct pxp_ctx *ctx)
35146fb9995SMauro Carvalho Chehab {
35246fb9995SMauro Carvalho Chehab struct pxp_dev *dev = ctx->dev;
35346fb9995SMauro Carvalho Chehab enum v4l2_ycbcr_encoding ycbcr_enc;
35446fb9995SMauro Carvalho Chehab enum v4l2_quantization quantization;
35546fb9995SMauro Carvalho Chehab
35646fb9995SMauro Carvalho Chehab if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
35746fb9995SMauro Carvalho Chehab !pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
35846fb9995SMauro Carvalho Chehab /*
35946fb9995SMauro Carvalho Chehab * CSC1 YUV/YCbCr to RGB conversion is implemented as follows:
36046fb9995SMauro Carvalho Chehab *
36146fb9995SMauro Carvalho Chehab * |R| |C0 0 C1| |Y + Yoffset |
36246fb9995SMauro Carvalho Chehab * |G| = |C0 C3 C2| * |Cb + UVoffset|
36346fb9995SMauro Carvalho Chehab * |B| |C0 C4 0 | |Cr + UVoffset|
36446fb9995SMauro Carvalho Chehab *
36546fb9995SMauro Carvalho Chehab * Results are clamped to 0..255.
36646fb9995SMauro Carvalho Chehab *
36746fb9995SMauro Carvalho Chehab * BT.601 limited range:
36846fb9995SMauro Carvalho Chehab *
36946fb9995SMauro Carvalho Chehab * |R| |1.1644 0.0000 1.5960| |Y - 16 |
37046fb9995SMauro Carvalho Chehab * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128|
37146fb9995SMauro Carvalho Chehab * |B| |1.1644 2.0172 0.0000| |Cr - 128|
37246fb9995SMauro Carvalho Chehab */
37346fb9995SMauro Carvalho Chehab static const u32 csc1_coef_bt601_lim[3] = {
37446fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
37546fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
37646fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
37746fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
37846fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x198) | /* 1.5938 (-0.23 %) */
37946fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x204), /* 2.0156 (-0.16 %) */
38046fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x730) | /* -0.8125 (+0.04 %) */
38146fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x79c), /* -0.3906 (+0.11 %) */
38246fb9995SMauro Carvalho Chehab };
38346fb9995SMauro Carvalho Chehab /*
38446fb9995SMauro Carvalho Chehab * BT.601 full range:
38546fb9995SMauro Carvalho Chehab *
38646fb9995SMauro Carvalho Chehab * |R| |1.0000 0.0000 1.4020| |Y + 0 |
38746fb9995SMauro Carvalho Chehab * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128|
38846fb9995SMauro Carvalho Chehab * |B| |1.0000 1.7720 0.0000| |Cr - 128|
38946fb9995SMauro Carvalho Chehab */
39046fb9995SMauro Carvalho Chehab static const u32 csc1_coef_bt601_full[3] = {
39146fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
39246fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
39346fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
39446fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(0),
39546fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x166) | /* 1.3984 (-0.36 %) */
39646fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x1c5), /* 1.7695 (-0.25 %) */
39746fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x74a) | /* -0.7109 (+0.32 %) */
39846fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7a8), /* -0.3438 (+0.04 %) */
39946fb9995SMauro Carvalho Chehab };
40046fb9995SMauro Carvalho Chehab /*
40146fb9995SMauro Carvalho Chehab * Rec.709 limited range:
40246fb9995SMauro Carvalho Chehab *
40346fb9995SMauro Carvalho Chehab * |R| |1.1644 0.0000 1.7927| |Y - 16 |
40446fb9995SMauro Carvalho Chehab * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128|
40546fb9995SMauro Carvalho Chehab * |B| |1.1644 2.1124 0.0000| |Cr - 128|
40646fb9995SMauro Carvalho Chehab */
40746fb9995SMauro Carvalho Chehab static const u32 csc1_coef_rec709_lim[3] = {
40846fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
40946fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
41046fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
41146fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
41246fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x1ca) | /* 1.7891 (-0.37 %) */
41346fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x21c), /* 2.1094 (-0.30 %) */
41446fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x778) | /* -0.5312 (+0.16 %) */
41546fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7ca), /* -0.2109 (+0.23 %) */
41646fb9995SMauro Carvalho Chehab };
41746fb9995SMauro Carvalho Chehab /*
41846fb9995SMauro Carvalho Chehab * Rec.709 full range:
41946fb9995SMauro Carvalho Chehab *
42046fb9995SMauro Carvalho Chehab * |R| |1.0000 0.0000 1.5748| |Y + 0 |
42146fb9995SMauro Carvalho Chehab * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128|
42246fb9995SMauro Carvalho Chehab * |B| |1.0000 1.8556 0.0000| |Cr - 128|
42346fb9995SMauro Carvalho Chehab */
42446fb9995SMauro Carvalho Chehab static const u32 csc1_coef_rec709_full[3] = {
42546fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
42646fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
42746fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
42846fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(0),
42946fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x193) | /* 1.5742 (-0.06 %) */
43046fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x1db), /* 1.8555 (-0.01 %) */
43146fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x789) | /* -0.4648 (+0.33 %) */
43246fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7d1), /* -0.1836 (+0.37 %) */
43346fb9995SMauro Carvalho Chehab };
43446fb9995SMauro Carvalho Chehab /*
43546fb9995SMauro Carvalho Chehab * BT.2020 limited range:
43646fb9995SMauro Carvalho Chehab *
43746fb9995SMauro Carvalho Chehab * |R| |1.1644 0.0000 1.6787| |Y - 16 |
43846fb9995SMauro Carvalho Chehab * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128|
43946fb9995SMauro Carvalho Chehab * |B| |1.1644 2.1418 0.0000| |Cr - 128|
44046fb9995SMauro Carvalho Chehab */
44146fb9995SMauro Carvalho Chehab static const u32 csc1_coef_bt2020_lim[3] = {
44246fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
44346fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
44446fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
44546fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
44646fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x1ad) | /* 1.6758 (-0.29 %) */
44746fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x224), /* 2.1406 (-0.11 %) */
44846fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x75a) | /* -0.6484 (+0.20 %) */
44946fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7d1), /* -0.1836 (+0.38 %) */
45046fb9995SMauro Carvalho Chehab };
45146fb9995SMauro Carvalho Chehab /*
45246fb9995SMauro Carvalho Chehab * BT.2020 full range:
45346fb9995SMauro Carvalho Chehab *
45446fb9995SMauro Carvalho Chehab * |R| |1.0000 0.0000 1.4746| |Y + 0 |
45546fb9995SMauro Carvalho Chehab * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128|
45646fb9995SMauro Carvalho Chehab * |B| |1.0000 1.8814 0.0000| |Cr - 128|
45746fb9995SMauro Carvalho Chehab */
45846fb9995SMauro Carvalho Chehab static const u32 csc1_coef_bt2020_full[3] = {
45946fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
46046fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
46146fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
46246fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(0),
46346fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x179) | /* 1.4727 (-0.19 %) */
46446fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x1e1), /* 1.8789 (-0.25 %) */
46546fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x76e) | /* -0.5703 (+0.11 %) */
46646fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7d6), /* -0.1641 (+0.05 %) */
46746fb9995SMauro Carvalho Chehab };
46846fb9995SMauro Carvalho Chehab /*
46946fb9995SMauro Carvalho Chehab * SMPTE 240m limited range:
47046fb9995SMauro Carvalho Chehab *
47146fb9995SMauro Carvalho Chehab * |R| |1.1644 0.0000 1.7937| |Y - 16 |
47246fb9995SMauro Carvalho Chehab * |G| = |1.1644 -0.2565 -0.5427| * |Cb - 128|
47346fb9995SMauro Carvalho Chehab * |B| |1.1644 2.0798 0.0000| |Cr - 128|
47446fb9995SMauro Carvalho Chehab */
47546fb9995SMauro Carvalho Chehab static const u32 csc1_coef_smpte240m_lim[3] = {
47646fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
47746fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
47846fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
47946fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
48046fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x1cb) | /* 1.7930 (-0.07 %) */
48146fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x214), /* 2.0781 (-0.17 %) */
48246fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x776) | /* -0.5391 (+0.36 %) */
48346fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7bf), /* -0.2539 (+0.26 %) */
48446fb9995SMauro Carvalho Chehab };
48546fb9995SMauro Carvalho Chehab /*
48646fb9995SMauro Carvalho Chehab * SMPTE 240m full range:
48746fb9995SMauro Carvalho Chehab *
48846fb9995SMauro Carvalho Chehab * |R| |1.0000 0.0000 1.5756| |Y + 0 |
48946fb9995SMauro Carvalho Chehab * |G| = |1.0000 -0.2253 -0.4767| * |Cb - 128|
49046fb9995SMauro Carvalho Chehab * |B| |1.0000 1.8270 0.0000| |Cr - 128|
49146fb9995SMauro Carvalho Chehab */
49246fb9995SMauro Carvalho Chehab static const u32 csc1_coef_smpte240m_full[3] = {
49346fb9995SMauro Carvalho Chehab BM_PXP_CSC1_COEF0_YCBCR_MODE |
49446fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
49546fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
49646fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF0_Y_OFFSET(0),
49746fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C1(0x193) | /* 1.5742 (-0.14 %) */
49846fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF1_C4(0x1d3), /* 1.8242 (-0.28 %) */
49946fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C2(0x786) | /* -0.4766 (+0.01 %) */
50046fb9995SMauro Carvalho Chehab BF_PXP_CSC1_COEF2_C3(0x7c7), /* -0.2227 (+0.26 %) */
50146fb9995SMauro Carvalho Chehab };
50246fb9995SMauro Carvalho Chehab const u32 *csc1_coef;
50346fb9995SMauro Carvalho Chehab
50446fb9995SMauro Carvalho Chehab ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
50546fb9995SMauro Carvalho Chehab quantization = ctx->q_data[V4L2_M2M_SRC].quant;
50646fb9995SMauro Carvalho Chehab
50746fb9995SMauro Carvalho Chehab if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
50846fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
50946fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_bt601_full;
51046fb9995SMauro Carvalho Chehab else
51146fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_bt601_lim;
51246fb9995SMauro Carvalho Chehab } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
51346fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
51446fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_rec709_full;
51546fb9995SMauro Carvalho Chehab else
51646fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_rec709_lim;
51746fb9995SMauro Carvalho Chehab } else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
51846fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
51946fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_bt2020_full;
52046fb9995SMauro Carvalho Chehab else
52146fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_bt2020_lim;
52246fb9995SMauro Carvalho Chehab } else {
52346fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
52446fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_smpte240m_full;
52546fb9995SMauro Carvalho Chehab else
52646fb9995SMauro Carvalho Chehab csc1_coef = csc1_coef_smpte240m_lim;
52746fb9995SMauro Carvalho Chehab }
52846fb9995SMauro Carvalho Chehab
52936e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC1_COEF0, csc1_coef[0]);
53036e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC1_COEF1, csc1_coef[1]);
53136e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC1_COEF2, csc1_coef[2]);
53246fb9995SMauro Carvalho Chehab } else {
53336e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC1_COEF0, BM_PXP_CSC1_COEF0_BYPASS);
53446fb9995SMauro Carvalho Chehab }
53546fb9995SMauro Carvalho Chehab
53646fb9995SMauro Carvalho Chehab if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
53746fb9995SMauro Carvalho Chehab pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
53846fb9995SMauro Carvalho Chehab /*
53946fb9995SMauro Carvalho Chehab * CSC2 RGB to YUV/YCbCr conversion is implemented as follows:
54046fb9995SMauro Carvalho Chehab *
54146fb9995SMauro Carvalho Chehab * |Y | |A1 A2 A3| |R| |D1|
54246fb9995SMauro Carvalho Chehab * |Cb| = |B1 B2 B3| * |G| + |D2|
54346fb9995SMauro Carvalho Chehab * |Cr| |C1 C2 C3| |B| |D3|
54446fb9995SMauro Carvalho Chehab *
54546fb9995SMauro Carvalho Chehab * Results are clamped to 0..255.
54646fb9995SMauro Carvalho Chehab *
54746fb9995SMauro Carvalho Chehab * BT.601 limited range:
54846fb9995SMauro Carvalho Chehab *
54946fb9995SMauro Carvalho Chehab * |Y | | 0.2568 0.5041 0.0979| |R| |16 |
55046fb9995SMauro Carvalho Chehab * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128|
55146fb9995SMauro Carvalho Chehab * |Cr| | 0.4392 0.4392 -0.3678| |B| |128|
55246fb9995SMauro Carvalho Chehab */
55346fb9995SMauro Carvalho Chehab static const u32 csc2_coef_bt601_lim[6] = {
55446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x081) | /* 0.5039 (-0.02 %) */
55546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x041), /* 0.2539 (-0.29 %) */
55646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7db) | /* -0.1445 (+0.37 %) */
55746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x019), /* 0.0977 (-0.02 %) */
55846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
55946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x7b6), /* -0.2891 (+0.20 %) */
56046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x7a2) | /* -0.3672 (+0.06 %) */
56146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
56246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(16) |
56346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7ee), /* -0.0703 (+0.11 %) */
56446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
56546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
56646fb9995SMauro Carvalho Chehab };
56746fb9995SMauro Carvalho Chehab /*
56846fb9995SMauro Carvalho Chehab * BT.601 full range:
56946fb9995SMauro Carvalho Chehab *
57046fb9995SMauro Carvalho Chehab * |Y | | 0.2990 0.5870 0.1140| |R| |0 |
57146fb9995SMauro Carvalho Chehab * |Cb| = |-0.1687 -0.3313 0.5000| * |G| + |128|
57246fb9995SMauro Carvalho Chehab * |Cr| | 0.5000 0.5000 -0.4187| |B| |128|
57346fb9995SMauro Carvalho Chehab */
57446fb9995SMauro Carvalho Chehab static const u32 csc2_coef_bt601_full[6] = {
57546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x096) | /* 0.5859 (-0.11 %) */
57646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x04c), /* 0.2969 (-0.21 %) */
57746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7d5) | /* -0.1680 (+0.07 %) */
57846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x01d), /* 0.1133 (-0.07 %) */
57946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
58046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x7ac), /* -0.3281 (+0.32 %) */
58146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x795) | /* -0.4180 (+0.07 %) */
58246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
58346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(0) |
58446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7ec), /* -0.0781 (+0.32 %) */
58546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
58646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
58746fb9995SMauro Carvalho Chehab };
58846fb9995SMauro Carvalho Chehab /*
58946fb9995SMauro Carvalho Chehab * Rec.709 limited range:
59046fb9995SMauro Carvalho Chehab *
59146fb9995SMauro Carvalho Chehab * |Y | | 0.1826 0.6142 0.0620| |R| |16 |
59246fb9995SMauro Carvalho Chehab * |Cb| = |-0.1007 -0.3385 0.4392| * |G| + |128|
59346fb9995SMauro Carvalho Chehab * |Cr| | 0.4392 0.4392 -0.3990| |B| |128|
59446fb9995SMauro Carvalho Chehab */
59546fb9995SMauro Carvalho Chehab static const u32 csc2_coef_rec709_lim[6] = {
59646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x09d) | /* 0.6133 (-0.09 %) */
59746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x02e), /* 0.1797 (-0.29 %) */
59846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7e7) | /* -0.0977 (+0.30 %) */
59946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x00f), /* 0.0586 (-0.34 %) */
60046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
60146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x7aa), /* -0.3359 (+0.26 %) */
60246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x79a) | /* -0.3984 (+0.05 %) */
60346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
60446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(16) |
60546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7f6), /* -0.0391 (+0.12 %) */
60646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
60746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
60846fb9995SMauro Carvalho Chehab };
60946fb9995SMauro Carvalho Chehab /*
61046fb9995SMauro Carvalho Chehab * Rec.709 full range:
61146fb9995SMauro Carvalho Chehab *
61246fb9995SMauro Carvalho Chehab * |Y | | 0.2126 0.7152 0.0722| |R| |0 |
61346fb9995SMauro Carvalho Chehab * |Cb| = |-0.1146 -0.3854 0.5000| * |G| + |128|
61446fb9995SMauro Carvalho Chehab * |Cr| | 0.5000 0.5000 -0.4542| |B| |128|
61546fb9995SMauro Carvalho Chehab */
61646fb9995SMauro Carvalho Chehab static const u32 csc2_coef_rec709_full[6] = {
61746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x0b7) | /* 0.7148 (-0.04 %) */
61846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x036), /* 0.2109 (-0.17 %) */
61946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7e3) | /* -0.1133 (+0.13 %) */
62046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x012), /* 0.0703 (-0.19 %) */
62146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
62246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x79e), /* -0.3828 (+0.26 %) */
62346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x78c) | /* -0.4531 (+0.11 %) */
62446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
62546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(0) |
62646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7f5), /* -0.0430 (+0.28 %) */
62746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
62846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
62946fb9995SMauro Carvalho Chehab };
63046fb9995SMauro Carvalho Chehab /*
63146fb9995SMauro Carvalho Chehab * BT.2020 limited range:
63246fb9995SMauro Carvalho Chehab *
63346fb9995SMauro Carvalho Chehab * |Y | | 0.2256 0.5823 0.0509| |R| |16 |
63446fb9995SMauro Carvalho Chehab * |Cb| = |-0.1226 -0.3166 0.4392| * |G| + |128|
63546fb9995SMauro Carvalho Chehab * |Cr| | 0.4392 0.4392 -0.4039| |B| |128|
63646fb9995SMauro Carvalho Chehab */
63746fb9995SMauro Carvalho Chehab static const u32 csc2_coef_bt2020_lim[6] = {
63846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x095) | /* 0.5820 (-0.03 %) */
63946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x039), /* 0.2227 (-0.30 %) */
64046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7e1) | /* -0.1211 (+0.15 %) */
64146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x00d), /* 0.0508 (-0.01 %) */
64246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
64346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x7af), /* -0.3164 (+0.02 %) */
64446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x799) | /* -0.4023 (+0.16 %) */
64546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
64646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(16) |
64746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7f7), /* -0.0352 (+0.02 %) */
64846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
64946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
65046fb9995SMauro Carvalho Chehab };
65146fb9995SMauro Carvalho Chehab /*
65246fb9995SMauro Carvalho Chehab * BT.2020 full range:
65346fb9995SMauro Carvalho Chehab *
65446fb9995SMauro Carvalho Chehab * |Y | | 0.2627 0.6780 0.0593| |R| |0 |
65546fb9995SMauro Carvalho Chehab * |Cb| = |-0.1396 -0.3604 0.5000| * |G| + |128|
65646fb9995SMauro Carvalho Chehab * |Cr| | 0.5000 0.5000 -0.4598| |B| |128|
65746fb9995SMauro Carvalho Chehab */
65846fb9995SMauro Carvalho Chehab static const u32 csc2_coef_bt2020_full[6] = {
65946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x0ad) | /* 0.6758 (-0.22 %) */
66046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x043), /* 0.2617 (-0.10 %) */
66146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7dd) | /* -0.1367 (+0.29 %) */
66246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x00f), /* 0.0586 (-0.07 %) */
66346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
66446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x7a4), /* -0.3594 (+0.10 %) */
66546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x78b) | /* -0.4570 (+0.28 %) */
66646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
66746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(0) |
66846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7f6), /* -0.0391 (+0.11 %) */
66946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
67046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
67146fb9995SMauro Carvalho Chehab };
67246fb9995SMauro Carvalho Chehab /*
67346fb9995SMauro Carvalho Chehab * SMPTE 240m limited range:
67446fb9995SMauro Carvalho Chehab *
67546fb9995SMauro Carvalho Chehab * |Y | | 0.1821 0.6020 0.0747| |R| |16 |
67646fb9995SMauro Carvalho Chehab * |Cb| = |-0.1019 -0.3373 0.4392| * |G| + |128|
67746fb9995SMauro Carvalho Chehab * |Cr| | 0.4392 0.4392 -0.3909| |B| |128|
67846fb9995SMauro Carvalho Chehab */
67946fb9995SMauro Carvalho Chehab static const u32 csc2_coef_smpte240m_lim[6] = {
68046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x09a) | /* 0.6016 (-0.05 %) */
68146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x02e), /* 0.1797 (-0.24 %) */
68246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7e6) | /* -0.1016 (+0.03 %) */
68346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x013), /* 0.0742 (-0.05 %) */
68446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
68546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x7aa), /* -0.3359 (+0.14 %) */
68646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x79c) | /* -0.3906 (+0.03 %) */
68746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
68846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(16) |
68946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7f4), /* -0.0469 (+0.14 %) */
69046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
69146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
69246fb9995SMauro Carvalho Chehab };
69346fb9995SMauro Carvalho Chehab /*
69446fb9995SMauro Carvalho Chehab * SMPTE 240m full range:
69546fb9995SMauro Carvalho Chehab *
69646fb9995SMauro Carvalho Chehab * |Y | | 0.2120 0.7010 0.0870| |R| |0 |
69746fb9995SMauro Carvalho Chehab * |Cb| = |-0.1160 -0.3840 0.5000| * |G| + |128|
69846fb9995SMauro Carvalho Chehab * |Cr| | 0.5000 0.5000 -0.4450| |B| |128|
69946fb9995SMauro Carvalho Chehab */
70046fb9995SMauro Carvalho Chehab static const u32 csc2_coef_smpte240m_full[6] = {
70146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A2(0x0b3) | /* 0.6992 (-0.18 %) */
70246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF0_A1(0x036), /* 0.2109 (-0.11 %) */
70346fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_B1(0x7e3) | /* -0.1133 (+0.27 %) */
70446fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF1_A3(0x016), /* 0.0859 (-0.11 %) */
70546fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
70646fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF2_B2(0x79e), /* -0.3828 (+0.12 %) */
70746fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C2(0x78f) | /* -0.4414 (+0.36 %) */
70846fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
70946fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_D1(0) |
71046fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF4_C3(0x7f2), /* -0.0547 (+0.03 %) */
71146fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D3(128) |
71246fb9995SMauro Carvalho Chehab BF_PXP_CSC2_COEF5_D2(128),
71346fb9995SMauro Carvalho Chehab };
71446fb9995SMauro Carvalho Chehab const u32 *csc2_coef;
71546fb9995SMauro Carvalho Chehab u32 csc2_ctrl;
71646fb9995SMauro Carvalho Chehab
71746fb9995SMauro Carvalho Chehab ycbcr_enc = ctx->q_data[V4L2_M2M_DST].ycbcr_enc;
71846fb9995SMauro Carvalho Chehab quantization = ctx->q_data[V4L2_M2M_DST].quant;
71946fb9995SMauro Carvalho Chehab
72046fb9995SMauro Carvalho Chehab if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
72146fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
72246fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_bt601_full;
72346fb9995SMauro Carvalho Chehab else
72446fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_bt601_lim;
72546fb9995SMauro Carvalho Chehab } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
72646fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
72746fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_rec709_full;
72846fb9995SMauro Carvalho Chehab else
72946fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_rec709_lim;
73046fb9995SMauro Carvalho Chehab } else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
73146fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
73246fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_bt2020_full;
73346fb9995SMauro Carvalho Chehab else
73446fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_bt2020_lim;
73546fb9995SMauro Carvalho Chehab } else {
73646fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
73746fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_smpte240m_full;
73846fb9995SMauro Carvalho Chehab else
73946fb9995SMauro Carvalho Chehab csc2_coef = csc2_coef_smpte240m_lim;
74046fb9995SMauro Carvalho Chehab }
74146fb9995SMauro Carvalho Chehab if (quantization == V4L2_QUANTIZATION_FULL_RANGE) {
74246fb9995SMauro Carvalho Chehab csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV <<
74346fb9995SMauro Carvalho Chehab BP_PXP_CSC2_CTRL_CSC_MODE;
74446fb9995SMauro Carvalho Chehab } else {
74546fb9995SMauro Carvalho Chehab csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr <<
74646fb9995SMauro Carvalho Chehab BP_PXP_CSC2_CTRL_CSC_MODE;
74746fb9995SMauro Carvalho Chehab }
74846fb9995SMauro Carvalho Chehab
74936e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_CTRL, csc2_ctrl);
75036e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_COEF0, csc2_coef[0]);
75136e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_COEF1, csc2_coef[1]);
75236e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_COEF2, csc2_coef[2]);
75336e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_COEF3, csc2_coef[3]);
75436e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_COEF4, csc2_coef[4]);
75536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_COEF5, csc2_coef[5]);
75646fb9995SMauro Carvalho Chehab } else {
75736e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CSC2_CTRL, BM_PXP_CSC2_CTRL_BYPASS);
75846fb9995SMauro Carvalho Chehab }
75946fb9995SMauro Carvalho Chehab }
76046fb9995SMauro Carvalho Chehab
pxp_imx6ull_data_path_ctrl0(struct pxp_ctx * ctx)76176985f4eSMichael Tretter static u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx)
7629fb41a05SMichael Tretter {
7639fb41a05SMichael Tretter u32 ctrl0;
7649fb41a05SMichael Tretter
7659fb41a05SMichael Tretter ctrl0 = 0;
76647956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
76747956c92SMichael Tretter /* Bypass Dithering x3CH */
7689fb41a05SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1);
76947956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
77047956c92SMichael Tretter /* Select Rotation */
7719fb41a05SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0);
772fb2e9aa8SMichael Tretter /* Bypass LUT */
773fb2e9aa8SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
77447956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
775fb2e9aa8SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
77647956c92SMichael Tretter /* Select CSC 2 */
7779fb41a05SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
77847956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
77947956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(3);
78047956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
78147956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
78247956c92SMichael Tretter /* Bypass Rotation 2 */
7839fb41a05SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
78447956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
78547956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
78647956c92SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
7879fb41a05SMichael Tretter
7889fb41a05SMichael Tretter return ctrl0;
7899fb41a05SMichael Tretter }
7909fb41a05SMichael Tretter
pxp_imx7d_data_path_ctrl0(struct pxp_ctx * ctx)791cbcd2373SMichael Tretter static u32 pxp_imx7d_data_path_ctrl0(struct pxp_ctx *ctx)
792cbcd2373SMichael Tretter {
793cbcd2373SMichael Tretter u32 ctrl0;
794cbcd2373SMichael Tretter
795cbcd2373SMichael Tretter ctrl0 = 0;
796cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
797cbcd2373SMichael Tretter /* Select Rotation 0 */
798cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(0);
799cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
800cbcd2373SMichael Tretter /* Select MUX11 for Rotation 0 */
801cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(1);
802cbcd2373SMichael Tretter /* Bypass LUT */
803cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
804cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
805cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
806cbcd2373SMichael Tretter /* Select CSC 2 */
807cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
808cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
809cbcd2373SMichael Tretter /* Select Composite Alpha Blending/Color Key 0 for CSC 2 */
810cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(1);
811cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
812cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
813cbcd2373SMichael Tretter /* Bypass Rotation 1 */
814cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
815cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
816cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
817cbcd2373SMichael Tretter ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
818cbcd2373SMichael Tretter
819cbcd2373SMichael Tretter return ctrl0;
820cbcd2373SMichael Tretter }
821cbcd2373SMichael Tretter
pxp_set_data_path(struct pxp_ctx * ctx)8229fb41a05SMichael Tretter static void pxp_set_data_path(struct pxp_ctx *ctx)
8239fb41a05SMichael Tretter {
8249fb41a05SMichael Tretter struct pxp_dev *dev = ctx->dev;
8259fb41a05SMichael Tretter u32 ctrl0;
8269fb41a05SMichael Tretter u32 ctrl1;
8279fb41a05SMichael Tretter
82876985f4eSMichael Tretter ctrl0 = dev->pdata->data_path_ctrl0(ctx);
8299fb41a05SMichael Tretter
8309fb41a05SMichael Tretter ctrl1 = 0;
83147956c92SMichael Tretter ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3);
83247956c92SMichael Tretter ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3);
8339fb41a05SMichael Tretter
83436e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_DATA_PATH_CTRL0, ctrl0);
83536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_DATA_PATH_CTRL1, ctrl1);
8369fb41a05SMichael Tretter }
8379fb41a05SMichael Tretter
pxp_start(struct pxp_ctx * ctx,struct vb2_v4l2_buffer * in_vb,struct vb2_v4l2_buffer * out_vb)83846fb9995SMauro Carvalho Chehab static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
83946fb9995SMauro Carvalho Chehab struct vb2_v4l2_buffer *out_vb)
84046fb9995SMauro Carvalho Chehab {
84146fb9995SMauro Carvalho Chehab struct pxp_dev *dev = ctx->dev;
84246fb9995SMauro Carvalho Chehab struct pxp_q_data *q_data;
84346fb9995SMauro Carvalho Chehab u32 src_width, src_height, src_stride, src_fourcc;
84446fb9995SMauro Carvalho Chehab u32 dst_width, dst_height, dst_stride, dst_fourcc;
84546fb9995SMauro Carvalho Chehab dma_addr_t p_in, p_out;
84646fb9995SMauro Carvalho Chehab u32 ctrl, out_ctrl, out_buf, out_buf2, out_pitch, out_lrc, out_ps_ulc;
84746fb9995SMauro Carvalho Chehab u32 out_ps_lrc;
84846fb9995SMauro Carvalho Chehab u32 ps_ctrl, ps_buf, ps_ubuf, ps_vbuf, ps_pitch, ps_scale, ps_offset;
84946fb9995SMauro Carvalho Chehab u32 as_ulc, as_lrc;
85046fb9995SMauro Carvalho Chehab u32 y_size;
85146fb9995SMauro Carvalho Chehab u32 decx, decy, xscale, yscale;
85246fb9995SMauro Carvalho Chehab
85346fb9995SMauro Carvalho Chehab q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
85446fb9995SMauro Carvalho Chehab
85546fb9995SMauro Carvalho Chehab src_width = ctx->q_data[V4L2_M2M_SRC].width;
85646fb9995SMauro Carvalho Chehab dst_width = ctx->q_data[V4L2_M2M_DST].width;
85746fb9995SMauro Carvalho Chehab src_height = ctx->q_data[V4L2_M2M_SRC].height;
85846fb9995SMauro Carvalho Chehab dst_height = ctx->q_data[V4L2_M2M_DST].height;
85946fb9995SMauro Carvalho Chehab src_stride = ctx->q_data[V4L2_M2M_SRC].bytesperline;
86046fb9995SMauro Carvalho Chehab dst_stride = ctx->q_data[V4L2_M2M_DST].bytesperline;
86146fb9995SMauro Carvalho Chehab src_fourcc = ctx->q_data[V4L2_M2M_SRC].fmt->fourcc;
86246fb9995SMauro Carvalho Chehab dst_fourcc = ctx->q_data[V4L2_M2M_DST].fmt->fourcc;
86346fb9995SMauro Carvalho Chehab
86446fb9995SMauro Carvalho Chehab p_in = vb2_dma_contig_plane_dma_addr(&in_vb->vb2_buf, 0);
86546fb9995SMauro Carvalho Chehab p_out = vb2_dma_contig_plane_dma_addr(&out_vb->vb2_buf, 0);
86646fb9995SMauro Carvalho Chehab
86746fb9995SMauro Carvalho Chehab if (!p_in || !p_out) {
86846fb9995SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev,
86946fb9995SMauro Carvalho Chehab "Acquiring DMA addresses of buffers failed\n");
87046fb9995SMauro Carvalho Chehab return -EFAULT;
87146fb9995SMauro Carvalho Chehab }
87246fb9995SMauro Carvalho Chehab
87346fb9995SMauro Carvalho Chehab out_vb->sequence =
87446fb9995SMauro Carvalho Chehab get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
87546fb9995SMauro Carvalho Chehab in_vb->sequence = q_data->sequence++;
87646fb9995SMauro Carvalho Chehab out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
87746fb9995SMauro Carvalho Chehab
87846fb9995SMauro Carvalho Chehab if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
87946fb9995SMauro Carvalho Chehab out_vb->timecode = in_vb->timecode;
88046fb9995SMauro Carvalho Chehab out_vb->field = in_vb->field;
88146fb9995SMauro Carvalho Chehab out_vb->flags = in_vb->flags &
88246fb9995SMauro Carvalho Chehab (V4L2_BUF_FLAG_TIMECODE |
88346fb9995SMauro Carvalho Chehab V4L2_BUF_FLAG_KEYFRAME |
88446fb9995SMauro Carvalho Chehab V4L2_BUF_FLAG_PFRAME |
88546fb9995SMauro Carvalho Chehab V4L2_BUF_FLAG_BFRAME |
88646fb9995SMauro Carvalho Chehab V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
88746fb9995SMauro Carvalho Chehab
88846fb9995SMauro Carvalho Chehab /* 8x8 block size */
88946fb9995SMauro Carvalho Chehab ctrl = BF_PXP_CTRL_VFLIP0(!!(ctx->mode & MEM2MEM_VFLIP)) |
89046fb9995SMauro Carvalho Chehab BF_PXP_CTRL_HFLIP0(!!(ctx->mode & MEM2MEM_HFLIP)) |
89146fb9995SMauro Carvalho Chehab BF_PXP_CTRL_ROTATE0(ctx->rotation);
89246fb9995SMauro Carvalho Chehab /* Always write alpha value as V4L2_CID_ALPHA_COMPONENT */
89346fb9995SMauro Carvalho Chehab out_ctrl = BF_PXP_OUT_CTRL_ALPHA(ctx->alpha_component) |
89446fb9995SMauro Carvalho Chehab BF_PXP_OUT_CTRL_ALPHA_OUTPUT(1) |
89546fb9995SMauro Carvalho Chehab pxp_v4l2_pix_fmt_to_out_format(dst_fourcc);
89646fb9995SMauro Carvalho Chehab out_buf = p_out;
89746fb9995SMauro Carvalho Chehab
89846fb9995SMauro Carvalho Chehab if (ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_90 ||
89946fb9995SMauro Carvalho Chehab ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_270)
90046fb9995SMauro Carvalho Chehab swap(dst_width, dst_height);
90146fb9995SMauro Carvalho Chehab
90246fb9995SMauro Carvalho Chehab switch (dst_fourcc) {
90346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12:
90446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21:
90546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16:
90646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61:
90746fb9995SMauro Carvalho Chehab out_buf2 = out_buf + dst_stride * dst_height;
90846fb9995SMauro Carvalho Chehab break;
90946fb9995SMauro Carvalho Chehab default:
91046fb9995SMauro Carvalho Chehab out_buf2 = 0;
91146fb9995SMauro Carvalho Chehab }
91246fb9995SMauro Carvalho Chehab
91346fb9995SMauro Carvalho Chehab out_pitch = BF_PXP_OUT_PITCH_PITCH(dst_stride);
91446fb9995SMauro Carvalho Chehab out_lrc = BF_PXP_OUT_LRC_X(dst_width - 1) |
91546fb9995SMauro Carvalho Chehab BF_PXP_OUT_LRC_Y(dst_height - 1);
91646fb9995SMauro Carvalho Chehab /* PS covers whole output */
91746fb9995SMauro Carvalho Chehab out_ps_ulc = BF_PXP_OUT_PS_ULC_X(0) | BF_PXP_OUT_PS_ULC_Y(0);
91846fb9995SMauro Carvalho Chehab out_ps_lrc = BF_PXP_OUT_PS_LRC_X(dst_width - 1) |
91946fb9995SMauro Carvalho Chehab BF_PXP_OUT_PS_LRC_Y(dst_height - 1);
92046fb9995SMauro Carvalho Chehab /* no AS */
92146fb9995SMauro Carvalho Chehab as_ulc = BF_PXP_OUT_AS_ULC_X(1) | BF_PXP_OUT_AS_ULC_Y(1);
92246fb9995SMauro Carvalho Chehab as_lrc = BF_PXP_OUT_AS_LRC_X(0) | BF_PXP_OUT_AS_LRC_Y(0);
92346fb9995SMauro Carvalho Chehab
92446fb9995SMauro Carvalho Chehab decx = (src_width <= dst_width) ? 0 : ilog2(src_width / dst_width);
92546fb9995SMauro Carvalho Chehab decy = (src_height <= dst_height) ? 0 : ilog2(src_height / dst_height);
92646fb9995SMauro Carvalho Chehab ps_ctrl = BF_PXP_PS_CTRL_DECX(decx) | BF_PXP_PS_CTRL_DECY(decy) |
92746fb9995SMauro Carvalho Chehab pxp_v4l2_pix_fmt_to_ps_format(src_fourcc);
92846fb9995SMauro Carvalho Chehab ps_buf = p_in;
92946fb9995SMauro Carvalho Chehab y_size = src_stride * src_height;
93046fb9995SMauro Carvalho Chehab switch (src_fourcc) {
93146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV420:
93246fb9995SMauro Carvalho Chehab ps_ubuf = ps_buf + y_size;
93346fb9995SMauro Carvalho Chehab ps_vbuf = ps_ubuf + y_size / 4;
93446fb9995SMauro Carvalho Chehab break;
93546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P:
93646fb9995SMauro Carvalho Chehab ps_ubuf = ps_buf + y_size;
93746fb9995SMauro Carvalho Chehab ps_vbuf = ps_ubuf + y_size / 2;
93846fb9995SMauro Carvalho Chehab break;
93946fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12:
94046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21:
94146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16:
94246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61:
94346fb9995SMauro Carvalho Chehab ps_ubuf = ps_buf + y_size;
94446fb9995SMauro Carvalho Chehab ps_vbuf = 0;
94546fb9995SMauro Carvalho Chehab break;
94646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_GREY:
94746fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_Y4:
94846fb9995SMauro Carvalho Chehab ps_ubuf = 0;
94946fb9995SMauro Carvalho Chehab /* In grayscale mode, ps_vbuf contents are reused as CbCr */
95046fb9995SMauro Carvalho Chehab ps_vbuf = 0x8080;
95146fb9995SMauro Carvalho Chehab break;
95246fb9995SMauro Carvalho Chehab default:
95346fb9995SMauro Carvalho Chehab ps_ubuf = 0;
95446fb9995SMauro Carvalho Chehab ps_vbuf = 0;
95546fb9995SMauro Carvalho Chehab break;
95646fb9995SMauro Carvalho Chehab }
95746fb9995SMauro Carvalho Chehab ps_pitch = BF_PXP_PS_PITCH_PITCH(src_stride);
95846fb9995SMauro Carvalho Chehab if (decx) {
95946fb9995SMauro Carvalho Chehab xscale = (src_width >> decx) * 0x1000 / dst_width;
96046fb9995SMauro Carvalho Chehab } else {
96146fb9995SMauro Carvalho Chehab switch (src_fourcc) {
96246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_UYVY:
96346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUYV:
96446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_VYUY:
96546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YVYU:
96646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16:
96746fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12:
96846fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21:
96946fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61:
97046fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P:
97146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV420:
97246fb9995SMauro Carvalho Chehab /*
97346fb9995SMauro Carvalho Chehab * This avoids sampling past the right edge for
97446fb9995SMauro Carvalho Chehab * horizontally chroma subsampled formats.
97546fb9995SMauro Carvalho Chehab */
97646fb9995SMauro Carvalho Chehab xscale = (src_width - 2) * 0x1000 / (dst_width - 1);
97746fb9995SMauro Carvalho Chehab break;
97846fb9995SMauro Carvalho Chehab default:
97946fb9995SMauro Carvalho Chehab xscale = (src_width - 1) * 0x1000 / (dst_width - 1);
98046fb9995SMauro Carvalho Chehab break;
98146fb9995SMauro Carvalho Chehab }
98246fb9995SMauro Carvalho Chehab }
98346fb9995SMauro Carvalho Chehab if (decy)
98446fb9995SMauro Carvalho Chehab yscale = (src_height >> decy) * 0x1000 / dst_height;
98546fb9995SMauro Carvalho Chehab else
98646fb9995SMauro Carvalho Chehab yscale = (src_height - 1) * 0x1000 / (dst_height - 1);
98746fb9995SMauro Carvalho Chehab ps_scale = BF_PXP_PS_SCALE_YSCALE(yscale) |
98846fb9995SMauro Carvalho Chehab BF_PXP_PS_SCALE_XSCALE(xscale);
98946fb9995SMauro Carvalho Chehab ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0);
99046fb9995SMauro Carvalho Chehab
99136e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL, ctrl);
99246fb9995SMauro Carvalho Chehab /* skip STAT */
99336e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_CTRL, out_ctrl);
99436e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_BUF, out_buf);
99536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_BUF2, out_buf2);
99636e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_PITCH, out_pitch);
99736e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_LRC, out_lrc);
99836e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_PS_ULC, out_ps_ulc);
99936e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_PS_LRC, out_ps_lrc);
100036e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_AS_ULC, as_ulc);
100136e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_OUT_AS_LRC, as_lrc);
100236e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_CTRL, ps_ctrl);
100336e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_BUF, ps_buf);
100436e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_UBUF, ps_ubuf);
100536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_VBUF, ps_vbuf);
100636e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_PITCH, ps_pitch);
100736e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_BACKGROUND_0, 0x00ffffff);
100836e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_SCALE, ps_scale);
100936e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_OFFSET, ps_offset);
101046fb9995SMauro Carvalho Chehab /* disable processed surface color keying */
101136e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_CLRKEYLOW_0, 0x00ffffff);
101236e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_PS_CLRKEYHIGH_0, 0x00000000);
101346fb9995SMauro Carvalho Chehab
101446fb9995SMauro Carvalho Chehab /* disable alpha surface color keying */
101536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_AS_CLRKEYLOW_0, 0x00ffffff);
101636e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_AS_CLRKEYHIGH_0, 0x00000000);
101746fb9995SMauro Carvalho Chehab
101846fb9995SMauro Carvalho Chehab /* setup CSC */
101946fb9995SMauro Carvalho Chehab pxp_setup_csc(ctx);
102046fb9995SMauro Carvalho Chehab
102146fb9995SMauro Carvalho Chehab /* bypass LUT */
102236e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_LUT_CTRL, BM_PXP_LUT_CTRL_BYPASS);
102346fb9995SMauro Carvalho Chehab
10249fb41a05SMichael Tretter pxp_set_data_path(ctx);
102546fb9995SMauro Carvalho Chehab
102636e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_IRQ_MASK, 0xffff);
102746fb9995SMauro Carvalho Chehab
102846fb9995SMauro Carvalho Chehab /* ungate, enable PS/AS/OUT and PXP operation */
102936e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_IRQ_ENABLE);
103036e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_SET,
103136e5c362SLaurent Pinchart BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
103236e5c362SLaurent Pinchart BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT);
103346fb9995SMauro Carvalho Chehab
103446fb9995SMauro Carvalho Chehab return 0;
103546fb9995SMauro Carvalho Chehab }
103646fb9995SMauro Carvalho Chehab
pxp_job_finish(struct pxp_dev * dev)103746fb9995SMauro Carvalho Chehab static void pxp_job_finish(struct pxp_dev *dev)
103846fb9995SMauro Carvalho Chehab {
103946fb9995SMauro Carvalho Chehab struct pxp_ctx *curr_ctx;
104046fb9995SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_vb, *dst_vb;
104146fb9995SMauro Carvalho Chehab unsigned long flags;
104246fb9995SMauro Carvalho Chehab
104346fb9995SMauro Carvalho Chehab curr_ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
104446fb9995SMauro Carvalho Chehab
104546fb9995SMauro Carvalho Chehab if (curr_ctx == NULL) {
104646fb9995SMauro Carvalho Chehab pr_err("Instance released before the end of transaction\n");
104746fb9995SMauro Carvalho Chehab return;
104846fb9995SMauro Carvalho Chehab }
104946fb9995SMauro Carvalho Chehab
105046fb9995SMauro Carvalho Chehab src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
105146fb9995SMauro Carvalho Chehab dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
105246fb9995SMauro Carvalho Chehab
105346fb9995SMauro Carvalho Chehab spin_lock_irqsave(&dev->irqlock, flags);
105446fb9995SMauro Carvalho Chehab v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
105546fb9995SMauro Carvalho Chehab v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
105646fb9995SMauro Carvalho Chehab spin_unlock_irqrestore(&dev->irqlock, flags);
105746fb9995SMauro Carvalho Chehab
105846fb9995SMauro Carvalho Chehab dprintk(curr_ctx->dev, "Finishing transaction\n");
105946fb9995SMauro Carvalho Chehab v4l2_m2m_job_finish(dev->m2m_dev, curr_ctx->fh.m2m_ctx);
106046fb9995SMauro Carvalho Chehab }
106146fb9995SMauro Carvalho Chehab
106246fb9995SMauro Carvalho Chehab /*
106346fb9995SMauro Carvalho Chehab * mem2mem callbacks
106446fb9995SMauro Carvalho Chehab */
pxp_device_run(void * priv)106546fb9995SMauro Carvalho Chehab static void pxp_device_run(void *priv)
106646fb9995SMauro Carvalho Chehab {
106746fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = priv;
106846fb9995SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_buf, *dst_buf;
106946fb9995SMauro Carvalho Chehab
107046fb9995SMauro Carvalho Chehab src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
107146fb9995SMauro Carvalho Chehab dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
107246fb9995SMauro Carvalho Chehab
107346fb9995SMauro Carvalho Chehab pxp_start(ctx, src_buf, dst_buf);
107446fb9995SMauro Carvalho Chehab }
107546fb9995SMauro Carvalho Chehab
pxp_job_ready(void * priv)107646fb9995SMauro Carvalho Chehab static int pxp_job_ready(void *priv)
107746fb9995SMauro Carvalho Chehab {
107846fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = priv;
107946fb9995SMauro Carvalho Chehab
108046fb9995SMauro Carvalho Chehab if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < 1 ||
108146fb9995SMauro Carvalho Chehab v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < 1) {
108246fb9995SMauro Carvalho Chehab dprintk(ctx->dev, "Not enough buffers available\n");
108346fb9995SMauro Carvalho Chehab return 0;
108446fb9995SMauro Carvalho Chehab }
108546fb9995SMauro Carvalho Chehab
108646fb9995SMauro Carvalho Chehab return 1;
108746fb9995SMauro Carvalho Chehab }
108846fb9995SMauro Carvalho Chehab
pxp_job_abort(void * priv)108946fb9995SMauro Carvalho Chehab static void pxp_job_abort(void *priv)
109046fb9995SMauro Carvalho Chehab {
109146fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = priv;
109246fb9995SMauro Carvalho Chehab
109346fb9995SMauro Carvalho Chehab /* Will cancel the transaction in the next interrupt handler */
109446fb9995SMauro Carvalho Chehab ctx->aborting = 1;
109546fb9995SMauro Carvalho Chehab }
109646fb9995SMauro Carvalho Chehab
109746fb9995SMauro Carvalho Chehab /*
109846fb9995SMauro Carvalho Chehab * interrupt handler
109946fb9995SMauro Carvalho Chehab */
pxp_irq_handler(int irq,void * dev_id)110046fb9995SMauro Carvalho Chehab static irqreturn_t pxp_irq_handler(int irq, void *dev_id)
110146fb9995SMauro Carvalho Chehab {
110246fb9995SMauro Carvalho Chehab struct pxp_dev *dev = dev_id;
110346fb9995SMauro Carvalho Chehab u32 stat;
110446fb9995SMauro Carvalho Chehab
110536e5c362SLaurent Pinchart stat = pxp_read(dev, HW_PXP_STAT);
110646fb9995SMauro Carvalho Chehab
110746fb9995SMauro Carvalho Chehab if (stat & BM_PXP_STAT_IRQ0) {
110846fb9995SMauro Carvalho Chehab /* we expect x = 0, y = height, irq0 = 1 */
110946fb9995SMauro Carvalho Chehab if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY |
111046fb9995SMauro Carvalho Chehab BM_PXP_STAT_IRQ0))
111146fb9995SMauro Carvalho Chehab dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
111236e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_STAT_CLR, BM_PXP_STAT_IRQ0);
111346fb9995SMauro Carvalho Chehab
111446fb9995SMauro Carvalho Chehab pxp_job_finish(dev);
111546fb9995SMauro Carvalho Chehab } else {
111636e5c362SLaurent Pinchart u32 irq = pxp_read(dev, HW_PXP_IRQ);
111746fb9995SMauro Carvalho Chehab
111846fb9995SMauro Carvalho Chehab dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
111946fb9995SMauro Carvalho Chehab dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq);
112046fb9995SMauro Carvalho Chehab
112136e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_IRQ_CLR, irq);
112246fb9995SMauro Carvalho Chehab }
112346fb9995SMauro Carvalho Chehab
112446fb9995SMauro Carvalho Chehab return IRQ_HANDLED;
112546fb9995SMauro Carvalho Chehab }
112646fb9995SMauro Carvalho Chehab
112746fb9995SMauro Carvalho Chehab /*
112846fb9995SMauro Carvalho Chehab * video ioctls
112946fb9995SMauro Carvalho Chehab */
pxp_querycap(struct file * file,void * priv,struct v4l2_capability * cap)113046fb9995SMauro Carvalho Chehab static int pxp_querycap(struct file *file, void *priv,
113146fb9995SMauro Carvalho Chehab struct v4l2_capability *cap)
113246fb9995SMauro Carvalho Chehab {
113346fb9995SMauro Carvalho Chehab strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
113446fb9995SMauro Carvalho Chehab strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
113546fb9995SMauro Carvalho Chehab return 0;
113646fb9995SMauro Carvalho Chehab }
113746fb9995SMauro Carvalho Chehab
pxp_enum_fmt(struct v4l2_fmtdesc * f,u32 type)113846fb9995SMauro Carvalho Chehab static int pxp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
113946fb9995SMauro Carvalho Chehab {
114046fb9995SMauro Carvalho Chehab int i, num;
114146fb9995SMauro Carvalho Chehab struct pxp_fmt *fmt;
114246fb9995SMauro Carvalho Chehab
114346fb9995SMauro Carvalho Chehab num = 0;
114446fb9995SMauro Carvalho Chehab
114546fb9995SMauro Carvalho Chehab for (i = 0; i < NUM_FORMATS; ++i) {
114646fb9995SMauro Carvalho Chehab if (formats[i].types & type) {
114746fb9995SMauro Carvalho Chehab /* index-th format of type type found ? */
114846fb9995SMauro Carvalho Chehab if (num == f->index)
114946fb9995SMauro Carvalho Chehab break;
115046fb9995SMauro Carvalho Chehab /*
115146fb9995SMauro Carvalho Chehab * Correct type but haven't reached our index yet,
115246fb9995SMauro Carvalho Chehab * just increment per-type index
115346fb9995SMauro Carvalho Chehab */
115446fb9995SMauro Carvalho Chehab ++num;
115546fb9995SMauro Carvalho Chehab }
115646fb9995SMauro Carvalho Chehab }
115746fb9995SMauro Carvalho Chehab
115846fb9995SMauro Carvalho Chehab if (i < NUM_FORMATS) {
115946fb9995SMauro Carvalho Chehab /* Format found */
116046fb9995SMauro Carvalho Chehab fmt = &formats[i];
116146fb9995SMauro Carvalho Chehab f->pixelformat = fmt->fourcc;
116246fb9995SMauro Carvalho Chehab return 0;
116346fb9995SMauro Carvalho Chehab }
116446fb9995SMauro Carvalho Chehab
116546fb9995SMauro Carvalho Chehab /* Format not found */
116646fb9995SMauro Carvalho Chehab return -EINVAL;
116746fb9995SMauro Carvalho Chehab }
116846fb9995SMauro Carvalho Chehab
pxp_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)116946fb9995SMauro Carvalho Chehab static int pxp_enum_fmt_vid_cap(struct file *file, void *priv,
117046fb9995SMauro Carvalho Chehab struct v4l2_fmtdesc *f)
117146fb9995SMauro Carvalho Chehab {
117246fb9995SMauro Carvalho Chehab return pxp_enum_fmt(f, MEM2MEM_CAPTURE);
117346fb9995SMauro Carvalho Chehab }
117446fb9995SMauro Carvalho Chehab
pxp_enum_fmt_vid_out(struct file * file,void * priv,struct v4l2_fmtdesc * f)117546fb9995SMauro Carvalho Chehab static int pxp_enum_fmt_vid_out(struct file *file, void *priv,
117646fb9995SMauro Carvalho Chehab struct v4l2_fmtdesc *f)
117746fb9995SMauro Carvalho Chehab {
117846fb9995SMauro Carvalho Chehab return pxp_enum_fmt(f, MEM2MEM_OUTPUT);
117946fb9995SMauro Carvalho Chehab }
118046fb9995SMauro Carvalho Chehab
pxp_g_fmt(struct pxp_ctx * ctx,struct v4l2_format * f)118146fb9995SMauro Carvalho Chehab static int pxp_g_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
118246fb9995SMauro Carvalho Chehab {
118346fb9995SMauro Carvalho Chehab struct vb2_queue *vq;
118446fb9995SMauro Carvalho Chehab struct pxp_q_data *q_data;
118546fb9995SMauro Carvalho Chehab
118646fb9995SMauro Carvalho Chehab vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
118746fb9995SMauro Carvalho Chehab if (!vq)
118846fb9995SMauro Carvalho Chehab return -EINVAL;
118946fb9995SMauro Carvalho Chehab
119046fb9995SMauro Carvalho Chehab q_data = get_q_data(ctx, f->type);
119146fb9995SMauro Carvalho Chehab
119246fb9995SMauro Carvalho Chehab f->fmt.pix.width = q_data->width;
119346fb9995SMauro Carvalho Chehab f->fmt.pix.height = q_data->height;
119446fb9995SMauro Carvalho Chehab f->fmt.pix.field = V4L2_FIELD_NONE;
119546fb9995SMauro Carvalho Chehab f->fmt.pix.pixelformat = q_data->fmt->fourcc;
119646fb9995SMauro Carvalho Chehab f->fmt.pix.bytesperline = q_data->bytesperline;
119746fb9995SMauro Carvalho Chehab f->fmt.pix.sizeimage = q_data->sizeimage;
119846fb9995SMauro Carvalho Chehab f->fmt.pix.colorspace = ctx->colorspace;
119946fb9995SMauro Carvalho Chehab f->fmt.pix.xfer_func = ctx->xfer_func;
120046fb9995SMauro Carvalho Chehab f->fmt.pix.ycbcr_enc = q_data->ycbcr_enc;
120146fb9995SMauro Carvalho Chehab f->fmt.pix.quantization = q_data->quant;
120246fb9995SMauro Carvalho Chehab
120346fb9995SMauro Carvalho Chehab return 0;
120446fb9995SMauro Carvalho Chehab }
120546fb9995SMauro Carvalho Chehab
pxp_g_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)120646fb9995SMauro Carvalho Chehab static int pxp_g_fmt_vid_out(struct file *file, void *priv,
120746fb9995SMauro Carvalho Chehab struct v4l2_format *f)
120846fb9995SMauro Carvalho Chehab {
120946fb9995SMauro Carvalho Chehab return pxp_g_fmt(file2ctx(file), f);
121046fb9995SMauro Carvalho Chehab }
121146fb9995SMauro Carvalho Chehab
pxp_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)121246fb9995SMauro Carvalho Chehab static int pxp_g_fmt_vid_cap(struct file *file, void *priv,
121346fb9995SMauro Carvalho Chehab struct v4l2_format *f)
121446fb9995SMauro Carvalho Chehab {
121546fb9995SMauro Carvalho Chehab return pxp_g_fmt(file2ctx(file), f);
121646fb9995SMauro Carvalho Chehab }
121746fb9995SMauro Carvalho Chehab
pxp_bytesperline(struct pxp_fmt * fmt,u32 width)121846fb9995SMauro Carvalho Chehab static inline u32 pxp_bytesperline(struct pxp_fmt *fmt, u32 width)
121946fb9995SMauro Carvalho Chehab {
122046fb9995SMauro Carvalho Chehab switch (fmt->fourcc) {
122146fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV420:
122246fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV12:
122346fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV21:
122446fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P:
122546fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV16:
122646fb9995SMauro Carvalho Chehab case V4L2_PIX_FMT_NV61:
122746fb9995SMauro Carvalho Chehab return width;
122846fb9995SMauro Carvalho Chehab default:
122946fb9995SMauro Carvalho Chehab return (width * fmt->depth) >> 3;
123046fb9995SMauro Carvalho Chehab }
123146fb9995SMauro Carvalho Chehab }
123246fb9995SMauro Carvalho Chehab
pxp_sizeimage(struct pxp_fmt * fmt,u32 width,u32 height)123346fb9995SMauro Carvalho Chehab static inline u32 pxp_sizeimage(struct pxp_fmt *fmt, u32 width, u32 height)
123446fb9995SMauro Carvalho Chehab {
123546fb9995SMauro Carvalho Chehab return (fmt->depth * width * height) >> 3;
123646fb9995SMauro Carvalho Chehab }
123746fb9995SMauro Carvalho Chehab
pxp_try_fmt(struct v4l2_format * f,struct pxp_fmt * fmt)123846fb9995SMauro Carvalho Chehab static int pxp_try_fmt(struct v4l2_format *f, struct pxp_fmt *fmt)
123946fb9995SMauro Carvalho Chehab {
124046fb9995SMauro Carvalho Chehab v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, ALIGN_W,
124146fb9995SMauro Carvalho Chehab &f->fmt.pix.height, MIN_H, MAX_H, ALIGN_H, 0);
124246fb9995SMauro Carvalho Chehab
124346fb9995SMauro Carvalho Chehab f->fmt.pix.bytesperline = pxp_bytesperline(fmt, f->fmt.pix.width);
124446fb9995SMauro Carvalho Chehab f->fmt.pix.sizeimage = pxp_sizeimage(fmt, f->fmt.pix.width,
124546fb9995SMauro Carvalho Chehab f->fmt.pix.height);
124646fb9995SMauro Carvalho Chehab f->fmt.pix.field = V4L2_FIELD_NONE;
124746fb9995SMauro Carvalho Chehab
124846fb9995SMauro Carvalho Chehab return 0;
124946fb9995SMauro Carvalho Chehab }
125046fb9995SMauro Carvalho Chehab
125146fb9995SMauro Carvalho Chehab static void
pxp_fixup_colorimetry_cap(struct pxp_ctx * ctx,u32 dst_fourcc,enum v4l2_ycbcr_encoding * ycbcr_enc,enum v4l2_quantization * quantization)125246fb9995SMauro Carvalho Chehab pxp_fixup_colorimetry_cap(struct pxp_ctx *ctx, u32 dst_fourcc,
125346fb9995SMauro Carvalho Chehab enum v4l2_ycbcr_encoding *ycbcr_enc,
125446fb9995SMauro Carvalho Chehab enum v4l2_quantization *quantization)
125546fb9995SMauro Carvalho Chehab {
125646fb9995SMauro Carvalho Chehab bool dst_is_yuv = pxp_v4l2_pix_fmt_is_yuv(dst_fourcc);
125746fb9995SMauro Carvalho Chehab
125846fb9995SMauro Carvalho Chehab if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) ==
125946fb9995SMauro Carvalho Chehab dst_is_yuv) {
126046fb9995SMauro Carvalho Chehab /*
126146fb9995SMauro Carvalho Chehab * There is no support for conversion between different YCbCr
126246fb9995SMauro Carvalho Chehab * encodings or between RGB limited and full range.
126346fb9995SMauro Carvalho Chehab */
126446fb9995SMauro Carvalho Chehab *ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
126546fb9995SMauro Carvalho Chehab *quantization = ctx->q_data[V4L2_M2M_SRC].quant;
126646fb9995SMauro Carvalho Chehab } else {
126746fb9995SMauro Carvalho Chehab *ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(ctx->colorspace);
126846fb9995SMauro Carvalho Chehab *quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!dst_is_yuv,
126946fb9995SMauro Carvalho Chehab ctx->colorspace,
127046fb9995SMauro Carvalho Chehab *ycbcr_enc);
127146fb9995SMauro Carvalho Chehab }
127246fb9995SMauro Carvalho Chehab }
127346fb9995SMauro Carvalho Chehab
pxp_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)127446fb9995SMauro Carvalho Chehab static int pxp_try_fmt_vid_cap(struct file *file, void *priv,
127546fb9995SMauro Carvalho Chehab struct v4l2_format *f)
127646fb9995SMauro Carvalho Chehab {
127746fb9995SMauro Carvalho Chehab struct pxp_fmt *fmt;
127846fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = file2ctx(file);
127946fb9995SMauro Carvalho Chehab
12808b57a21aSLaurent Pinchart fmt = find_format(f->fmt.pix.pixelformat);
128146fb9995SMauro Carvalho Chehab if (!fmt) {
128246fb9995SMauro Carvalho Chehab f->fmt.pix.pixelformat = formats[0].fourcc;
12838b57a21aSLaurent Pinchart fmt = find_format(f->fmt.pix.pixelformat);
128446fb9995SMauro Carvalho Chehab }
128546fb9995SMauro Carvalho Chehab if (!(fmt->types & MEM2MEM_CAPTURE)) {
128646fb9995SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev,
128746fb9995SMauro Carvalho Chehab "Fourcc format (0x%08x) invalid.\n",
128846fb9995SMauro Carvalho Chehab f->fmt.pix.pixelformat);
128946fb9995SMauro Carvalho Chehab return -EINVAL;
129046fb9995SMauro Carvalho Chehab }
129146fb9995SMauro Carvalho Chehab
129246fb9995SMauro Carvalho Chehab f->fmt.pix.colorspace = ctx->colorspace;
129346fb9995SMauro Carvalho Chehab f->fmt.pix.xfer_func = ctx->xfer_func;
129446fb9995SMauro Carvalho Chehab
129546fb9995SMauro Carvalho Chehab pxp_fixup_colorimetry_cap(ctx, fmt->fourcc,
129646fb9995SMauro Carvalho Chehab &f->fmt.pix.ycbcr_enc,
129746fb9995SMauro Carvalho Chehab &f->fmt.pix.quantization);
129846fb9995SMauro Carvalho Chehab
129946fb9995SMauro Carvalho Chehab return pxp_try_fmt(f, fmt);
130046fb9995SMauro Carvalho Chehab }
130146fb9995SMauro Carvalho Chehab
pxp_try_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)130246fb9995SMauro Carvalho Chehab static int pxp_try_fmt_vid_out(struct file *file, void *priv,
130346fb9995SMauro Carvalho Chehab struct v4l2_format *f)
130446fb9995SMauro Carvalho Chehab {
130546fb9995SMauro Carvalho Chehab struct pxp_fmt *fmt;
130646fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = file2ctx(file);
130746fb9995SMauro Carvalho Chehab
13088b57a21aSLaurent Pinchart fmt = find_format(f->fmt.pix.pixelformat);
130946fb9995SMauro Carvalho Chehab if (!fmt) {
131046fb9995SMauro Carvalho Chehab f->fmt.pix.pixelformat = formats[0].fourcc;
13118b57a21aSLaurent Pinchart fmt = find_format(f->fmt.pix.pixelformat);
131246fb9995SMauro Carvalho Chehab }
131346fb9995SMauro Carvalho Chehab if (!(fmt->types & MEM2MEM_OUTPUT)) {
131446fb9995SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev,
131546fb9995SMauro Carvalho Chehab "Fourcc format (0x%08x) invalid.\n",
131646fb9995SMauro Carvalho Chehab f->fmt.pix.pixelformat);
131746fb9995SMauro Carvalho Chehab return -EINVAL;
131846fb9995SMauro Carvalho Chehab }
131946fb9995SMauro Carvalho Chehab
132046fb9995SMauro Carvalho Chehab if (!f->fmt.pix.colorspace)
132146fb9995SMauro Carvalho Chehab f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
132246fb9995SMauro Carvalho Chehab
132346fb9995SMauro Carvalho Chehab return pxp_try_fmt(f, fmt);
132446fb9995SMauro Carvalho Chehab }
132546fb9995SMauro Carvalho Chehab
pxp_s_fmt(struct pxp_ctx * ctx,struct v4l2_format * f)132646fb9995SMauro Carvalho Chehab static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
132746fb9995SMauro Carvalho Chehab {
132846fb9995SMauro Carvalho Chehab struct pxp_q_data *q_data;
132946fb9995SMauro Carvalho Chehab struct vb2_queue *vq;
133046fb9995SMauro Carvalho Chehab
133146fb9995SMauro Carvalho Chehab vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
133246fb9995SMauro Carvalho Chehab if (!vq)
133346fb9995SMauro Carvalho Chehab return -EINVAL;
133446fb9995SMauro Carvalho Chehab
133546fb9995SMauro Carvalho Chehab q_data = get_q_data(ctx, f->type);
133646fb9995SMauro Carvalho Chehab if (!q_data)
133746fb9995SMauro Carvalho Chehab return -EINVAL;
133846fb9995SMauro Carvalho Chehab
133946fb9995SMauro Carvalho Chehab if (vb2_is_busy(vq)) {
134046fb9995SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
134146fb9995SMauro Carvalho Chehab return -EBUSY;
134246fb9995SMauro Carvalho Chehab }
134346fb9995SMauro Carvalho Chehab
13448b57a21aSLaurent Pinchart q_data->fmt = find_format(f->fmt.pix.pixelformat);
134546fb9995SMauro Carvalho Chehab q_data->width = f->fmt.pix.width;
134646fb9995SMauro Carvalho Chehab q_data->height = f->fmt.pix.height;
134746fb9995SMauro Carvalho Chehab q_data->bytesperline = f->fmt.pix.bytesperline;
134846fb9995SMauro Carvalho Chehab q_data->sizeimage = f->fmt.pix.sizeimage;
134946fb9995SMauro Carvalho Chehab
135046fb9995SMauro Carvalho Chehab dprintk(ctx->dev,
135146fb9995SMauro Carvalho Chehab "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
135246fb9995SMauro Carvalho Chehab f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
135346fb9995SMauro Carvalho Chehab
135446fb9995SMauro Carvalho Chehab return 0;
135546fb9995SMauro Carvalho Chehab }
135646fb9995SMauro Carvalho Chehab
pxp_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)135746fb9995SMauro Carvalho Chehab static int pxp_s_fmt_vid_cap(struct file *file, void *priv,
135846fb9995SMauro Carvalho Chehab struct v4l2_format *f)
135946fb9995SMauro Carvalho Chehab {
136046fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = file2ctx(file);
136146fb9995SMauro Carvalho Chehab int ret;
136246fb9995SMauro Carvalho Chehab
136346fb9995SMauro Carvalho Chehab ret = pxp_try_fmt_vid_cap(file, priv, f);
136446fb9995SMauro Carvalho Chehab if (ret)
136546fb9995SMauro Carvalho Chehab return ret;
136646fb9995SMauro Carvalho Chehab
136746fb9995SMauro Carvalho Chehab ret = pxp_s_fmt(file2ctx(file), f);
136846fb9995SMauro Carvalho Chehab if (ret)
136946fb9995SMauro Carvalho Chehab return ret;
137046fb9995SMauro Carvalho Chehab
137146fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_DST].ycbcr_enc = f->fmt.pix.ycbcr_enc;
137246fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_DST].quant = f->fmt.pix.quantization;
137346fb9995SMauro Carvalho Chehab
137446fb9995SMauro Carvalho Chehab return 0;
137546fb9995SMauro Carvalho Chehab }
137646fb9995SMauro Carvalho Chehab
pxp_s_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)137746fb9995SMauro Carvalho Chehab static int pxp_s_fmt_vid_out(struct file *file, void *priv,
137846fb9995SMauro Carvalho Chehab struct v4l2_format *f)
137946fb9995SMauro Carvalho Chehab {
138046fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = file2ctx(file);
138146fb9995SMauro Carvalho Chehab int ret;
138246fb9995SMauro Carvalho Chehab
138346fb9995SMauro Carvalho Chehab ret = pxp_try_fmt_vid_out(file, priv, f);
138446fb9995SMauro Carvalho Chehab if (ret)
138546fb9995SMauro Carvalho Chehab return ret;
138646fb9995SMauro Carvalho Chehab
138746fb9995SMauro Carvalho Chehab ret = pxp_s_fmt(file2ctx(file), f);
138846fb9995SMauro Carvalho Chehab if (ret)
138946fb9995SMauro Carvalho Chehab return ret;
139046fb9995SMauro Carvalho Chehab
139146fb9995SMauro Carvalho Chehab ctx->colorspace = f->fmt.pix.colorspace;
139246fb9995SMauro Carvalho Chehab ctx->xfer_func = f->fmt.pix.xfer_func;
139346fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].ycbcr_enc = f->fmt.pix.ycbcr_enc;
139446fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].quant = f->fmt.pix.quantization;
139546fb9995SMauro Carvalho Chehab
139646fb9995SMauro Carvalho Chehab pxp_fixup_colorimetry_cap(ctx, ctx->q_data[V4L2_M2M_DST].fmt->fourcc,
139746fb9995SMauro Carvalho Chehab &ctx->q_data[V4L2_M2M_DST].ycbcr_enc,
139846fb9995SMauro Carvalho Chehab &ctx->q_data[V4L2_M2M_DST].quant);
139946fb9995SMauro Carvalho Chehab
140046fb9995SMauro Carvalho Chehab return 0;
140146fb9995SMauro Carvalho Chehab }
140246fb9995SMauro Carvalho Chehab
pxp_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)14038293b3eeSLaurent Pinchart static int pxp_enum_framesizes(struct file *file, void *fh,
14048293b3eeSLaurent Pinchart struct v4l2_frmsizeenum *fsize)
14058293b3eeSLaurent Pinchart {
14068293b3eeSLaurent Pinchart if (fsize->index > 0)
14078293b3eeSLaurent Pinchart return -EINVAL;
14088293b3eeSLaurent Pinchart
14098293b3eeSLaurent Pinchart if (!find_format(fsize->pixel_format))
14108293b3eeSLaurent Pinchart return -EINVAL;
14118293b3eeSLaurent Pinchart
14128293b3eeSLaurent Pinchart fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
14138293b3eeSLaurent Pinchart fsize->stepwise.min_width = MIN_W;
14148293b3eeSLaurent Pinchart fsize->stepwise.max_width = MAX_W;
14158293b3eeSLaurent Pinchart fsize->stepwise.step_width = 1 << ALIGN_W;
14168293b3eeSLaurent Pinchart fsize->stepwise.min_height = MIN_H;
14178293b3eeSLaurent Pinchart fsize->stepwise.max_height = MAX_H;
14188293b3eeSLaurent Pinchart fsize->stepwise.step_height = 1 << ALIGN_H;
14198293b3eeSLaurent Pinchart
14208293b3eeSLaurent Pinchart return 0;
14218293b3eeSLaurent Pinchart }
14228293b3eeSLaurent Pinchart
pxp_degrees_to_rot_mode(u32 degrees)142346fb9995SMauro Carvalho Chehab static u8 pxp_degrees_to_rot_mode(u32 degrees)
142446fb9995SMauro Carvalho Chehab {
142546fb9995SMauro Carvalho Chehab switch (degrees) {
142646fb9995SMauro Carvalho Chehab case 90:
142746fb9995SMauro Carvalho Chehab return BV_PXP_CTRL_ROTATE0__ROT_90;
142846fb9995SMauro Carvalho Chehab case 180:
142946fb9995SMauro Carvalho Chehab return BV_PXP_CTRL_ROTATE0__ROT_180;
143046fb9995SMauro Carvalho Chehab case 270:
143146fb9995SMauro Carvalho Chehab return BV_PXP_CTRL_ROTATE0__ROT_270;
143246fb9995SMauro Carvalho Chehab case 0:
143346fb9995SMauro Carvalho Chehab default:
143446fb9995SMauro Carvalho Chehab return BV_PXP_CTRL_ROTATE0__ROT_0;
143546fb9995SMauro Carvalho Chehab }
143646fb9995SMauro Carvalho Chehab }
143746fb9995SMauro Carvalho Chehab
pxp_s_ctrl(struct v4l2_ctrl * ctrl)143846fb9995SMauro Carvalho Chehab static int pxp_s_ctrl(struct v4l2_ctrl *ctrl)
143946fb9995SMauro Carvalho Chehab {
144046fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx =
144146fb9995SMauro Carvalho Chehab container_of(ctrl->handler, struct pxp_ctx, hdl);
144246fb9995SMauro Carvalho Chehab
144346fb9995SMauro Carvalho Chehab switch (ctrl->id) {
144446fb9995SMauro Carvalho Chehab case V4L2_CID_HFLIP:
144546fb9995SMauro Carvalho Chehab if (ctrl->val)
144646fb9995SMauro Carvalho Chehab ctx->mode |= MEM2MEM_HFLIP;
144746fb9995SMauro Carvalho Chehab else
144846fb9995SMauro Carvalho Chehab ctx->mode &= ~MEM2MEM_HFLIP;
144946fb9995SMauro Carvalho Chehab break;
145046fb9995SMauro Carvalho Chehab
145146fb9995SMauro Carvalho Chehab case V4L2_CID_VFLIP:
145246fb9995SMauro Carvalho Chehab if (ctrl->val)
145346fb9995SMauro Carvalho Chehab ctx->mode |= MEM2MEM_VFLIP;
145446fb9995SMauro Carvalho Chehab else
145546fb9995SMauro Carvalho Chehab ctx->mode &= ~MEM2MEM_VFLIP;
145646fb9995SMauro Carvalho Chehab break;
145746fb9995SMauro Carvalho Chehab
145846fb9995SMauro Carvalho Chehab case V4L2_CID_ROTATE:
145946fb9995SMauro Carvalho Chehab ctx->rotation = pxp_degrees_to_rot_mode(ctrl->val);
146046fb9995SMauro Carvalho Chehab break;
146146fb9995SMauro Carvalho Chehab
146246fb9995SMauro Carvalho Chehab case V4L2_CID_ALPHA_COMPONENT:
146346fb9995SMauro Carvalho Chehab ctx->alpha_component = ctrl->val;
146446fb9995SMauro Carvalho Chehab break;
146546fb9995SMauro Carvalho Chehab
146646fb9995SMauro Carvalho Chehab default:
146746fb9995SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
146846fb9995SMauro Carvalho Chehab return -EINVAL;
146946fb9995SMauro Carvalho Chehab }
147046fb9995SMauro Carvalho Chehab
147146fb9995SMauro Carvalho Chehab return 0;
147246fb9995SMauro Carvalho Chehab }
147346fb9995SMauro Carvalho Chehab
147446fb9995SMauro Carvalho Chehab static const struct v4l2_ctrl_ops pxp_ctrl_ops = {
147546fb9995SMauro Carvalho Chehab .s_ctrl = pxp_s_ctrl,
147646fb9995SMauro Carvalho Chehab };
147746fb9995SMauro Carvalho Chehab
147846fb9995SMauro Carvalho Chehab static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
147946fb9995SMauro Carvalho Chehab .vidioc_querycap = pxp_querycap,
148046fb9995SMauro Carvalho Chehab
148146fb9995SMauro Carvalho Chehab .vidioc_enum_fmt_vid_cap = pxp_enum_fmt_vid_cap,
148246fb9995SMauro Carvalho Chehab .vidioc_g_fmt_vid_cap = pxp_g_fmt_vid_cap,
148346fb9995SMauro Carvalho Chehab .vidioc_try_fmt_vid_cap = pxp_try_fmt_vid_cap,
148446fb9995SMauro Carvalho Chehab .vidioc_s_fmt_vid_cap = pxp_s_fmt_vid_cap,
148546fb9995SMauro Carvalho Chehab
148646fb9995SMauro Carvalho Chehab .vidioc_enum_fmt_vid_out = pxp_enum_fmt_vid_out,
148746fb9995SMauro Carvalho Chehab .vidioc_g_fmt_vid_out = pxp_g_fmt_vid_out,
148846fb9995SMauro Carvalho Chehab .vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out,
148946fb9995SMauro Carvalho Chehab .vidioc_s_fmt_vid_out = pxp_s_fmt_vid_out,
149046fb9995SMauro Carvalho Chehab
14918293b3eeSLaurent Pinchart .vidioc_enum_framesizes = pxp_enum_framesizes,
14928293b3eeSLaurent Pinchart
149346fb9995SMauro Carvalho Chehab .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
149446fb9995SMauro Carvalho Chehab .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
149546fb9995SMauro Carvalho Chehab .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
149646fb9995SMauro Carvalho Chehab .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
149746fb9995SMauro Carvalho Chehab .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
149846fb9995SMauro Carvalho Chehab .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
149946fb9995SMauro Carvalho Chehab .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
150046fb9995SMauro Carvalho Chehab
150146fb9995SMauro Carvalho Chehab .vidioc_streamon = v4l2_m2m_ioctl_streamon,
150246fb9995SMauro Carvalho Chehab .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
150346fb9995SMauro Carvalho Chehab
150446fb9995SMauro Carvalho Chehab .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
150546fb9995SMauro Carvalho Chehab .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
150646fb9995SMauro Carvalho Chehab };
150746fb9995SMauro Carvalho Chehab
150846fb9995SMauro Carvalho Chehab /*
150946fb9995SMauro Carvalho Chehab * Queue operations
151046fb9995SMauro Carvalho Chehab */
pxp_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])151146fb9995SMauro Carvalho Chehab static int pxp_queue_setup(struct vb2_queue *vq,
151246fb9995SMauro Carvalho Chehab unsigned int *nbuffers, unsigned int *nplanes,
151346fb9995SMauro Carvalho Chehab unsigned int sizes[], struct device *alloc_devs[])
151446fb9995SMauro Carvalho Chehab {
151546fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = vb2_get_drv_priv(vq);
151646fb9995SMauro Carvalho Chehab struct pxp_q_data *q_data;
151746fb9995SMauro Carvalho Chehab unsigned int size, count = *nbuffers;
151846fb9995SMauro Carvalho Chehab
151946fb9995SMauro Carvalho Chehab q_data = get_q_data(ctx, vq->type);
152046fb9995SMauro Carvalho Chehab
152146fb9995SMauro Carvalho Chehab size = q_data->sizeimage;
152246fb9995SMauro Carvalho Chehab
152346fb9995SMauro Carvalho Chehab *nbuffers = count;
152446fb9995SMauro Carvalho Chehab
152546fb9995SMauro Carvalho Chehab if (*nplanes)
152646fb9995SMauro Carvalho Chehab return sizes[0] < size ? -EINVAL : 0;
152746fb9995SMauro Carvalho Chehab
152846fb9995SMauro Carvalho Chehab *nplanes = 1;
152946fb9995SMauro Carvalho Chehab sizes[0] = size;
153046fb9995SMauro Carvalho Chehab
153146fb9995SMauro Carvalho Chehab dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
153246fb9995SMauro Carvalho Chehab
153346fb9995SMauro Carvalho Chehab return 0;
153446fb9995SMauro Carvalho Chehab }
153546fb9995SMauro Carvalho Chehab
pxp_buf_prepare(struct vb2_buffer * vb)153646fb9995SMauro Carvalho Chehab static int pxp_buf_prepare(struct vb2_buffer *vb)
153746fb9995SMauro Carvalho Chehab {
153846fb9995SMauro Carvalho Chehab struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
153946fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
154046fb9995SMauro Carvalho Chehab struct pxp_dev *dev = ctx->dev;
154146fb9995SMauro Carvalho Chehab struct pxp_q_data *q_data;
154246fb9995SMauro Carvalho Chehab
154346fb9995SMauro Carvalho Chehab dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
154446fb9995SMauro Carvalho Chehab
154546fb9995SMauro Carvalho Chehab q_data = get_q_data(ctx, vb->vb2_queue->type);
154646fb9995SMauro Carvalho Chehab if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
154746fb9995SMauro Carvalho Chehab if (vbuf->field == V4L2_FIELD_ANY)
154846fb9995SMauro Carvalho Chehab vbuf->field = V4L2_FIELD_NONE;
154946fb9995SMauro Carvalho Chehab if (vbuf->field != V4L2_FIELD_NONE) {
155046fb9995SMauro Carvalho Chehab dprintk(dev, "%s field isn't supported\n", __func__);
155146fb9995SMauro Carvalho Chehab return -EINVAL;
155246fb9995SMauro Carvalho Chehab }
155346fb9995SMauro Carvalho Chehab }
155446fb9995SMauro Carvalho Chehab
155546fb9995SMauro Carvalho Chehab if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
155646fb9995SMauro Carvalho Chehab dprintk(dev, "%s data will not fit into plane (%lu < %lu)\n",
155746fb9995SMauro Carvalho Chehab __func__, vb2_plane_size(vb, 0),
155846fb9995SMauro Carvalho Chehab (long)q_data->sizeimage);
155946fb9995SMauro Carvalho Chehab return -EINVAL;
156046fb9995SMauro Carvalho Chehab }
156146fb9995SMauro Carvalho Chehab
156246fb9995SMauro Carvalho Chehab vb2_set_plane_payload(vb, 0, q_data->sizeimage);
156346fb9995SMauro Carvalho Chehab
156446fb9995SMauro Carvalho Chehab return 0;
156546fb9995SMauro Carvalho Chehab }
156646fb9995SMauro Carvalho Chehab
pxp_buf_queue(struct vb2_buffer * vb)156746fb9995SMauro Carvalho Chehab static void pxp_buf_queue(struct vb2_buffer *vb)
156846fb9995SMauro Carvalho Chehab {
156946fb9995SMauro Carvalho Chehab struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
157046fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
157146fb9995SMauro Carvalho Chehab
157246fb9995SMauro Carvalho Chehab v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
157346fb9995SMauro Carvalho Chehab }
157446fb9995SMauro Carvalho Chehab
pxp_start_streaming(struct vb2_queue * q,unsigned int count)157546fb9995SMauro Carvalho Chehab static int pxp_start_streaming(struct vb2_queue *q, unsigned int count)
157646fb9995SMauro Carvalho Chehab {
157746fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = vb2_get_drv_priv(q);
157846fb9995SMauro Carvalho Chehab struct pxp_q_data *q_data = get_q_data(ctx, q->type);
157946fb9995SMauro Carvalho Chehab
158046fb9995SMauro Carvalho Chehab q_data->sequence = 0;
158146fb9995SMauro Carvalho Chehab return 0;
158246fb9995SMauro Carvalho Chehab }
158346fb9995SMauro Carvalho Chehab
pxp_stop_streaming(struct vb2_queue * q)158446fb9995SMauro Carvalho Chehab static void pxp_stop_streaming(struct vb2_queue *q)
158546fb9995SMauro Carvalho Chehab {
158646fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = vb2_get_drv_priv(q);
158746fb9995SMauro Carvalho Chehab struct vb2_v4l2_buffer *vbuf;
158846fb9995SMauro Carvalho Chehab unsigned long flags;
158946fb9995SMauro Carvalho Chehab
159046fb9995SMauro Carvalho Chehab for (;;) {
159146fb9995SMauro Carvalho Chehab if (V4L2_TYPE_IS_OUTPUT(q->type))
159246fb9995SMauro Carvalho Chehab vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
159346fb9995SMauro Carvalho Chehab else
159446fb9995SMauro Carvalho Chehab vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
159546fb9995SMauro Carvalho Chehab if (vbuf == NULL)
159646fb9995SMauro Carvalho Chehab return;
159746fb9995SMauro Carvalho Chehab spin_lock_irqsave(&ctx->dev->irqlock, flags);
159846fb9995SMauro Carvalho Chehab v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
159946fb9995SMauro Carvalho Chehab spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
160046fb9995SMauro Carvalho Chehab }
160146fb9995SMauro Carvalho Chehab }
160246fb9995SMauro Carvalho Chehab
160346fb9995SMauro Carvalho Chehab static const struct vb2_ops pxp_qops = {
160446fb9995SMauro Carvalho Chehab .queue_setup = pxp_queue_setup,
160546fb9995SMauro Carvalho Chehab .buf_prepare = pxp_buf_prepare,
160646fb9995SMauro Carvalho Chehab .buf_queue = pxp_buf_queue,
160746fb9995SMauro Carvalho Chehab .start_streaming = pxp_start_streaming,
160846fb9995SMauro Carvalho Chehab .stop_streaming = pxp_stop_streaming,
160946fb9995SMauro Carvalho Chehab .wait_prepare = vb2_ops_wait_prepare,
161046fb9995SMauro Carvalho Chehab .wait_finish = vb2_ops_wait_finish,
161146fb9995SMauro Carvalho Chehab };
161246fb9995SMauro Carvalho Chehab
queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)161346fb9995SMauro Carvalho Chehab static int queue_init(void *priv, struct vb2_queue *src_vq,
161446fb9995SMauro Carvalho Chehab struct vb2_queue *dst_vq)
161546fb9995SMauro Carvalho Chehab {
161646fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = priv;
161746fb9995SMauro Carvalho Chehab int ret;
161846fb9995SMauro Carvalho Chehab
161946fb9995SMauro Carvalho Chehab src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
162046fb9995SMauro Carvalho Chehab src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
162146fb9995SMauro Carvalho Chehab src_vq->drv_priv = ctx;
162246fb9995SMauro Carvalho Chehab src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
162346fb9995SMauro Carvalho Chehab src_vq->ops = &pxp_qops;
162446fb9995SMauro Carvalho Chehab src_vq->mem_ops = &vb2_dma_contig_memops;
162546fb9995SMauro Carvalho Chehab src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
162646fb9995SMauro Carvalho Chehab src_vq->lock = &ctx->dev->dev_mutex;
162746fb9995SMauro Carvalho Chehab src_vq->dev = ctx->dev->v4l2_dev.dev;
162846fb9995SMauro Carvalho Chehab
162946fb9995SMauro Carvalho Chehab ret = vb2_queue_init(src_vq);
163046fb9995SMauro Carvalho Chehab if (ret)
163146fb9995SMauro Carvalho Chehab return ret;
163246fb9995SMauro Carvalho Chehab
163346fb9995SMauro Carvalho Chehab dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
163446fb9995SMauro Carvalho Chehab dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
163546fb9995SMauro Carvalho Chehab dst_vq->drv_priv = ctx;
163646fb9995SMauro Carvalho Chehab dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
163746fb9995SMauro Carvalho Chehab dst_vq->ops = &pxp_qops;
163846fb9995SMauro Carvalho Chehab dst_vq->mem_ops = &vb2_dma_contig_memops;
163946fb9995SMauro Carvalho Chehab dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
164046fb9995SMauro Carvalho Chehab dst_vq->lock = &ctx->dev->dev_mutex;
164146fb9995SMauro Carvalho Chehab dst_vq->dev = ctx->dev->v4l2_dev.dev;
164246fb9995SMauro Carvalho Chehab
164346fb9995SMauro Carvalho Chehab return vb2_queue_init(dst_vq);
164446fb9995SMauro Carvalho Chehab }
164546fb9995SMauro Carvalho Chehab
164646fb9995SMauro Carvalho Chehab /*
164746fb9995SMauro Carvalho Chehab * File operations
164846fb9995SMauro Carvalho Chehab */
pxp_open(struct file * file)164946fb9995SMauro Carvalho Chehab static int pxp_open(struct file *file)
165046fb9995SMauro Carvalho Chehab {
165146fb9995SMauro Carvalho Chehab struct pxp_dev *dev = video_drvdata(file);
165246fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = NULL;
165346fb9995SMauro Carvalho Chehab struct v4l2_ctrl_handler *hdl;
165446fb9995SMauro Carvalho Chehab int rc = 0;
165546fb9995SMauro Carvalho Chehab
165646fb9995SMauro Carvalho Chehab if (mutex_lock_interruptible(&dev->dev_mutex))
165746fb9995SMauro Carvalho Chehab return -ERESTARTSYS;
165846fb9995SMauro Carvalho Chehab ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
165946fb9995SMauro Carvalho Chehab if (!ctx) {
166046fb9995SMauro Carvalho Chehab rc = -ENOMEM;
166146fb9995SMauro Carvalho Chehab goto open_unlock;
166246fb9995SMauro Carvalho Chehab }
166346fb9995SMauro Carvalho Chehab
166446fb9995SMauro Carvalho Chehab v4l2_fh_init(&ctx->fh, video_devdata(file));
166546fb9995SMauro Carvalho Chehab file->private_data = &ctx->fh;
166646fb9995SMauro Carvalho Chehab ctx->dev = dev;
166746fb9995SMauro Carvalho Chehab hdl = &ctx->hdl;
166846fb9995SMauro Carvalho Chehab v4l2_ctrl_handler_init(hdl, 4);
166946fb9995SMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
167046fb9995SMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
167146fb9995SMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
167246fb9995SMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
167346fb9995SMauro Carvalho Chehab 0, 255, 1, 255);
167446fb9995SMauro Carvalho Chehab if (hdl->error) {
167546fb9995SMauro Carvalho Chehab rc = hdl->error;
167646fb9995SMauro Carvalho Chehab v4l2_ctrl_handler_free(hdl);
167746fb9995SMauro Carvalho Chehab kfree(ctx);
167846fb9995SMauro Carvalho Chehab goto open_unlock;
167946fb9995SMauro Carvalho Chehab }
168046fb9995SMauro Carvalho Chehab ctx->fh.ctrl_handler = hdl;
168146fb9995SMauro Carvalho Chehab v4l2_ctrl_handler_setup(hdl);
168246fb9995SMauro Carvalho Chehab
168346fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
168446fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].width = 640;
168546fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].height = 480;
168646fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].bytesperline =
168746fb9995SMauro Carvalho Chehab pxp_bytesperline(&formats[0], 640);
168846fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_SRC].sizeimage =
168946fb9995SMauro Carvalho Chehab pxp_sizeimage(&formats[0], 640, 480);
169046fb9995SMauro Carvalho Chehab ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
169146fb9995SMauro Carvalho Chehab ctx->colorspace = V4L2_COLORSPACE_REC709;
169246fb9995SMauro Carvalho Chehab
169346fb9995SMauro Carvalho Chehab ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
169446fb9995SMauro Carvalho Chehab
169546fb9995SMauro Carvalho Chehab if (IS_ERR(ctx->fh.m2m_ctx)) {
169646fb9995SMauro Carvalho Chehab rc = PTR_ERR(ctx->fh.m2m_ctx);
169746fb9995SMauro Carvalho Chehab
169846fb9995SMauro Carvalho Chehab v4l2_ctrl_handler_free(hdl);
169946fb9995SMauro Carvalho Chehab v4l2_fh_exit(&ctx->fh);
170046fb9995SMauro Carvalho Chehab kfree(ctx);
170146fb9995SMauro Carvalho Chehab goto open_unlock;
170246fb9995SMauro Carvalho Chehab }
170346fb9995SMauro Carvalho Chehab
170446fb9995SMauro Carvalho Chehab v4l2_fh_add(&ctx->fh);
170546fb9995SMauro Carvalho Chehab atomic_inc(&dev->num_inst);
170646fb9995SMauro Carvalho Chehab
170746fb9995SMauro Carvalho Chehab dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
170846fb9995SMauro Carvalho Chehab ctx, ctx->fh.m2m_ctx);
170946fb9995SMauro Carvalho Chehab
171046fb9995SMauro Carvalho Chehab open_unlock:
171146fb9995SMauro Carvalho Chehab mutex_unlock(&dev->dev_mutex);
171246fb9995SMauro Carvalho Chehab return rc;
171346fb9995SMauro Carvalho Chehab }
171446fb9995SMauro Carvalho Chehab
pxp_release(struct file * file)171546fb9995SMauro Carvalho Chehab static int pxp_release(struct file *file)
171646fb9995SMauro Carvalho Chehab {
171746fb9995SMauro Carvalho Chehab struct pxp_dev *dev = video_drvdata(file);
171846fb9995SMauro Carvalho Chehab struct pxp_ctx *ctx = file2ctx(file);
171946fb9995SMauro Carvalho Chehab
172046fb9995SMauro Carvalho Chehab dprintk(dev, "Releasing instance %p\n", ctx);
172146fb9995SMauro Carvalho Chehab
172246fb9995SMauro Carvalho Chehab v4l2_fh_del(&ctx->fh);
172346fb9995SMauro Carvalho Chehab v4l2_fh_exit(&ctx->fh);
172446fb9995SMauro Carvalho Chehab v4l2_ctrl_handler_free(&ctx->hdl);
172546fb9995SMauro Carvalho Chehab mutex_lock(&dev->dev_mutex);
172646fb9995SMauro Carvalho Chehab v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
172746fb9995SMauro Carvalho Chehab mutex_unlock(&dev->dev_mutex);
172846fb9995SMauro Carvalho Chehab kfree(ctx);
172946fb9995SMauro Carvalho Chehab
173046fb9995SMauro Carvalho Chehab atomic_dec(&dev->num_inst);
173146fb9995SMauro Carvalho Chehab
173246fb9995SMauro Carvalho Chehab return 0;
173346fb9995SMauro Carvalho Chehab }
173446fb9995SMauro Carvalho Chehab
173546fb9995SMauro Carvalho Chehab static const struct v4l2_file_operations pxp_fops = {
173646fb9995SMauro Carvalho Chehab .owner = THIS_MODULE,
173746fb9995SMauro Carvalho Chehab .open = pxp_open,
173846fb9995SMauro Carvalho Chehab .release = pxp_release,
173946fb9995SMauro Carvalho Chehab .poll = v4l2_m2m_fop_poll,
174046fb9995SMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2,
174146fb9995SMauro Carvalho Chehab .mmap = v4l2_m2m_fop_mmap,
174246fb9995SMauro Carvalho Chehab };
174346fb9995SMauro Carvalho Chehab
174446fb9995SMauro Carvalho Chehab static const struct video_device pxp_videodev = {
174546fb9995SMauro Carvalho Chehab .name = MEM2MEM_NAME,
174646fb9995SMauro Carvalho Chehab .vfl_dir = VFL_DIR_M2M,
174746fb9995SMauro Carvalho Chehab .fops = &pxp_fops,
174846fb9995SMauro Carvalho Chehab .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
174946fb9995SMauro Carvalho Chehab .ioctl_ops = &pxp_ioctl_ops,
175046fb9995SMauro Carvalho Chehab .minor = -1,
175146fb9995SMauro Carvalho Chehab .release = video_device_release_empty,
175246fb9995SMauro Carvalho Chehab };
175346fb9995SMauro Carvalho Chehab
175446fb9995SMauro Carvalho Chehab static const struct v4l2_m2m_ops m2m_ops = {
175546fb9995SMauro Carvalho Chehab .device_run = pxp_device_run,
175646fb9995SMauro Carvalho Chehab .job_ready = pxp_job_ready,
175746fb9995SMauro Carvalho Chehab .job_abort = pxp_job_abort,
175846fb9995SMauro Carvalho Chehab };
175946fb9995SMauro Carvalho Chehab
pxp_soft_reset(struct pxp_dev * dev)176046fb9995SMauro Carvalho Chehab static int pxp_soft_reset(struct pxp_dev *dev)
176146fb9995SMauro Carvalho Chehab {
176246fb9995SMauro Carvalho Chehab int ret;
176346fb9995SMauro Carvalho Chehab u32 val;
176446fb9995SMauro Carvalho Chehab
176536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
176636e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
176746fb9995SMauro Carvalho Chehab
176836e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
176946fb9995SMauro Carvalho Chehab
17704e5bd3fdSMichael Tretter ret = regmap_read_poll_timeout(dev->regmap, HW_PXP_CTRL, val,
177146fb9995SMauro Carvalho Chehab val & BM_PXP_CTRL_CLKGATE, 0, 100);
177246fb9995SMauro Carvalho Chehab if (ret < 0)
177346fb9995SMauro Carvalho Chehab return ret;
177446fb9995SMauro Carvalho Chehab
177536e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
177636e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
177746fb9995SMauro Carvalho Chehab
177846fb9995SMauro Carvalho Chehab return 0;
177946fb9995SMauro Carvalho Chehab }
178046fb9995SMauro Carvalho Chehab
pxp_probe(struct platform_device * pdev)178146fb9995SMauro Carvalho Chehab static int pxp_probe(struct platform_device *pdev)
178246fb9995SMauro Carvalho Chehab {
178346fb9995SMauro Carvalho Chehab struct pxp_dev *dev;
178446fb9995SMauro Carvalho Chehab struct video_device *vfd;
1785a4a69d13SMichael Tretter u32 hw_version;
178646fb9995SMauro Carvalho Chehab int irq;
178746fb9995SMauro Carvalho Chehab int ret;
17884e5bd3fdSMichael Tretter void __iomem *mmio;
178946fb9995SMauro Carvalho Chehab
179046fb9995SMauro Carvalho Chehab dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
179146fb9995SMauro Carvalho Chehab if (!dev)
179246fb9995SMauro Carvalho Chehab return -ENOMEM;
179346fb9995SMauro Carvalho Chehab
179476985f4eSMichael Tretter dev->pdata = of_device_get_match_data(&pdev->dev);
179576985f4eSMichael Tretter
179646fb9995SMauro Carvalho Chehab dev->clk = devm_clk_get(&pdev->dev, "axi");
179746fb9995SMauro Carvalho Chehab if (IS_ERR(dev->clk)) {
179846fb9995SMauro Carvalho Chehab ret = PTR_ERR(dev->clk);
179946fb9995SMauro Carvalho Chehab dev_err(&pdev->dev, "Failed to get clk: %d\n", ret);
180046fb9995SMauro Carvalho Chehab return ret;
180146fb9995SMauro Carvalho Chehab }
180246fb9995SMauro Carvalho Chehab
18034e5bd3fdSMichael Tretter mmio = devm_platform_ioremap_resource(pdev, 0);
18044e5bd3fdSMichael Tretter if (IS_ERR(mmio))
18054e5bd3fdSMichael Tretter return PTR_ERR(mmio);
18064e5bd3fdSMichael Tretter dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio,
18074e5bd3fdSMichael Tretter &pxp_regmap_config);
1808*57e9ce68SHarshit Mogalapalli if (IS_ERR(dev->regmap))
1809*57e9ce68SHarshit Mogalapalli return dev_err_probe(&pdev->dev, PTR_ERR(dev->regmap),
1810*57e9ce68SHarshit Mogalapalli "Failed to init regmap\n");
181146fb9995SMauro Carvalho Chehab
181246fb9995SMauro Carvalho Chehab irq = platform_get_irq(pdev, 0);
181346fb9995SMauro Carvalho Chehab if (irq < 0)
181446fb9995SMauro Carvalho Chehab return irq;
181546fb9995SMauro Carvalho Chehab
181646fb9995SMauro Carvalho Chehab spin_lock_init(&dev->irqlock);
181746fb9995SMauro Carvalho Chehab
18184d25e977SLaurent Pinchart ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0,
18194d25e977SLaurent Pinchart dev_name(&pdev->dev), dev);
182046fb9995SMauro Carvalho Chehab if (ret < 0) {
182146fb9995SMauro Carvalho Chehab dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
182246fb9995SMauro Carvalho Chehab return ret;
182346fb9995SMauro Carvalho Chehab }
182446fb9995SMauro Carvalho Chehab
182546fb9995SMauro Carvalho Chehab ret = clk_prepare_enable(dev->clk);
182646fb9995SMauro Carvalho Chehab if (ret < 0)
182746fb9995SMauro Carvalho Chehab return ret;
182846fb9995SMauro Carvalho Chehab
182946fb9995SMauro Carvalho Chehab ret = pxp_soft_reset(dev);
183046fb9995SMauro Carvalho Chehab if (ret < 0) {
183146fb9995SMauro Carvalho Chehab dev_err(&pdev->dev, "PXP reset timeout: %d\n", ret);
183246fb9995SMauro Carvalho Chehab goto err_clk;
183346fb9995SMauro Carvalho Chehab }
183446fb9995SMauro Carvalho Chehab
183536e5c362SLaurent Pinchart hw_version = pxp_read(dev, HW_PXP_VERSION);
1836a4a69d13SMichael Tretter dev_dbg(&pdev->dev, "PXP Version %u.%u\n",
1837a4a69d13SMichael Tretter PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version));
1838a4a69d13SMichael Tretter
183946fb9995SMauro Carvalho Chehab ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
184046fb9995SMauro Carvalho Chehab if (ret)
184146fb9995SMauro Carvalho Chehab goto err_clk;
184246fb9995SMauro Carvalho Chehab
184346fb9995SMauro Carvalho Chehab atomic_set(&dev->num_inst, 0);
184446fb9995SMauro Carvalho Chehab mutex_init(&dev->dev_mutex);
184546fb9995SMauro Carvalho Chehab
184646fb9995SMauro Carvalho Chehab dev->vfd = pxp_videodev;
184746fb9995SMauro Carvalho Chehab vfd = &dev->vfd;
184846fb9995SMauro Carvalho Chehab vfd->lock = &dev->dev_mutex;
184946fb9995SMauro Carvalho Chehab vfd->v4l2_dev = &dev->v4l2_dev;
185046fb9995SMauro Carvalho Chehab
185146fb9995SMauro Carvalho Chehab video_set_drvdata(vfd, dev);
185246fb9995SMauro Carvalho Chehab snprintf(vfd->name, sizeof(vfd->name), "%s", pxp_videodev.name);
185346fb9995SMauro Carvalho Chehab v4l2_info(&dev->v4l2_dev,
185446fb9995SMauro Carvalho Chehab "Device registered as /dev/video%d\n", vfd->num);
185546fb9995SMauro Carvalho Chehab
185646fb9995SMauro Carvalho Chehab platform_set_drvdata(pdev, dev);
185746fb9995SMauro Carvalho Chehab
185846fb9995SMauro Carvalho Chehab dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
185946fb9995SMauro Carvalho Chehab if (IS_ERR(dev->m2m_dev)) {
186046fb9995SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
186146fb9995SMauro Carvalho Chehab ret = PTR_ERR(dev->m2m_dev);
186246fb9995SMauro Carvalho Chehab goto err_v4l2;
186346fb9995SMauro Carvalho Chehab }
186446fb9995SMauro Carvalho Chehab
186546fb9995SMauro Carvalho Chehab ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
186646fb9995SMauro Carvalho Chehab if (ret) {
186746fb9995SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
186846fb9995SMauro Carvalho Chehab goto err_m2m;
186946fb9995SMauro Carvalho Chehab }
187046fb9995SMauro Carvalho Chehab
1871ff89b9b4SLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER
1872ff89b9b4SLaurent Pinchart dev->mdev.dev = &pdev->dev;
1873ff89b9b4SLaurent Pinchart strscpy(dev->mdev.model, MEM2MEM_NAME, sizeof(dev->mdev.model));
1874ff89b9b4SLaurent Pinchart media_device_init(&dev->mdev);
1875ff89b9b4SLaurent Pinchart dev->v4l2_dev.mdev = &dev->mdev;
1876ff89b9b4SLaurent Pinchart
1877ff89b9b4SLaurent Pinchart ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
1878ff89b9b4SLaurent Pinchart MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
1879ff89b9b4SLaurent Pinchart if (ret) {
1880ff89b9b4SLaurent Pinchart dev_err(&pdev->dev, "Failed to initialize media device\n");
1881ff89b9b4SLaurent Pinchart goto err_vfd;
1882ff89b9b4SLaurent Pinchart }
1883ff89b9b4SLaurent Pinchart
1884ff89b9b4SLaurent Pinchart ret = media_device_register(&dev->mdev);
1885ff89b9b4SLaurent Pinchart if (ret) {
1886ff89b9b4SLaurent Pinchart dev_err(&pdev->dev, "Failed to register media device\n");
1887ff89b9b4SLaurent Pinchart goto err_m2m_mc;
1888ff89b9b4SLaurent Pinchart }
1889ff89b9b4SLaurent Pinchart #endif
1890ff89b9b4SLaurent Pinchart
189146fb9995SMauro Carvalho Chehab return 0;
189246fb9995SMauro Carvalho Chehab
1893ff89b9b4SLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER
1894ff89b9b4SLaurent Pinchart err_m2m_mc:
1895ff89b9b4SLaurent Pinchart v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1896ff89b9b4SLaurent Pinchart err_vfd:
1897ff89b9b4SLaurent Pinchart video_unregister_device(vfd);
1898ff89b9b4SLaurent Pinchart #endif
189946fb9995SMauro Carvalho Chehab err_m2m:
190046fb9995SMauro Carvalho Chehab v4l2_m2m_release(dev->m2m_dev);
190146fb9995SMauro Carvalho Chehab err_v4l2:
190246fb9995SMauro Carvalho Chehab v4l2_device_unregister(&dev->v4l2_dev);
190346fb9995SMauro Carvalho Chehab err_clk:
190446fb9995SMauro Carvalho Chehab clk_disable_unprepare(dev->clk);
190546fb9995SMauro Carvalho Chehab
190646fb9995SMauro Carvalho Chehab return ret;
190746fb9995SMauro Carvalho Chehab }
190846fb9995SMauro Carvalho Chehab
pxp_remove(struct platform_device * pdev)19097505faa0SUwe Kleine-König static void pxp_remove(struct platform_device *pdev)
191046fb9995SMauro Carvalho Chehab {
191146fb9995SMauro Carvalho Chehab struct pxp_dev *dev = platform_get_drvdata(pdev);
191246fb9995SMauro Carvalho Chehab
191336e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_CLKGATE);
191436e5c362SLaurent Pinchart pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
191546fb9995SMauro Carvalho Chehab
191646fb9995SMauro Carvalho Chehab clk_disable_unprepare(dev->clk);
191746fb9995SMauro Carvalho Chehab
191846fb9995SMauro Carvalho Chehab v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
1919ff89b9b4SLaurent Pinchart
1920ff89b9b4SLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER
1921ff89b9b4SLaurent Pinchart media_device_unregister(&dev->mdev);
1922ff89b9b4SLaurent Pinchart v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1923ff89b9b4SLaurent Pinchart #endif
192446fb9995SMauro Carvalho Chehab video_unregister_device(&dev->vfd);
192546fb9995SMauro Carvalho Chehab v4l2_m2m_release(dev->m2m_dev);
192646fb9995SMauro Carvalho Chehab v4l2_device_unregister(&dev->v4l2_dev);
192746fb9995SMauro Carvalho Chehab }
192846fb9995SMauro Carvalho Chehab
192976985f4eSMichael Tretter static const struct pxp_pdata pxp_imx6ull_pdata = {
193076985f4eSMichael Tretter .data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0,
193176985f4eSMichael Tretter };
193276985f4eSMichael Tretter
1933cbcd2373SMichael Tretter static const struct pxp_pdata pxp_imx7d_pdata = {
1934cbcd2373SMichael Tretter .data_path_ctrl0 = pxp_imx7d_data_path_ctrl0,
1935cbcd2373SMichael Tretter };
1936cbcd2373SMichael Tretter
193746fb9995SMauro Carvalho Chehab static const struct of_device_id pxp_dt_ids[] = {
193876985f4eSMichael Tretter { .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata },
1939cbcd2373SMichael Tretter { .compatible = "fsl,imx7d-pxp", .data = &pxp_imx7d_pdata },
194046fb9995SMauro Carvalho Chehab { },
194146fb9995SMauro Carvalho Chehab };
194246fb9995SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, pxp_dt_ids);
194346fb9995SMauro Carvalho Chehab
194446fb9995SMauro Carvalho Chehab static struct platform_driver pxp_driver = {
194546fb9995SMauro Carvalho Chehab .probe = pxp_probe,
19467505faa0SUwe Kleine-König .remove_new = pxp_remove,
194746fb9995SMauro Carvalho Chehab .driver = {
194846fb9995SMauro Carvalho Chehab .name = MEM2MEM_NAME,
194946fb9995SMauro Carvalho Chehab .of_match_table = pxp_dt_ids,
195046fb9995SMauro Carvalho Chehab },
195146fb9995SMauro Carvalho Chehab };
195246fb9995SMauro Carvalho Chehab
195346fb9995SMauro Carvalho Chehab module_platform_driver(pxp_driver);
195446fb9995SMauro Carvalho Chehab
195546fb9995SMauro Carvalho Chehab MODULE_DESCRIPTION("i.MX PXP mem2mem scaler/CSC/rotator");
195646fb9995SMauro Carvalho Chehab MODULE_AUTHOR("Philipp Zabel <kernel@pengutronix.de>");
195746fb9995SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1958