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