162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * i.MX Pixel Pipeline (PXP) mem-to-mem scaler/CSC/rotator driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2018 Pengutronix, Philipp Zabel
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * based on vim2m
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
1062306a36Sopenharmony_ci * Pawel Osciak, <pawel@osciak.com>
1162306a36Sopenharmony_ci * Marek Szyprowski, <m.szyprowski@samsung.com>
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/bitfield.h>
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/io.h>
1962306a36Sopenharmony_ci#include <linux/iopoll.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include <linux/platform_device.h>
2362306a36Sopenharmony_ci#include <linux/regmap.h>
2462306a36Sopenharmony_ci#include <linux/sched.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <media/media-device.h>
2862306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
2962306a36Sopenharmony_ci#include <media/v4l2-device.h>
3062306a36Sopenharmony_ci#include <media/v4l2-event.h>
3162306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
3262306a36Sopenharmony_ci#include <media/v4l2-mem2mem.h>
3362306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "imx-pxp.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic unsigned int debug;
3862306a36Sopenharmony_cimodule_param(debug, uint, 0644);
3962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "activates debug info");
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define MIN_W 8
4262306a36Sopenharmony_ci#define MIN_H 8
4362306a36Sopenharmony_ci#define MAX_W 4096
4462306a36Sopenharmony_ci#define MAX_H 4096
4562306a36Sopenharmony_ci#define ALIGN_W 3 /* 8x8 pixel blocks */
4662306a36Sopenharmony_ci#define ALIGN_H 3
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Flags that indicate a format can be used for capture/output */
4962306a36Sopenharmony_ci#define MEM2MEM_CAPTURE	(1 << 0)
5062306a36Sopenharmony_ci#define MEM2MEM_OUTPUT	(1 << 1)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define MEM2MEM_NAME		"pxp"
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* Flags that indicate processing mode */
5562306a36Sopenharmony_ci#define MEM2MEM_HFLIP	(1 << 0)
5662306a36Sopenharmony_ci#define MEM2MEM_VFLIP	(1 << 1)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define PXP_VERSION_MAJOR(version) \
5962306a36Sopenharmony_ci	FIELD_GET(BM_PXP_VERSION_MAJOR, version)
6062306a36Sopenharmony_ci#define PXP_VERSION_MINOR(version) \
6162306a36Sopenharmony_ci	FIELD_GET(BM_PXP_VERSION_MINOR, version)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define dprintk(dev, fmt, arg...) \
6462306a36Sopenharmony_ci	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct pxp_fmt {
6762306a36Sopenharmony_ci	u32	fourcc;
6862306a36Sopenharmony_ci	int	depth;
6962306a36Sopenharmony_ci	/* Types the format can be used for */
7062306a36Sopenharmony_ci	u32	types;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic struct pxp_fmt formats[] = {
7462306a36Sopenharmony_ci	{
7562306a36Sopenharmony_ci		.fourcc	= V4L2_PIX_FMT_XBGR32,
7662306a36Sopenharmony_ci		.depth	= 32,
7762306a36Sopenharmony_ci		/* Both capture and output format */
7862306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
7962306a36Sopenharmony_ci	}, {
8062306a36Sopenharmony_ci		.fourcc	= V4L2_PIX_FMT_ABGR32,
8162306a36Sopenharmony_ci		.depth	= 32,
8262306a36Sopenharmony_ci		/* Capture-only format */
8362306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE,
8462306a36Sopenharmony_ci	}, {
8562306a36Sopenharmony_ci		.fourcc	= V4L2_PIX_FMT_BGR24,
8662306a36Sopenharmony_ci		.depth	= 24,
8762306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE,
8862306a36Sopenharmony_ci	}, {
8962306a36Sopenharmony_ci		.fourcc	= V4L2_PIX_FMT_RGB565,
9062306a36Sopenharmony_ci		.depth	= 16,
9162306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
9262306a36Sopenharmony_ci	}, {
9362306a36Sopenharmony_ci		.fourcc	= V4L2_PIX_FMT_RGB555,
9462306a36Sopenharmony_ci		.depth	= 16,
9562306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
9662306a36Sopenharmony_ci	}, {
9762306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_RGB444,
9862306a36Sopenharmony_ci		.depth	= 16,
9962306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
10062306a36Sopenharmony_ci	}, {
10162306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_VUYA32,
10262306a36Sopenharmony_ci		.depth	= 32,
10362306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE,
10462306a36Sopenharmony_ci	}, {
10562306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_VUYX32,
10662306a36Sopenharmony_ci		.depth	= 32,
10762306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
10862306a36Sopenharmony_ci	}, {
10962306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_UYVY,
11062306a36Sopenharmony_ci		.depth	= 16,
11162306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
11262306a36Sopenharmony_ci	}, {
11362306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_YUYV,
11462306a36Sopenharmony_ci		.depth	= 16,
11562306a36Sopenharmony_ci		/* Output-only format */
11662306a36Sopenharmony_ci		.types	= MEM2MEM_OUTPUT,
11762306a36Sopenharmony_ci	}, {
11862306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_VYUY,
11962306a36Sopenharmony_ci		.depth	= 16,
12062306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
12162306a36Sopenharmony_ci	}, {
12262306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_YVYU,
12362306a36Sopenharmony_ci		.depth	= 16,
12462306a36Sopenharmony_ci		.types	= MEM2MEM_OUTPUT,
12562306a36Sopenharmony_ci	}, {
12662306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_GREY,
12762306a36Sopenharmony_ci		.depth	= 8,
12862306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
12962306a36Sopenharmony_ci	}, {
13062306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_Y4,
13162306a36Sopenharmony_ci		.depth	= 4,
13262306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
13362306a36Sopenharmony_ci	}, {
13462306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_NV16,
13562306a36Sopenharmony_ci		.depth	= 16,
13662306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
13762306a36Sopenharmony_ci	}, {
13862306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_NV12,
13962306a36Sopenharmony_ci		.depth	= 12,
14062306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
14162306a36Sopenharmony_ci	}, {
14262306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_NV21,
14362306a36Sopenharmony_ci		.depth	= 12,
14462306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
14562306a36Sopenharmony_ci	}, {
14662306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_NV61,
14762306a36Sopenharmony_ci		.depth	= 16,
14862306a36Sopenharmony_ci		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
14962306a36Sopenharmony_ci	}, {
15062306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_YUV422P,
15162306a36Sopenharmony_ci		.depth	= 16,
15262306a36Sopenharmony_ci		.types	= MEM2MEM_OUTPUT,
15362306a36Sopenharmony_ci	}, {
15462306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_YUV420,
15562306a36Sopenharmony_ci		.depth	= 12,
15662306a36Sopenharmony_ci		.types	= MEM2MEM_OUTPUT,
15762306a36Sopenharmony_ci	},
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#define NUM_FORMATS ARRAY_SIZE(formats)
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* Per-queue, driver-specific private data */
16362306a36Sopenharmony_cistruct pxp_q_data {
16462306a36Sopenharmony_ci	unsigned int		width;
16562306a36Sopenharmony_ci	unsigned int		height;
16662306a36Sopenharmony_ci	unsigned int		bytesperline;
16762306a36Sopenharmony_ci	unsigned int		sizeimage;
16862306a36Sopenharmony_ci	unsigned int		sequence;
16962306a36Sopenharmony_ci	struct pxp_fmt		*fmt;
17062306a36Sopenharmony_ci	enum v4l2_ycbcr_encoding ycbcr_enc;
17162306a36Sopenharmony_ci	enum v4l2_quantization	quant;
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cienum {
17562306a36Sopenharmony_ci	V4L2_M2M_SRC = 0,
17662306a36Sopenharmony_ci	V4L2_M2M_DST = 1,
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic const struct regmap_config pxp_regmap_config = {
18062306a36Sopenharmony_ci	.reg_bits = 32,
18162306a36Sopenharmony_ci	.reg_stride = 4,
18262306a36Sopenharmony_ci	.val_bits = 32,
18362306a36Sopenharmony_ci	.max_register = HW_PXP_VERSION,
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic struct pxp_fmt *find_format(unsigned int pixelformat)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct pxp_fmt *fmt;
18962306a36Sopenharmony_ci	unsigned int k;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	for (k = 0; k < NUM_FORMATS; k++) {
19262306a36Sopenharmony_ci		fmt = &formats[k];
19362306a36Sopenharmony_ci		if (fmt->fourcc == pixelformat)
19462306a36Sopenharmony_ci			break;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (k == NUM_FORMATS)
19862306a36Sopenharmony_ci		return NULL;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return &formats[k];
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistruct pxp_ctx;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistruct pxp_pdata {
20662306a36Sopenharmony_ci	u32 (*data_path_ctrl0)(struct pxp_ctx *ctx);
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistruct pxp_dev {
21062306a36Sopenharmony_ci	struct v4l2_device	v4l2_dev;
21162306a36Sopenharmony_ci	struct video_device	vfd;
21262306a36Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
21362306a36Sopenharmony_ci	struct media_device	mdev;
21462306a36Sopenharmony_ci#endif
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	struct clk		*clk;
21762306a36Sopenharmony_ci	struct regmap		*regmap;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	const struct pxp_pdata	*pdata;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	atomic_t		num_inst;
22262306a36Sopenharmony_ci	struct mutex		dev_mutex;
22362306a36Sopenharmony_ci	spinlock_t		irqlock;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	struct v4l2_m2m_dev	*m2m_dev;
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistruct pxp_ctx {
22962306a36Sopenharmony_ci	struct v4l2_fh		fh;
23062306a36Sopenharmony_ci	struct pxp_dev	*dev;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	struct v4l2_ctrl_handler hdl;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Abort requested by m2m */
23562306a36Sopenharmony_ci	int			aborting;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Processing mode */
23862306a36Sopenharmony_ci	int			mode;
23962306a36Sopenharmony_ci	u8			alpha_component;
24062306a36Sopenharmony_ci	u8			rotation;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	enum v4l2_colorspace	colorspace;
24362306a36Sopenharmony_ci	enum v4l2_xfer_func	xfer_func;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* Source and destination queue data */
24662306a36Sopenharmony_ci	struct pxp_q_data   q_data[2];
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline struct pxp_ctx *file2ctx(struct file *file)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return container_of(file->private_data, struct pxp_ctx, fh);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
25562306a36Sopenharmony_ci					 enum v4l2_buf_type type)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
25862306a36Sopenharmony_ci		return &ctx->q_data[V4L2_M2M_SRC];
25962306a36Sopenharmony_ci	else
26062306a36Sopenharmony_ci		return &ctx->q_data[V4L2_M2M_DST];
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic inline u32 pxp_read(struct pxp_dev *dev, u32 reg)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	u32 value;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	regmap_read(dev->regmap, reg, &value);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return value;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	regmap_write(dev->regmap, reg, value);
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	switch (v4l2_pix_fmt) {
28062306a36Sopenharmony_ci	case V4L2_PIX_FMT_XBGR32:  return BV_PXP_PS_CTRL_FORMAT__RGB888;
28162306a36Sopenharmony_ci	case V4L2_PIX_FMT_RGB555:  return BV_PXP_PS_CTRL_FORMAT__RGB555;
28262306a36Sopenharmony_ci	case V4L2_PIX_FMT_RGB444:  return BV_PXP_PS_CTRL_FORMAT__RGB444;
28362306a36Sopenharmony_ci	case V4L2_PIX_FMT_RGB565:  return BV_PXP_PS_CTRL_FORMAT__RGB565;
28462306a36Sopenharmony_ci	case V4L2_PIX_FMT_VUYX32:  return BV_PXP_PS_CTRL_FORMAT__YUV1P444;
28562306a36Sopenharmony_ci	case V4L2_PIX_FMT_UYVY:    return BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
28662306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUYV:    return BM_PXP_PS_CTRL_WB_SWAP |
28762306a36Sopenharmony_ci					  BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
28862306a36Sopenharmony_ci	case V4L2_PIX_FMT_VYUY:    return BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
28962306a36Sopenharmony_ci	case V4L2_PIX_FMT_YVYU:    return BM_PXP_PS_CTRL_WB_SWAP |
29062306a36Sopenharmony_ci					  BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
29162306a36Sopenharmony_ci	case V4L2_PIX_FMT_GREY:    return BV_PXP_PS_CTRL_FORMAT__Y8;
29262306a36Sopenharmony_ci	default:
29362306a36Sopenharmony_ci	case V4L2_PIX_FMT_Y4:      return BV_PXP_PS_CTRL_FORMAT__Y4;
29462306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV16:    return BV_PXP_PS_CTRL_FORMAT__YUV2P422;
29562306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV12:    return BV_PXP_PS_CTRL_FORMAT__YUV2P420;
29662306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV21:    return BV_PXP_PS_CTRL_FORMAT__YVU2P420;
29762306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV61:    return BV_PXP_PS_CTRL_FORMAT__YVU2P422;
29862306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV422P: return BV_PXP_PS_CTRL_FORMAT__YUV422;
29962306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV420:  return BV_PXP_PS_CTRL_FORMAT__YUV420;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic u32 pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	switch (v4l2_pix_fmt) {
30662306a36Sopenharmony_ci	case V4L2_PIX_FMT_XBGR32:   return BV_PXP_OUT_CTRL_FORMAT__RGB888;
30762306a36Sopenharmony_ci	case V4L2_PIX_FMT_ABGR32:   return BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
30862306a36Sopenharmony_ci	case V4L2_PIX_FMT_BGR24:    return BV_PXP_OUT_CTRL_FORMAT__RGB888P;
30962306a36Sopenharmony_ci	/* Missing V4L2 pixel formats for ARGB1555 and ARGB4444 */
31062306a36Sopenharmony_ci	case V4L2_PIX_FMT_RGB555:   return BV_PXP_OUT_CTRL_FORMAT__RGB555;
31162306a36Sopenharmony_ci	case V4L2_PIX_FMT_RGB444:   return BV_PXP_OUT_CTRL_FORMAT__RGB444;
31262306a36Sopenharmony_ci	case V4L2_PIX_FMT_RGB565:   return BV_PXP_OUT_CTRL_FORMAT__RGB565;
31362306a36Sopenharmony_ci	case V4L2_PIX_FMT_VUYA32:
31462306a36Sopenharmony_ci	case V4L2_PIX_FMT_VUYX32:   return BV_PXP_OUT_CTRL_FORMAT__YUV1P444;
31562306a36Sopenharmony_ci	case V4L2_PIX_FMT_UYVY:     return BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
31662306a36Sopenharmony_ci	case V4L2_PIX_FMT_VYUY:     return BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
31762306a36Sopenharmony_ci	case V4L2_PIX_FMT_GREY:     return BV_PXP_OUT_CTRL_FORMAT__Y8;
31862306a36Sopenharmony_ci	default:
31962306a36Sopenharmony_ci	case V4L2_PIX_FMT_Y4:       return BV_PXP_OUT_CTRL_FORMAT__Y4;
32062306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV16:     return BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
32162306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV12:     return BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
32262306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV61:     return BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
32362306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV21:     return BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic bool pxp_v4l2_pix_fmt_is_yuv(u32 v4l2_pix_fmt)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	switch (v4l2_pix_fmt) {
33062306a36Sopenharmony_ci	case V4L2_PIX_FMT_VUYA32:
33162306a36Sopenharmony_ci	case V4L2_PIX_FMT_VUYX32:
33262306a36Sopenharmony_ci	case V4L2_PIX_FMT_UYVY:
33362306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUYV:
33462306a36Sopenharmony_ci	case V4L2_PIX_FMT_VYUY:
33562306a36Sopenharmony_ci	case V4L2_PIX_FMT_YVYU:
33662306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
33762306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
33862306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV61:
33962306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV21:
34062306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV420:
34162306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV422P:
34262306a36Sopenharmony_ci	case V4L2_PIX_FMT_GREY:
34362306a36Sopenharmony_ci	case V4L2_PIX_FMT_Y4:
34462306a36Sopenharmony_ci		return true;
34562306a36Sopenharmony_ci	default:
34662306a36Sopenharmony_ci		return false;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void pxp_setup_csc(struct pxp_ctx *ctx)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct pxp_dev *dev = ctx->dev;
35362306a36Sopenharmony_ci	enum v4l2_ycbcr_encoding ycbcr_enc;
35462306a36Sopenharmony_ci	enum v4l2_quantization quantization;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
35762306a36Sopenharmony_ci	    !pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
35862306a36Sopenharmony_ci		/*
35962306a36Sopenharmony_ci		 * CSC1 YUV/YCbCr to RGB conversion is implemented as follows:
36062306a36Sopenharmony_ci		 *
36162306a36Sopenharmony_ci		 * |R|   |C0 0  C1|   |Y  + Yoffset |
36262306a36Sopenharmony_ci		 * |G| = |C0 C3 C2| * |Cb + UVoffset|
36362306a36Sopenharmony_ci		 * |B|   |C0 C4 0 |   |Cr + UVoffset|
36462306a36Sopenharmony_ci		 *
36562306a36Sopenharmony_ci		 * Results are clamped to 0..255.
36662306a36Sopenharmony_ci		 *
36762306a36Sopenharmony_ci		 * BT.601 limited range:
36862306a36Sopenharmony_ci		 *
36962306a36Sopenharmony_ci		 * |R|   |1.1644  0.0000  1.5960|   |Y  - 16 |
37062306a36Sopenharmony_ci		 * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128|
37162306a36Sopenharmony_ci		 * |B|   |1.1644  2.0172  0.0000|   |Cr - 128|
37262306a36Sopenharmony_ci		 */
37362306a36Sopenharmony_ci		static const u32 csc1_coef_bt601_lim[3] = {
37462306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
37562306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x12a) |	/*  1.1641 (-0.03 %) */
37662306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
37762306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
37862306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x198) |	/*  1.5938 (-0.23 %) */
37962306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x204),	/*  2.0156 (-0.16 %) */
38062306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x730) |	/* -0.8125 (+0.04 %) */
38162306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x79c),	/* -0.3906 (+0.11 %) */
38262306a36Sopenharmony_ci		};
38362306a36Sopenharmony_ci		/*
38462306a36Sopenharmony_ci		 * BT.601 full range:
38562306a36Sopenharmony_ci		 *
38662306a36Sopenharmony_ci		 * |R|   |1.0000  0.0000  1.4020|   |Y  + 0  |
38762306a36Sopenharmony_ci		 * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128|
38862306a36Sopenharmony_ci		 * |B|   |1.0000  1.7720  0.0000|   |Cr - 128|
38962306a36Sopenharmony_ci		 */
39062306a36Sopenharmony_ci		static const u32 csc1_coef_bt601_full[3] = {
39162306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
39262306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x100) |	/*  1.0000 (+0.00 %) */
39362306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
39462306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(0),
39562306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x166) |	/*  1.3984 (-0.36 %) */
39662306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x1c5),	/*  1.7695 (-0.25 %) */
39762306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x74a) |	/* -0.7109 (+0.32 %) */
39862306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7a8),	/* -0.3438 (+0.04 %) */
39962306a36Sopenharmony_ci		};
40062306a36Sopenharmony_ci		/*
40162306a36Sopenharmony_ci		 * Rec.709 limited range:
40262306a36Sopenharmony_ci		 *
40362306a36Sopenharmony_ci		 * |R|   |1.1644  0.0000  1.7927|   |Y  - 16 |
40462306a36Sopenharmony_ci		 * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128|
40562306a36Sopenharmony_ci		 * |B|   |1.1644  2.1124  0.0000|   |Cr - 128|
40662306a36Sopenharmony_ci		 */
40762306a36Sopenharmony_ci		static const u32 csc1_coef_rec709_lim[3] = {
40862306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
40962306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x12a) |	/*  1.1641 (-0.03 %) */
41062306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
41162306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
41262306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x1ca) |	/*  1.7891 (-0.37 %) */
41362306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x21c),	/*  2.1094 (-0.30 %) */
41462306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x778) |	/* -0.5312 (+0.16 %) */
41562306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7ca),	/* -0.2109 (+0.23 %) */
41662306a36Sopenharmony_ci		};
41762306a36Sopenharmony_ci		/*
41862306a36Sopenharmony_ci		 * Rec.709 full range:
41962306a36Sopenharmony_ci		 *
42062306a36Sopenharmony_ci		 * |R|   |1.0000  0.0000  1.5748|   |Y  + 0  |
42162306a36Sopenharmony_ci		 * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128|
42262306a36Sopenharmony_ci		 * |B|   |1.0000  1.8556  0.0000|   |Cr - 128|
42362306a36Sopenharmony_ci		 */
42462306a36Sopenharmony_ci		static const u32 csc1_coef_rec709_full[3] = {
42562306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
42662306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x100) |	/*  1.0000 (+0.00 %) */
42762306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
42862306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(0),
42962306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x193) |	/*  1.5742 (-0.06 %) */
43062306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x1db),	/*  1.8555 (-0.01 %) */
43162306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x789) |	/* -0.4648 (+0.33 %) */
43262306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7d1),	/* -0.1836 (+0.37 %) */
43362306a36Sopenharmony_ci		};
43462306a36Sopenharmony_ci		/*
43562306a36Sopenharmony_ci		 * BT.2020 limited range:
43662306a36Sopenharmony_ci		 *
43762306a36Sopenharmony_ci		 * |R|   |1.1644  0.0000  1.6787|   |Y  - 16 |
43862306a36Sopenharmony_ci		 * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128|
43962306a36Sopenharmony_ci		 * |B|   |1.1644  2.1418  0.0000|   |Cr - 128|
44062306a36Sopenharmony_ci		 */
44162306a36Sopenharmony_ci		static const u32 csc1_coef_bt2020_lim[3] = {
44262306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
44362306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x12a) |	/*  1.1641 (-0.03 %) */
44462306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
44562306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
44662306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x1ad) |	/*  1.6758 (-0.29 %) */
44762306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x224),	/*  2.1406 (-0.11 %) */
44862306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x75a) |	/* -0.6484 (+0.20 %) */
44962306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7d1),	/* -0.1836 (+0.38 %) */
45062306a36Sopenharmony_ci		};
45162306a36Sopenharmony_ci		/*
45262306a36Sopenharmony_ci		 * BT.2020 full range:
45362306a36Sopenharmony_ci		 *
45462306a36Sopenharmony_ci		 * |R|   |1.0000  0.0000  1.4746|   |Y  + 0  |
45562306a36Sopenharmony_ci		 * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128|
45662306a36Sopenharmony_ci		 * |B|   |1.0000  1.8814  0.0000|   |Cr - 128|
45762306a36Sopenharmony_ci		 */
45862306a36Sopenharmony_ci		static const u32 csc1_coef_bt2020_full[3] = {
45962306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
46062306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x100) |	/*  1.0000 (+0.00 %) */
46162306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
46262306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(0),
46362306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x179) |	/*  1.4727 (-0.19 %) */
46462306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x1e1),	/*  1.8789 (-0.25 %) */
46562306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x76e) |	/* -0.5703 (+0.11 %) */
46662306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7d6),	/* -0.1641 (+0.05 %) */
46762306a36Sopenharmony_ci		};
46862306a36Sopenharmony_ci		/*
46962306a36Sopenharmony_ci		 * SMPTE 240m limited range:
47062306a36Sopenharmony_ci		 *
47162306a36Sopenharmony_ci		 * |R|   |1.1644  0.0000  1.7937|   |Y  - 16 |
47262306a36Sopenharmony_ci		 * |G| = |1.1644 -0.2565 -0.5427| * |Cb - 128|
47362306a36Sopenharmony_ci		 * |B|   |1.1644  2.0798  0.0000|   |Cr - 128|
47462306a36Sopenharmony_ci		 */
47562306a36Sopenharmony_ci		static const u32 csc1_coef_smpte240m_lim[3] = {
47662306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
47762306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x12a) |	/*  1.1641 (-0.03 %) */
47862306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
47962306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
48062306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x1cb) |	/*  1.7930 (-0.07 %) */
48162306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x214),	/*  2.0781 (-0.17 %) */
48262306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x776) |	/* -0.5391 (+0.36 %) */
48362306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7bf),	/* -0.2539 (+0.26 %) */
48462306a36Sopenharmony_ci		};
48562306a36Sopenharmony_ci		/*
48662306a36Sopenharmony_ci		 * SMPTE 240m full range:
48762306a36Sopenharmony_ci		 *
48862306a36Sopenharmony_ci		 * |R|   |1.0000  0.0000  1.5756|   |Y  + 0  |
48962306a36Sopenharmony_ci		 * |G| = |1.0000 -0.2253 -0.4767| * |Cb - 128|
49062306a36Sopenharmony_ci		 * |B|   |1.0000  1.8270  0.0000|   |Cr - 128|
49162306a36Sopenharmony_ci		 */
49262306a36Sopenharmony_ci		static const u32 csc1_coef_smpte240m_full[3] = {
49362306a36Sopenharmony_ci			BM_PXP_CSC1_COEF0_YCBCR_MODE |
49462306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_C0(0x100) |	/*  1.0000 (+0.00 %) */
49562306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
49662306a36Sopenharmony_ci			BF_PXP_CSC1_COEF0_Y_OFFSET(0),
49762306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C1(0x193) |	/*  1.5742 (-0.14 %) */
49862306a36Sopenharmony_ci			BF_PXP_CSC1_COEF1_C4(0x1d3),	/*  1.8242 (-0.28 %) */
49962306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C2(0x786) |	/* -0.4766 (+0.01 %) */
50062306a36Sopenharmony_ci			BF_PXP_CSC1_COEF2_C3(0x7c7),	/* -0.2227 (+0.26 %) */
50162306a36Sopenharmony_ci		};
50262306a36Sopenharmony_ci		const u32 *csc1_coef;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
50562306a36Sopenharmony_ci		quantization = ctx->q_data[V4L2_M2M_SRC].quant;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
50862306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
50962306a36Sopenharmony_ci				csc1_coef = csc1_coef_bt601_full;
51062306a36Sopenharmony_ci			else
51162306a36Sopenharmony_ci				csc1_coef = csc1_coef_bt601_lim;
51262306a36Sopenharmony_ci		} else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
51362306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
51462306a36Sopenharmony_ci				csc1_coef = csc1_coef_rec709_full;
51562306a36Sopenharmony_ci			else
51662306a36Sopenharmony_ci				csc1_coef = csc1_coef_rec709_lim;
51762306a36Sopenharmony_ci		} else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
51862306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
51962306a36Sopenharmony_ci				csc1_coef = csc1_coef_bt2020_full;
52062306a36Sopenharmony_ci			else
52162306a36Sopenharmony_ci				csc1_coef = csc1_coef_bt2020_lim;
52262306a36Sopenharmony_ci		} else {
52362306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
52462306a36Sopenharmony_ci				csc1_coef = csc1_coef_smpte240m_full;
52562306a36Sopenharmony_ci			else
52662306a36Sopenharmony_ci				csc1_coef = csc1_coef_smpte240m_lim;
52762306a36Sopenharmony_ci		}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC1_COEF0, csc1_coef[0]);
53062306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC1_COEF1, csc1_coef[1]);
53162306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC1_COEF2, csc1_coef[2]);
53262306a36Sopenharmony_ci	} else {
53362306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC1_COEF0, BM_PXP_CSC1_COEF0_BYPASS);
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
53762306a36Sopenharmony_ci	    pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
53862306a36Sopenharmony_ci		/*
53962306a36Sopenharmony_ci		 * CSC2 RGB to YUV/YCbCr conversion is implemented as follows:
54062306a36Sopenharmony_ci		 *
54162306a36Sopenharmony_ci		 * |Y |   |A1 A2 A3|   |R|   |D1|
54262306a36Sopenharmony_ci		 * |Cb| = |B1 B2 B3| * |G| + |D2|
54362306a36Sopenharmony_ci		 * |Cr|   |C1 C2 C3|   |B|   |D3|
54462306a36Sopenharmony_ci		 *
54562306a36Sopenharmony_ci		 * Results are clamped to 0..255.
54662306a36Sopenharmony_ci		 *
54762306a36Sopenharmony_ci		 * BT.601 limited range:
54862306a36Sopenharmony_ci		 *
54962306a36Sopenharmony_ci		 * |Y |   | 0.2568  0.5041  0.0979|   |R|   |16 |
55062306a36Sopenharmony_ci		 * |Cb| = |-0.1482 -0.2910  0.4392| * |G| + |128|
55162306a36Sopenharmony_ci		 * |Cr|   | 0.4392  0.4392 -0.3678|   |B|   |128|
55262306a36Sopenharmony_ci		 */
55362306a36Sopenharmony_ci		static const u32 csc2_coef_bt601_lim[6] = {
55462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x081) |	/*  0.5039 (-0.02 %) */
55562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x041),	/*  0.2539 (-0.29 %) */
55662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7db) |	/* -0.1445 (+0.37 %) */
55762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x019),	/*  0.0977 (-0.02 %) */
55862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x070) |	/*  0.4375 (-0.17 %) */
55962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x7b6),	/* -0.2891 (+0.20 %) */
56062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x7a2) |	/* -0.3672 (+0.06 %) */
56162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x070),	/*  0.4375 (-0.17 %) */
56262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(16) |
56362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7ee),	/* -0.0703 (+0.11 %) */
56462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
56562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
56662306a36Sopenharmony_ci		};
56762306a36Sopenharmony_ci		/*
56862306a36Sopenharmony_ci		 * BT.601 full range:
56962306a36Sopenharmony_ci		 *
57062306a36Sopenharmony_ci		 * |Y |   | 0.2990  0.5870  0.1140|   |R|   |0  |
57162306a36Sopenharmony_ci		 * |Cb| = |-0.1687 -0.3313  0.5000| * |G| + |128|
57262306a36Sopenharmony_ci		 * |Cr|   | 0.5000  0.5000 -0.4187|   |B|   |128|
57362306a36Sopenharmony_ci		 */
57462306a36Sopenharmony_ci		static const u32 csc2_coef_bt601_full[6] = {
57562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x096) |	/*  0.5859 (-0.11 %) */
57662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x04c),	/*  0.2969 (-0.21 %) */
57762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7d5) |	/* -0.1680 (+0.07 %) */
57862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x01d),	/*  0.1133 (-0.07 %) */
57962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x080) |	/*  0.5000 (+0.00 %) */
58062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x7ac),	/* -0.3281 (+0.32 %) */
58162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x795) |	/* -0.4180 (+0.07 %) */
58262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x080),	/*  0.5000 (+0.00 %) */
58362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(0) |
58462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7ec),	/* -0.0781 (+0.32 %) */
58562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
58662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
58762306a36Sopenharmony_ci		};
58862306a36Sopenharmony_ci		/*
58962306a36Sopenharmony_ci		 * Rec.709 limited range:
59062306a36Sopenharmony_ci		 *
59162306a36Sopenharmony_ci		 * |Y |   | 0.1826  0.6142  0.0620|   |R|   |16 |
59262306a36Sopenharmony_ci		 * |Cb| = |-0.1007 -0.3385  0.4392| * |G| + |128|
59362306a36Sopenharmony_ci		 * |Cr|   | 0.4392  0.4392 -0.3990|   |B|   |128|
59462306a36Sopenharmony_ci		 */
59562306a36Sopenharmony_ci		static const u32 csc2_coef_rec709_lim[6] = {
59662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x09d) |	/*  0.6133 (-0.09 %) */
59762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x02e),	/*  0.1797 (-0.29 %) */
59862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7e7) |	/* -0.0977 (+0.30 %) */
59962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x00f),	/*  0.0586 (-0.34 %) */
60062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x070) |	/*  0.4375 (-0.17 %) */
60162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x7aa),	/* -0.3359 (+0.26 %) */
60262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x79a) |	/* -0.3984 (+0.05 %) */
60362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x070),	/*  0.4375 (-0.17 %) */
60462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(16) |
60562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7f6),	/* -0.0391 (+0.12 %) */
60662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
60762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
60862306a36Sopenharmony_ci		};
60962306a36Sopenharmony_ci		/*
61062306a36Sopenharmony_ci		 * Rec.709 full range:
61162306a36Sopenharmony_ci		 *
61262306a36Sopenharmony_ci		 * |Y |   | 0.2126  0.7152  0.0722|   |R|   |0  |
61362306a36Sopenharmony_ci		 * |Cb| = |-0.1146 -0.3854  0.5000| * |G| + |128|
61462306a36Sopenharmony_ci		 * |Cr|   | 0.5000  0.5000 -0.4542|   |B|   |128|
61562306a36Sopenharmony_ci		 */
61662306a36Sopenharmony_ci		static const u32 csc2_coef_rec709_full[6] = {
61762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x0b7) |	/*  0.7148 (-0.04 %) */
61862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x036),	/*  0.2109 (-0.17 %) */
61962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7e3) |	/* -0.1133 (+0.13 %) */
62062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x012),	/*  0.0703 (-0.19 %) */
62162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x080) |	/*  0.5000 (+0.00 %) */
62262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x79e),	/* -0.3828 (+0.26 %) */
62362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x78c) |	/* -0.4531 (+0.11 %) */
62462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x080),	/*  0.5000 (+0.00 %) */
62562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(0) |
62662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7f5),	/* -0.0430 (+0.28 %) */
62762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
62862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
62962306a36Sopenharmony_ci		};
63062306a36Sopenharmony_ci		/*
63162306a36Sopenharmony_ci		 * BT.2020 limited range:
63262306a36Sopenharmony_ci		 *
63362306a36Sopenharmony_ci		 * |Y |   | 0.2256  0.5823  0.0509|   |R|   |16 |
63462306a36Sopenharmony_ci		 * |Cb| = |-0.1226 -0.3166  0.4392| * |G| + |128|
63562306a36Sopenharmony_ci		 * |Cr|   | 0.4392  0.4392 -0.4039|   |B|   |128|
63662306a36Sopenharmony_ci		 */
63762306a36Sopenharmony_ci		static const u32 csc2_coef_bt2020_lim[6] = {
63862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x095) |	/*  0.5820 (-0.03 %) */
63962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x039),	/*  0.2227 (-0.30 %) */
64062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7e1) |	/* -0.1211 (+0.15 %) */
64162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x00d),	/*  0.0508 (-0.01 %) */
64262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x070) |	/*  0.4375 (-0.17 %) */
64362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x7af),	/* -0.3164 (+0.02 %) */
64462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x799) |	/* -0.4023 (+0.16 %) */
64562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x070),	/*  0.4375 (-0.17 %) */
64662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(16) |
64762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7f7),	/* -0.0352 (+0.02 %) */
64862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
64962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
65062306a36Sopenharmony_ci		};
65162306a36Sopenharmony_ci		/*
65262306a36Sopenharmony_ci		 * BT.2020 full range:
65362306a36Sopenharmony_ci		 *
65462306a36Sopenharmony_ci		 * |Y |   | 0.2627  0.6780  0.0593|   |R|   |0  |
65562306a36Sopenharmony_ci		 * |Cb| = |-0.1396 -0.3604  0.5000| * |G| + |128|
65662306a36Sopenharmony_ci		 * |Cr|   | 0.5000  0.5000 -0.4598|   |B|   |128|
65762306a36Sopenharmony_ci		 */
65862306a36Sopenharmony_ci		static const u32 csc2_coef_bt2020_full[6] = {
65962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x0ad) |	/*  0.6758 (-0.22 %) */
66062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x043),	/*  0.2617 (-0.10 %) */
66162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7dd) |	/* -0.1367 (+0.29 %) */
66262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x00f),	/*  0.0586 (-0.07 %) */
66362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x080) |	/*  0.5000 (+0.00 %) */
66462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x7a4),	/* -0.3594 (+0.10 %) */
66562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x78b) |	/* -0.4570 (+0.28 %) */
66662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x080),	/*  0.5000 (+0.00 %) */
66762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(0) |
66862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7f6),	/* -0.0391 (+0.11 %) */
66962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
67062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
67162306a36Sopenharmony_ci		};
67262306a36Sopenharmony_ci		/*
67362306a36Sopenharmony_ci		 * SMPTE 240m limited range:
67462306a36Sopenharmony_ci		 *
67562306a36Sopenharmony_ci		 * |Y |   | 0.1821  0.6020  0.0747|   |R|   |16 |
67662306a36Sopenharmony_ci		 * |Cb| = |-0.1019 -0.3373  0.4392| * |G| + |128|
67762306a36Sopenharmony_ci		 * |Cr|   | 0.4392  0.4392 -0.3909|   |B|   |128|
67862306a36Sopenharmony_ci		 */
67962306a36Sopenharmony_ci		static const u32 csc2_coef_smpte240m_lim[6] = {
68062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x09a) |	/*  0.6016 (-0.05 %) */
68162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x02e),	/*  0.1797 (-0.24 %) */
68262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7e6) |	/* -0.1016 (+0.03 %) */
68362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x013),	/*  0.0742 (-0.05 %) */
68462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x070) |	/*  0.4375 (-0.17 %) */
68562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x7aa),	/* -0.3359 (+0.14 %) */
68662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x79c) |	/* -0.3906 (+0.03 %) */
68762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x070),	/*  0.4375 (-0.17 %) */
68862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(16) |
68962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7f4),	/* -0.0469 (+0.14 %) */
69062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
69162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
69262306a36Sopenharmony_ci		};
69362306a36Sopenharmony_ci		/*
69462306a36Sopenharmony_ci		 * SMPTE 240m full range:
69562306a36Sopenharmony_ci		 *
69662306a36Sopenharmony_ci		 * |Y |   | 0.2120  0.7010  0.0870|   |R|   |0  |
69762306a36Sopenharmony_ci		 * |Cb| = |-0.1160 -0.3840  0.5000| * |G| + |128|
69862306a36Sopenharmony_ci		 * |Cr|   | 0.5000  0.5000 -0.4450|   |B|   |128|
69962306a36Sopenharmony_ci		 */
70062306a36Sopenharmony_ci		static const u32 csc2_coef_smpte240m_full[6] = {
70162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A2(0x0b3) |	/*  0.6992 (-0.18 %) */
70262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF0_A1(0x036),	/*  0.2109 (-0.11 %) */
70362306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_B1(0x7e3) |	/* -0.1133 (+0.27 %) */
70462306a36Sopenharmony_ci			BF_PXP_CSC2_COEF1_A3(0x016),	/*  0.0859 (-0.11 %) */
70562306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B3(0x080) |	/*  0.5000 (+0.00 %) */
70662306a36Sopenharmony_ci			BF_PXP_CSC2_COEF2_B2(0x79e),	/* -0.3828 (+0.12 %) */
70762306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C2(0x78f) |	/* -0.4414 (+0.36 %) */
70862306a36Sopenharmony_ci			BF_PXP_CSC2_COEF3_C1(0x080),	/*  0.5000 (+0.00 %) */
70962306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_D1(0) |
71062306a36Sopenharmony_ci			BF_PXP_CSC2_COEF4_C3(0x7f2),	/* -0.0547 (+0.03 %) */
71162306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D3(128) |
71262306a36Sopenharmony_ci			BF_PXP_CSC2_COEF5_D2(128),
71362306a36Sopenharmony_ci		};
71462306a36Sopenharmony_ci		const u32 *csc2_coef;
71562306a36Sopenharmony_ci		u32 csc2_ctrl;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		ycbcr_enc = ctx->q_data[V4L2_M2M_DST].ycbcr_enc;
71862306a36Sopenharmony_ci		quantization = ctx->q_data[V4L2_M2M_DST].quant;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
72162306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
72262306a36Sopenharmony_ci				csc2_coef = csc2_coef_bt601_full;
72362306a36Sopenharmony_ci			else
72462306a36Sopenharmony_ci				csc2_coef = csc2_coef_bt601_lim;
72562306a36Sopenharmony_ci		} else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
72662306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
72762306a36Sopenharmony_ci				csc2_coef = csc2_coef_rec709_full;
72862306a36Sopenharmony_ci			else
72962306a36Sopenharmony_ci				csc2_coef = csc2_coef_rec709_lim;
73062306a36Sopenharmony_ci		} else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
73162306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
73262306a36Sopenharmony_ci				csc2_coef = csc2_coef_bt2020_full;
73362306a36Sopenharmony_ci			else
73462306a36Sopenharmony_ci				csc2_coef = csc2_coef_bt2020_lim;
73562306a36Sopenharmony_ci		} else {
73662306a36Sopenharmony_ci			if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
73762306a36Sopenharmony_ci				csc2_coef = csc2_coef_smpte240m_full;
73862306a36Sopenharmony_ci			else
73962306a36Sopenharmony_ci				csc2_coef = csc2_coef_smpte240m_lim;
74062306a36Sopenharmony_ci		}
74162306a36Sopenharmony_ci		if (quantization == V4L2_QUANTIZATION_FULL_RANGE) {
74262306a36Sopenharmony_ci			csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV <<
74362306a36Sopenharmony_ci				    BP_PXP_CSC2_CTRL_CSC_MODE;
74462306a36Sopenharmony_ci		} else {
74562306a36Sopenharmony_ci			csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr <<
74662306a36Sopenharmony_ci				    BP_PXP_CSC2_CTRL_CSC_MODE;
74762306a36Sopenharmony_ci		}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_CTRL, csc2_ctrl);
75062306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_COEF0, csc2_coef[0]);
75162306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_COEF1, csc2_coef[1]);
75262306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_COEF2, csc2_coef[2]);
75362306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_COEF3, csc2_coef[3]);
75462306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_COEF4, csc2_coef[4]);
75562306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_COEF5, csc2_coef[5]);
75662306a36Sopenharmony_ci	} else {
75762306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_CSC2_CTRL, BM_PXP_CSC2_CTRL_BYPASS);
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	u32 ctrl0;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ctrl0 = 0;
76662306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
76762306a36Sopenharmony_ci	/* Bypass Dithering x3CH */
76862306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1);
76962306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
77062306a36Sopenharmony_ci	/* Select Rotation */
77162306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0);
77262306a36Sopenharmony_ci	/* Bypass LUT */
77362306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
77462306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
77562306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
77662306a36Sopenharmony_ci	/* Select CSC 2 */
77762306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
77862306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
77962306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(3);
78062306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
78162306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
78262306a36Sopenharmony_ci	/* Bypass Rotation 2 */
78362306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
78462306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
78562306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
78662306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	return ctrl0;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic u32 pxp_imx7d_data_path_ctrl0(struct pxp_ctx *ctx)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	u32 ctrl0;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ctrl0 = 0;
79662306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
79762306a36Sopenharmony_ci	/* Select Rotation 0 */
79862306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(0);
79962306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
80062306a36Sopenharmony_ci	/* Select MUX11 for Rotation 0 */
80162306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(1);
80262306a36Sopenharmony_ci	/* Bypass LUT */
80362306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
80462306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
80562306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
80662306a36Sopenharmony_ci	/* Select CSC 2 */
80762306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
80862306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
80962306a36Sopenharmony_ci	/* Select Composite Alpha Blending/Color Key 0 for CSC 2 */
81062306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(1);
81162306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
81262306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
81362306a36Sopenharmony_ci	/* Bypass Rotation 1 */
81462306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
81562306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
81662306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
81762306a36Sopenharmony_ci	ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return ctrl0;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic void pxp_set_data_path(struct pxp_ctx *ctx)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	struct pxp_dev *dev = ctx->dev;
82562306a36Sopenharmony_ci	u32 ctrl0;
82662306a36Sopenharmony_ci	u32 ctrl1;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	ctrl0 = dev->pdata->data_path_ctrl0(ctx);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	ctrl1 = 0;
83162306a36Sopenharmony_ci	ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3);
83262306a36Sopenharmony_ci	ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_DATA_PATH_CTRL0, ctrl0);
83562306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_DATA_PATH_CTRL1, ctrl1);
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
83962306a36Sopenharmony_ci		     struct vb2_v4l2_buffer *out_vb)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	struct pxp_dev *dev = ctx->dev;
84262306a36Sopenharmony_ci	struct pxp_q_data *q_data;
84362306a36Sopenharmony_ci	u32 src_width, src_height, src_stride, src_fourcc;
84462306a36Sopenharmony_ci	u32 dst_width, dst_height, dst_stride, dst_fourcc;
84562306a36Sopenharmony_ci	dma_addr_t p_in, p_out;
84662306a36Sopenharmony_ci	u32 ctrl, out_ctrl, out_buf, out_buf2, out_pitch, out_lrc, out_ps_ulc;
84762306a36Sopenharmony_ci	u32 out_ps_lrc;
84862306a36Sopenharmony_ci	u32 ps_ctrl, ps_buf, ps_ubuf, ps_vbuf, ps_pitch, ps_scale, ps_offset;
84962306a36Sopenharmony_ci	u32 as_ulc, as_lrc;
85062306a36Sopenharmony_ci	u32 y_size;
85162306a36Sopenharmony_ci	u32 decx, decy, xscale, yscale;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	src_width = ctx->q_data[V4L2_M2M_SRC].width;
85662306a36Sopenharmony_ci	dst_width = ctx->q_data[V4L2_M2M_DST].width;
85762306a36Sopenharmony_ci	src_height = ctx->q_data[V4L2_M2M_SRC].height;
85862306a36Sopenharmony_ci	dst_height = ctx->q_data[V4L2_M2M_DST].height;
85962306a36Sopenharmony_ci	src_stride = ctx->q_data[V4L2_M2M_SRC].bytesperline;
86062306a36Sopenharmony_ci	dst_stride = ctx->q_data[V4L2_M2M_DST].bytesperline;
86162306a36Sopenharmony_ci	src_fourcc = ctx->q_data[V4L2_M2M_SRC].fmt->fourcc;
86262306a36Sopenharmony_ci	dst_fourcc = ctx->q_data[V4L2_M2M_DST].fmt->fourcc;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	p_in = vb2_dma_contig_plane_dma_addr(&in_vb->vb2_buf, 0);
86562306a36Sopenharmony_ci	p_out = vb2_dma_contig_plane_dma_addr(&out_vb->vb2_buf, 0);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (!p_in || !p_out) {
86862306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
86962306a36Sopenharmony_ci			 "Acquiring DMA addresses of buffers failed\n");
87062306a36Sopenharmony_ci		return -EFAULT;
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	out_vb->sequence =
87462306a36Sopenharmony_ci		get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
87562306a36Sopenharmony_ci	in_vb->sequence = q_data->sequence++;
87662306a36Sopenharmony_ci	out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
87962306a36Sopenharmony_ci		out_vb->timecode = in_vb->timecode;
88062306a36Sopenharmony_ci	out_vb->field = in_vb->field;
88162306a36Sopenharmony_ci	out_vb->flags = in_vb->flags &
88262306a36Sopenharmony_ci		(V4L2_BUF_FLAG_TIMECODE |
88362306a36Sopenharmony_ci		 V4L2_BUF_FLAG_KEYFRAME |
88462306a36Sopenharmony_ci		 V4L2_BUF_FLAG_PFRAME |
88562306a36Sopenharmony_ci		 V4L2_BUF_FLAG_BFRAME |
88662306a36Sopenharmony_ci		 V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* 8x8 block size */
88962306a36Sopenharmony_ci	ctrl = BF_PXP_CTRL_VFLIP0(!!(ctx->mode & MEM2MEM_VFLIP)) |
89062306a36Sopenharmony_ci	       BF_PXP_CTRL_HFLIP0(!!(ctx->mode & MEM2MEM_HFLIP)) |
89162306a36Sopenharmony_ci	       BF_PXP_CTRL_ROTATE0(ctx->rotation);
89262306a36Sopenharmony_ci	/* Always write alpha value as V4L2_CID_ALPHA_COMPONENT */
89362306a36Sopenharmony_ci	out_ctrl = BF_PXP_OUT_CTRL_ALPHA(ctx->alpha_component) |
89462306a36Sopenharmony_ci		   BF_PXP_OUT_CTRL_ALPHA_OUTPUT(1) |
89562306a36Sopenharmony_ci		   pxp_v4l2_pix_fmt_to_out_format(dst_fourcc);
89662306a36Sopenharmony_ci	out_buf = p_out;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_90 ||
89962306a36Sopenharmony_ci	    ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_270)
90062306a36Sopenharmony_ci		swap(dst_width, dst_height);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	switch (dst_fourcc) {
90362306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
90462306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV21:
90562306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
90662306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV61:
90762306a36Sopenharmony_ci		out_buf2 = out_buf + dst_stride * dst_height;
90862306a36Sopenharmony_ci		break;
90962306a36Sopenharmony_ci	default:
91062306a36Sopenharmony_ci		out_buf2 = 0;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	out_pitch = BF_PXP_OUT_PITCH_PITCH(dst_stride);
91462306a36Sopenharmony_ci	out_lrc = BF_PXP_OUT_LRC_X(dst_width - 1) |
91562306a36Sopenharmony_ci		  BF_PXP_OUT_LRC_Y(dst_height - 1);
91662306a36Sopenharmony_ci	/* PS covers whole output */
91762306a36Sopenharmony_ci	out_ps_ulc = BF_PXP_OUT_PS_ULC_X(0) | BF_PXP_OUT_PS_ULC_Y(0);
91862306a36Sopenharmony_ci	out_ps_lrc = BF_PXP_OUT_PS_LRC_X(dst_width - 1) |
91962306a36Sopenharmony_ci		     BF_PXP_OUT_PS_LRC_Y(dst_height - 1);
92062306a36Sopenharmony_ci	/* no AS */
92162306a36Sopenharmony_ci	as_ulc = BF_PXP_OUT_AS_ULC_X(1) | BF_PXP_OUT_AS_ULC_Y(1);
92262306a36Sopenharmony_ci	as_lrc = BF_PXP_OUT_AS_LRC_X(0) | BF_PXP_OUT_AS_LRC_Y(0);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	decx = (src_width <= dst_width) ? 0 : ilog2(src_width / dst_width);
92562306a36Sopenharmony_ci	decy = (src_height <= dst_height) ? 0 : ilog2(src_height / dst_height);
92662306a36Sopenharmony_ci	ps_ctrl = BF_PXP_PS_CTRL_DECX(decx) | BF_PXP_PS_CTRL_DECY(decy) |
92762306a36Sopenharmony_ci		  pxp_v4l2_pix_fmt_to_ps_format(src_fourcc);
92862306a36Sopenharmony_ci	ps_buf = p_in;
92962306a36Sopenharmony_ci	y_size = src_stride * src_height;
93062306a36Sopenharmony_ci	switch (src_fourcc) {
93162306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV420:
93262306a36Sopenharmony_ci		ps_ubuf = ps_buf + y_size;
93362306a36Sopenharmony_ci		ps_vbuf = ps_ubuf + y_size / 4;
93462306a36Sopenharmony_ci		break;
93562306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV422P:
93662306a36Sopenharmony_ci		ps_ubuf = ps_buf + y_size;
93762306a36Sopenharmony_ci		ps_vbuf = ps_ubuf + y_size / 2;
93862306a36Sopenharmony_ci		break;
93962306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
94062306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV21:
94162306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
94262306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV61:
94362306a36Sopenharmony_ci		ps_ubuf = ps_buf + y_size;
94462306a36Sopenharmony_ci		ps_vbuf = 0;
94562306a36Sopenharmony_ci		break;
94662306a36Sopenharmony_ci	case V4L2_PIX_FMT_GREY:
94762306a36Sopenharmony_ci	case V4L2_PIX_FMT_Y4:
94862306a36Sopenharmony_ci		ps_ubuf = 0;
94962306a36Sopenharmony_ci		/* In grayscale mode, ps_vbuf contents are reused as CbCr */
95062306a36Sopenharmony_ci		ps_vbuf = 0x8080;
95162306a36Sopenharmony_ci		break;
95262306a36Sopenharmony_ci	default:
95362306a36Sopenharmony_ci		ps_ubuf = 0;
95462306a36Sopenharmony_ci		ps_vbuf = 0;
95562306a36Sopenharmony_ci		break;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci	ps_pitch = BF_PXP_PS_PITCH_PITCH(src_stride);
95862306a36Sopenharmony_ci	if (decx) {
95962306a36Sopenharmony_ci		xscale = (src_width >> decx) * 0x1000 / dst_width;
96062306a36Sopenharmony_ci	} else {
96162306a36Sopenharmony_ci		switch (src_fourcc) {
96262306a36Sopenharmony_ci		case V4L2_PIX_FMT_UYVY:
96362306a36Sopenharmony_ci		case V4L2_PIX_FMT_YUYV:
96462306a36Sopenharmony_ci		case V4L2_PIX_FMT_VYUY:
96562306a36Sopenharmony_ci		case V4L2_PIX_FMT_YVYU:
96662306a36Sopenharmony_ci		case V4L2_PIX_FMT_NV16:
96762306a36Sopenharmony_ci		case V4L2_PIX_FMT_NV12:
96862306a36Sopenharmony_ci		case V4L2_PIX_FMT_NV21:
96962306a36Sopenharmony_ci		case V4L2_PIX_FMT_NV61:
97062306a36Sopenharmony_ci		case V4L2_PIX_FMT_YUV422P:
97162306a36Sopenharmony_ci		case V4L2_PIX_FMT_YUV420:
97262306a36Sopenharmony_ci			/*
97362306a36Sopenharmony_ci			 * This avoids sampling past the right edge for
97462306a36Sopenharmony_ci			 * horizontally chroma subsampled formats.
97562306a36Sopenharmony_ci			 */
97662306a36Sopenharmony_ci			xscale = (src_width - 2) * 0x1000 / (dst_width - 1);
97762306a36Sopenharmony_ci			break;
97862306a36Sopenharmony_ci		default:
97962306a36Sopenharmony_ci			xscale = (src_width - 1) * 0x1000 / (dst_width - 1);
98062306a36Sopenharmony_ci			break;
98162306a36Sopenharmony_ci		}
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci	if (decy)
98462306a36Sopenharmony_ci		yscale = (src_height >> decy) * 0x1000 / dst_height;
98562306a36Sopenharmony_ci	else
98662306a36Sopenharmony_ci		yscale = (src_height - 1) * 0x1000 / (dst_height - 1);
98762306a36Sopenharmony_ci	ps_scale = BF_PXP_PS_SCALE_YSCALE(yscale) |
98862306a36Sopenharmony_ci		   BF_PXP_PS_SCALE_XSCALE(xscale);
98962306a36Sopenharmony_ci	ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL, ctrl);
99262306a36Sopenharmony_ci	/* skip STAT */
99362306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_CTRL, out_ctrl);
99462306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_BUF, out_buf);
99562306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_BUF2, out_buf2);
99662306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_PITCH, out_pitch);
99762306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_LRC, out_lrc);
99862306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_PS_ULC, out_ps_ulc);
99962306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_PS_LRC, out_ps_lrc);
100062306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_AS_ULC, as_ulc);
100162306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_OUT_AS_LRC, as_lrc);
100262306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_CTRL, ps_ctrl);
100362306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_BUF, ps_buf);
100462306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_UBUF, ps_ubuf);
100562306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_VBUF, ps_vbuf);
100662306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_PITCH, ps_pitch);
100762306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_BACKGROUND_0, 0x00ffffff);
100862306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_SCALE, ps_scale);
100962306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_OFFSET, ps_offset);
101062306a36Sopenharmony_ci	/* disable processed surface color keying */
101162306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_CLRKEYLOW_0, 0x00ffffff);
101262306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_PS_CLRKEYHIGH_0, 0x00000000);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* disable alpha surface color keying */
101562306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_AS_CLRKEYLOW_0, 0x00ffffff);
101662306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_AS_CLRKEYHIGH_0, 0x00000000);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* setup CSC */
101962306a36Sopenharmony_ci	pxp_setup_csc(ctx);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	/* bypass LUT */
102262306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_LUT_CTRL, BM_PXP_LUT_CTRL_BYPASS);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	pxp_set_data_path(ctx);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_IRQ_MASK, 0xffff);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/* ungate, enable PS/AS/OUT and PXP operation */
102962306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_IRQ_ENABLE);
103062306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_SET,
103162306a36Sopenharmony_ci		  BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
103262306a36Sopenharmony_ci		  BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	return 0;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic void pxp_job_finish(struct pxp_dev *dev)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	struct pxp_ctx *curr_ctx;
104062306a36Sopenharmony_ci	struct vb2_v4l2_buffer *src_vb, *dst_vb;
104162306a36Sopenharmony_ci	unsigned long flags;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	curr_ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	if (curr_ctx == NULL) {
104662306a36Sopenharmony_ci		pr_err("Instance released before the end of transaction\n");
104762306a36Sopenharmony_ci		return;
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
105162306a36Sopenharmony_ci	dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->irqlock, flags);
105462306a36Sopenharmony_ci	v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
105562306a36Sopenharmony_ci	v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
105662306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->irqlock, flags);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	dprintk(curr_ctx->dev, "Finishing transaction\n");
105962306a36Sopenharmony_ci	v4l2_m2m_job_finish(dev->m2m_dev, curr_ctx->fh.m2m_ctx);
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/*
106362306a36Sopenharmony_ci * mem2mem callbacks
106462306a36Sopenharmony_ci */
106562306a36Sopenharmony_cistatic void pxp_device_run(void *priv)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct pxp_ctx *ctx = priv;
106862306a36Sopenharmony_ci	struct vb2_v4l2_buffer *src_buf, *dst_buf;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
107162306a36Sopenharmony_ci	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	pxp_start(ctx, src_buf, dst_buf);
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic int pxp_job_ready(void *priv)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	struct pxp_ctx *ctx = priv;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < 1 ||
108162306a36Sopenharmony_ci	    v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < 1) {
108262306a36Sopenharmony_ci		dprintk(ctx->dev, "Not enough buffers available\n");
108362306a36Sopenharmony_ci		return 0;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	return 1;
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_cistatic void pxp_job_abort(void *priv)
109062306a36Sopenharmony_ci{
109162306a36Sopenharmony_ci	struct pxp_ctx *ctx = priv;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	/* Will cancel the transaction in the next interrupt handler */
109462306a36Sopenharmony_ci	ctx->aborting = 1;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci/*
109862306a36Sopenharmony_ci * interrupt handler
109962306a36Sopenharmony_ci */
110062306a36Sopenharmony_cistatic irqreturn_t pxp_irq_handler(int irq, void *dev_id)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	struct pxp_dev *dev = dev_id;
110362306a36Sopenharmony_ci	u32 stat;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	stat = pxp_read(dev, HW_PXP_STAT);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	if (stat & BM_PXP_STAT_IRQ0) {
110862306a36Sopenharmony_ci		/* we expect x = 0, y = height, irq0 = 1 */
110962306a36Sopenharmony_ci		if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY |
111062306a36Sopenharmony_ci			     BM_PXP_STAT_IRQ0))
111162306a36Sopenharmony_ci			dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
111262306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_STAT_CLR, BM_PXP_STAT_IRQ0);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci		pxp_job_finish(dev);
111562306a36Sopenharmony_ci	} else {
111662306a36Sopenharmony_ci		u32 irq = pxp_read(dev, HW_PXP_IRQ);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
111962306a36Sopenharmony_ci		dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		pxp_write(dev, HW_PXP_IRQ_CLR, irq);
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	return IRQ_HANDLED;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci/*
112862306a36Sopenharmony_ci * video ioctls
112962306a36Sopenharmony_ci */
113062306a36Sopenharmony_cistatic int pxp_querycap(struct file *file, void *priv,
113162306a36Sopenharmony_ci			   struct v4l2_capability *cap)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
113462306a36Sopenharmony_ci	strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic int pxp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	int i, num;
114162306a36Sopenharmony_ci	struct pxp_fmt *fmt;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	num = 0;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	for (i = 0; i < NUM_FORMATS; ++i) {
114662306a36Sopenharmony_ci		if (formats[i].types & type) {
114762306a36Sopenharmony_ci			/* index-th format of type type found ? */
114862306a36Sopenharmony_ci			if (num == f->index)
114962306a36Sopenharmony_ci				break;
115062306a36Sopenharmony_ci			/*
115162306a36Sopenharmony_ci			 * Correct type but haven't reached our index yet,
115262306a36Sopenharmony_ci			 * just increment per-type index
115362306a36Sopenharmony_ci			 */
115462306a36Sopenharmony_ci			++num;
115562306a36Sopenharmony_ci		}
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (i < NUM_FORMATS) {
115962306a36Sopenharmony_ci		/* Format found */
116062306a36Sopenharmony_ci		fmt = &formats[i];
116162306a36Sopenharmony_ci		f->pixelformat = fmt->fourcc;
116262306a36Sopenharmony_ci		return 0;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* Format not found */
116662306a36Sopenharmony_ci	return -EINVAL;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic int pxp_enum_fmt_vid_cap(struct file *file, void *priv,
117062306a36Sopenharmony_ci				struct v4l2_fmtdesc *f)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	return pxp_enum_fmt(f, MEM2MEM_CAPTURE);
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistatic int pxp_enum_fmt_vid_out(struct file *file, void *priv,
117662306a36Sopenharmony_ci				struct v4l2_fmtdesc *f)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	return pxp_enum_fmt(f, MEM2MEM_OUTPUT);
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_cistatic int pxp_g_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	struct vb2_queue *vq;
118462306a36Sopenharmony_ci	struct pxp_q_data *q_data;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
118762306a36Sopenharmony_ci	if (!vq)
118862306a36Sopenharmony_ci		return -EINVAL;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	q_data = get_q_data(ctx, f->type);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	f->fmt.pix.width	= q_data->width;
119362306a36Sopenharmony_ci	f->fmt.pix.height	= q_data->height;
119462306a36Sopenharmony_ci	f->fmt.pix.field	= V4L2_FIELD_NONE;
119562306a36Sopenharmony_ci	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
119662306a36Sopenharmony_ci	f->fmt.pix.bytesperline	= q_data->bytesperline;
119762306a36Sopenharmony_ci	f->fmt.pix.sizeimage	= q_data->sizeimage;
119862306a36Sopenharmony_ci	f->fmt.pix.colorspace	= ctx->colorspace;
119962306a36Sopenharmony_ci	f->fmt.pix.xfer_func	= ctx->xfer_func;
120062306a36Sopenharmony_ci	f->fmt.pix.ycbcr_enc	= q_data->ycbcr_enc;
120162306a36Sopenharmony_ci	f->fmt.pix.quantization	= q_data->quant;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	return 0;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic int pxp_g_fmt_vid_out(struct file *file, void *priv,
120762306a36Sopenharmony_ci				struct v4l2_format *f)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	return pxp_g_fmt(file2ctx(file), f);
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_cistatic int pxp_g_fmt_vid_cap(struct file *file, void *priv,
121362306a36Sopenharmony_ci				struct v4l2_format *f)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	return pxp_g_fmt(file2ctx(file), f);
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_cistatic inline u32 pxp_bytesperline(struct pxp_fmt *fmt, u32 width)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	switch (fmt->fourcc) {
122162306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV420:
122262306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
122362306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV21:
122462306a36Sopenharmony_ci	case V4L2_PIX_FMT_YUV422P:
122562306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
122662306a36Sopenharmony_ci	case V4L2_PIX_FMT_NV61:
122762306a36Sopenharmony_ci		return width;
122862306a36Sopenharmony_ci	default:
122962306a36Sopenharmony_ci		return (width * fmt->depth) >> 3;
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic inline u32 pxp_sizeimage(struct pxp_fmt *fmt, u32 width, u32 height)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	return (fmt->depth * width * height) >> 3;
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic int pxp_try_fmt(struct v4l2_format *f, struct pxp_fmt *fmt)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, ALIGN_W,
124162306a36Sopenharmony_ci			      &f->fmt.pix.height, MIN_H, MAX_H, ALIGN_H, 0);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	f->fmt.pix.bytesperline = pxp_bytesperline(fmt, f->fmt.pix.width);
124462306a36Sopenharmony_ci	f->fmt.pix.sizeimage = pxp_sizeimage(fmt, f->fmt.pix.width,
124562306a36Sopenharmony_ci					     f->fmt.pix.height);
124662306a36Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_NONE;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	return 0;
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic void
125262306a36Sopenharmony_cipxp_fixup_colorimetry_cap(struct pxp_ctx *ctx, u32 dst_fourcc,
125362306a36Sopenharmony_ci			  enum v4l2_ycbcr_encoding *ycbcr_enc,
125462306a36Sopenharmony_ci			  enum v4l2_quantization *quantization)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	bool dst_is_yuv = pxp_v4l2_pix_fmt_is_yuv(dst_fourcc);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) ==
125962306a36Sopenharmony_ci	    dst_is_yuv) {
126062306a36Sopenharmony_ci		/*
126162306a36Sopenharmony_ci		 * There is no support for conversion between different YCbCr
126262306a36Sopenharmony_ci		 * encodings or between RGB limited and full range.
126362306a36Sopenharmony_ci		 */
126462306a36Sopenharmony_ci		*ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
126562306a36Sopenharmony_ci		*quantization = ctx->q_data[V4L2_M2M_SRC].quant;
126662306a36Sopenharmony_ci	} else {
126762306a36Sopenharmony_ci		*ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(ctx->colorspace);
126862306a36Sopenharmony_ci		*quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!dst_is_yuv,
126962306a36Sopenharmony_ci							      ctx->colorspace,
127062306a36Sopenharmony_ci							      *ycbcr_enc);
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic int pxp_try_fmt_vid_cap(struct file *file, void *priv,
127562306a36Sopenharmony_ci			       struct v4l2_format *f)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct pxp_fmt *fmt;
127862306a36Sopenharmony_ci	struct pxp_ctx *ctx = file2ctx(file);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	fmt = find_format(f->fmt.pix.pixelformat);
128162306a36Sopenharmony_ci	if (!fmt) {
128262306a36Sopenharmony_ci		f->fmt.pix.pixelformat = formats[0].fourcc;
128362306a36Sopenharmony_ci		fmt = find_format(f->fmt.pix.pixelformat);
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci	if (!(fmt->types & MEM2MEM_CAPTURE)) {
128662306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
128762306a36Sopenharmony_ci			 "Fourcc format (0x%08x) invalid.\n",
128862306a36Sopenharmony_ci			 f->fmt.pix.pixelformat);
128962306a36Sopenharmony_ci		return -EINVAL;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	f->fmt.pix.colorspace = ctx->colorspace;
129362306a36Sopenharmony_ci	f->fmt.pix.xfer_func = ctx->xfer_func;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	pxp_fixup_colorimetry_cap(ctx, fmt->fourcc,
129662306a36Sopenharmony_ci				  &f->fmt.pix.ycbcr_enc,
129762306a36Sopenharmony_ci				  &f->fmt.pix.quantization);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	return pxp_try_fmt(f, fmt);
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic int pxp_try_fmt_vid_out(struct file *file, void *priv,
130362306a36Sopenharmony_ci			       struct v4l2_format *f)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	struct pxp_fmt *fmt;
130662306a36Sopenharmony_ci	struct pxp_ctx *ctx = file2ctx(file);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	fmt = find_format(f->fmt.pix.pixelformat);
130962306a36Sopenharmony_ci	if (!fmt) {
131062306a36Sopenharmony_ci		f->fmt.pix.pixelformat = formats[0].fourcc;
131162306a36Sopenharmony_ci		fmt = find_format(f->fmt.pix.pixelformat);
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci	if (!(fmt->types & MEM2MEM_OUTPUT)) {
131462306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
131562306a36Sopenharmony_ci			 "Fourcc format (0x%08x) invalid.\n",
131662306a36Sopenharmony_ci			 f->fmt.pix.pixelformat);
131762306a36Sopenharmony_ci		return -EINVAL;
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	if (!f->fmt.pix.colorspace)
132162306a36Sopenharmony_ci		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	return pxp_try_fmt(f, fmt);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	struct pxp_q_data *q_data;
132962306a36Sopenharmony_ci	struct vb2_queue *vq;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
133262306a36Sopenharmony_ci	if (!vq)
133362306a36Sopenharmony_ci		return -EINVAL;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	q_data = get_q_data(ctx, f->type);
133662306a36Sopenharmony_ci	if (!q_data)
133762306a36Sopenharmony_ci		return -EINVAL;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (vb2_is_busy(vq)) {
134062306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
134162306a36Sopenharmony_ci		return -EBUSY;
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	q_data->fmt		= find_format(f->fmt.pix.pixelformat);
134562306a36Sopenharmony_ci	q_data->width		= f->fmt.pix.width;
134662306a36Sopenharmony_ci	q_data->height		= f->fmt.pix.height;
134762306a36Sopenharmony_ci	q_data->bytesperline	= f->fmt.pix.bytesperline;
134862306a36Sopenharmony_ci	q_data->sizeimage	= f->fmt.pix.sizeimage;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	dprintk(ctx->dev,
135162306a36Sopenharmony_ci		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
135262306a36Sopenharmony_ci		f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	return 0;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_cistatic int pxp_s_fmt_vid_cap(struct file *file, void *priv,
135862306a36Sopenharmony_ci			     struct v4l2_format *f)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct pxp_ctx *ctx = file2ctx(file);
136162306a36Sopenharmony_ci	int ret;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	ret = pxp_try_fmt_vid_cap(file, priv, f);
136462306a36Sopenharmony_ci	if (ret)
136562306a36Sopenharmony_ci		return ret;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	ret = pxp_s_fmt(file2ctx(file), f);
136862306a36Sopenharmony_ci	if (ret)
136962306a36Sopenharmony_ci		return ret;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_DST].ycbcr_enc = f->fmt.pix.ycbcr_enc;
137262306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_DST].quant = f->fmt.pix.quantization;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	return 0;
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic int pxp_s_fmt_vid_out(struct file *file, void *priv,
137862306a36Sopenharmony_ci			     struct v4l2_format *f)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	struct pxp_ctx *ctx = file2ctx(file);
138162306a36Sopenharmony_ci	int ret;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	ret = pxp_try_fmt_vid_out(file, priv, f);
138462306a36Sopenharmony_ci	if (ret)
138562306a36Sopenharmony_ci		return ret;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	ret = pxp_s_fmt(file2ctx(file), f);
138862306a36Sopenharmony_ci	if (ret)
138962306a36Sopenharmony_ci		return ret;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	ctx->colorspace = f->fmt.pix.colorspace;
139262306a36Sopenharmony_ci	ctx->xfer_func = f->fmt.pix.xfer_func;
139362306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].ycbcr_enc = f->fmt.pix.ycbcr_enc;
139462306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].quant = f->fmt.pix.quantization;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	pxp_fixup_colorimetry_cap(ctx, ctx->q_data[V4L2_M2M_DST].fmt->fourcc,
139762306a36Sopenharmony_ci				  &ctx->q_data[V4L2_M2M_DST].ycbcr_enc,
139862306a36Sopenharmony_ci				  &ctx->q_data[V4L2_M2M_DST].quant);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	return 0;
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic int pxp_enum_framesizes(struct file *file, void *fh,
140462306a36Sopenharmony_ci			       struct v4l2_frmsizeenum *fsize)
140562306a36Sopenharmony_ci{
140662306a36Sopenharmony_ci	if (fsize->index > 0)
140762306a36Sopenharmony_ci		return -EINVAL;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	if (!find_format(fsize->pixel_format))
141062306a36Sopenharmony_ci		return -EINVAL;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
141362306a36Sopenharmony_ci	fsize->stepwise.min_width = MIN_W;
141462306a36Sopenharmony_ci	fsize->stepwise.max_width = MAX_W;
141562306a36Sopenharmony_ci	fsize->stepwise.step_width = 1 << ALIGN_W;
141662306a36Sopenharmony_ci	fsize->stepwise.min_height = MIN_H;
141762306a36Sopenharmony_ci	fsize->stepwise.max_height = MAX_H;
141862306a36Sopenharmony_ci	fsize->stepwise.step_height = 1 << ALIGN_H;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	return 0;
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_cistatic u8 pxp_degrees_to_rot_mode(u32 degrees)
142462306a36Sopenharmony_ci{
142562306a36Sopenharmony_ci	switch (degrees) {
142662306a36Sopenharmony_ci	case 90:
142762306a36Sopenharmony_ci		return BV_PXP_CTRL_ROTATE0__ROT_90;
142862306a36Sopenharmony_ci	case 180:
142962306a36Sopenharmony_ci		return BV_PXP_CTRL_ROTATE0__ROT_180;
143062306a36Sopenharmony_ci	case 270:
143162306a36Sopenharmony_ci		return BV_PXP_CTRL_ROTATE0__ROT_270;
143262306a36Sopenharmony_ci	case 0:
143362306a36Sopenharmony_ci	default:
143462306a36Sopenharmony_ci		return BV_PXP_CTRL_ROTATE0__ROT_0;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_cistatic int pxp_s_ctrl(struct v4l2_ctrl *ctrl)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	struct pxp_ctx *ctx =
144162306a36Sopenharmony_ci		container_of(ctrl->handler, struct pxp_ctx, hdl);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	switch (ctrl->id) {
144462306a36Sopenharmony_ci	case V4L2_CID_HFLIP:
144562306a36Sopenharmony_ci		if (ctrl->val)
144662306a36Sopenharmony_ci			ctx->mode |= MEM2MEM_HFLIP;
144762306a36Sopenharmony_ci		else
144862306a36Sopenharmony_ci			ctx->mode &= ~MEM2MEM_HFLIP;
144962306a36Sopenharmony_ci		break;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	case V4L2_CID_VFLIP:
145262306a36Sopenharmony_ci		if (ctrl->val)
145362306a36Sopenharmony_ci			ctx->mode |= MEM2MEM_VFLIP;
145462306a36Sopenharmony_ci		else
145562306a36Sopenharmony_ci			ctx->mode &= ~MEM2MEM_VFLIP;
145662306a36Sopenharmony_ci		break;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	case V4L2_CID_ROTATE:
145962306a36Sopenharmony_ci		ctx->rotation = pxp_degrees_to_rot_mode(ctrl->val);
146062306a36Sopenharmony_ci		break;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	case V4L2_CID_ALPHA_COMPONENT:
146362306a36Sopenharmony_ci		ctx->alpha_component = ctrl->val;
146462306a36Sopenharmony_ci		break;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	default:
146762306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
146862306a36Sopenharmony_ci		return -EINVAL;
146962306a36Sopenharmony_ci	}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	return 0;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops pxp_ctrl_ops = {
147562306a36Sopenharmony_ci	.s_ctrl = pxp_s_ctrl,
147662306a36Sopenharmony_ci};
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops pxp_ioctl_ops = {
147962306a36Sopenharmony_ci	.vidioc_querycap	= pxp_querycap,
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap = pxp_enum_fmt_vid_cap,
148262306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap	= pxp_g_fmt_vid_cap,
148362306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap	= pxp_try_fmt_vid_cap,
148462306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap	= pxp_s_fmt_vid_cap,
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_out = pxp_enum_fmt_vid_out,
148762306a36Sopenharmony_ci	.vidioc_g_fmt_vid_out	= pxp_g_fmt_vid_out,
148862306a36Sopenharmony_ci	.vidioc_try_fmt_vid_out	= pxp_try_fmt_vid_out,
148962306a36Sopenharmony_ci	.vidioc_s_fmt_vid_out	= pxp_s_fmt_vid_out,
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	.vidioc_enum_framesizes	= pxp_enum_framesizes,
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
149462306a36Sopenharmony_ci	.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
149562306a36Sopenharmony_ci	.vidioc_qbuf		= v4l2_m2m_ioctl_qbuf,
149662306a36Sopenharmony_ci	.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
149762306a36Sopenharmony_ci	.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
149862306a36Sopenharmony_ci	.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
149962306a36Sopenharmony_ci	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
150262306a36Sopenharmony_ci	.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
150562306a36Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
150662306a36Sopenharmony_ci};
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci/*
150962306a36Sopenharmony_ci * Queue operations
151062306a36Sopenharmony_ci */
151162306a36Sopenharmony_cistatic int pxp_queue_setup(struct vb2_queue *vq,
151262306a36Sopenharmony_ci			   unsigned int *nbuffers, unsigned int *nplanes,
151362306a36Sopenharmony_ci			   unsigned int sizes[], struct device *alloc_devs[])
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	struct pxp_ctx *ctx = vb2_get_drv_priv(vq);
151662306a36Sopenharmony_ci	struct pxp_q_data *q_data;
151762306a36Sopenharmony_ci	unsigned int size, count = *nbuffers;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	q_data = get_q_data(ctx, vq->type);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	size = q_data->sizeimage;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	*nbuffers = count;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (*nplanes)
152662306a36Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	*nplanes = 1;
152962306a36Sopenharmony_ci	sizes[0] = size;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	return 0;
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic int pxp_buf_prepare(struct vb2_buffer *vb)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
153962306a36Sopenharmony_ci	struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
154062306a36Sopenharmony_ci	struct pxp_dev *dev = ctx->dev;
154162306a36Sopenharmony_ci	struct pxp_q_data *q_data;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	q_data = get_q_data(ctx, vb->vb2_queue->type);
154662306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
154762306a36Sopenharmony_ci		if (vbuf->field == V4L2_FIELD_ANY)
154862306a36Sopenharmony_ci			vbuf->field = V4L2_FIELD_NONE;
154962306a36Sopenharmony_ci		if (vbuf->field != V4L2_FIELD_NONE) {
155062306a36Sopenharmony_ci			dprintk(dev, "%s field isn't supported\n", __func__);
155162306a36Sopenharmony_ci			return -EINVAL;
155262306a36Sopenharmony_ci		}
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
155662306a36Sopenharmony_ci		dprintk(dev, "%s data will not fit into plane (%lu < %lu)\n",
155762306a36Sopenharmony_ci			__func__, vb2_plane_size(vb, 0),
155862306a36Sopenharmony_ci			(long)q_data->sizeimage);
155962306a36Sopenharmony_ci		return -EINVAL;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	vb2_set_plane_payload(vb, 0, q_data->sizeimage);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	return 0;
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cistatic void pxp_buf_queue(struct vb2_buffer *vb)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
157062306a36Sopenharmony_ci	struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic int pxp_start_streaming(struct vb2_queue *q, unsigned int count)
157662306a36Sopenharmony_ci{
157762306a36Sopenharmony_ci	struct pxp_ctx *ctx = vb2_get_drv_priv(q);
157862306a36Sopenharmony_ci	struct pxp_q_data *q_data = get_q_data(ctx, q->type);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	q_data->sequence = 0;
158162306a36Sopenharmony_ci	return 0;
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic void pxp_stop_streaming(struct vb2_queue *q)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	struct pxp_ctx *ctx = vb2_get_drv_priv(q);
158762306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
158862306a36Sopenharmony_ci	unsigned long flags;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	for (;;) {
159162306a36Sopenharmony_ci		if (V4L2_TYPE_IS_OUTPUT(q->type))
159262306a36Sopenharmony_ci			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
159362306a36Sopenharmony_ci		else
159462306a36Sopenharmony_ci			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
159562306a36Sopenharmony_ci		if (vbuf == NULL)
159662306a36Sopenharmony_ci			return;
159762306a36Sopenharmony_ci		spin_lock_irqsave(&ctx->dev->irqlock, flags);
159862306a36Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
159962306a36Sopenharmony_ci		spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
160062306a36Sopenharmony_ci	}
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic const struct vb2_ops pxp_qops = {
160462306a36Sopenharmony_ci	.queue_setup	 = pxp_queue_setup,
160562306a36Sopenharmony_ci	.buf_prepare	 = pxp_buf_prepare,
160662306a36Sopenharmony_ci	.buf_queue	 = pxp_buf_queue,
160762306a36Sopenharmony_ci	.start_streaming = pxp_start_streaming,
160862306a36Sopenharmony_ci	.stop_streaming  = pxp_stop_streaming,
160962306a36Sopenharmony_ci	.wait_prepare	 = vb2_ops_wait_prepare,
161062306a36Sopenharmony_ci	.wait_finish	 = vb2_ops_wait_finish,
161162306a36Sopenharmony_ci};
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_cistatic int queue_init(void *priv, struct vb2_queue *src_vq,
161462306a36Sopenharmony_ci		      struct vb2_queue *dst_vq)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	struct pxp_ctx *ctx = priv;
161762306a36Sopenharmony_ci	int ret;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
162062306a36Sopenharmony_ci	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
162162306a36Sopenharmony_ci	src_vq->drv_priv = ctx;
162262306a36Sopenharmony_ci	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
162362306a36Sopenharmony_ci	src_vq->ops = &pxp_qops;
162462306a36Sopenharmony_ci	src_vq->mem_ops = &vb2_dma_contig_memops;
162562306a36Sopenharmony_ci	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
162662306a36Sopenharmony_ci	src_vq->lock = &ctx->dev->dev_mutex;
162762306a36Sopenharmony_ci	src_vq->dev = ctx->dev->v4l2_dev.dev;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	ret = vb2_queue_init(src_vq);
163062306a36Sopenharmony_ci	if (ret)
163162306a36Sopenharmony_ci		return ret;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
163462306a36Sopenharmony_ci	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
163562306a36Sopenharmony_ci	dst_vq->drv_priv = ctx;
163662306a36Sopenharmony_ci	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
163762306a36Sopenharmony_ci	dst_vq->ops = &pxp_qops;
163862306a36Sopenharmony_ci	dst_vq->mem_ops = &vb2_dma_contig_memops;
163962306a36Sopenharmony_ci	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
164062306a36Sopenharmony_ci	dst_vq->lock = &ctx->dev->dev_mutex;
164162306a36Sopenharmony_ci	dst_vq->dev = ctx->dev->v4l2_dev.dev;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	return vb2_queue_init(dst_vq);
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci/*
164762306a36Sopenharmony_ci * File operations
164862306a36Sopenharmony_ci */
164962306a36Sopenharmony_cistatic int pxp_open(struct file *file)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	struct pxp_dev *dev = video_drvdata(file);
165262306a36Sopenharmony_ci	struct pxp_ctx *ctx = NULL;
165362306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl;
165462306a36Sopenharmony_ci	int rc = 0;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	if (mutex_lock_interruptible(&dev->dev_mutex))
165762306a36Sopenharmony_ci		return -ERESTARTSYS;
165862306a36Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
165962306a36Sopenharmony_ci	if (!ctx) {
166062306a36Sopenharmony_ci		rc = -ENOMEM;
166162306a36Sopenharmony_ci		goto open_unlock;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	v4l2_fh_init(&ctx->fh, video_devdata(file));
166562306a36Sopenharmony_ci	file->private_data = &ctx->fh;
166662306a36Sopenharmony_ci	ctx->dev = dev;
166762306a36Sopenharmony_ci	hdl = &ctx->hdl;
166862306a36Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 4);
166962306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
167062306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
167162306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
167262306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
167362306a36Sopenharmony_ci			  0, 255, 1, 255);
167462306a36Sopenharmony_ci	if (hdl->error) {
167562306a36Sopenharmony_ci		rc = hdl->error;
167662306a36Sopenharmony_ci		v4l2_ctrl_handler_free(hdl);
167762306a36Sopenharmony_ci		kfree(ctx);
167862306a36Sopenharmony_ci		goto open_unlock;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci	ctx->fh.ctrl_handler = hdl;
168162306a36Sopenharmony_ci	v4l2_ctrl_handler_setup(hdl);
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
168462306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].width = 640;
168562306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].height = 480;
168662306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].bytesperline =
168762306a36Sopenharmony_ci		pxp_bytesperline(&formats[0], 640);
168862306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_SRC].sizeimage =
168962306a36Sopenharmony_ci		pxp_sizeimage(&formats[0], 640, 480);
169062306a36Sopenharmony_ci	ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
169162306a36Sopenharmony_ci	ctx->colorspace = V4L2_COLORSPACE_REC709;
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	if (IS_ERR(ctx->fh.m2m_ctx)) {
169662306a36Sopenharmony_ci		rc = PTR_ERR(ctx->fh.m2m_ctx);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci		v4l2_ctrl_handler_free(hdl);
169962306a36Sopenharmony_ci		v4l2_fh_exit(&ctx->fh);
170062306a36Sopenharmony_ci		kfree(ctx);
170162306a36Sopenharmony_ci		goto open_unlock;
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	v4l2_fh_add(&ctx->fh);
170562306a36Sopenharmony_ci	atomic_inc(&dev->num_inst);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
170862306a36Sopenharmony_ci		ctx, ctx->fh.m2m_ctx);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ciopen_unlock:
171162306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
171262306a36Sopenharmony_ci	return rc;
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistatic int pxp_release(struct file *file)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	struct pxp_dev *dev = video_drvdata(file);
171862306a36Sopenharmony_ci	struct pxp_ctx *ctx = file2ctx(file);
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	dprintk(dev, "Releasing instance %p\n", ctx);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	v4l2_fh_del(&ctx->fh);
172362306a36Sopenharmony_ci	v4l2_fh_exit(&ctx->fh);
172462306a36Sopenharmony_ci	v4l2_ctrl_handler_free(&ctx->hdl);
172562306a36Sopenharmony_ci	mutex_lock(&dev->dev_mutex);
172662306a36Sopenharmony_ci	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
172762306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
172862306a36Sopenharmony_ci	kfree(ctx);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	atomic_dec(&dev->num_inst);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	return 0;
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic const struct v4l2_file_operations pxp_fops = {
173662306a36Sopenharmony_ci	.owner		= THIS_MODULE,
173762306a36Sopenharmony_ci	.open		= pxp_open,
173862306a36Sopenharmony_ci	.release	= pxp_release,
173962306a36Sopenharmony_ci	.poll		= v4l2_m2m_fop_poll,
174062306a36Sopenharmony_ci	.unlocked_ioctl	= video_ioctl2,
174162306a36Sopenharmony_ci	.mmap		= v4l2_m2m_fop_mmap,
174262306a36Sopenharmony_ci};
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_cistatic const struct video_device pxp_videodev = {
174562306a36Sopenharmony_ci	.name		= MEM2MEM_NAME,
174662306a36Sopenharmony_ci	.vfl_dir	= VFL_DIR_M2M,
174762306a36Sopenharmony_ci	.fops		= &pxp_fops,
174862306a36Sopenharmony_ci	.device_caps	= V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
174962306a36Sopenharmony_ci	.ioctl_ops	= &pxp_ioctl_ops,
175062306a36Sopenharmony_ci	.minor		= -1,
175162306a36Sopenharmony_ci	.release	= video_device_release_empty,
175262306a36Sopenharmony_ci};
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_cistatic const struct v4l2_m2m_ops m2m_ops = {
175562306a36Sopenharmony_ci	.device_run	= pxp_device_run,
175662306a36Sopenharmony_ci	.job_ready	= pxp_job_ready,
175762306a36Sopenharmony_ci	.job_abort	= pxp_job_abort,
175862306a36Sopenharmony_ci};
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic int pxp_soft_reset(struct pxp_dev *dev)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	int ret;
176362306a36Sopenharmony_ci	u32 val;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
176662306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(dev->regmap, HW_PXP_CTRL, val,
177162306a36Sopenharmony_ci				       val & BM_PXP_CTRL_CLKGATE, 0, 100);
177262306a36Sopenharmony_ci	if (ret < 0)
177362306a36Sopenharmony_ci		return ret;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
177662306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	return 0;
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistatic int pxp_probe(struct platform_device *pdev)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	struct pxp_dev *dev;
178462306a36Sopenharmony_ci	struct video_device *vfd;
178562306a36Sopenharmony_ci	u32 hw_version;
178662306a36Sopenharmony_ci	int irq;
178762306a36Sopenharmony_ci	int ret;
178862306a36Sopenharmony_ci	void __iomem *mmio;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
179162306a36Sopenharmony_ci	if (!dev)
179262306a36Sopenharmony_ci		return -ENOMEM;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	dev->pdata = of_device_get_match_data(&pdev->dev);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	dev->clk = devm_clk_get(&pdev->dev, "axi");
179762306a36Sopenharmony_ci	if (IS_ERR(dev->clk)) {
179862306a36Sopenharmony_ci		ret = PTR_ERR(dev->clk);
179962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get clk: %d\n", ret);
180062306a36Sopenharmony_ci		return ret;
180162306a36Sopenharmony_ci	}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	mmio = devm_platform_ioremap_resource(pdev, 0);
180462306a36Sopenharmony_ci	if (IS_ERR(mmio))
180562306a36Sopenharmony_ci		return PTR_ERR(mmio);
180662306a36Sopenharmony_ci	dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio,
180762306a36Sopenharmony_ci					    &pxp_regmap_config);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
181062306a36Sopenharmony_ci	if (irq < 0)
181162306a36Sopenharmony_ci		return irq;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	spin_lock_init(&dev->irqlock);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0,
181662306a36Sopenharmony_ci			       dev_name(&pdev->dev), dev);
181762306a36Sopenharmony_ci	if (ret < 0) {
181862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
181962306a36Sopenharmony_ci		return ret;
182062306a36Sopenharmony_ci	}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	ret = clk_prepare_enable(dev->clk);
182362306a36Sopenharmony_ci	if (ret < 0)
182462306a36Sopenharmony_ci		return ret;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	ret = pxp_soft_reset(dev);
182762306a36Sopenharmony_ci	if (ret < 0) {
182862306a36Sopenharmony_ci		dev_err(&pdev->dev, "PXP reset timeout: %d\n", ret);
182962306a36Sopenharmony_ci		goto err_clk;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	hw_version = pxp_read(dev, HW_PXP_VERSION);
183362306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "PXP Version %u.%u\n",
183462306a36Sopenharmony_ci		PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version));
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
183762306a36Sopenharmony_ci	if (ret)
183862306a36Sopenharmony_ci		goto err_clk;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	atomic_set(&dev->num_inst, 0);
184162306a36Sopenharmony_ci	mutex_init(&dev->dev_mutex);
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	dev->vfd = pxp_videodev;
184462306a36Sopenharmony_ci	vfd = &dev->vfd;
184562306a36Sopenharmony_ci	vfd->lock = &dev->dev_mutex;
184662306a36Sopenharmony_ci	vfd->v4l2_dev = &dev->v4l2_dev;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	video_set_drvdata(vfd, dev);
184962306a36Sopenharmony_ci	snprintf(vfd->name, sizeof(vfd->name), "%s", pxp_videodev.name);
185062306a36Sopenharmony_ci	v4l2_info(&dev->v4l2_dev,
185162306a36Sopenharmony_ci			"Device registered as /dev/video%d\n", vfd->num);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	platform_set_drvdata(pdev, dev);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
185662306a36Sopenharmony_ci	if (IS_ERR(dev->m2m_dev)) {
185762306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
185862306a36Sopenharmony_ci		ret = PTR_ERR(dev->m2m_dev);
185962306a36Sopenharmony_ci		goto err_v4l2;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
186362306a36Sopenharmony_ci	if (ret) {
186462306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
186562306a36Sopenharmony_ci		goto err_m2m;
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
186962306a36Sopenharmony_ci	dev->mdev.dev = &pdev->dev;
187062306a36Sopenharmony_ci	strscpy(dev->mdev.model, MEM2MEM_NAME, sizeof(dev->mdev.model));
187162306a36Sopenharmony_ci	media_device_init(&dev->mdev);
187262306a36Sopenharmony_ci	dev->v4l2_dev.mdev = &dev->mdev;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
187562306a36Sopenharmony_ci						 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
187662306a36Sopenharmony_ci	if (ret) {
187762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to initialize media device\n");
187862306a36Sopenharmony_ci		goto err_vfd;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	ret = media_device_register(&dev->mdev);
188262306a36Sopenharmony_ci	if (ret) {
188362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register media device\n");
188462306a36Sopenharmony_ci		goto err_m2m_mc;
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci#endif
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	return 0;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
189162306a36Sopenharmony_cierr_m2m_mc:
189262306a36Sopenharmony_ci	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
189362306a36Sopenharmony_cierr_vfd:
189462306a36Sopenharmony_ci	video_unregister_device(vfd);
189562306a36Sopenharmony_ci#endif
189662306a36Sopenharmony_cierr_m2m:
189762306a36Sopenharmony_ci	v4l2_m2m_release(dev->m2m_dev);
189862306a36Sopenharmony_cierr_v4l2:
189962306a36Sopenharmony_ci	v4l2_device_unregister(&dev->v4l2_dev);
190062306a36Sopenharmony_cierr_clk:
190162306a36Sopenharmony_ci	clk_disable_unprepare(dev->clk);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	return ret;
190462306a36Sopenharmony_ci}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_cistatic void pxp_remove(struct platform_device *pdev)
190762306a36Sopenharmony_ci{
190862306a36Sopenharmony_ci	struct pxp_dev *dev = platform_get_drvdata(pdev);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_CLKGATE);
191162306a36Sopenharmony_ci	pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	clk_disable_unprepare(dev->clk);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
191862306a36Sopenharmony_ci	media_device_unregister(&dev->mdev);
191962306a36Sopenharmony_ci	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
192062306a36Sopenharmony_ci#endif
192162306a36Sopenharmony_ci	video_unregister_device(&dev->vfd);
192262306a36Sopenharmony_ci	v4l2_m2m_release(dev->m2m_dev);
192362306a36Sopenharmony_ci	v4l2_device_unregister(&dev->v4l2_dev);
192462306a36Sopenharmony_ci}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_cistatic const struct pxp_pdata pxp_imx6ull_pdata = {
192762306a36Sopenharmony_ci	.data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0,
192862306a36Sopenharmony_ci};
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_cistatic const struct pxp_pdata pxp_imx7d_pdata = {
193162306a36Sopenharmony_ci	.data_path_ctrl0 = pxp_imx7d_data_path_ctrl0,
193262306a36Sopenharmony_ci};
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_cistatic const struct of_device_id pxp_dt_ids[] = {
193562306a36Sopenharmony_ci	{ .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata },
193662306a36Sopenharmony_ci	{ .compatible = "fsl,imx7d-pxp", .data = &pxp_imx7d_pdata },
193762306a36Sopenharmony_ci	{ },
193862306a36Sopenharmony_ci};
193962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pxp_dt_ids);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_cistatic struct platform_driver pxp_driver = {
194262306a36Sopenharmony_ci	.probe		= pxp_probe,
194362306a36Sopenharmony_ci	.remove_new	= pxp_remove,
194462306a36Sopenharmony_ci	.driver		= {
194562306a36Sopenharmony_ci		.name	= MEM2MEM_NAME,
194662306a36Sopenharmony_ci		.of_match_table = pxp_dt_ids,
194762306a36Sopenharmony_ci	},
194862306a36Sopenharmony_ci};
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cimodule_platform_driver(pxp_driver);
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ciMODULE_DESCRIPTION("i.MX PXP mem2mem scaler/CSC/rotator");
195362306a36Sopenharmony_ciMODULE_AUTHOR("Philipp Zabel <kernel@pengutronix.de>");
195462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1955