cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sh_vou.c (37657B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * SuperH Video Output Unit (VOU) driver
      4 *
      5 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
      6 */
      7
      8#include <linux/dma-mapping.h>
      9#include <linux/delay.h>
     10#include <linux/errno.h>
     11#include <linux/fs.h>
     12#include <linux/i2c.h>
     13#include <linux/init.h>
     14#include <linux/interrupt.h>
     15#include <linux/kernel.h>
     16#include <linux/platform_device.h>
     17#include <linux/pm_runtime.h>
     18#include <linux/slab.h>
     19#include <linux/videodev2.h>
     20#include <linux/module.h>
     21
     22#include <media/drv-intf/sh_vou.h>
     23#include <media/v4l2-common.h>
     24#include <media/v4l2-device.h>
     25#include <media/v4l2-ioctl.h>
     26#include <media/v4l2-mediabus.h>
     27#include <media/videobuf2-v4l2.h>
     28#include <media/videobuf2-dma-contig.h>
     29
     30/* Mirror addresses are not available for all registers */
     31#define VOUER	0
     32#define VOUCR	4
     33#define VOUSTR	8
     34#define VOUVCR	0xc
     35#define VOUISR	0x10
     36#define VOUBCR	0x14
     37#define VOUDPR	0x18
     38#define VOUDSR	0x1c
     39#define VOUVPR	0x20
     40#define VOUIR	0x24
     41#define VOUSRR	0x28
     42#define VOUMSR	0x2c
     43#define VOUHIR	0x30
     44#define VOUDFR	0x34
     45#define VOUAD1R	0x38
     46#define VOUAD2R	0x3c
     47#define VOUAIR	0x40
     48#define VOUSWR	0x44
     49#define VOURCR	0x48
     50#define VOURPR	0x50
     51
     52enum sh_vou_status {
     53	SH_VOU_IDLE,
     54	SH_VOU_INITIALISING,
     55	SH_VOU_RUNNING,
     56};
     57
     58#define VOU_MIN_IMAGE_WIDTH	16
     59#define VOU_MAX_IMAGE_WIDTH	720
     60#define VOU_MIN_IMAGE_HEIGHT	16
     61
     62struct sh_vou_buffer {
     63	struct vb2_v4l2_buffer vb;
     64	struct list_head list;
     65};
     66
     67static inline struct
     68sh_vou_buffer *to_sh_vou_buffer(struct vb2_v4l2_buffer *vb2)
     69{
     70	return container_of(vb2, struct sh_vou_buffer, vb);
     71}
     72
     73struct sh_vou_device {
     74	struct v4l2_device v4l2_dev;
     75	struct video_device vdev;
     76	struct sh_vou_pdata *pdata;
     77	spinlock_t lock;
     78	void __iomem *base;
     79	/* State information */
     80	struct v4l2_pix_format pix;
     81	struct v4l2_rect rect;
     82	struct list_head buf_list;
     83	v4l2_std_id std;
     84	int pix_idx;
     85	struct vb2_queue queue;
     86	struct sh_vou_buffer *active;
     87	enum sh_vou_status status;
     88	unsigned sequence;
     89	struct mutex fop_lock;
     90};
     91
     92/* Register access routines for sides A, B and mirror addresses */
     93static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg,
     94			       u32 value)
     95{
     96	__raw_writel(value, vou_dev->base + reg);
     97}
     98
     99static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg,
    100				u32 value)
    101{
    102	__raw_writel(value, vou_dev->base + reg);
    103	__raw_writel(value, vou_dev->base + reg + 0x1000);
    104}
    105
    106static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg,
    107			       u32 value)
    108{
    109	__raw_writel(value, vou_dev->base + reg + 0x2000);
    110}
    111
    112static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg)
    113{
    114	return __raw_readl(vou_dev->base + reg);
    115}
    116
    117static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg,
    118			     u32 value, u32 mask)
    119{
    120	u32 old = __raw_readl(vou_dev->base + reg);
    121
    122	value = (value & mask) | (old & ~mask);
    123	__raw_writel(value, vou_dev->base + reg);
    124}
    125
    126static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg,
    127			     u32 value, u32 mask)
    128{
    129	sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask);
    130}
    131
    132static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
    133			      u32 value, u32 mask)
    134{
    135	sh_vou_reg_a_set(vou_dev, reg, value, mask);
    136	sh_vou_reg_b_set(vou_dev, reg, value, mask);
    137}
    138
    139struct sh_vou_fmt {
    140	u32		pfmt;
    141	unsigned char	bpp;
    142	unsigned char	bpl;
    143	unsigned char	rgb;
    144	unsigned char	yf;
    145	unsigned char	pkf;
    146};
    147
    148/* Further pixel formats can be added */
    149static struct sh_vou_fmt vou_fmt[] = {
    150	{
    151		.pfmt	= V4L2_PIX_FMT_NV12,
    152		.bpp	= 12,
    153		.bpl	= 1,
    154		.yf	= 0,
    155		.rgb	= 0,
    156	},
    157	{
    158		.pfmt	= V4L2_PIX_FMT_NV16,
    159		.bpp	= 16,
    160		.bpl	= 1,
    161		.yf	= 1,
    162		.rgb	= 0,
    163	},
    164	{
    165		.pfmt	= V4L2_PIX_FMT_RGB24,
    166		.bpp	= 24,
    167		.bpl	= 3,
    168		.pkf	= 2,
    169		.rgb	= 1,
    170	},
    171	{
    172		.pfmt	= V4L2_PIX_FMT_RGB565,
    173		.bpp	= 16,
    174		.bpl	= 2,
    175		.pkf	= 3,
    176		.rgb	= 1,
    177	},
    178	{
    179		.pfmt	= V4L2_PIX_FMT_RGB565X,
    180		.bpp	= 16,
    181		.bpl	= 2,
    182		.pkf	= 3,
    183		.rgb	= 1,
    184	},
    185};
    186
    187static void sh_vou_schedule_next(struct sh_vou_device *vou_dev,
    188				 struct vb2_v4l2_buffer *vbuf)
    189{
    190	dma_addr_t addr1, addr2;
    191
    192	addr1 = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
    193	switch (vou_dev->pix.pixelformat) {
    194	case V4L2_PIX_FMT_NV12:
    195	case V4L2_PIX_FMT_NV16:
    196		addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height;
    197		break;
    198	default:
    199		addr2 = 0;
    200	}
    201
    202	sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1);
    203	sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2);
    204}
    205
    206static void sh_vou_stream_config(struct sh_vou_device *vou_dev)
    207{
    208	unsigned int row_coeff;
    209#ifdef __LITTLE_ENDIAN
    210	u32 dataswap = 7;
    211#else
    212	u32 dataswap = 0;
    213#endif
    214
    215	switch (vou_dev->pix.pixelformat) {
    216	default:
    217	case V4L2_PIX_FMT_NV12:
    218	case V4L2_PIX_FMT_NV16:
    219		row_coeff = 1;
    220		break;
    221	case V4L2_PIX_FMT_RGB565:
    222		dataswap ^= 1;
    223		fallthrough;
    224	case V4L2_PIX_FMT_RGB565X:
    225		row_coeff = 2;
    226		break;
    227	case V4L2_PIX_FMT_RGB24:
    228		row_coeff = 3;
    229		break;
    230	}
    231
    232	sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap);
    233	sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff);
    234}
    235
    236/* Locking: caller holds fop_lock mutex */
    237static int sh_vou_queue_setup(struct vb2_queue *vq,
    238		       unsigned int *nbuffers, unsigned int *nplanes,
    239		       unsigned int sizes[], struct device *alloc_devs[])
    240{
    241	struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq);
    242	struct v4l2_pix_format *pix = &vou_dev->pix;
    243	int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
    244
    245	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    246
    247	if (*nplanes)
    248		return sizes[0] < pix->height * bytes_per_line ? -EINVAL : 0;
    249	*nplanes = 1;
    250	sizes[0] = pix->height * bytes_per_line;
    251	return 0;
    252}
    253
    254static int sh_vou_buf_prepare(struct vb2_buffer *vb)
    255{
    256	struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue);
    257	struct v4l2_pix_format *pix = &vou_dev->pix;
    258	unsigned bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
    259	unsigned size = pix->height * bytes_per_line;
    260
    261	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    262
    263	if (vb2_plane_size(vb, 0) < size) {
    264		/* User buffer too small */
    265		dev_warn(vou_dev->v4l2_dev.dev, "buffer too small (%lu < %u)\n",
    266			 vb2_plane_size(vb, 0), size);
    267		return -EINVAL;
    268	}
    269
    270	vb2_set_plane_payload(vb, 0, size);
    271	return 0;
    272}
    273
    274/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
    275static void sh_vou_buf_queue(struct vb2_buffer *vb)
    276{
    277	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
    278	struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue);
    279	struct sh_vou_buffer *shbuf = to_sh_vou_buffer(vbuf);
    280	unsigned long flags;
    281
    282	spin_lock_irqsave(&vou_dev->lock, flags);
    283	list_add_tail(&shbuf->list, &vou_dev->buf_list);
    284	spin_unlock_irqrestore(&vou_dev->lock, flags);
    285}
    286
    287static int sh_vou_start_streaming(struct vb2_queue *vq, unsigned int count)
    288{
    289	struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq);
    290	struct sh_vou_buffer *buf, *node;
    291	int ret;
    292
    293	vou_dev->sequence = 0;
    294	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
    295					 video, s_stream, 1);
    296	if (ret < 0 && ret != -ENOIOCTLCMD) {
    297		list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) {
    298			vb2_buffer_done(&buf->vb.vb2_buf,
    299					VB2_BUF_STATE_QUEUED);
    300			list_del(&buf->list);
    301		}
    302		vou_dev->active = NULL;
    303		return ret;
    304	}
    305
    306	buf = list_entry(vou_dev->buf_list.next, struct sh_vou_buffer, list);
    307
    308	vou_dev->active = buf;
    309
    310	/* Start from side A: we use mirror addresses, so, set B */
    311	sh_vou_reg_a_write(vou_dev, VOURPR, 1);
    312	dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n",
    313		__func__, sh_vou_reg_a_read(vou_dev, VOUSTR));
    314	sh_vou_schedule_next(vou_dev, &buf->vb);
    315
    316	buf = list_entry(buf->list.next, struct sh_vou_buffer, list);
    317
    318	/* Second buffer - initialise register side B */
    319	sh_vou_reg_a_write(vou_dev, VOURPR, 0);
    320	sh_vou_schedule_next(vou_dev, &buf->vb);
    321
    322	/* Register side switching with frame VSYNC */
    323	sh_vou_reg_a_write(vou_dev, VOURCR, 5);
    324
    325	sh_vou_stream_config(vou_dev);
    326	/* Enable End-of-Frame (VSYNC) interrupts */
    327	sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
    328
    329	/* Two buffers on the queue - activate the hardware */
    330	vou_dev->status = SH_VOU_RUNNING;
    331	sh_vou_reg_a_write(vou_dev, VOUER, 0x107);
    332	return 0;
    333}
    334
    335static void sh_vou_stop_streaming(struct vb2_queue *vq)
    336{
    337	struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq);
    338	struct sh_vou_buffer *buf, *node;
    339	unsigned long flags;
    340
    341	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
    342					 video, s_stream, 0);
    343	/* disable output */
    344	sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
    345	/* ...but the current frame will complete */
    346	sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
    347	msleep(50);
    348	spin_lock_irqsave(&vou_dev->lock, flags);
    349	list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) {
    350		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
    351		list_del(&buf->list);
    352	}
    353	vou_dev->active = NULL;
    354	spin_unlock_irqrestore(&vou_dev->lock, flags);
    355}
    356
    357static const struct vb2_ops sh_vou_qops = {
    358	.queue_setup		= sh_vou_queue_setup,
    359	.buf_prepare		= sh_vou_buf_prepare,
    360	.buf_queue		= sh_vou_buf_queue,
    361	.start_streaming	= sh_vou_start_streaming,
    362	.stop_streaming		= sh_vou_stop_streaming,
    363	.wait_prepare		= vb2_ops_wait_prepare,
    364	.wait_finish		= vb2_ops_wait_finish,
    365};
    366
    367/* Video IOCTLs */
    368static int sh_vou_querycap(struct file *file, void  *priv,
    369			   struct v4l2_capability *cap)
    370{
    371	struct sh_vou_device *vou_dev = video_drvdata(file);
    372
    373	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    374
    375	strscpy(cap->card, "SuperH VOU", sizeof(cap->card));
    376	strscpy(cap->driver, "sh-vou", sizeof(cap->driver));
    377	strscpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info));
    378	return 0;
    379}
    380
    381/* Enumerate formats, that the device can accept from the user */
    382static int sh_vou_enum_fmt_vid_out(struct file *file, void  *priv,
    383				   struct v4l2_fmtdesc *fmt)
    384{
    385	struct sh_vou_device *vou_dev = video_drvdata(file);
    386
    387	if (fmt->index >= ARRAY_SIZE(vou_fmt))
    388		return -EINVAL;
    389
    390	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    391
    392	fmt->pixelformat = vou_fmt[fmt->index].pfmt;
    393
    394	return 0;
    395}
    396
    397static int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
    398				struct v4l2_format *fmt)
    399{
    400	struct sh_vou_device *vou_dev = video_drvdata(file);
    401
    402	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    403
    404	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    405	fmt->fmt.pix = vou_dev->pix;
    406
    407	return 0;
    408}
    409
    410static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4};
    411static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1};
    412static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3};
    413static const unsigned char vou_scale_v_num[] = {1, 2, 4};
    414static const unsigned char vou_scale_v_den[] = {1, 1, 1};
    415static const unsigned char vou_scale_v_fld[] = {0, 1};
    416
    417static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
    418				      int pix_idx, int w_idx, int h_idx)
    419{
    420	struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
    421	unsigned int black_left, black_top, width_max,
    422		frame_in_height, frame_out_height, frame_out_top;
    423	struct v4l2_rect *rect = &vou_dev->rect;
    424	struct v4l2_pix_format *pix = &vou_dev->pix;
    425	u32 vouvcr = 0, dsr_h, dsr_v;
    426
    427	if (vou_dev->std & V4L2_STD_525_60) {
    428		width_max = 858;
    429		/* height_max = 262; */
    430	} else {
    431		width_max = 864;
    432		/* height_max = 312; */
    433	}
    434
    435	frame_in_height = pix->height / 2;
    436	frame_out_height = rect->height / 2;
    437	frame_out_top = rect->top / 2;
    438
    439	/*
    440	 * Cropping scheme: max useful image is 720x480, and the total video
    441	 * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts
    442	 * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock,
    443	 * of which the first 33 / 25 clocks HSYNC must be held active. This
    444	 * has to be configured in CR[HW]. 1 pixel equals 2 clock periods.
    445	 * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives
    446	 * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area,
    447	 * beyond DSR, specified on the left and top by the VPR register "black
    448	 * pixels" and out-of-image area (DPR) "background pixels." We fix VPR
    449	 * at 138 / 144 : 20, because that's the HSYNC timing, that our first
    450	 * client requires, and that's exactly what leaves us 720 pixels for the
    451	 * image; we leave VPR[VVP] at default 20 for now, because the client
    452	 * doesn't seem to have any special requirements for it. Otherwise we
    453	 * could also set it to max - 240 = 22 / 72. Thus VPR depends only on
    454	 * the selected standard, and DPR and DSR are selected according to
    455	 * cropping. Q: how does the client detect the first valid line? Does
    456	 * HSYNC stay inactive during invalid (black) lines?
    457	 */
    458	black_left = width_max - VOU_MAX_IMAGE_WIDTH;
    459	black_top = 20;
    460
    461	dsr_h = rect->width + rect->left;
    462	dsr_v = frame_out_height + frame_out_top;
    463
    464	dev_dbg(vou_dev->v4l2_dev.dev,
    465		"image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n",
    466		pix->width, frame_in_height, black_left, black_top,
    467		rect->left, frame_out_top, dsr_h, dsr_v);
    468
    469	/* VOUISR height - half of a frame height in frame mode */
    470	sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height);
    471	sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top);
    472	sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top);
    473	sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v);
    474
    475	/*
    476	 * if necessary, we could set VOUHIR to
    477	 * max(black_left + dsr_h, width_max) here
    478	 */
    479
    480	if (w_idx)
    481		vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4);
    482	if (h_idx)
    483		vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
    484
    485	dev_dbg(vou_dev->v4l2_dev.dev, "0x%08x: scaling 0x%x\n",
    486		fmt->pfmt, vouvcr);
    487
    488	/* To produce a colour bar for testing set bit 23 of VOUVCR */
    489	sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
    490	sh_vou_reg_ab_write(vou_dev, VOUDFR,
    491			    fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16));
    492}
    493
    494struct sh_vou_geometry {
    495	struct v4l2_rect output;
    496	unsigned int in_width;
    497	unsigned int in_height;
    498	int scale_idx_h;
    499	int scale_idx_v;
    500};
    501
    502/*
    503 * Find input geometry, that we can use to produce output, closest to the
    504 * requested rectangle, using VOU scaling
    505 */
    506static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
    507{
    508	/* The compiler cannot know, that best and idx will indeed be set */
    509	unsigned int best_err = UINT_MAX, best = 0, img_height_max;
    510	int i, idx = 0;
    511
    512	if (std & V4L2_STD_525_60)
    513		img_height_max = 480;
    514	else
    515		img_height_max = 576;
    516
    517	/* Image width must be a multiple of 4 */
    518	v4l_bound_align_image(&geo->in_width,
    519			      VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2,
    520			      &geo->in_height,
    521			      VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0);
    522
    523	/* Select scales to come as close as possible to the output image */
    524	for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
    525		unsigned int err;
    526		unsigned int found = geo->output.width * vou_scale_h_den[i] /
    527			vou_scale_h_num[i];
    528
    529		if (found > VOU_MAX_IMAGE_WIDTH)
    530			/* scales increase */
    531			break;
    532
    533		err = abs(found - geo->in_width);
    534		if (err < best_err) {
    535			best_err = err;
    536			idx = i;
    537			best = found;
    538		}
    539		if (!err)
    540			break;
    541	}
    542
    543	geo->in_width = best;
    544	geo->scale_idx_h = idx;
    545
    546	best_err = UINT_MAX;
    547
    548	/* This loop can be replaced with one division */
    549	for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) {
    550		unsigned int err;
    551		unsigned int found = geo->output.height * vou_scale_v_den[i] /
    552			vou_scale_v_num[i];
    553
    554		if (found > img_height_max)
    555			/* scales increase */
    556			break;
    557
    558		err = abs(found - geo->in_height);
    559		if (err < best_err) {
    560			best_err = err;
    561			idx = i;
    562			best = found;
    563		}
    564		if (!err)
    565			break;
    566	}
    567
    568	geo->in_height = best;
    569	geo->scale_idx_v = idx;
    570}
    571
    572/*
    573 * Find output geometry, that we can produce, using VOU scaling, closest to
    574 * the requested rectangle
    575 */
    576static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
    577{
    578	unsigned int best_err = UINT_MAX, best = geo->in_width,
    579		width_max, height_max, img_height_max;
    580	int i, idx_h = 0, idx_v = 0;
    581
    582	if (std & V4L2_STD_525_60) {
    583		width_max = 858;
    584		height_max = 262 * 2;
    585		img_height_max = 480;
    586	} else {
    587		width_max = 864;
    588		height_max = 312 * 2;
    589		img_height_max = 576;
    590	}
    591
    592	/* Select scales to come as close as possible to the output image */
    593	for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) {
    594		unsigned int err;
    595		unsigned int found = geo->in_width * vou_scale_h_num[i] /
    596			vou_scale_h_den[i];
    597
    598		if (found > VOU_MAX_IMAGE_WIDTH)
    599			/* scales increase */
    600			break;
    601
    602		err = abs(found - geo->output.width);
    603		if (err < best_err) {
    604			best_err = err;
    605			idx_h = i;
    606			best = found;
    607		}
    608		if (!err)
    609			break;
    610	}
    611
    612	geo->output.width = best;
    613	geo->scale_idx_h = idx_h;
    614	if (geo->output.left + best > width_max)
    615		geo->output.left = width_max - best;
    616
    617	pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width,
    618		 vou_scale_h_num[idx_h], vou_scale_h_den[idx_h], best);
    619
    620	best_err = UINT_MAX;
    621
    622	/* This loop can be replaced with one division */
    623	for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) {
    624		unsigned int err;
    625		unsigned int found = geo->in_height * vou_scale_v_num[i] /
    626			vou_scale_v_den[i];
    627
    628		if (found > img_height_max)
    629			/* scales increase */
    630			break;
    631
    632		err = abs(found - geo->output.height);
    633		if (err < best_err) {
    634			best_err = err;
    635			idx_v = i;
    636			best = found;
    637		}
    638		if (!err)
    639			break;
    640	}
    641
    642	geo->output.height = best;
    643	geo->scale_idx_v = idx_v;
    644	if (geo->output.top + best > height_max)
    645		geo->output.top = height_max - best;
    646
    647	pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height,
    648		 vou_scale_v_num[idx_v], vou_scale_v_den[idx_v], best);
    649}
    650
    651static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
    652				  struct v4l2_format *fmt)
    653{
    654	struct sh_vou_device *vou_dev = video_drvdata(file);
    655	struct v4l2_pix_format *pix = &fmt->fmt.pix;
    656	unsigned int img_height_max;
    657	int pix_idx;
    658
    659	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    660
    661	pix->field = V4L2_FIELD_INTERLACED;
    662	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
    663	pix->ycbcr_enc = pix->quantization = 0;
    664
    665	for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
    666		if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
    667			break;
    668
    669	if (pix_idx == ARRAY_SIZE(vou_fmt))
    670		return -EINVAL;
    671
    672	if (vou_dev->std & V4L2_STD_525_60)
    673		img_height_max = 480;
    674	else
    675		img_height_max = 576;
    676
    677	v4l_bound_align_image(&pix->width,
    678			      VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2,
    679			      &pix->height,
    680			      VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0);
    681	pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl;
    682	pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3);
    683
    684	return 0;
    685}
    686
    687static int sh_vou_set_fmt_vid_out(struct sh_vou_device *vou_dev,
    688				struct v4l2_pix_format *pix)
    689{
    690	unsigned int img_height_max;
    691	struct sh_vou_geometry geo;
    692	struct v4l2_subdev_format format = {
    693		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
    694		/* Revisit: is this the correct code? */
    695		.format.code = MEDIA_BUS_FMT_YUYV8_2X8,
    696		.format.field = V4L2_FIELD_INTERLACED,
    697		.format.colorspace = V4L2_COLORSPACE_SMPTE170M,
    698	};
    699	struct v4l2_mbus_framefmt *mbfmt = &format.format;
    700	int pix_idx;
    701	int ret;
    702
    703	if (vb2_is_busy(&vou_dev->queue))
    704		return -EBUSY;
    705
    706	for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
    707		if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
    708			break;
    709
    710	geo.in_width = pix->width;
    711	geo.in_height = pix->height;
    712	geo.output = vou_dev->rect;
    713
    714	vou_adjust_output(&geo, vou_dev->std);
    715
    716	mbfmt->width = geo.output.width;
    717	mbfmt->height = geo.output.height;
    718	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad,
    719					 set_fmt, NULL, &format);
    720	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
    721	if (ret < 0)
    722		return ret;
    723
    724	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
    725		geo.output.width, geo.output.height, mbfmt->width, mbfmt->height);
    726
    727	if (vou_dev->std & V4L2_STD_525_60)
    728		img_height_max = 480;
    729	else
    730		img_height_max = 576;
    731
    732	/* Sanity checks */
    733	if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH ||
    734	    (unsigned)mbfmt->height > img_height_max ||
    735	    mbfmt->code != MEDIA_BUS_FMT_YUYV8_2X8)
    736		return -EIO;
    737
    738	if (mbfmt->width != geo.output.width ||
    739	    mbfmt->height != geo.output.height) {
    740		geo.output.width = mbfmt->width;
    741		geo.output.height = mbfmt->height;
    742
    743		vou_adjust_input(&geo, vou_dev->std);
    744	}
    745
    746	/* We tried to preserve output rectangle, but it could have changed */
    747	vou_dev->rect = geo.output;
    748	pix->width = geo.in_width;
    749	pix->height = geo.in_height;
    750
    751	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__,
    752		pix->width, pix->height);
    753
    754	vou_dev->pix_idx = pix_idx;
    755
    756	vou_dev->pix = *pix;
    757
    758	sh_vou_configure_geometry(vou_dev, pix_idx,
    759				  geo.scale_idx_h, geo.scale_idx_v);
    760
    761	return 0;
    762}
    763
    764static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
    765				struct v4l2_format *fmt)
    766{
    767	struct sh_vou_device *vou_dev = video_drvdata(file);
    768	int ret = sh_vou_try_fmt_vid_out(file, priv, fmt);
    769
    770	if (ret)
    771		return ret;
    772	return sh_vou_set_fmt_vid_out(vou_dev, &fmt->fmt.pix);
    773}
    774
    775static int sh_vou_enum_output(struct file *file, void *fh,
    776			      struct v4l2_output *a)
    777{
    778	struct sh_vou_device *vou_dev = video_drvdata(file);
    779
    780	if (a->index)
    781		return -EINVAL;
    782	strscpy(a->name, "Video Out", sizeof(a->name));
    783	a->type = V4L2_OUTPUT_TYPE_ANALOG;
    784	a->std = vou_dev->vdev.tvnorms;
    785	return 0;
    786}
    787
    788static int sh_vou_g_output(struct file *file, void *fh, unsigned int *i)
    789{
    790	*i = 0;
    791	return 0;
    792}
    793
    794static int sh_vou_s_output(struct file *file, void *fh, unsigned int i)
    795{
    796	return i ? -EINVAL : 0;
    797}
    798
    799static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
    800{
    801	switch (bus_fmt) {
    802	default:
    803		pr_warn("%s(): Invalid bus-format code %d, using default 8-bit\n",
    804			__func__, bus_fmt);
    805		fallthrough;
    806	case SH_VOU_BUS_8BIT:
    807		return 1;
    808	case SH_VOU_BUS_16BIT:
    809		return 0;
    810	case SH_VOU_BUS_BT656:
    811		return 3;
    812	}
    813}
    814
    815static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id)
    816{
    817	struct sh_vou_device *vou_dev = video_drvdata(file);
    818	int ret;
    819
    820	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id);
    821
    822	if (std_id == vou_dev->std)
    823		return 0;
    824
    825	if (vb2_is_busy(&vou_dev->queue))
    826		return -EBUSY;
    827
    828	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
    829					 s_std_output, std_id);
    830	/* Shall we continue, if the subdev doesn't support .s_std_output()? */
    831	if (ret < 0 && ret != -ENOIOCTLCMD)
    832		return ret;
    833
    834	vou_dev->rect.top = vou_dev->rect.left = 0;
    835	vou_dev->rect.width = VOU_MAX_IMAGE_WIDTH;
    836	if (std_id & V4L2_STD_525_60) {
    837		sh_vou_reg_ab_set(vou_dev, VOUCR,
    838			sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
    839		vou_dev->rect.height = 480;
    840	} else {
    841		sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
    842		vou_dev->rect.height = 576;
    843	}
    844
    845	vou_dev->pix.width = vou_dev->rect.width;
    846	vou_dev->pix.height = vou_dev->rect.height;
    847	vou_dev->pix.bytesperline =
    848		vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpl;
    849	vou_dev->pix.sizeimage = vou_dev->pix.height *
    850		((vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpp) >> 3);
    851	vou_dev->std = std_id;
    852	sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix);
    853
    854	return 0;
    855}
    856
    857static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
    858{
    859	struct sh_vou_device *vou_dev = video_drvdata(file);
    860
    861	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
    862
    863	*std = vou_dev->std;
    864
    865	return 0;
    866}
    867
    868static int sh_vou_log_status(struct file *file, void *priv)
    869{
    870	struct sh_vou_device *vou_dev = video_drvdata(file);
    871
    872	pr_info("VOUER:   0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUER));
    873	pr_info("VOUCR:   0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUCR));
    874	pr_info("VOUSTR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSTR));
    875	pr_info("VOUVCR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVCR));
    876	pr_info("VOUISR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUISR));
    877	pr_info("VOUBCR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUBCR));
    878	pr_info("VOUDPR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDPR));
    879	pr_info("VOUDSR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDSR));
    880	pr_info("VOUVPR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVPR));
    881	pr_info("VOUIR:   0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUIR));
    882	pr_info("VOUSRR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSRR));
    883	pr_info("VOUMSR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUMSR));
    884	pr_info("VOUHIR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUHIR));
    885	pr_info("VOUDFR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDFR));
    886	pr_info("VOUAD1R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD1R));
    887	pr_info("VOUAD2R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD2R));
    888	pr_info("VOUAIR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAIR));
    889	pr_info("VOUSWR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSWR));
    890	pr_info("VOURCR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURCR));
    891	pr_info("VOURPR:  0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURPR));
    892	return 0;
    893}
    894
    895static int sh_vou_g_selection(struct file *file, void *fh,
    896			      struct v4l2_selection *sel)
    897{
    898	struct sh_vou_device *vou_dev = video_drvdata(file);
    899
    900	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
    901		return -EINVAL;
    902	switch (sel->target) {
    903	case V4L2_SEL_TGT_COMPOSE:
    904		sel->r = vou_dev->rect;
    905		break;
    906	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
    907	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
    908		sel->r.left = 0;
    909		sel->r.top = 0;
    910		sel->r.width = VOU_MAX_IMAGE_WIDTH;
    911		if (vou_dev->std & V4L2_STD_525_60)
    912			sel->r.height = 480;
    913		else
    914			sel->r.height = 576;
    915		break;
    916	default:
    917		return -EINVAL;
    918	}
    919	return 0;
    920}
    921
    922/* Assume a dull encoder, do all the work ourselves. */
    923static int sh_vou_s_selection(struct file *file, void *fh,
    924			      struct v4l2_selection *sel)
    925{
    926	struct v4l2_rect *rect = &sel->r;
    927	struct sh_vou_device *vou_dev = video_drvdata(file);
    928	struct v4l2_subdev_selection sd_sel = {
    929		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
    930		.target = V4L2_SEL_TGT_COMPOSE,
    931	};
    932	struct v4l2_pix_format *pix = &vou_dev->pix;
    933	struct sh_vou_geometry geo;
    934	struct v4l2_subdev_format format = {
    935		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
    936		/* Revisit: is this the correct code? */
    937		.format.code = MEDIA_BUS_FMT_YUYV8_2X8,
    938		.format.field = V4L2_FIELD_INTERLACED,
    939		.format.colorspace = V4L2_COLORSPACE_SMPTE170M,
    940	};
    941	unsigned int img_height_max;
    942	int ret;
    943
    944	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
    945	    sel->target != V4L2_SEL_TGT_COMPOSE)
    946		return -EINVAL;
    947
    948	if (vb2_is_busy(&vou_dev->queue))
    949		return -EBUSY;
    950
    951	if (vou_dev->std & V4L2_STD_525_60)
    952		img_height_max = 480;
    953	else
    954		img_height_max = 576;
    955
    956	v4l_bound_align_image(&rect->width,
    957			      VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 1,
    958			      &rect->height,
    959			      VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0);
    960
    961	if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
    962		rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
    963
    964	if (rect->height + rect->top > img_height_max)
    965		rect->top = img_height_max - rect->height;
    966
    967	geo.output = *rect;
    968	geo.in_width = pix->width;
    969	geo.in_height = pix->height;
    970
    971	/* Configure the encoder one-to-one, position at 0, ignore errors */
    972	sd_sel.r.width = geo.output.width;
    973	sd_sel.r.height = geo.output.height;
    974	/*
    975	 * We first issue a S_SELECTION, so that the subsequent S_FMT delivers the
    976	 * final encoder configuration.
    977	 */
    978	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad,
    979				   set_selection, NULL, &sd_sel);
    980	format.format.width = geo.output.width;
    981	format.format.height = geo.output.height;
    982	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad,
    983					 set_fmt, NULL, &format);
    984	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
    985	if (ret < 0)
    986		return ret;
    987
    988	/* Sanity checks */
    989	if ((unsigned)format.format.width > VOU_MAX_IMAGE_WIDTH ||
    990	    (unsigned)format.format.height > img_height_max ||
    991	    format.format.code != MEDIA_BUS_FMT_YUYV8_2X8)
    992		return -EIO;
    993
    994	geo.output.width = format.format.width;
    995	geo.output.height = format.format.height;
    996
    997	/*
    998	 * No down-scaling. According to the API, current call has precedence:
    999	 * https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/crop.html#cropping-structures
   1000	 */
   1001	vou_adjust_input(&geo, vou_dev->std);
   1002
   1003	/* We tried to preserve output rectangle, but it could have changed */
   1004	vou_dev->rect = geo.output;
   1005	pix->width = geo.in_width;
   1006	pix->height = geo.in_height;
   1007
   1008	sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx,
   1009				  geo.scale_idx_h, geo.scale_idx_v);
   1010
   1011	return 0;
   1012}
   1013
   1014static irqreturn_t sh_vou_isr(int irq, void *dev_id)
   1015{
   1016	struct sh_vou_device *vou_dev = dev_id;
   1017	static unsigned long j;
   1018	struct sh_vou_buffer *vb;
   1019	static int cnt;
   1020	u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
   1021	u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
   1022
   1023	if (!(irq_status & 0x300)) {
   1024		if (printk_timed_ratelimit(&j, 500))
   1025			dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n",
   1026				 irq_status);
   1027		return IRQ_NONE;
   1028	}
   1029
   1030	spin_lock(&vou_dev->lock);
   1031	if (!vou_dev->active || list_empty(&vou_dev->buf_list)) {
   1032		if (printk_timed_ratelimit(&j, 500))
   1033			dev_warn(vou_dev->v4l2_dev.dev,
   1034				 "IRQ without active buffer: %x!\n", irq_status);
   1035		/* Just ack: buf_release will disable further interrupts */
   1036		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300);
   1037		spin_unlock(&vou_dev->lock);
   1038		return IRQ_HANDLED;
   1039	}
   1040
   1041	masked = ~(0x300 & irq_status) & irq_status & 0x30304;
   1042	dev_dbg(vou_dev->v4l2_dev.dev,
   1043		"IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n",
   1044		irq_status, masked, vou_status, cnt);
   1045
   1046	cnt++;
   1047	/* side = vou_status & 0x10000; */
   1048
   1049	/* Clear only set interrupts */
   1050	sh_vou_reg_a_write(vou_dev, VOUIR, masked);
   1051
   1052	vb = vou_dev->active;
   1053	if (list_is_singular(&vb->list)) {
   1054		/* Keep cycling while no next buffer is available */
   1055		sh_vou_schedule_next(vou_dev, &vb->vb);
   1056		spin_unlock(&vou_dev->lock);
   1057		return IRQ_HANDLED;
   1058	}
   1059
   1060	list_del(&vb->list);
   1061
   1062	vb->vb.vb2_buf.timestamp = ktime_get_ns();
   1063	vb->vb.sequence = vou_dev->sequence++;
   1064	vb->vb.field = V4L2_FIELD_INTERLACED;
   1065	vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE);
   1066
   1067	vou_dev->active = list_entry(vou_dev->buf_list.next,
   1068				     struct sh_vou_buffer, list);
   1069
   1070	if (list_is_singular(&vou_dev->buf_list)) {
   1071		/* Keep cycling while no next buffer is available */
   1072		sh_vou_schedule_next(vou_dev, &vou_dev->active->vb);
   1073	} else {
   1074		struct sh_vou_buffer *new = list_entry(vou_dev->active->list.next,
   1075						struct sh_vou_buffer, list);
   1076		sh_vou_schedule_next(vou_dev, &new->vb);
   1077	}
   1078
   1079	spin_unlock(&vou_dev->lock);
   1080
   1081	return IRQ_HANDLED;
   1082}
   1083
   1084static int sh_vou_hw_init(struct sh_vou_device *vou_dev)
   1085{
   1086	struct sh_vou_pdata *pdata = vou_dev->pdata;
   1087	u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29;
   1088	int i = 100;
   1089
   1090	/* Disable all IRQs */
   1091	sh_vou_reg_a_write(vou_dev, VOUIR, 0);
   1092
   1093	/* Reset VOU interfaces - registers unaffected */
   1094	sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101);
   1095	while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101))
   1096		udelay(1);
   1097
   1098	if (!i)
   1099		return -ETIMEDOUT;
   1100
   1101	dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i);
   1102
   1103	if (pdata->flags & SH_VOU_PCLK_FALLING)
   1104		voucr |= 1 << 28;
   1105	if (pdata->flags & SH_VOU_HSYNC_LOW)
   1106		voucr |= 1 << 27;
   1107	if (pdata->flags & SH_VOU_VSYNC_LOW)
   1108		voucr |= 1 << 26;
   1109	sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000);
   1110
   1111	/* Manual register side switching at first */
   1112	sh_vou_reg_a_write(vou_dev, VOURCR, 4);
   1113	/* Default - fixed HSYNC length, can be made configurable is required */
   1114	sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000);
   1115
   1116	sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix);
   1117
   1118	return 0;
   1119}
   1120
   1121/* File operations */
   1122static int sh_vou_open(struct file *file)
   1123{
   1124	struct sh_vou_device *vou_dev = video_drvdata(file);
   1125	int err;
   1126
   1127	if (mutex_lock_interruptible(&vou_dev->fop_lock))
   1128		return -ERESTARTSYS;
   1129
   1130	err = v4l2_fh_open(file);
   1131	if (err)
   1132		goto done_open;
   1133	if (v4l2_fh_is_singular_file(file) &&
   1134	    vou_dev->status == SH_VOU_INITIALISING) {
   1135		/* First open */
   1136		err = pm_runtime_resume_and_get(vou_dev->v4l2_dev.dev);
   1137		if (err < 0) {
   1138			v4l2_fh_release(file);
   1139			goto done_open;
   1140		}
   1141		err = sh_vou_hw_init(vou_dev);
   1142		if (err < 0) {
   1143			pm_runtime_put(vou_dev->v4l2_dev.dev);
   1144			v4l2_fh_release(file);
   1145		} else {
   1146			vou_dev->status = SH_VOU_IDLE;
   1147		}
   1148	}
   1149done_open:
   1150	mutex_unlock(&vou_dev->fop_lock);
   1151	return err;
   1152}
   1153
   1154static int sh_vou_release(struct file *file)
   1155{
   1156	struct sh_vou_device *vou_dev = video_drvdata(file);
   1157	bool is_last;
   1158
   1159	mutex_lock(&vou_dev->fop_lock);
   1160	is_last = v4l2_fh_is_singular_file(file);
   1161	_vb2_fop_release(file, NULL);
   1162	if (is_last) {
   1163		/* Last close */
   1164		vou_dev->status = SH_VOU_INITIALISING;
   1165		sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
   1166		pm_runtime_put(vou_dev->v4l2_dev.dev);
   1167	}
   1168	mutex_unlock(&vou_dev->fop_lock);
   1169	return 0;
   1170}
   1171
   1172/* sh_vou display ioctl operations */
   1173static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
   1174	.vidioc_querycap		= sh_vou_querycap,
   1175	.vidioc_enum_fmt_vid_out	= sh_vou_enum_fmt_vid_out,
   1176	.vidioc_g_fmt_vid_out		= sh_vou_g_fmt_vid_out,
   1177	.vidioc_s_fmt_vid_out		= sh_vou_s_fmt_vid_out,
   1178	.vidioc_try_fmt_vid_out		= sh_vou_try_fmt_vid_out,
   1179	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
   1180	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
   1181	.vidioc_querybuf		= vb2_ioctl_querybuf,
   1182	.vidioc_qbuf			= vb2_ioctl_qbuf,
   1183	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
   1184	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
   1185	.vidioc_streamon		= vb2_ioctl_streamon,
   1186	.vidioc_streamoff		= vb2_ioctl_streamoff,
   1187	.vidioc_expbuf			= vb2_ioctl_expbuf,
   1188	.vidioc_g_output		= sh_vou_g_output,
   1189	.vidioc_s_output		= sh_vou_s_output,
   1190	.vidioc_enum_output		= sh_vou_enum_output,
   1191	.vidioc_s_std			= sh_vou_s_std,
   1192	.vidioc_g_std			= sh_vou_g_std,
   1193	.vidioc_g_selection		= sh_vou_g_selection,
   1194	.vidioc_s_selection		= sh_vou_s_selection,
   1195	.vidioc_log_status		= sh_vou_log_status,
   1196};
   1197
   1198static const struct v4l2_file_operations sh_vou_fops = {
   1199	.owner		= THIS_MODULE,
   1200	.open		= sh_vou_open,
   1201	.release	= sh_vou_release,
   1202	.unlocked_ioctl	= video_ioctl2,
   1203	.mmap		= vb2_fop_mmap,
   1204	.poll		= vb2_fop_poll,
   1205	.write		= vb2_fop_write,
   1206};
   1207
   1208static const struct video_device sh_vou_video_template = {
   1209	.name		= "sh_vou",
   1210	.fops		= &sh_vou_fops,
   1211	.ioctl_ops	= &sh_vou_ioctl_ops,
   1212	.tvnorms	= V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
   1213	.vfl_dir	= VFL_DIR_TX,
   1214	.device_caps	= V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE |
   1215			  V4L2_CAP_STREAMING,
   1216};
   1217
   1218static int sh_vou_probe(struct platform_device *pdev)
   1219{
   1220	struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
   1221	struct v4l2_rect *rect;
   1222	struct v4l2_pix_format *pix;
   1223	struct i2c_adapter *i2c_adap;
   1224	struct video_device *vdev;
   1225	struct sh_vou_device *vou_dev;
   1226	struct resource *reg_res;
   1227	struct v4l2_subdev *subdev;
   1228	struct vb2_queue *q;
   1229	int irq, ret;
   1230
   1231	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
   1232	irq = platform_get_irq(pdev, 0);
   1233
   1234	if (!vou_pdata || !reg_res || irq <= 0) {
   1235		dev_err(&pdev->dev, "Insufficient VOU platform information.\n");
   1236		return -ENODEV;
   1237	}
   1238
   1239	vou_dev = devm_kzalloc(&pdev->dev, sizeof(*vou_dev), GFP_KERNEL);
   1240	if (!vou_dev)
   1241		return -ENOMEM;
   1242
   1243	INIT_LIST_HEAD(&vou_dev->buf_list);
   1244	spin_lock_init(&vou_dev->lock);
   1245	mutex_init(&vou_dev->fop_lock);
   1246	vou_dev->pdata = vou_pdata;
   1247	vou_dev->status = SH_VOU_INITIALISING;
   1248	vou_dev->pix_idx = 1;
   1249
   1250	rect = &vou_dev->rect;
   1251	pix = &vou_dev->pix;
   1252
   1253	/* Fill in defaults */
   1254	vou_dev->std		= V4L2_STD_NTSC_M;
   1255	rect->left		= 0;
   1256	rect->top		= 0;
   1257	rect->width		= VOU_MAX_IMAGE_WIDTH;
   1258	rect->height		= 480;
   1259	pix->width		= VOU_MAX_IMAGE_WIDTH;
   1260	pix->height		= 480;
   1261	pix->pixelformat	= V4L2_PIX_FMT_NV16;
   1262	pix->field		= V4L2_FIELD_INTERLACED;
   1263	pix->bytesperline	= VOU_MAX_IMAGE_WIDTH;
   1264	pix->sizeimage		= VOU_MAX_IMAGE_WIDTH * 2 * 480;
   1265	pix->colorspace		= V4L2_COLORSPACE_SMPTE170M;
   1266
   1267	vou_dev->base = devm_ioremap_resource(&pdev->dev, reg_res);
   1268	if (IS_ERR(vou_dev->base))
   1269		return PTR_ERR(vou_dev->base);
   1270
   1271	ret = devm_request_irq(&pdev->dev, irq, sh_vou_isr, 0, "vou", vou_dev);
   1272	if (ret < 0)
   1273		return ret;
   1274
   1275	ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev);
   1276	if (ret < 0) {
   1277		dev_err(&pdev->dev, "Error registering v4l2 device\n");
   1278		return ret;
   1279	}
   1280
   1281	vdev = &vou_dev->vdev;
   1282	*vdev = sh_vou_video_template;
   1283	if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
   1284		vdev->tvnorms |= V4L2_STD_PAL;
   1285	vdev->v4l2_dev = &vou_dev->v4l2_dev;
   1286	vdev->release = video_device_release_empty;
   1287	vdev->lock = &vou_dev->fop_lock;
   1288
   1289	video_set_drvdata(vdev, vou_dev);
   1290
   1291	/* Initialize the vb2 queue */
   1292	q = &vou_dev->queue;
   1293	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
   1294	q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE;
   1295	q->drv_priv = vou_dev;
   1296	q->buf_struct_size = sizeof(struct sh_vou_buffer);
   1297	q->ops = &sh_vou_qops;
   1298	q->mem_ops = &vb2_dma_contig_memops;
   1299	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
   1300	q->min_buffers_needed = 2;
   1301	q->lock = &vou_dev->fop_lock;
   1302	q->dev = &pdev->dev;
   1303	ret = vb2_queue_init(q);
   1304	if (ret)
   1305		goto ei2cgadap;
   1306
   1307	vdev->queue = q;
   1308	INIT_LIST_HEAD(&vou_dev->buf_list);
   1309
   1310	pm_runtime_enable(&pdev->dev);
   1311	pm_runtime_resume(&pdev->dev);
   1312
   1313	i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap);
   1314	if (!i2c_adap) {
   1315		ret = -ENODEV;
   1316		goto ei2cgadap;
   1317	}
   1318
   1319	ret = sh_vou_hw_init(vou_dev);
   1320	if (ret < 0)
   1321		goto ereset;
   1322
   1323	subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
   1324			vou_pdata->board_info, NULL);
   1325	if (!subdev) {
   1326		ret = -ENOMEM;
   1327		goto ei2cnd;
   1328	}
   1329
   1330	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
   1331	if (ret < 0)
   1332		goto evregdev;
   1333
   1334	return 0;
   1335
   1336evregdev:
   1337ei2cnd:
   1338ereset:
   1339	i2c_put_adapter(i2c_adap);
   1340ei2cgadap:
   1341	pm_runtime_disable(&pdev->dev);
   1342	v4l2_device_unregister(&vou_dev->v4l2_dev);
   1343	return ret;
   1344}
   1345
   1346static int sh_vou_remove(struct platform_device *pdev)
   1347{
   1348	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
   1349	struct sh_vou_device *vou_dev = container_of(v4l2_dev,
   1350						struct sh_vou_device, v4l2_dev);
   1351	struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
   1352					    struct v4l2_subdev, list);
   1353	struct i2c_client *client = v4l2_get_subdevdata(sd);
   1354
   1355	pm_runtime_disable(&pdev->dev);
   1356	video_unregister_device(&vou_dev->vdev);
   1357	i2c_put_adapter(client->adapter);
   1358	v4l2_device_unregister(&vou_dev->v4l2_dev);
   1359	return 0;
   1360}
   1361
   1362static struct platform_driver sh_vou = {
   1363	.remove  = sh_vou_remove,
   1364	.driver  = {
   1365		.name	= "sh-vou",
   1366	},
   1367};
   1368
   1369module_platform_driver_probe(sh_vou, sh_vou_probe);
   1370
   1371MODULE_DESCRIPTION("SuperH VOU driver");
   1372MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
   1373MODULE_LICENSE("GPL v2");
   1374MODULE_VERSION("0.1.0");
   1375MODULE_ALIAS("platform:sh-vou");