1a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/*
2a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * SuperH Video Output Unit (VOU) driver
3a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski *
4a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski *
6a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * This program is free software; you can redistribute it and/or modify
7a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * it under the terms of the GNU General Public License version 2 as
8a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * published by the Free Software Foundation.
9a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski */
10a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
11a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/dma-mapping.h>
12a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/delay.h>
13a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/errno.h>
14a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/fs.h>
15a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/i2c.h>
16a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/init.h>
17a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/interrupt.h>
18a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/kernel.h>
19a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/platform_device.h>
20a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/pm_runtime.h>
213b23db39b4a780219a06e9408e08070461724957Guennadi Liakhovetski#include <linux/slab.h>
22a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <linux/videodev2.h>
237a707b89202f905bd9f9fbde326933c59a81214cPaul Gortmaker#include <linux/module.h>
24a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
25a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <media/sh_vou.h>
26a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <media/v4l2-common.h>
27a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <media/v4l2-device.h>
28a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <media/v4l2-ioctl.h>
29a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <media/v4l2-mediabus.h>
30a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#include <media/videobuf-dma-contig.h>
31a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
32a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* Mirror addresses are not available for all registers */
33a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUER	0
34a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUCR	4
35a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUSTR	8
36a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUVCR	0xc
37a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUISR	0x10
38a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUBCR	0x14
39a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUDPR	0x18
40a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUDSR	0x1c
41a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUVPR	0x20
42a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUIR	0x24
43a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUSRR	0x28
44a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUMSR	0x2c
45a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUHIR	0x30
46a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUDFR	0x34
47a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUAD1R	0x38
48a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUAD2R	0x3c
49a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUAIR	0x40
50a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOUSWR	0x44
51a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOURCR	0x48
52a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOURPR	0x50
53a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
54a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskienum sh_vou_status {
55a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	SH_VOU_IDLE,
56a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	SH_VOU_INITIALISING,
57a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	SH_VOU_RUNNING,
58a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
59a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
60a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#define VOU_MAX_IMAGE_WIDTH	720
61765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski#define VOU_MAX_IMAGE_HEIGHT	576
62a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
63a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistruct sh_vou_device {
64a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_device v4l2_dev;
65a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev;
66a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	atomic_t use_count;
67a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_pdata *pdata;
68a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	spinlock_t lock;
69a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	void __iomem *base;
70a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* State information */
71a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format pix;
72a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_rect rect;
73a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct list_head queue;
74a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l2_std_id std;
75a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int pix_idx;
76a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct videobuf_buffer *active;
77a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	enum sh_vou_status status;
78697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil	struct mutex fop_lock;
79a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
80a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
81a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistruct sh_vou_file {
82a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct videobuf_queue vbq;
83a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
84a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
85a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* Register access routines for sides A, B and mirror addresses */
86a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg,
87a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			       u32 value)
88a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
89a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	__raw_writel(value, vou_dev->base + reg);
90a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
91a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
92a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg,
93a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				u32 value)
94a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
95a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	__raw_writel(value, vou_dev->base + reg);
96a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	__raw_writel(value, vou_dev->base + reg + 0x1000);
97a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
98a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
99a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg,
100a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			       u32 value)
101a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
102a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	__raw_writel(value, vou_dev->base + reg + 0x2000);
103a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
104a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
105a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg)
106a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
107a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return __raw_readl(vou_dev->base + reg);
108a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
109a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
110a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg,
111a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			     u32 value, u32 mask)
112a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
113a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 old = __raw_readl(vou_dev->base + reg);
114a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
115a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	value = (value & mask) | (old & ~mask);
116a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	__raw_writel(value, vou_dev->base + reg);
117a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
118a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
119a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg,
120a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			     u32 value, u32 mask)
121a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
122a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask);
123a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
124a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
125a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
126a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			      u32 value, u32 mask)
127a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
128a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_set(vou_dev, reg, value, mask);
129a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_b_set(vou_dev, reg, value, mask);
130a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
131a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
132a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistruct sh_vou_fmt {
133a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32		pfmt;
134a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	char		*desc;
135a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned char	bpp;
136a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned char	rgb;
137a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned char	yf;
138a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned char	pkf;
139a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
140a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
141a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* Further pixel formats can be added */
142a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic struct sh_vou_fmt vou_fmt[] = {
143a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	{
144a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pfmt	= V4L2_PIX_FMT_NV12,
145a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.bpp	= 12,
146a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.desc	= "YVU420 planar",
147a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.yf	= 0,
148a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.rgb	= 0,
149a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	},
150a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	{
151a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pfmt	= V4L2_PIX_FMT_NV16,
152a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.bpp	= 16,
153a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.desc	= "YVYU planar",
154a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.yf	= 1,
155a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.rgb	= 0,
156a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	},
157a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	{
158a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pfmt	= V4L2_PIX_FMT_RGB24,
159a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.bpp	= 24,
160a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.desc	= "RGB24",
161a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pkf	= 2,
162a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.rgb	= 1,
163a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	},
164a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	{
165a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pfmt	= V4L2_PIX_FMT_RGB565,
166a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.bpp	= 16,
167a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.desc	= "RGB565",
168a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pkf	= 3,
169a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.rgb	= 1,
170a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	},
171a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	{
172a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pfmt	= V4L2_PIX_FMT_RGB565X,
173a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.bpp	= 16,
174a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.desc	= "RGB565 byteswapped",
175a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.pkf	= 3,
176a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.rgb	= 1,
177a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	},
178a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
179a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
180a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_schedule_next(struct sh_vou_device *vou_dev,
181a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				 struct videobuf_buffer *vb)
182a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
183a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dma_addr_t addr1, addr2;
184a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
185a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	addr1 = videobuf_to_dma_contig(vb);
186a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	switch (vou_dev->pix.pixelformat) {
187a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_NV12:
188a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_NV16:
189a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height;
190a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		break;
191a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	default:
192a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		addr2 = 0;
193a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
194a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
195a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1);
196a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2);
197a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
198a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
199a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_stream_start(struct sh_vou_device *vou_dev,
200a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				struct videobuf_buffer *vb)
201a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
202a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned int row_coeff;
203a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#ifdef __LITTLE_ENDIAN
204a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 dataswap = 7;
205a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#else
206a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 dataswap = 0;
207a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#endif
208a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
209a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	switch (vou_dev->pix.pixelformat) {
210a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_NV12:
211a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_NV16:
212a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		row_coeff = 1;
213a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		break;
214a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_RGB565:
215a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dataswap ^= 1;
216a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_RGB565X:
217a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		row_coeff = 2;
218a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		break;
219a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case V4L2_PIX_FMT_RGB24:
220a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		row_coeff = 3;
221a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		break;
222a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
223a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
224a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap);
225a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff);
226a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_schedule_next(vou_dev, vb);
227a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
228a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
229a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
230a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
231a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	BUG_ON(in_interrupt());
232a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
233a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
2340e0809a58869e3e422985f868ad5e0da1fc0ba85Hans Verkuil	videobuf_waiton(vq, vb, 0, 0);
235a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	videobuf_dma_contig_free(vq, vb);
236a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vb->state = VIDEOBUF_NEEDS_INIT;
237a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
238a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
239697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil/* Locking: caller holds fop_lock mutex */
240a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
241a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			    unsigned int *size)
242a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
243a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = vq->priv_data;
244a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
245a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
246a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	*size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width *
247a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->pix.height / 8;
248a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
249a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (*count < 2)
250a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		*count = 2;
251a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
252a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Taking into account maximum frame size, *count will stay >= 2 */
253a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024)
254a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		*count = 4 * 1024 * 1024 / PAGE_ALIGN(*size);
255a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
256a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size);
257a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
258a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
259a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
260a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
261697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil/* Locking: caller holds fop_lock mutex */
262a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_buf_prepare(struct videobuf_queue *vq,
263a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			      struct videobuf_buffer *vb,
264a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			      enum v4l2_field field)
265a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
266a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = vq->priv_data;
267a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
268a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format *pix = &vou_dev->pix;
269a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
270a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int ret;
271a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
272a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vq->dev, "%s()\n", __func__);
273a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
274a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vb->width	!= pix->width ||
275a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	    vb->height	!= pix->height ||
276a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	    vb->field	!= pix->field) {
277a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vb->width	= pix->width;
278a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vb->height	= pix->height;
279a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vb->field	= field;
280a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (vb->state != VIDEOBUF_NEEDS_INIT)
281a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			free_buffer(vq, vb);
282a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
283a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
284a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vb->size = vb->height * bytes_per_line;
285a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vb->baddr && vb->bsize < vb->size) {
286a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* User buffer too small */
287a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n",
288a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			 vb->bsize, vb->baddr);
289a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
290a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
291a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
292a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vb->state == VIDEOBUF_NEEDS_INIT) {
293a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = videobuf_iolock(vq, vb, NULL);
294a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (ret < 0) {
295a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n",
296a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				 vb->memory, ret);
297a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			return ret;
298a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		}
299a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vb->state = VIDEOBUF_PREPARED;
300a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
301a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
302a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vq->dev,
303a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		"%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
304a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		__func__, vou_dev->pix_idx, bytes_per_line,
305a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		videobuf_to_dma_contig(vb), vb->memory, vb->state);
306a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
307a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
308a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
309a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
310697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
311a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_buf_queue(struct videobuf_queue *vq,
312a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			     struct videobuf_buffer *vb)
313a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
314a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = vq->priv_data;
315a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
316a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
317a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vq->dev, "%s()\n", __func__);
318a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
319a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vb->state = VIDEOBUF_QUEUED;
320a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	list_add_tail(&vb->queue, &vou_dev->queue);
321a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
322a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vou_dev->status == SH_VOU_RUNNING) {
323a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return;
324a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	} else if (!vou_dev->active) {
325a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->active = vb;
326a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Start from side A: we use mirror addresses, so, set B */
327a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_write(vou_dev, VOURPR, 1);
328a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__,
329a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			sh_vou_reg_a_read(vou_dev, VOUSTR));
330a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_schedule_next(vou_dev, vb);
331a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Only activate VOU after the second buffer */
332a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	} else if (vou_dev->active->queue.next == &vb->queue) {
333a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Second buffer - initialise register side B */
334a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_write(vou_dev, VOURPR, 0);
335a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_stream_start(vou_dev, vb);
336a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
337a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Register side switching with frame VSYNC */
338a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_write(vou_dev, VOURCR, 5);
339a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__,
340a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			sh_vou_reg_a_read(vou_dev, VOUSTR));
341a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
342a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Enable End-of-Frame (VSYNC) interrupts */
343a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
344a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Two buffers on the queue - activate the hardware */
345a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
346a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->status = SH_VOU_RUNNING;
347a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_write(vou_dev, VOUER, 0x107);
348a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
349a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
350a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
351a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_buf_release(struct videobuf_queue *vq,
352a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			       struct videobuf_buffer *vb)
353a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
354a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = vq->priv_data;
355a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
356a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned long flags;
357a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
358a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vq->dev, "%s()\n", __func__);
359a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
360a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	spin_lock_irqsave(&vou_dev->lock, flags);
361a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
362a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vou_dev->active == vb) {
363a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* disable output */
364a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
365a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* ...but the current frame will complete */
366a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
367a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->active = NULL;
368a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
369a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
370a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) {
371a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vb->state = VIDEOBUF_ERROR;
372a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		list_del(&vb->queue);
373a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
374a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
375a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	spin_unlock_irqrestore(&vou_dev->lock, flags);
376a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
377a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	free_buffer(vq, vb);
378a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
379a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
380a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic struct videobuf_queue_ops sh_vou_video_qops = {
381a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.buf_setup	= sh_vou_buf_setup,
382a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.buf_prepare	= sh_vou_buf_prepare,
383a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.buf_queue	= sh_vou_buf_queue,
384a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.buf_release	= sh_vou_buf_release,
385a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
386a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
387a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* Video IOCTLs */
388a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_querycap(struct file *file, void  *priv,
389a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			   struct v4l2_capability *cap)
390a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
391a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
392a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
393a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
394a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
395a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
396a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
397a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
398a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
399a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
400a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* Enumerate formats, that the device can accept from the user */
401a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_enum_fmt_vid_out(struct file *file, void  *priv,
402a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				   struct v4l2_fmtdesc *fmt)
403a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
404a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
405a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
406a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (fmt->index >= ARRAY_SIZE(vou_fmt))
407a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
408a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
409a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
410a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
411a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
412a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	strlcpy(fmt->description, vou_fmt[fmt->index].desc,
413a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sizeof(fmt->description));
414a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	fmt->pixelformat = vou_fmt[fmt->index].pfmt;
415a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
416a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
417a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
418a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
419a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
420a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				struct v4l2_format *fmt)
421a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
422a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
423a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
424a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
425a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
426a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
427a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
428a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	fmt->fmt.pix = vou_dev->pix;
429a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
430a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
431a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
432a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
433a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4};
434a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1};
435a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3};
436a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const unsigned char vou_scale_v_num[] = {1, 2, 4};
437a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const unsigned char vou_scale_v_den[] = {1, 1, 1};
438a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const unsigned char vou_scale_v_fld[] = {0, 1};
439a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
440a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
441a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				      int pix_idx, int w_idx, int h_idx)
442a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
443a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
444a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned int black_left, black_top, width_max, height_max,
445a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		frame_in_height, frame_out_height, frame_out_top;
446a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_rect *rect = &vou_dev->rect;
447a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format *pix = &vou_dev->pix;
448a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 vouvcr = 0, dsr_h, dsr_v;
449a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
450a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vou_dev->std & V4L2_STD_525_60) {
451a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		width_max = 858;
452a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		height_max = 262;
453a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	} else {
454a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		width_max = 864;
455a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		height_max = 312;
456a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
457a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
458a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	frame_in_height = pix->height / 2;
459a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	frame_out_height = rect->height / 2;
460a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	frame_out_top = rect->top / 2;
461a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
462a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/*
463a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * Cropping scheme: max useful image is 720x480, and the total video
464a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts
465a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock,
466a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * of which the first 33 / 25 clocks HSYNC must be held active. This
467a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * has to be configured in CR[HW]. 1 pixel equals 2 clock periods.
468a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives
469a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area,
470a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * beyond DSR, specified on the left and top by the VPR register "black
471a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * pixels" and out-of-image area (DPR) "background pixels." We fix VPR
472a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * at 138 / 144 : 20, because that's the HSYNC timing, that our first
473a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * client requires, and that's exactly what leaves us 720 pixels for the
474a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * image; we leave VPR[VVP] at default 20 for now, because the client
475a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * doesn't seem to have any special requirements for it. Otherwise we
476a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * could also set it to max - 240 = 22 / 72. Thus VPR depends only on
477a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * the selected standard, and DPR and DSR are selected according to
478a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * cropping. Q: how does the client detect the first valid line? Does
479a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * HSYNC stay inactive during invalid (black) lines?
480a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 */
481a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	black_left = width_max - VOU_MAX_IMAGE_WIDTH;
482a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	black_top = 20;
483a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
484a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dsr_h = rect->width + rect->left;
485a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dsr_v = frame_out_height + frame_out_top;
486a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
487a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev,
488a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		"image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n",
489a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pix->width, frame_in_height, black_left, black_top,
490a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		rect->left, frame_out_top, dsr_h, dsr_v);
491a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
492a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* VOUISR height - half of a frame height in frame mode */
493a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height);
494a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top);
495a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top);
496a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v);
497a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
498a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/*
499a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * if necessary, we could set VOUHIR to
500a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * max(black_left + dsr_h, width_max) here
501a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 */
502a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
503a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (w_idx)
504a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4);
505a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (h_idx)
506a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
507a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
508a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr);
509a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
510a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* To produce a colour bar for testing set bit 23 of VOUVCR */
511a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
512a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUDFR,
513a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			    fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16));
514a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
515a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
516a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistruct sh_vou_geometry {
517a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_rect output;
518a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned int in_width;
519a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	unsigned int in_height;
520a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int scale_idx_h;
521a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int scale_idx_v;
522a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
523a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
524a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/*
525a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * Find input geometry, that we can use to produce output, closest to the
526a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * requested rectangle, using VOU scaling
527a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski */
528a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
529a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
530a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* The compiler cannot know, that best and idx will indeed be set */
531765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	unsigned int best_err = UINT_MAX, best = 0, img_height_max;
532a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int i, idx = 0;
533a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
534765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	if (std & V4L2_STD_525_60)
535765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 480;
536765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	else
537765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 576;
538a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
539a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Image width must be a multiple of 4 */
540a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
541765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski			      &geo->in_height, 0, img_height_max, 1, 0);
542a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
543a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Select scales to come as close as possible to the output image */
544a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
545a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int err;
546a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int found = geo->output.width * vou_scale_h_den[i] /
547a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			vou_scale_h_num[i];
548a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
549a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (found > VOU_MAX_IMAGE_WIDTH)
550a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			/* scales increase */
551a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
552a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
553a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		err = abs(found - geo->in_width);
554a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (err < best_err) {
555a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best_err = err;
556a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			idx = i;
557a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best = found;
558a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		}
559a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (!err)
560a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
561a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
562a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
563a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->in_width = best;
564a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->scale_idx_h = idx;
565a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
566a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	best_err = UINT_MAX;
567a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
568a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* This loop can be replaced with one division */
569a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) {
570a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int err;
571a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int found = geo->output.height * vou_scale_v_den[i] /
572a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			vou_scale_v_num[i];
573a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
574765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		if (found > img_height_max)
575a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			/* scales increase */
576a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
577a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
578a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		err = abs(found - geo->in_height);
579a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (err < best_err) {
580a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best_err = err;
581a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			idx = i;
582a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best = found;
583a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		}
584a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (!err)
585a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
586a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
587a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
588a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->in_height = best;
589a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->scale_idx_v = idx;
590a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
591a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
592a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/*
593a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * Find output geometry, that we can produce, using VOU scaling, closest to
594a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * the requested rectangle
595a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski */
596a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
597a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
598765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	unsigned int best_err = UINT_MAX, best, width_max, height_max,
599765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max;
600a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int i, idx;
601a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
602a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (std & V4L2_STD_525_60) {
603a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		width_max = 858;
604a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		height_max = 262 * 2;
605765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 480;
606a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	} else {
607a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		width_max = 864;
608a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		height_max = 312 * 2;
609765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 576;
610a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
611a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
612a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Select scales to come as close as possible to the output image */
613a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) {
614a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int err;
615a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int found = geo->in_width * vou_scale_h_num[i] /
616a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			vou_scale_h_den[i];
617a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
618a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (found > VOU_MAX_IMAGE_WIDTH)
619a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			/* scales increase */
620a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
621a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
622a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		err = abs(found - geo->output.width);
623a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (err < best_err) {
624a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best_err = err;
625a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			idx = i;
626a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best = found;
627a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		}
628a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (!err)
629a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
630a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
631a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
632a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->output.width = best;
633a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->scale_idx_h = idx;
634a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (geo->output.left + best > width_max)
635a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		geo->output.left = width_max - best;
636a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
637a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width,
638a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		 vou_scale_h_num[idx], vou_scale_h_den[idx], best);
639a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
640a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	best_err = UINT_MAX;
641a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
642a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* This loop can be replaced with one division */
643a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) {
644a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int err;
645a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		unsigned int found = geo->in_height * vou_scale_v_num[i] /
646a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			vou_scale_v_den[i];
647a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
648765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		if (found > img_height_max)
649a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			/* scales increase */
650a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
651a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
652a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		err = abs(found - geo->output.height);
653a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (err < best_err) {
654a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best_err = err;
655a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			idx = i;
656a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			best = found;
657a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		}
658a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (!err)
659a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
660a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
661a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
662a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->output.height = best;
663a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo->scale_idx_v = idx;
664a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (geo->output.top + best > height_max)
665a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		geo->output.top = height_max - best;
666a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
667a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height,
668a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		 vou_scale_v_num[idx], vou_scale_v_den[idx], best);
669a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
670a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
671a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
672a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				struct v4l2_format *fmt)
673a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
674a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
675a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
676a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format *pix = &fmt->fmt.pix;
677765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	unsigned int img_height_max;
678a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int pix_idx;
679a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_geometry geo;
680a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_mbus_framefmt mbfmt = {
681a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Revisit: is this the correct code? */
682ace6e9799f585994c92ac3c0696bc336e50077e6Guennadi Liakhovetski		.code = V4L2_MBUS_FMT_YUYV8_2X8,
683a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.field = V4L2_FIELD_INTERLACED,
684a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.colorspace = V4L2_COLORSPACE_SMPTE170M,
685a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	};
686a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int ret;
687a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
688a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
689a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->rect.width, vou_dev->rect.height,
690a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pix->width, pix->height);
691a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
692a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (pix->field == V4L2_FIELD_ANY)
693a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pix->field = V4L2_FIELD_NONE;
694a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
695a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
696a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	    pix->field != V4L2_FIELD_NONE)
697a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
698a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
699a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
700a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
701a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			break;
702a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
703a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (pix_idx == ARRAY_SIZE(vou_fmt))
704a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
705a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
706765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	if (vou_dev->std & V4L2_STD_525_60)
707765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 480;
708765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	else
709765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 576;
710765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski
711a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Image width must be a multiple of 4 */
712a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
713765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski			      &pix->height, 0, img_height_max, 1, 0);
714a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
715a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.in_width = pix->width;
716a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.in_height = pix->height;
717a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.output = vou_dev->rect;
718a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
719a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_adjust_output(&geo, vou_dev->std);
720a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
721a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	mbfmt.width = geo.output.width;
722a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	mbfmt.height = geo.output.height;
723a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
724a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski					 s_mbus_fmt, &mbfmt);
725a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
726a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0)
727a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return ret;
728a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
729a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
730a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		geo.output.width, geo.output.height, mbfmt.width, mbfmt.height);
731a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
732a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Sanity checks */
733a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
734765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	    (unsigned)mbfmt.height > img_height_max ||
735ace6e9799f585994c92ac3c0696bc336e50077e6Guennadi Liakhovetski	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
736a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EIO;
737a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
738a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (mbfmt.width != geo.output.width ||
739a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	    mbfmt.height != geo.output.height) {
740a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		geo.output.width = mbfmt.width;
741a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		geo.output.height = mbfmt.height;
742a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
743a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_adjust_input(&geo, vou_dev->std);
744a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
745a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
746a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* We tried to preserve output rectangle, but it could have changed */
747a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->rect = geo.output;
748a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->width = geo.in_width;
749a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->height = geo.in_height;
750a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
751a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__,
752a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pix->width, pix->height);
753a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
754a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->pix_idx = pix_idx;
755a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
756a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->pix = *pix;
757a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
758a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_configure_geometry(vou_dev, pix_idx,
759a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				  geo.scale_idx_h, geo.scale_idx_v);
760a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
761a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
762a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
763a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
764a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
765a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				  struct v4l2_format *fmt)
766a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
767a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
768a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format *pix = &fmt->fmt.pix;
769a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int i;
770a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
771a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
772a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
773a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
774a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->field = V4L2_FIELD_NONE;
775a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
776a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
777a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			      &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
778a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
779a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	for (i = 0; ARRAY_SIZE(vou_fmt); i++)
780a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (vou_fmt[i].pfmt == pix->pixelformat)
781a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			return 0;
782a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
783a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->pixelformat = vou_fmt[0].pfmt;
784a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
785a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
786a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
787a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
788a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_reqbufs(struct file *file, void *priv,
789a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			  struct v4l2_requestbuffers *req)
790a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
791a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
792a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
793a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
794a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
795a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
796a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
797a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
798a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_reqbufs(&vou_file->vbq, req);
799a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
800a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
801a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_querybuf(struct file *file, void *priv,
802a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			   struct v4l2_buffer *b)
803a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
804a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
805a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
806a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
807a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
808a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_querybuf(&vou_file->vbq, b);
809a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
810a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
811a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
812a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
813a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
814a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
815a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
816a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
817a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_qbuf(&vou_file->vbq, b);
818a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
819a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
820a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
821a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
822a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
823a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
824a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
825a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
826a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK);
827a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
828a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
829a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_streamon(struct file *file, void *priv,
830a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			   enum v4l2_buf_type buftype)
831a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
832a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
833a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
834a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
835a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int ret;
836a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
837a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
838a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
839a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
840a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski					 video, s_stream, 1);
841a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0 && ret != -ENOIOCTLCMD)
842a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return ret;
843a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
844a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* This calls our .buf_queue() (== sh_vou_buf_queue) */
845a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_streamon(&vou_file->vbq);
846a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
847a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
848a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_streamoff(struct file *file, void *priv,
849a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			    enum v4l2_buf_type buftype)
850a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
851a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
852a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
853a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
854a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
855a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
856a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
857a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/*
858a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * This calls buf_release from host driver's videobuf_queue_ops for all
859a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * remaining buffers. When the last buffer is freed, stop streaming
860a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 */
861a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	videobuf_streamoff(&vou_file->vbq);
862a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0);
863a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
864a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
865a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
866a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
867a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
868a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
869a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	switch (bus_fmt) {
870a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	default:
871a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n",
872a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			   __func__, bus_fmt);
873a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case SH_VOU_BUS_8BIT:
874a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return 1;
875a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case SH_VOU_BUS_16BIT:
876a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return 0;
877a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	case SH_VOU_BUS_BT656:
878a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return 3;
879a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
880a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
881a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
882a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
883a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
884a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
885a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
886a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int ret;
887a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
888a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
889a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
890a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (*std_id & ~vdev->tvnorms)
891a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
892a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
893a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
894a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski					 s_std_output, *std_id);
895a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Shall we continue, if the subdev doesn't support .s_std_output()? */
896a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0 && ret != -ENOIOCTLCMD)
897a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return ret;
898a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
899a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (*std_id & V4L2_STD_525_60)
900a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_ab_set(vou_dev, VOUCR,
901a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
902a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	else
903a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
904a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
905a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->std = *std_id;
906a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
907a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
908a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
909a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
910a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
911a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
912a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
913a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
914a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
915a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
916a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
917a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	*std = vou_dev->std;
918a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
919a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
920a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
921a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
922a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
923a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
924a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
925a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
926a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
927a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
928a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
929a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
930a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->c = vou_dev->rect;
931a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
932a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
933a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
934a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
935a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* Assume a dull encoder, do all the work ourselves. */
936a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
937a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
938a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
939a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
940a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_rect *rect = &a->c;
941a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
942a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format *pix = &vou_dev->pix;
943a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_geometry geo;
944a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_mbus_framefmt mbfmt = {
945a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Revisit: is this the correct code? */
946ace6e9799f585994c92ac3c0696bc336e50077e6Guennadi Liakhovetski		.code = V4L2_MBUS_FMT_YUYV8_2X8,
947a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.field = V4L2_FIELD_INTERLACED,
948a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.colorspace = V4L2_COLORSPACE_SMPTE170M,
949a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	};
950765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	unsigned int img_height_max;
951a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int ret;
952a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
953a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
954a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		rect->width, rect->height, rect->left, rect->top);
955a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
956a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
957a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EINVAL;
958a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
959765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	if (vou_dev->std & V4L2_STD_525_60)
960765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 480;
961765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	else
962765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		img_height_max = 576;
963765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski
964a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
965765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski			      &rect->height, 0, img_height_max, 1, 0);
966a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
967a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
968a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
969a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
970765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	if (rect->height + rect->top > img_height_max)
971765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski		rect->top = img_height_max - rect->height;
972a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
973a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.output = *rect;
974a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.in_width = pix->width;
975a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.in_height = pix->height;
976a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
977a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Configure the encoder one-to-one, position at 0, ignore errors */
978a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sd_crop.c.width = geo.output.width;
979a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sd_crop.c.height = geo.output.height;
980a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/*
981a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * We first issue a S_CROP, so that the subsequent S_FMT delivers the
982a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * final encoder configuration.
983a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 */
984a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
985a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				   s_crop, &sd_crop);
986a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	mbfmt.width = geo.output.width;
987a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	mbfmt.height = geo.output.height;
988a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
989a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski					 s_mbus_fmt, &mbfmt);
990a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
991a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0)
992a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return ret;
993a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
994a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Sanity checks */
995a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
996765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	    (unsigned)mbfmt.height > img_height_max ||
997ace6e9799f585994c92ac3c0696bc336e50077e6Guennadi Liakhovetski	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
998a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -EIO;
999a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1000a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.output.width = mbfmt.width;
1001a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	geo.output.height = mbfmt.height;
1002a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1003a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/*
1004a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * No down-scaling. According to the API, current call has precedence:
1005a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two.
1006a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	 */
1007a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_adjust_input(&geo, vou_dev->std);
1008a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1009a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* We tried to preserve output rectangle, but it could have changed */
1010a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->rect = geo.output;
1011a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->width = geo.in_width;
1012a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->height = geo.in_height;
1013a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1014a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx,
1015a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				  geo.scale_idx_h, geo.scale_idx_v);
1016a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1017a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1018a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1019a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1020a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/*
1021a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle
1022a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * is the initial register values, height takes the interlaced format into
1023a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can
1024a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * actually only meaningfully contain values <= 720 and <= 240 respectively, and
1025a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski * not <= 864 and <= 312.
1026a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski */
1027a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_cropcap(struct file *file, void *priv,
1028a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			  struct v4l2_cropcap *a)
1029a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1030a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = priv;
1031a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1032a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
1033a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1034a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->type				= V4L2_BUF_TYPE_VIDEO_OUTPUT;
1035a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->bounds.left			= 0;
1036a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->bounds.top			= 0;
1037a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->bounds.width			= VOU_MAX_IMAGE_WIDTH;
1038a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->bounds.height		= VOU_MAX_IMAGE_HEIGHT;
1039a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Default = max, set VOUDPR = 0, which is not hardware default */
1040a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->defrect.left			= 0;
1041a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->defrect.top			= 0;
1042a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->defrect.width		= VOU_MAX_IMAGE_WIDTH;
1043a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->defrect.height		= VOU_MAX_IMAGE_HEIGHT;
1044a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->pixelaspect.numerator	= 1;
1045a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	a->pixelaspect.denominator	= 1;
1046a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1047a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1048a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1049a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1050a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic irqreturn_t sh_vou_isr(int irq, void *dev_id)
1051a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1052a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = dev_id;
1053a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	static unsigned long j;
1054a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct videobuf_buffer *vb;
1055a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	static int cnt;
1056a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	static int side;
1057a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
1058a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
1059a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1060a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!(irq_status & 0x300)) {
1061a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (printk_timed_ratelimit(&j, 500))
1062a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n",
1063a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				 irq_status);
1064a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return IRQ_NONE;
1065a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1066a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1067a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	spin_lock(&vou_dev->lock);
1068a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!vou_dev->active || list_empty(&vou_dev->queue)) {
1069a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (printk_timed_ratelimit(&j, 500))
1070a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			dev_warn(vou_dev->v4l2_dev.dev,
1071a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				 "IRQ without active buffer: %x!\n", irq_status);
1072a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Just ack: buf_release will disable further interrupts */
1073a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300);
1074a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		spin_unlock(&vou_dev->lock);
1075a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return IRQ_HANDLED;
1076a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1077a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1078a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	masked = ~(0x300 & irq_status) & irq_status & 0x30304;
1079a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev,
1080a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		"IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n",
1081a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		irq_status, masked, vou_status, cnt);
1082a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1083a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	cnt++;
1084a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	side = vou_status & 0x10000;
1085a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1086a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Clear only set interrupts */
1087a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_write(vou_dev, VOUIR, masked);
1088a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1089a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vb = vou_dev->active;
1090a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	list_del(&vb->queue);
1091a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1092a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vb->state = VIDEOBUF_DONE;
1093a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	do_gettimeofday(&vb->ts);
1094a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vb->field_count++;
1095a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	wake_up(&vb->done);
1096a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1097a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (list_empty(&vou_dev->queue)) {
1098a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Stop VOU */
1099a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n",
1100a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			__func__, cnt);
1101a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
1102a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->active = NULL;
1103a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->status = SH_VOU_INITIALISING;
1104a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Disable End-of-Frame (VSYNC) interrupts */
1105a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
1106a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		spin_unlock(&vou_dev->lock);
1107a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return IRQ_HANDLED;
1108a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1109a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1110a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->active = list_entry(vou_dev->queue.next,
1111a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				     struct videobuf_buffer, queue);
1112a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1113a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vou_dev->active->queue.next != &vou_dev->queue) {
1114a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next,
1115a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski						struct videobuf_buffer, queue);
1116a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_schedule_next(vou_dev, new);
1117a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1118a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1119a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	spin_unlock(&vou_dev->lock);
1120a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1121a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return IRQ_HANDLED;
1122a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1123a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1124a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_hw_init(struct sh_vou_device *vou_dev)
1125a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1126a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_pdata *pdata = vou_dev->pdata;
1127a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29;
1128a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int i = 100;
1129a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1130a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Disable all IRQs */
1131a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_write(vou_dev, VOUIR, 0);
1132a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1133a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Reset VOU interfaces - registers unaffected */
1134a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101);
1135a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101))
1136a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		udelay(1);
1137a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1138a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!i)
1139a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -ETIMEDOUT;
1140a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1141a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i);
1142a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1143a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (pdata->flags & SH_VOU_PCLK_FALLING)
1144a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		voucr |= 1 << 28;
1145a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (pdata->flags & SH_VOU_HSYNC_LOW)
1146a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		voucr |= 1 << 27;
1147a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (pdata->flags & SH_VOU_VSYNC_LOW)
1148a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		voucr |= 1 << 26;
1149a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000);
1150a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1151a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Manual register side switching at first */
1152a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_a_write(vou_dev, VOURCR, 4);
1153a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Default - fixed HSYNC length, can be made configurable is required */
1154a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000);
1155a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1156a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1157a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1158a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1159a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* File operations */
1160a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_open(struct file *file)
1161a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1162a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
1163a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
1164a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file),
1165a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski					       GFP_KERNEL);
1166a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1167a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!vou_file)
1168a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -ENOMEM;
1169a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1170a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
1171a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1172a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	file->private_data = vou_file;
1173a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1174a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (atomic_inc_return(&vou_dev->use_count) == 1) {
1175a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		int ret;
1176a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* First open */
1177a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->status = SH_VOU_INITIALISING;
1178a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pm_runtime_get_sync(vdev->v4l2_dev->dev);
1179a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = sh_vou_hw_init(vou_dev);
1180a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		if (ret < 0) {
1181a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			atomic_dec(&vou_dev->use_count);
1182a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			pm_runtime_put(vdev->v4l2_dev->dev);
1183a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			vou_dev->status = SH_VOU_IDLE;
1184a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski			return ret;
1185a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		}
1186a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1187a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1188a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops,
1189a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				       vou_dev->v4l2_dev.dev, &vou_dev->lock,
1190a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				       V4L2_BUF_TYPE_VIDEO_OUTPUT,
1191a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				       V4L2_FIELD_NONE,
1192e3cfd447d01cf723ccda0ad6bfa2e85b73d3d747Hans Verkuil				       sizeof(struct videobuf_buffer), vdev,
1193697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil				       &vou_dev->fop_lock);
1194a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1195a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1196a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1197a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1198a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_release(struct file *file)
1199a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1200a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
1201a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
1202a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = file->private_data;
1203a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1204a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
1205a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1206a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!atomic_dec_return(&vou_dev->use_count)) {
1207a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		/* Last close */
1208a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vou_dev->status = SH_VOU_IDLE;
1209a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
1210a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		pm_runtime_put(vdev->v4l2_dev->dev);
1211a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1212a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1213a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	file->private_data = NULL;
1214a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	kfree(vou_file);
1215a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1216a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1217a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1218a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1219a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
1220a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1221a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = file->private_data;
1222a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1223a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
1224a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1225a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_mmap_mapper(&vou_file->vbq, vma);
1226a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1227a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1228a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic unsigned int sh_vou_poll(struct file *file, poll_table *wait)
1229a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1230a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_file *vou_file = file->private_data;
1231a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1232a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
1233a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1234a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return videobuf_poll_stream(file, &vou_file->vbq, wait);
1235a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1236a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1237a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_g_chip_ident(struct file *file, void *fh,
1238a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				   struct v4l2_dbg_chip_ident *id)
1239a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1240a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
1241a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
1242a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1243a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
1244a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1245a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1246a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#ifdef CONFIG_VIDEO_ADV_DEBUG
1247a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_g_register(struct file *file, void *fh,
1248a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				 struct v4l2_dbg_register *reg)
1249a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1250a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
1251a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
1252a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1253a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
1254a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1255a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1256a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int sh_vou_s_register(struct file *file, void *fh,
1257a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				 struct v4l2_dbg_register *reg)
1258a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1259a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev = video_devdata(file);
1260a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
1261a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1262a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
1263a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1264a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#endif
1265a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1266a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski/* sh_vou display ioctl operations */
1267a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
1268a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_querycap        	= sh_vou_querycap,
1269a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_enum_fmt_vid_out	= sh_vou_enum_fmt_vid_out,
1270a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_g_fmt_vid_out		= sh_vou_g_fmt_vid_out,
1271a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_s_fmt_vid_out		= sh_vou_s_fmt_vid_out,
1272a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_try_fmt_vid_out		= sh_vou_try_fmt_vid_out,
1273a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_reqbufs			= sh_vou_reqbufs,
1274a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_querybuf		= sh_vou_querybuf,
1275a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_qbuf			= sh_vou_qbuf,
1276a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_dqbuf			= sh_vou_dqbuf,
1277a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_streamon		= sh_vou_streamon,
1278a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_streamoff		= sh_vou_streamoff,
1279a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_s_std			= sh_vou_s_std,
1280a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_g_std			= sh_vou_g_std,
1281a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_cropcap			= sh_vou_cropcap,
1282a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_g_crop			= sh_vou_g_crop,
1283a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_s_crop			= sh_vou_s_crop,
1284a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_g_chip_ident		= sh_vou_g_chip_ident,
1285a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#ifdef CONFIG_VIDEO_ADV_DEBUG
1286a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_g_register		= sh_vou_g_register,
1287a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.vidioc_s_register		= sh_vou_s_register,
1288a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski#endif
1289a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
1290a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1291a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const struct v4l2_file_operations sh_vou_fops = {
1292a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.owner		= THIS_MODULE,
1293a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.open		= sh_vou_open,
1294a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.release	= sh_vou_release,
1295697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil	.unlocked_ioctl	= video_ioctl2,
1296a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.mmap		= sh_vou_mmap,
1297a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.poll		= sh_vou_poll,
1298a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
1299a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1300a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic const struct video_device sh_vou_video_template = {
1301a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.name		= "sh_vou",
1302a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.fops		= &sh_vou_fops,
1303a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.ioctl_ops	= &sh_vou_ioctl_ops,
1304a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.tvnorms	= V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
1305a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.current_norm	= V4L2_STD_NTSC_M,
1306a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
1307a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1308a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int __devinit sh_vou_probe(struct platform_device *pdev)
1309a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1310a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
1311a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_rect *rect;
1312a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_pix_format *pix;
1313a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct i2c_adapter *i2c_adap;
1314a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct video_device *vdev;
1315a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev;
1316a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct resource *reg_res, *region;
1317a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_subdev *subdev;
1318a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int irq, ret;
1319a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1320a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1321a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	irq = platform_get_irq(pdev, 0);
1322a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1323a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!vou_pdata || !reg_res || irq <= 0) {
1324a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_err(&pdev->dev, "Insufficient VOU platform information.\n");
1325a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -ENODEV;
1326a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1327a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1328a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL);
1329a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!vou_dev)
1330a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		return -ENOMEM;
1331a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1332a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	INIT_LIST_HEAD(&vou_dev->queue);
1333a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	spin_lock_init(&vou_dev->lock);
1334697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil	mutex_init(&vou_dev->fop_lock);
1335a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	atomic_set(&vou_dev->use_count, 0);
1336a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->pdata = vou_pdata;
1337a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->status = SH_VOU_IDLE;
1338a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1339a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	rect = &vou_dev->rect;
1340a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix = &vou_dev->pix;
1341a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1342a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Fill in defaults */
1343a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->std		= sh_vou_video_template.current_norm;
1344a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	rect->left		= 0;
1345a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	rect->top		= 0;
1346a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	rect->width		= VOU_MAX_IMAGE_WIDTH;
1347765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	rect->height		= 480;
1348a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->width		= VOU_MAX_IMAGE_WIDTH;
1349765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	pix->height		= 480;
1350a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->pixelformat	= V4L2_PIX_FMT_YVYU;
1351a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->field		= V4L2_FIELD_NONE;
1352a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->bytesperline	= VOU_MAX_IMAGE_WIDTH * 2;
1353765fe17c4f018c019f1976455084f528474fc7f8Guennadi Liakhovetski	pix->sizeimage		= VOU_MAX_IMAGE_WIDTH * 2 * 480;
1354a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pix->colorspace		= V4L2_COLORSPACE_SMPTE170M;
1355a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1356a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	region = request_mem_region(reg_res->start, resource_size(reg_res),
1357a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski				    pdev->name);
1358a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!region) {
1359a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_err(&pdev->dev, "VOU region already claimed\n");
1360a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = -EBUSY;
1361a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto ereqmemreg;
1362a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1363a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1364a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->base = ioremap(reg_res->start, resource_size(reg_res));
1365a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!vou_dev->base) {
1366a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = -ENOMEM;
1367a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto emap;
1368a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1369a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1370a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev);
1371a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0)
1372a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto ereqirq;
1373a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1374a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev);
1375a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0) {
1376a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		dev_err(&pdev->dev, "Error registering v4l2 device\n");
1377a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto ev4l2devreg;
1378a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1379a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1380a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	/* Allocate memory for video device */
1381a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vdev = video_device_alloc();
1382a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vdev == NULL) {
1383a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = -ENOMEM;
1384a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto evdevalloc;
1385a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1386a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1387a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	*vdev = sh_vou_video_template;
1388a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
1389a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		vdev->tvnorms |= V4L2_STD_PAL;
1390a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vdev->v4l2_dev = &vou_dev->v4l2_dev;
1391a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vdev->release = video_device_release;
1392697566939dc60048fca6e6dd69c7e089aaeb7ff8Hans Verkuil	vdev->lock = &vou_dev->fop_lock;
1393a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1394a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	vou_dev->vdev = vdev;
1395a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	video_set_drvdata(vdev, vou_dev);
1396a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1397a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pm_runtime_enable(&pdev->dev);
1398a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pm_runtime_resume(&pdev->dev);
1399a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1400a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap);
1401a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!i2c_adap) {
1402a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = -ENODEV;
1403a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto ei2cgadap;
1404a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1405a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1406a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = sh_vou_hw_init(vou_dev);
1407a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0)
1408a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto ereset;
1409a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1410a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
14119a1f8b34aa539000da17a06235e4bec254d0bfb5Laurent Pinchart			vou_pdata->board_info, NULL);
1412a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (!subdev) {
1413a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		ret = -ENOMEM;
1414a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto ei2cnd;
1415a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	}
1416a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1417a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
1418a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (ret < 0)
1419a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		goto evregdev;
1420a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1421a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1422a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1423a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskievregdev:
1424a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiei2cnd:
1425a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiereset:
1426a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	i2c_put_adapter(i2c_adap);
1427a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiei2cgadap:
1428a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	video_device_release(vdev);
1429a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pm_runtime_disable(&pdev->dev);
1430a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskievdevalloc:
1431a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l2_device_unregister(&vou_dev->v4l2_dev);
1432a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiev4l2devreg:
1433a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	free_irq(irq, vou_dev);
1434a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiereqirq:
1435a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	iounmap(vou_dev->base);
1436a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiemap:
1437a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	release_mem_region(reg_res->start, resource_size(reg_res));
1438a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskiereqmemreg:
1439a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	kfree(vou_dev);
1440a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return ret;
1441a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1442a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1443a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int __devexit sh_vou_remove(struct platform_device *pdev)
1444a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1445a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	int irq = platform_get_irq(pdev, 0);
1446a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
1447a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct sh_vou_device *vou_dev = container_of(v4l2_dev,
1448a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski						struct sh_vou_device, v4l2_dev);
1449a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
1450a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski					    struct v4l2_subdev, list);
1451a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct i2c_client *client = v4l2_get_subdevdata(sd);
1452a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	struct resource *reg_res;
1453a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1454a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (irq > 0)
1455a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		free_irq(irq, vou_dev);
1456a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	pm_runtime_disable(&pdev->dev);
1457a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	video_unregister_device(vou_dev->vdev);
1458a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	i2c_put_adapter(client->adapter);
1459a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	v4l2_device_unregister(&vou_dev->v4l2_dev);
1460a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	iounmap(vou_dev->base);
1461a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1462a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	if (reg_res)
1463a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		release_mem_region(reg_res->start, resource_size(reg_res));
1464a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	kfree(vou_dev);
1465a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return 0;
1466a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1467a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1468a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic struct platform_driver __refdata sh_vou = {
1469a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.remove  = __devexit_p(sh_vou_remove),
1470a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	.driver  = {
1471a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.name	= "sh-vou",
1472a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski		.owner	= THIS_MODULE,
1473a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	},
1474a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski};
1475a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1476a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic int __init sh_vou_init(void)
1477a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1478a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	return platform_driver_probe(&sh_vou, sh_vou_probe);
1479a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1480a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1481a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskistatic void __exit sh_vou_exit(void)
1482a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski{
1483a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski	platform_driver_unregister(&sh_vou);
1484a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski}
1485a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1486a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskimodule_init(sh_vou_init);
1487a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetskimodule_exit(sh_vou_exit);
1488a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi Liakhovetski
1489a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi LiakhovetskiMODULE_DESCRIPTION("SuperH VOU driver");
1490a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi LiakhovetskiMODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
1491a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi LiakhovetskiMODULE_LICENSE("GPL v2");
149264dc3c1a906467d90c24913b0b38dd13d9378f4fMauro Carvalho ChehabMODULE_VERSION("0.1.0");
1493a81fb9b223508f5773d8d7e226b1574d1b068642Guennadi LiakhovetskiMODULE_ALIAS("platform:sh-vou");
1494