// SPDX-License-Identifier: GPL-2.0
/*
* sh-mobile VEU mem2mem driver
*
* Copyright (C) 2012 Renesas Electronics Corporation
* Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
* Copyright (C) 2008 Magnus Damm
*/
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-image-sizes.h>
#include <media/videobuf2-dma-contig.h>
#define VEU_STR 0x00 /* start register */
#define VEU_SWR 0x10 /* src: line length */
#define VEU_SSR 0x14 /* src: image size */
#define VEU_SAYR 0x18 /* src: y/rgb plane address */
#define VEU_SACR 0x1c /* src: c plane address */
#define VEU_BSSR 0x20 /* bundle mode register */
#define VEU_EDWR 0x30 /* dst: line length */
#define VEU_DAYR 0x34 /* dst: y/rgb plane address */
#define VEU_DACR 0x38 /* dst: c plane address */
#define VEU_TRCR 0x50 /* transform control */
#define VEU_RFCR 0x54 /* resize scale */
#define VEU_RFSR 0x58 /* resize clip */
#define VEU_ENHR 0x5c /* enhance */
#define VEU_FMCR 0x70 /* filter mode */
#define VEU_VTCR 0x74 /* lowpass vertical */
#define VEU_HTCR 0x78 /* lowpass horizontal */
#define VEU_APCR 0x80 /* color match */
#define VEU_ECCR 0x84 /* color replace */
#define VEU_AFXR 0x90 /* fixed mode */
#define VEU_SWPR 0x94 /* swap */
#define VEU_EIER 0xa0 /* interrupt mask */
#define VEU_EVTR 0xa4 /* interrupt event */
#define VEU_STAR 0xb0 /* status */
#define VEU_BSRR 0xb4 /* reset */
#define VEU_MCR00 0x200 /* color conversion matrix coefficient 00 */
#define VEU_MCR01 0x204 /* color conversion matrix coefficient 01 */
#define VEU_MCR02 0x208 /* color conversion matrix coefficient 02 */
#define VEU_MCR10 0x20c /* color conversion matrix coefficient 10 */
#define VEU_MCR11 0x210 /* color conversion matrix coefficient 11 */
#define VEU_MCR12 0x214 /* color conversion matrix coefficient 12 */
#define VEU_MCR20 0x218 /* color conversion matrix coefficient 20 */
#define VEU_MCR21 0x21c /* color conversion matrix coefficient 21 */
#define VEU_MCR22 0x220 /* color conversion matrix coefficient 22 */
#define VEU_COFFR 0x224 /* color conversion offset */
#define VEU_CBR 0x228 /* color conversion clip */
/*
* 4092x4092 max size is the normal case. In some cases it can be reduced to
* 2048x2048, in other cases it can be 4092x8188 or even 8188x8188.
*/
#define MAX_W 4092
#define MAX_H 4092
#define MIN_W 8
#define MIN_H 8
#define ALIGN_W 4
/* 3 buffers of 2048 x 1536 - 3 megapixels @ 16bpp */
#define VIDEO_MEM_LIMIT ALIGN(2048 * 1536 * 2 * 3, 1024 * 1024)
#define MEM2MEM_DEF_TRANSLEN 1
struct sh_veu_dev;
struct sh_veu_file {
struct sh_veu_dev *veu_dev;
bool cfg_needed;
};
struct sh_veu_format {
char *name;
u32 fourcc;
unsigned int depth;
unsigned int ydepth;
};
/* video data format */
struct sh_veu_vfmt {
/* Replace with v4l2_rect */
struct v4l2_rect frame;
unsigned int bytesperline;
unsigned int offset_y;
unsigned int offset_c;
const struct sh_veu_format *fmt;
};
struct sh_veu_dev {
struct v4l2_device v4l2_dev;
struct video_device vdev;
struct v4l2_m2m_dev *m2m_dev;
struct device *dev;
struct v4l2_m2m_ctx *m2m_ctx;
struct sh_veu_vfmt vfmt_out;
struct sh_veu_vfmt vfmt_in;
/* Only single user per direction so far */
struct sh_veu_file *capture;
struct sh_veu_file *output;
struct mutex fop_lock;
void __iomem *base;
spinlock_t lock;
bool is_2h;
unsigned int xaction;
bool aborting;
};
enum sh_veu_fmt_idx {
SH_VEU_FMT_NV12,
SH_VEU_FMT_NV16,
SH_VEU_FMT_NV24,
SH_VEU_FMT_RGB332,
SH_VEU_FMT_RGB444,
SH_VEU_FMT_RGB565,
SH_VEU_FMT_RGB666,
SH_VEU_FMT_RGB24,
};
#define DEFAULT_IN_WIDTH VGA_WIDTH
#define DEFAULT_IN_HEIGHT VGA_HEIGHT
#define DEFAULT_IN_FMTIDX SH_VEU_FMT_NV12
#define DEFAULT_OUT_WIDTH VGA_WIDTH
#define DEFAULT_OUT_HEIGHT VGA_HEIGHT
#define DEFAULT_OUT_FMTIDX SH_VEU_FMT_RGB565
/*
* Alignment: Y-plane should be 4-byte aligned for NV12 and NV16, and 8-byte
* aligned for NV24.
*/
static const struct sh_veu_format sh_veu_fmt[] = {
[SH_VEU_FMT_NV12] = { .ydepth = 8, .depth = 12, .name = "NV12", .fourcc = V4L2_PIX_FMT_NV12 },
[SH_VEU_FMT_NV16] = { .ydepth