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