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