18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * omap_vout.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005-2010 Texas Instruments. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 78c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 88c2ecf20Sopenharmony_ci * kind, whether express or implied. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Leveraged code from the OMAP2 camera driver 118c2ecf20Sopenharmony_ci * Video-for-Linux (Version 2) camera capture driver for 128c2ecf20Sopenharmony_ci * the OMAP24xx camera controller. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Author: Andy Lowe (source@mvista.com) 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Copyright (C) 2004 MontaVista Software, Inc. 178c2ecf20Sopenharmony_ci * Copyright (C) 2010 Texas Instruments. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * History: 208c2ecf20Sopenharmony_ci * 20-APR-2006 Khasim Modified VRFB based Rotation, 218c2ecf20Sopenharmony_ci * The image data is always read from 0 degree 228c2ecf20Sopenharmony_ci * view and written 238c2ecf20Sopenharmony_ci * to the virtual space of desired rotation angle 248c2ecf20Sopenharmony_ci * 4-DEC-2006 Jian Changed to support better memory management 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * 17-Nov-2008 Hardik Changed driver to use video_ioctl2 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * 23-Feb-2010 Vaibhav H Modified to use new DSS2 interface 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <linux/init.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 358c2ecf20Sopenharmony_ci#include <linux/sched.h> 368c2ecf20Sopenharmony_ci#include <linux/types.h> 378c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 388c2ecf20Sopenharmony_ci#include <linux/irq.h> 398c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 408c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 448c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 458c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <video/omapvrfb.h> 488c2ecf20Sopenharmony_ci#include <video/omapfb_dss.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "omap_voutlib.h" 518c2ecf20Sopenharmony_ci#include "omap_voutdef.h" 528c2ecf20Sopenharmony_ci#include "omap_vout_vrfb.h" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Texas Instruments"); 558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); 568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Driver Configuration macros */ 598c2ecf20Sopenharmony_ci#define VOUT_NAME "omap_vout" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cienum omap_vout_channels { 628c2ecf20Sopenharmony_ci OMAP_VIDEO1, 638c2ecf20Sopenharmony_ci OMAP_VIDEO2, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Variables configurable through module params*/ 678c2ecf20Sopenharmony_cistatic bool vid1_static_vrfb_alloc; 688c2ecf20Sopenharmony_cistatic bool vid2_static_vrfb_alloc; 698c2ecf20Sopenharmony_cistatic bool debug; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* Module parameters */ 728c2ecf20Sopenharmony_cimodule_param(vid1_static_vrfb_alloc, bool, S_IRUGO); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vid1_static_vrfb_alloc, 748c2ecf20Sopenharmony_ci "Static allocation of the VRFB buffer for video1 device"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cimodule_param(vid2_static_vrfb_alloc, bool, S_IRUGO); 778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vid2_static_vrfb_alloc, 788c2ecf20Sopenharmony_ci "Static allocation of the VRFB buffer for video2 device"); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cimodule_param(debug, bool, S_IRUGO); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level (0-1)"); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* list of image formats supported by OMAP2 video pipelines */ 848c2ecf20Sopenharmony_cistatic const struct v4l2_fmtdesc omap_formats[] = { 858c2ecf20Sopenharmony_ci { 868c2ecf20Sopenharmony_ci /* Note: V4L2 defines RGB565 as: 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Byte 0 Byte 1 898c2ecf20Sopenharmony_ci * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * We interpret RGB565 as: 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Byte 0 Byte 1 948c2ecf20Sopenharmony_ci * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_RGB565, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci { 998c2ecf20Sopenharmony_ci /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use 1008c2ecf20Sopenharmony_ci * this for RGB24 unpack mode, the last 8 bits are ignored 1018c2ecf20Sopenharmony_ci * */ 1028c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_RGB32, 1038c2ecf20Sopenharmony_ci }, 1048c2ecf20Sopenharmony_ci { 1058c2ecf20Sopenharmony_ci /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use 1068c2ecf20Sopenharmony_ci * this for RGB24 packed mode 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_RGB24, 1108c2ecf20Sopenharmony_ci }, 1118c2ecf20Sopenharmony_ci { 1128c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_YUYV, 1138c2ecf20Sopenharmony_ci }, 1148c2ecf20Sopenharmony_ci { 1158c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_UYVY, 1168c2ecf20Sopenharmony_ci }, 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * Try format 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistatic int omap_vout_try_format(struct v4l2_pix_format *pix) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci int ifmt, bpp = 0; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT, 1298c2ecf20Sopenharmony_ci (u32)VID_MAX_HEIGHT); 1308c2ecf20Sopenharmony_ci pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) { 1338c2ecf20Sopenharmony_ci if (pix->pixelformat == omap_formats[ifmt].pixelformat) 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (ifmt == NUM_OUTPUT_FORMATS) 1388c2ecf20Sopenharmony_ci ifmt = 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci pix->pixelformat = omap_formats[ifmt].pixelformat; 1418c2ecf20Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci switch (pix->pixelformat) { 1448c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 1458c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 1468c2ecf20Sopenharmony_ci default: 1478c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 1488c2ecf20Sopenharmony_ci bpp = YUYV_BPP; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB565: 1518c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB565X: 1528c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 1538c2ecf20Sopenharmony_ci bpp = RGB565_BPP; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 1568c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 1578c2ecf20Sopenharmony_ci bpp = RGB24_BPP; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB32: 1608c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 1618c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 1628c2ecf20Sopenharmony_ci bpp = RGB32_BPP; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci pix->bytesperline = pix->width * bpp; 1668c2ecf20Sopenharmony_ci pix->sizeimage = pix->bytesperline * pix->height; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return bpp; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* 1728c2ecf20Sopenharmony_ci * Convert V4L2 rotation to DSS rotation 1738c2ecf20Sopenharmony_ci * V4L2 understand 0, 90, 180, 270. 1748c2ecf20Sopenharmony_ci * Convert to 0, 1, 2 and 3 respectively for DSS 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistatic int v4l2_rot_to_dss_rot(int v4l2_rotation, 1778c2ecf20Sopenharmony_ci enum dss_rotation *rotation, bool mirror) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int ret = 0; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci switch (v4l2_rotation) { 1828c2ecf20Sopenharmony_ci case 90: 1838c2ecf20Sopenharmony_ci *rotation = dss_rotation_90_degree; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci case 180: 1868c2ecf20Sopenharmony_ci *rotation = dss_rotation_180_degree; 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci case 270: 1898c2ecf20Sopenharmony_ci *rotation = dss_rotation_270_degree; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case 0: 1928c2ecf20Sopenharmony_ci *rotation = dss_rotation_0_degree; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci default: 1958c2ecf20Sopenharmony_ci ret = -EINVAL; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int omap_vout_calculate_offset(struct omap_vout_device *vout) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 2038c2ecf20Sopenharmony_ci struct v4l2_rect *crop = &vout->crop; 2048c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &vout->pix; 2058c2ecf20Sopenharmony_ci int *cropped_offset = &vout->cropped_offset; 2068c2ecf20Sopenharmony_ci int ps = 2, line_length = 0; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (ovid->rotation_type == VOUT_ROT_VRFB) { 2118c2ecf20Sopenharmony_ci omap_vout_calculate_vrfb_offset(vout); 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci vout->line_length = line_length = pix->width; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (V4L2_PIX_FMT_YUYV == pix->pixelformat || 2168c2ecf20Sopenharmony_ci V4L2_PIX_FMT_UYVY == pix->pixelformat) 2178c2ecf20Sopenharmony_ci ps = 2; 2188c2ecf20Sopenharmony_ci else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) 2198c2ecf20Sopenharmony_ci ps = 4; 2208c2ecf20Sopenharmony_ci else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) 2218c2ecf20Sopenharmony_ci ps = 3; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci vout->ps = ps; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci *cropped_offset = (line_length * ps) * 2268c2ecf20Sopenharmony_ci crop->top + crop->left * ps; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n", 2308c2ecf20Sopenharmony_ci __func__, vout->cropped_offset); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* 2368c2ecf20Sopenharmony_ci * Convert V4L2 pixel format to DSS pixel format 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_cistatic int video_mode_to_dss_mode(struct omap_vout_device *vout) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 2418c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 2428c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &vout->pix; 2438c2ecf20Sopenharmony_ci enum omap_color_mode mode; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 2468c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch (pix->pixelformat) { 2498c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 2508c2ecf20Sopenharmony_ci mode = OMAP_DSS_COLOR_YUV2; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 2538c2ecf20Sopenharmony_ci mode = OMAP_DSS_COLOR_UYVY; 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB565: 2568c2ecf20Sopenharmony_ci mode = OMAP_DSS_COLOR_RGB16; 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 2598c2ecf20Sopenharmony_ci mode = OMAP_DSS_COLOR_RGB24P; 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB32: 2628c2ecf20Sopenharmony_ci mode = (ovl->id == OMAP_DSS_VIDEO1) ? 2638c2ecf20Sopenharmony_ci OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 2668c2ecf20Sopenharmony_ci mode = OMAP_DSS_COLOR_RGBX32; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci default: 2698c2ecf20Sopenharmony_ci mode = -EINVAL; 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci return mode; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* 2768c2ecf20Sopenharmony_ci * Setup the overlay 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic int omapvid_setup_overlay(struct omap_vout_device *vout, 2798c2ecf20Sopenharmony_ci struct omap_overlay *ovl, int posx, int posy, int outw, 2808c2ecf20Sopenharmony_ci int outh, u32 addr) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci int ret = 0; 2838c2ecf20Sopenharmony_ci struct omap_overlay_info info; 2848c2ecf20Sopenharmony_ci int cropheight, cropwidth, pixwidth; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 && 2878c2ecf20Sopenharmony_ci (outw != vout->pix.width || outh != vout->pix.height)) { 2888c2ecf20Sopenharmony_ci ret = -EINVAL; 2898c2ecf20Sopenharmony_ci goto setup_ovl_err; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci vout->dss_mode = video_mode_to_dss_mode(vout); 2938c2ecf20Sopenharmony_ci if (vout->dss_mode == -EINVAL) { 2948c2ecf20Sopenharmony_ci ret = -EINVAL; 2958c2ecf20Sopenharmony_ci goto setup_ovl_err; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Setup the input plane parameters according to 2998c2ecf20Sopenharmony_ci * rotation value selected. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci if (is_rotation_90_or_270(vout)) { 3028c2ecf20Sopenharmony_ci cropheight = vout->crop.width; 3038c2ecf20Sopenharmony_ci cropwidth = vout->crop.height; 3048c2ecf20Sopenharmony_ci pixwidth = vout->pix.height; 3058c2ecf20Sopenharmony_ci } else { 3068c2ecf20Sopenharmony_ci cropheight = vout->crop.height; 3078c2ecf20Sopenharmony_ci cropwidth = vout->crop.width; 3088c2ecf20Sopenharmony_ci pixwidth = vout->pix.width; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ovl->get_overlay_info(ovl, &info); 3128c2ecf20Sopenharmony_ci info.paddr = addr; 3138c2ecf20Sopenharmony_ci info.width = cropwidth; 3148c2ecf20Sopenharmony_ci info.height = cropheight; 3158c2ecf20Sopenharmony_ci info.color_mode = vout->dss_mode; 3168c2ecf20Sopenharmony_ci info.mirror = vout->mirror; 3178c2ecf20Sopenharmony_ci info.pos_x = posx; 3188c2ecf20Sopenharmony_ci info.pos_y = posy; 3198c2ecf20Sopenharmony_ci info.out_width = outw; 3208c2ecf20Sopenharmony_ci info.out_height = outh; 3218c2ecf20Sopenharmony_ci info.global_alpha = vout->win.global_alpha; 3228c2ecf20Sopenharmony_ci if (!is_rotation_enabled(vout)) { 3238c2ecf20Sopenharmony_ci info.rotation = 0; 3248c2ecf20Sopenharmony_ci info.rotation_type = OMAP_DSS_ROT_DMA; 3258c2ecf20Sopenharmony_ci info.screen_width = pixwidth; 3268c2ecf20Sopenharmony_ci } else { 3278c2ecf20Sopenharmony_ci info.rotation = vout->rotation; 3288c2ecf20Sopenharmony_ci info.rotation_type = OMAP_DSS_ROT_VRFB; 3298c2ecf20Sopenharmony_ci info.screen_width = 2048; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, 3338c2ecf20Sopenharmony_ci "%s enable=%d addr=%pad width=%d\n height=%d color_mode=%d\n" 3348c2ecf20Sopenharmony_ci "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" 3358c2ecf20Sopenharmony_ci "out_height=%d rotation_type=%d screen_width=%d\n", __func__, 3368c2ecf20Sopenharmony_ci ovl->is_enabled(ovl), &info.paddr, info.width, info.height, 3378c2ecf20Sopenharmony_ci info.color_mode, info.rotation, info.mirror, info.pos_x, 3388c2ecf20Sopenharmony_ci info.pos_y, info.out_width, info.out_height, info.rotation_type, 3398c2ecf20Sopenharmony_ci info.screen_width); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = ovl->set_overlay_info(ovl, &info); 3428c2ecf20Sopenharmony_ci if (ret) 3438c2ecf20Sopenharmony_ci goto setup_ovl_err; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cisetup_ovl_err: 3488c2ecf20Sopenharmony_ci v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n"); 3498c2ecf20Sopenharmony_ci return ret; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * Initialize the overlay structure 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_cistatic int omapvid_init(struct omap_vout_device *vout, u32 addr) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int ret = 0, i; 3588c2ecf20Sopenharmony_ci struct v4l2_window *win; 3598c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 3608c2ecf20Sopenharmony_ci int posx, posy, outw, outh; 3618c2ecf20Sopenharmony_ci struct omap_video_timings *timing; 3628c2ecf20Sopenharmony_ci struct omapvideo_info *ovid = &vout->vid_info; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci win = &vout->win; 3658c2ecf20Sopenharmony_ci for (i = 0; i < ovid->num_overlays; i++) { 3668c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ovl = ovid->overlays[i]; 3698c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (!dssdev) 3728c2ecf20Sopenharmony_ci return -EINVAL; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci timing = &dssdev->panel.timings; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci outw = win->w.width; 3778c2ecf20Sopenharmony_ci outh = win->w.height; 3788c2ecf20Sopenharmony_ci switch (vout->rotation) { 3798c2ecf20Sopenharmony_ci case dss_rotation_90_degree: 3808c2ecf20Sopenharmony_ci /* Invert the height and width for 90 3818c2ecf20Sopenharmony_ci * and 270 degree rotation 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci swap(outw, outh); 3848c2ecf20Sopenharmony_ci posy = (timing->y_res - win->w.width) - win->w.left; 3858c2ecf20Sopenharmony_ci posx = win->w.top; 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci case dss_rotation_180_degree: 3898c2ecf20Sopenharmony_ci posx = (timing->x_res - win->w.width) - win->w.left; 3908c2ecf20Sopenharmony_ci posy = (timing->y_res - win->w.height) - win->w.top; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci case dss_rotation_270_degree: 3948c2ecf20Sopenharmony_ci swap(outw, outh); 3958c2ecf20Sopenharmony_ci posy = win->w.left; 3968c2ecf20Sopenharmony_ci posx = (timing->x_res - win->w.height) - win->w.top; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci default: 4008c2ecf20Sopenharmony_ci posx = win->w.left; 4018c2ecf20Sopenharmony_ci posy = win->w.top; 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci ret = omapvid_setup_overlay(vout, ovl, posx, posy, 4068c2ecf20Sopenharmony_ci outw, outh, addr); 4078c2ecf20Sopenharmony_ci if (ret) 4088c2ecf20Sopenharmony_ci goto omapvid_init_err; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ciomapvid_init_err: 4138c2ecf20Sopenharmony_ci v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n"); 4148c2ecf20Sopenharmony_ci return ret; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* 4188c2ecf20Sopenharmony_ci * Apply the changes set the go bit of DSS 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cistatic int omapvid_apply_changes(struct omap_vout_device *vout) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci int i; 4238c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 4248c2ecf20Sopenharmony_ci struct omapvideo_info *ovid = &vout->vid_info; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci for (i = 0; i < ovid->num_overlays; i++) { 4278c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ovl = ovid->overlays[i]; 4308c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 4318c2ecf20Sopenharmony_ci if (!dssdev) 4328c2ecf20Sopenharmony_ci return -EINVAL; 4338c2ecf20Sopenharmony_ci ovl->manager->apply(ovl->manager); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int omapvid_handle_interlace_display(struct omap_vout_device *vout, 4408c2ecf20Sopenharmony_ci unsigned int irqstatus, u64 ts) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci u32 fid; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (vout->first_int) { 4458c2ecf20Sopenharmony_ci vout->first_int = 0; 4468c2ecf20Sopenharmony_ci goto err; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (irqstatus & DISPC_IRQ_EVSYNC_ODD) 4508c2ecf20Sopenharmony_ci fid = 1; 4518c2ecf20Sopenharmony_ci else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) 4528c2ecf20Sopenharmony_ci fid = 0; 4538c2ecf20Sopenharmony_ci else 4548c2ecf20Sopenharmony_ci goto err; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci vout->field_id ^= 1; 4578c2ecf20Sopenharmony_ci if (fid != vout->field_id) { 4588c2ecf20Sopenharmony_ci if (fid == 0) 4598c2ecf20Sopenharmony_ci vout->field_id = fid; 4608c2ecf20Sopenharmony_ci } else if (0 == fid) { 4618c2ecf20Sopenharmony_ci if (vout->cur_frm == vout->next_frm) 4628c2ecf20Sopenharmony_ci goto err; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci vout->cur_frm->vbuf.vb2_buf.timestamp = ts; 4658c2ecf20Sopenharmony_ci vout->cur_frm->vbuf.sequence = vout->sequence++; 4668c2ecf20Sopenharmony_ci vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); 4678c2ecf20Sopenharmony_ci vout->cur_frm = vout->next_frm; 4688c2ecf20Sopenharmony_ci } else { 4698c2ecf20Sopenharmony_ci if (list_empty(&vout->dma_queue) || 4708c2ecf20Sopenharmony_ci (vout->cur_frm != vout->next_frm)) 4718c2ecf20Sopenharmony_ci goto err; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return vout->field_id; 4758c2ecf20Sopenharmony_cierr: 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void omap_vout_isr(void *arg, unsigned int irqstatus) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci int ret, fid, mgr_id; 4828c2ecf20Sopenharmony_ci u32 addr, irq; 4838c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 4848c2ecf20Sopenharmony_ci u64 ts; 4858c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 4868c2ecf20Sopenharmony_ci struct omap_dss_device *cur_display; 4878c2ecf20Sopenharmony_ci struct omap_vout_device *vout = (struct omap_vout_device *)arg; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 4908c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci mgr_id = ovl->manager->id; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* get the display device attached to the overlay */ 4958c2ecf20Sopenharmony_ci cur_display = ovl->get_device(ovl); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (!cur_display) 4988c2ecf20Sopenharmony_ci return; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci spin_lock(&vout->vbq_lock); 5018c2ecf20Sopenharmony_ci ts = ktime_get_ns(); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci switch (cur_display->type) { 5048c2ecf20Sopenharmony_ci case OMAP_DISPLAY_TYPE_DSI: 5058c2ecf20Sopenharmony_ci case OMAP_DISPLAY_TYPE_DPI: 5068c2ecf20Sopenharmony_ci case OMAP_DISPLAY_TYPE_DVI: 5078c2ecf20Sopenharmony_ci if (mgr_id == OMAP_DSS_CHANNEL_LCD) 5088c2ecf20Sopenharmony_ci irq = DISPC_IRQ_VSYNC; 5098c2ecf20Sopenharmony_ci else if (mgr_id == OMAP_DSS_CHANNEL_LCD2) 5108c2ecf20Sopenharmony_ci irq = DISPC_IRQ_VSYNC2; 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci goto vout_isr_err; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (!(irqstatus & irq)) 5158c2ecf20Sopenharmony_ci goto vout_isr_err; 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci case OMAP_DISPLAY_TYPE_VENC: 5188c2ecf20Sopenharmony_ci fid = omapvid_handle_interlace_display(vout, irqstatus, 5198c2ecf20Sopenharmony_ci ts); 5208c2ecf20Sopenharmony_ci if (!fid) 5218c2ecf20Sopenharmony_ci goto vout_isr_err; 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case OMAP_DISPLAY_TYPE_HDMI: 5248c2ecf20Sopenharmony_ci if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) 5258c2ecf20Sopenharmony_ci goto vout_isr_err; 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci default: 5288c2ecf20Sopenharmony_ci goto vout_isr_err; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { 5328c2ecf20Sopenharmony_ci vout->cur_frm->vbuf.vb2_buf.timestamp = ts; 5338c2ecf20Sopenharmony_ci vout->cur_frm->vbuf.sequence = vout->sequence++; 5348c2ecf20Sopenharmony_ci vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); 5358c2ecf20Sopenharmony_ci vout->cur_frm = vout->next_frm; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci vout->first_int = 0; 5398c2ecf20Sopenharmony_ci if (list_empty(&vout->dma_queue)) 5408c2ecf20Sopenharmony_ci goto vout_isr_err; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci vout->next_frm = list_entry(vout->dma_queue.next, 5438c2ecf20Sopenharmony_ci struct omap_vout_buffer, queue); 5448c2ecf20Sopenharmony_ci list_del(&vout->next_frm->queue); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci addr = (unsigned long)vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index] 5478c2ecf20Sopenharmony_ci + vout->cropped_offset; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* First save the configuration in ovelray structure */ 5508c2ecf20Sopenharmony_ci ret = omapvid_init(vout, addr); 5518c2ecf20Sopenharmony_ci if (ret) { 5528c2ecf20Sopenharmony_ci printk(KERN_ERR VOUT_NAME 5538c2ecf20Sopenharmony_ci "failed to set overlay info\n"); 5548c2ecf20Sopenharmony_ci goto vout_isr_err; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Enable the pipeline and set the Go bit */ 5588c2ecf20Sopenharmony_ci ret = omapvid_apply_changes(vout); 5598c2ecf20Sopenharmony_ci if (ret) 5608c2ecf20Sopenharmony_ci printk(KERN_ERR VOUT_NAME "failed to change mode\n"); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_civout_isr_err: 5638c2ecf20Sopenharmony_ci spin_unlock(&vout->vbq_lock); 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci/* 5688c2ecf20Sopenharmony_ci * V4L2 ioctls 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *fh, 5718c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); 5768c2ecf20Sopenharmony_ci strscpy(cap->card, vout->vfd->name, sizeof(cap->card)); 5778c2ecf20Sopenharmony_ci snprintf(cap->bus_info, sizeof(cap->bus_info), 5788c2ecf20Sopenharmony_ci "platform:%s.%d", VOUT_NAME, vout->vid); 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_out(struct file *file, void *fh, 5838c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *fmt) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci int index = fmt->index; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (index >= NUM_OUTPUT_FORMATS) 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci fmt->flags = omap_formats[index].flags; 5918c2ecf20Sopenharmony_ci fmt->pixelformat = omap_formats[index].pixelformat; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci return 0; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_out(struct file *file, void *fh, 5978c2ecf20Sopenharmony_ci struct v4l2_format *f) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci f->fmt.pix = vout->pix; 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_out(struct file *file, void *fh, 6078c2ecf20Sopenharmony_ci struct v4l2_format *f) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 6108c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 6118c2ecf20Sopenharmony_ci struct omap_video_timings *timing; 6128c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 6138c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 6168c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 6178c2ecf20Sopenharmony_ci /* get the display device attached to the overlay */ 6188c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (!dssdev) 6218c2ecf20Sopenharmony_ci return -EINVAL; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci timing = &dssdev->panel.timings; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = timing->y_res; 6268c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = timing->x_res; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci omap_vout_try_format(&f->fmt.pix); 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vid_out(struct file *file, void *fh, 6338c2ecf20Sopenharmony_ci struct v4l2_format *f) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci int ret, bpp; 6368c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 6378c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 6388c2ecf20Sopenharmony_ci struct omap_video_timings *timing; 6398c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 6408c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (vb2_is_busy(&vout->vq)) 6438c2ecf20Sopenharmony_ci return -EBUSY; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 6468c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 6478c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* get the display device attached to the overlay */ 6508c2ecf20Sopenharmony_ci if (!dssdev) { 6518c2ecf20Sopenharmony_ci ret = -EINVAL; 6528c2ecf20Sopenharmony_ci goto s_fmt_vid_out_exit; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci timing = &dssdev->panel.timings; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* We don't support RGB24-packed mode if vrfb rotation 6578c2ecf20Sopenharmony_ci * is enabled*/ 6588c2ecf20Sopenharmony_ci if ((is_rotation_enabled(vout)) && 6598c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { 6608c2ecf20Sopenharmony_ci ret = -EINVAL; 6618c2ecf20Sopenharmony_ci goto s_fmt_vid_out_exit; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* get the framebuffer parameters */ 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (is_rotation_90_or_270(vout)) { 6678c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = timing->x_res; 6688c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = timing->y_res; 6698c2ecf20Sopenharmony_ci } else { 6708c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = timing->y_res; 6718c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = timing->x_res; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* change to smaller size is OK */ 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci bpp = omap_vout_try_format(&f->fmt.pix); 6778c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* try & set the new output format */ 6808c2ecf20Sopenharmony_ci vout->bpp = bpp; 6818c2ecf20Sopenharmony_ci vout->pix = f->fmt.pix; 6828c2ecf20Sopenharmony_ci vout->vrfb_bpp = 1; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* If YUYV then vrfb bpp is 2, for others its 1 */ 6858c2ecf20Sopenharmony_ci if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat || 6868c2ecf20Sopenharmony_ci V4L2_PIX_FMT_UYVY == vout->pix.pixelformat) 6878c2ecf20Sopenharmony_ci vout->vrfb_bpp = 2; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* set default crop and win */ 6908c2ecf20Sopenharmony_ci omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ret = 0; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cis_fmt_vid_out_exit: 6958c2ecf20Sopenharmony_ci return ret; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, 6998c2ecf20Sopenharmony_ci struct v4l2_format *f) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci int ret = 0; 7028c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 7038c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 7048c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 7058c2ecf20Sopenharmony_ci struct v4l2_window *win = &f->fmt.win; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 7088c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci ret = omap_vout_try_window(&vout->fbuf, win); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!ret && !(ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)) 7138c2ecf20Sopenharmony_ci win->global_alpha = 0; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return ret; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, 7198c2ecf20Sopenharmony_ci struct v4l2_format *f) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci int ret = 0; 7228c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 7238c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 7248c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 7258c2ecf20Sopenharmony_ci struct v4l2_window *win = &f->fmt.win; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 7288c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); 7318c2ecf20Sopenharmony_ci if (!ret) { 7328c2ecf20Sopenharmony_ci enum omap_dss_trans_key_type key_type = 7338c2ecf20Sopenharmony_ci OMAP_DSS_COLOR_KEY_GFX_DST; 7348c2ecf20Sopenharmony_ci int enable; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Video1 plane does not support global alpha on OMAP3 */ 7378c2ecf20Sopenharmony_ci if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) 7388c2ecf20Sopenharmony_ci vout->win.global_alpha = win->global_alpha; 7398c2ecf20Sopenharmony_ci else 7408c2ecf20Sopenharmony_ci win->global_alpha = 0; 7418c2ecf20Sopenharmony_ci if (vout->fbuf.flags & (V4L2_FBUF_FLAG_CHROMAKEY | 7428c2ecf20Sopenharmony_ci V4L2_FBUF_FLAG_SRC_CHROMAKEY)) 7438c2ecf20Sopenharmony_ci enable = 1; 7448c2ecf20Sopenharmony_ci else 7458c2ecf20Sopenharmony_ci enable = 0; 7468c2ecf20Sopenharmony_ci if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) 7478c2ecf20Sopenharmony_ci key_type = OMAP_DSS_COLOR_KEY_VID_SRC; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (ovl->manager && ovl->manager->get_manager_info && 7508c2ecf20Sopenharmony_ci ovl->manager->set_manager_info) { 7518c2ecf20Sopenharmony_ci struct omap_overlay_manager_info info; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci ovl->manager->get_manager_info(ovl->manager, &info); 7548c2ecf20Sopenharmony_ci info.trans_enabled = enable; 7558c2ecf20Sopenharmony_ci info.trans_key_type = key_type; 7568c2ecf20Sopenharmony_ci info.trans_key = vout->win.chromakey; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (ovl->manager->set_manager_info(ovl->manager, &info)) 7598c2ecf20Sopenharmony_ci return -EINVAL; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci return ret; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, 7668c2ecf20Sopenharmony_ci struct v4l2_format *f) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 7698c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 7708c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 7718c2ecf20Sopenharmony_ci struct v4l2_window *win = &f->fmt.win; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 7748c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci win->w = vout->win.w; 7778c2ecf20Sopenharmony_ci win->field = vout->win.field; 7788c2ecf20Sopenharmony_ci win->chromakey = vout->win.chromakey; 7798c2ecf20Sopenharmony_ci if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) 7808c2ecf20Sopenharmony_ci win->global_alpha = vout->win.global_alpha; 7818c2ecf20Sopenharmony_ci else 7828c2ecf20Sopenharmony_ci win->global_alpha = 0; 7838c2ecf20Sopenharmony_ci win->clips = NULL; 7848c2ecf20Sopenharmony_ci win->clipcount = 0; 7858c2ecf20Sopenharmony_ci win->bitmap = NULL; 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 7928c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &vout->pix; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 7958c2ecf20Sopenharmony_ci return -EINVAL; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci switch (sel->target) { 7988c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP: 7998c2ecf20Sopenharmony_ci sel->r = vout->crop; 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 8028c2ecf20Sopenharmony_ci omap_vout_default_crop(&vout->pix, &vout->fbuf, &sel->r); 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 8058c2ecf20Sopenharmony_ci /* Width and height are always even */ 8068c2ecf20Sopenharmony_ci sel->r.width = pix->width & ~1; 8078c2ecf20Sopenharmony_ci sel->r.height = pix->height & ~1; 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci default: 8108c2ecf20Sopenharmony_ci return -EINVAL; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci return 0; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci int ret = -EINVAL; 8188c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 8198c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 8208c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 8218c2ecf20Sopenharmony_ci struct omap_video_timings *timing; 8228c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 8258c2ecf20Sopenharmony_ci return -EINVAL; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (sel->target != V4L2_SEL_TGT_CROP) 8288c2ecf20Sopenharmony_ci return -EINVAL; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (vb2_is_busy(&vout->vq)) 8318c2ecf20Sopenharmony_ci return -EBUSY; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 8348c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 8358c2ecf20Sopenharmony_ci /* get the display device attached to the overlay */ 8368c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (!dssdev) { 8398c2ecf20Sopenharmony_ci ret = -EINVAL; 8408c2ecf20Sopenharmony_ci goto s_crop_err; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci timing = &dssdev->panel.timings; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (is_rotation_90_or_270(vout)) { 8468c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = timing->x_res; 8478c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = timing->y_res; 8488c2ecf20Sopenharmony_ci } else { 8498c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = timing->y_res; 8508c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = timing->x_res; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win, 8548c2ecf20Sopenharmony_ci &vout->fbuf, &sel->r); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cis_crop_err: 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct omap_vout_device *vout = 8638c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct omap_vout_device, ctrl_handler); 8648c2ecf20Sopenharmony_ci int ret = 0; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci switch (ctrl->id) { 8678c2ecf20Sopenharmony_ci case V4L2_CID_ROTATE: { 8688c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 8698c2ecf20Sopenharmony_ci int rotation = ctrl->val; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (rotation && ovid->rotation_type == VOUT_ROT_NONE) { 8748c2ecf20Sopenharmony_ci ret = -ERANGE; 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { 8798c2ecf20Sopenharmony_ci ret = -EINVAL; 8808c2ecf20Sopenharmony_ci break; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (v4l2_rot_to_dss_rot(rotation, &vout->rotation, 8848c2ecf20Sopenharmony_ci vout->mirror)) { 8858c2ecf20Sopenharmony_ci ret = -EINVAL; 8868c2ecf20Sopenharmony_ci break; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci case V4L2_CID_BG_COLOR: 8918c2ecf20Sopenharmony_ci { 8928c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 8938c2ecf20Sopenharmony_ci unsigned int color = ctrl->val; 8948c2ecf20Sopenharmony_ci struct omap_overlay_manager_info info; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci ovl = vout->vid_info.overlays[0]; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (!ovl->manager || !ovl->manager->get_manager_info) { 8998c2ecf20Sopenharmony_ci ret = -EINVAL; 9008c2ecf20Sopenharmony_ci break; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci ovl->manager->get_manager_info(ovl->manager, &info); 9048c2ecf20Sopenharmony_ci info.default_color = color; 9058c2ecf20Sopenharmony_ci if (ovl->manager->set_manager_info(ovl->manager, &info)) { 9068c2ecf20Sopenharmony_ci ret = -EINVAL; 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci case V4L2_CID_VFLIP: 9128c2ecf20Sopenharmony_ci { 9138c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 9148c2ecf20Sopenharmony_ci unsigned int mirror = ctrl->val; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { 9198c2ecf20Sopenharmony_ci ret = -ERANGE; 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { 9248c2ecf20Sopenharmony_ci ret = -EINVAL; 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci vout->mirror = mirror; 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci default: 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci return ret; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops omap_vout_ctrl_ops = { 9378c2ecf20Sopenharmony_ci .s_ctrl = omap_vout_s_ctrl, 9388c2ecf20Sopenharmony_ci}; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int omap_vout_vb2_queue_setup(struct vb2_queue *vq, 9418c2ecf20Sopenharmony_ci unsigned int *nbufs, 9428c2ecf20Sopenharmony_ci unsigned int *num_planes, unsigned int sizes[], 9438c2ecf20Sopenharmony_ci struct device *alloc_devs[]) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct omap_vout_device *vout = vb2_get_drv_priv(vq); 9468c2ecf20Sopenharmony_ci int size = vout->pix.sizeimage; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) { 9498c2ecf20Sopenharmony_ci *nbufs = VRFB_NUM_BUFS - vq->num_buffers; 9508c2ecf20Sopenharmony_ci if (*nbufs == 0) 9518c2ecf20Sopenharmony_ci return -EINVAL; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (*num_planes) 9558c2ecf20Sopenharmony_ci return sizes[0] < size ? -EINVAL : 0; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci *num_planes = 1; 9588c2ecf20Sopenharmony_ci sizes[0] = size; 9598c2ecf20Sopenharmony_ci return 0; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic int omap_vout_vb2_prepare(struct vb2_buffer *vb) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); 9658c2ecf20Sopenharmony_ci struct omapvideo_info *ovid = &vout->vid_info; 9668c2ecf20Sopenharmony_ci struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); 9678c2ecf20Sopenharmony_ci dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (vb2_plane_size(vb, 0) < vout->pix.sizeimage) { 9708c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, 9718c2ecf20Sopenharmony_ci "%s data will not fit into plane (%lu < %u)\n", 9728c2ecf20Sopenharmony_ci __func__, vb2_plane_size(vb, 0), vout->pix.sizeimage); 9738c2ecf20Sopenharmony_ci return -EINVAL; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci vb2_set_plane_payload(vb, 0, vout->pix.sizeimage); 9778c2ecf20Sopenharmony_ci voutbuf->vbuf.field = V4L2_FIELD_NONE; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci vout->queued_buf_addr[vb->index] = (u8 *)buf_phy_addr; 9808c2ecf20Sopenharmony_ci if (ovid->rotation_type == VOUT_ROT_VRFB) 9818c2ecf20Sopenharmony_ci return omap_vout_prepare_vrfb(vout, vb); 9828c2ecf20Sopenharmony_ci return 0; 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic void omap_vout_vb2_queue(struct vb2_buffer *vb) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); 9888c2ecf20Sopenharmony_ci struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci list_add_tail(&voutbuf->queue, &vout->dma_queue); 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci struct omap_vout_device *vout = vb2_get_drv_priv(vq); 9968c2ecf20Sopenharmony_ci struct omapvideo_info *ovid = &vout->vid_info; 9978c2ecf20Sopenharmony_ci struct omap_vout_buffer *buf, *tmp; 9988c2ecf20Sopenharmony_ci u32 addr = 0, mask = 0; 9998c2ecf20Sopenharmony_ci int ret, j; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Get the next frame from the buffer queue */ 10028c2ecf20Sopenharmony_ci vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next, 10038c2ecf20Sopenharmony_ci struct omap_vout_buffer, queue); 10048c2ecf20Sopenharmony_ci /* Remove buffer from the buffer queue */ 10058c2ecf20Sopenharmony_ci list_del(&vout->cur_frm->queue); 10068c2ecf20Sopenharmony_ci /* Initialize field_id and started member */ 10078c2ecf20Sopenharmony_ci vout->field_id = 0; 10088c2ecf20Sopenharmony_ci vout->first_int = 1; 10098c2ecf20Sopenharmony_ci vout->sequence = 0; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (omap_vout_calculate_offset(vout)) { 10128c2ecf20Sopenharmony_ci ret = -EINVAL; 10138c2ecf20Sopenharmony_ci goto out; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci if (ovid->rotation_type == VOUT_ROT_VRFB) 10168c2ecf20Sopenharmony_ci if (omap_vout_vrfb_buffer_setup(vout, &count, 0)) { 10178c2ecf20Sopenharmony_ci ret = -ENOMEM; 10188c2ecf20Sopenharmony_ci goto out; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci addr = (unsigned long)vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index] 10228c2ecf20Sopenharmony_ci + vout->cropped_offset; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD 10258c2ecf20Sopenharmony_ci | DISPC_IRQ_VSYNC2; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* First save the configuration in overlay structure */ 10288c2ecf20Sopenharmony_ci ret = omapvid_init(vout, addr); 10298c2ecf20Sopenharmony_ci if (ret) { 10308c2ecf20Sopenharmony_ci v4l2_err(&vout->vid_dev->v4l2_dev, 10318c2ecf20Sopenharmony_ci "failed to set overlay info\n"); 10328c2ecf20Sopenharmony_ci goto streamon_err1; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci omap_dispc_register_isr(omap_vout_isr, vout, mask); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Enable the pipeline and set the Go bit */ 10388c2ecf20Sopenharmony_ci ret = omapvid_apply_changes(vout); 10398c2ecf20Sopenharmony_ci if (ret) 10408c2ecf20Sopenharmony_ci v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci for (j = 0; j < ovid->num_overlays; j++) { 10438c2ecf20Sopenharmony_ci struct omap_overlay *ovl = ovid->overlays[j]; 10448c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev = ovl->get_device(ovl); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (dssdev) { 10478c2ecf20Sopenharmony_ci ret = ovl->enable(ovl); 10488c2ecf20Sopenharmony_ci if (ret) 10498c2ecf20Sopenharmony_ci goto streamon_err1; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci return 0; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistreamon_err1: 10558c2ecf20Sopenharmony_ci mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD 10568c2ecf20Sopenharmony_ci | DISPC_IRQ_VSYNC2; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci omap_dispc_unregister_isr(omap_vout_isr, vout, mask); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci for (j = 0; j < ovid->num_overlays; j++) { 10618c2ecf20Sopenharmony_ci struct omap_overlay *ovl = ovid->overlays[j]; 10628c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev = ovl->get_device(ovl); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (dssdev) 10658c2ecf20Sopenharmony_ci ovl->disable(ovl); 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci /* Turn of the pipeline */ 10688c2ecf20Sopenharmony_ci if (omapvid_apply_changes(vout)) 10698c2ecf20Sopenharmony_ci v4l2_err(&vout->vid_dev->v4l2_dev, 10708c2ecf20Sopenharmony_ci "failed to change mode in streamoff\n"); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ciout: 10738c2ecf20Sopenharmony_ci vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); 10748c2ecf20Sopenharmony_ci list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { 10758c2ecf20Sopenharmony_ci list_del(&buf->queue); 10768c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci return ret; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic void omap_vout_vb2_stop_streaming(struct vb2_queue *vq) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct omap_vout_device *vout = vb2_get_drv_priv(vq); 10848c2ecf20Sopenharmony_ci struct omapvideo_info *ovid = &vout->vid_info; 10858c2ecf20Sopenharmony_ci struct omap_vout_buffer *buf, *tmp; 10868c2ecf20Sopenharmony_ci u32 mask = 0; 10878c2ecf20Sopenharmony_ci int j; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD 10908c2ecf20Sopenharmony_ci | DISPC_IRQ_VSYNC2; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci omap_dispc_unregister_isr(omap_vout_isr, vout, mask); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci for (j = 0; j < ovid->num_overlays; j++) { 10958c2ecf20Sopenharmony_ci struct omap_overlay *ovl = ovid->overlays[j]; 10968c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev = ovl->get_device(ovl); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (dssdev) 10998c2ecf20Sopenharmony_ci ovl->disable(ovl); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci /* Turn of the pipeline */ 11028c2ecf20Sopenharmony_ci if (omapvid_apply_changes(vout)) 11038c2ecf20Sopenharmony_ci v4l2_err(&vout->vid_dev->v4l2_dev, 11048c2ecf20Sopenharmony_ci "failed to change mode in streamoff\n"); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (vout->next_frm != vout->cur_frm) 11078c2ecf20Sopenharmony_ci vb2_buffer_done(&vout->next_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); 11088c2ecf20Sopenharmony_ci vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); 11098c2ecf20Sopenharmony_ci list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { 11108c2ecf20Sopenharmony_ci list_del(&buf->queue); 11118c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic int vidioc_s_fbuf(struct file *file, void *fh, 11168c2ecf20Sopenharmony_ci const struct v4l2_framebuffer *a) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci int enable = 0; 11198c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 11208c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 11218c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 11228c2ecf20Sopenharmony_ci struct omap_overlay_manager_info info; 11238c2ecf20Sopenharmony_ci enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 11268c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* OMAP DSS doesn't support Source and Destination color 11298c2ecf20Sopenharmony_ci key together */ 11308c2ecf20Sopenharmony_ci if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && 11318c2ecf20Sopenharmony_ci (a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) 11328c2ecf20Sopenharmony_ci return -EINVAL; 11338c2ecf20Sopenharmony_ci /* OMAP DSS Doesn't support the Destination color key 11348c2ecf20Sopenharmony_ci and alpha blending together */ 11358c2ecf20Sopenharmony_ci if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) && 11368c2ecf20Sopenharmony_ci (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) 11378c2ecf20Sopenharmony_ci return -EINVAL; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) { 11408c2ecf20Sopenharmony_ci vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; 11418c2ecf20Sopenharmony_ci key_type = OMAP_DSS_COLOR_KEY_VID_SRC; 11428c2ecf20Sopenharmony_ci } else 11438c2ecf20Sopenharmony_ci vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) { 11468c2ecf20Sopenharmony_ci vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY; 11478c2ecf20Sopenharmony_ci key_type = OMAP_DSS_COLOR_KEY_GFX_DST; 11488c2ecf20Sopenharmony_ci } else 11498c2ecf20Sopenharmony_ci vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY | 11528c2ecf20Sopenharmony_ci V4L2_FBUF_FLAG_SRC_CHROMAKEY)) 11538c2ecf20Sopenharmony_ci enable = 1; 11548c2ecf20Sopenharmony_ci else 11558c2ecf20Sopenharmony_ci enable = 0; 11568c2ecf20Sopenharmony_ci if (ovl->manager && ovl->manager->get_manager_info && 11578c2ecf20Sopenharmony_ci ovl->manager->set_manager_info) { 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci ovl->manager->get_manager_info(ovl->manager, &info); 11608c2ecf20Sopenharmony_ci info.trans_enabled = enable; 11618c2ecf20Sopenharmony_ci info.trans_key_type = key_type; 11628c2ecf20Sopenharmony_ci info.trans_key = vout->win.chromakey; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (ovl->manager->set_manager_info(ovl->manager, &info)) 11658c2ecf20Sopenharmony_ci return -EINVAL; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) { 11688c2ecf20Sopenharmony_ci vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; 11698c2ecf20Sopenharmony_ci enable = 1; 11708c2ecf20Sopenharmony_ci } else { 11718c2ecf20Sopenharmony_ci vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA; 11728c2ecf20Sopenharmony_ci enable = 0; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci if (ovl->manager && ovl->manager->get_manager_info && 11758c2ecf20Sopenharmony_ci ovl->manager->set_manager_info) { 11768c2ecf20Sopenharmony_ci ovl->manager->get_manager_info(ovl->manager, &info); 11778c2ecf20Sopenharmony_ci /* enable this only if there is no zorder cap */ 11788c2ecf20Sopenharmony_ci if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) 11798c2ecf20Sopenharmony_ci info.partial_alpha_enabled = enable; 11808c2ecf20Sopenharmony_ci if (ovl->manager->set_manager_info(ovl->manager, &info)) 11818c2ecf20Sopenharmony_ci return -EINVAL; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci return 0; 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic int vidioc_g_fbuf(struct file *file, void *fh, 11888c2ecf20Sopenharmony_ci struct v4l2_framebuffer *a) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 11918c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 11928c2ecf20Sopenharmony_ci struct omap_vout_device *vout = video_drvdata(file); 11938c2ecf20Sopenharmony_ci struct omap_overlay_manager_info info; 11948c2ecf20Sopenharmony_ci struct omap_video_timings *timing; 11958c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 11988c2ecf20Sopenharmony_ci ovl = ovid->overlays[0]; 11998c2ecf20Sopenharmony_ci /* get the display device attached to the overlay */ 12008c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (!dssdev) 12038c2ecf20Sopenharmony_ci return -EINVAL; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci timing = &dssdev->panel.timings; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = timing->y_res; 12088c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = timing->x_res; 12098c2ecf20Sopenharmony_ci a->fmt.field = V4L2_FIELD_NONE; 12108c2ecf20Sopenharmony_ci a->fmt.colorspace = V4L2_COLORSPACE_SRGB; 12118c2ecf20Sopenharmony_ci a->fmt.pixelformat = V4L2_PIX_FMT_RGBA32; 12128c2ecf20Sopenharmony_ci a->fmt.height = vout->fbuf.fmt.height; 12138c2ecf20Sopenharmony_ci a->fmt.width = vout->fbuf.fmt.width; 12148c2ecf20Sopenharmony_ci a->fmt.bytesperline = vout->fbuf.fmt.width * 4; 12158c2ecf20Sopenharmony_ci a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; 12168c2ecf20Sopenharmony_ci a->base = vout->fbuf.base; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci a->flags = vout->fbuf.flags; 12198c2ecf20Sopenharmony_ci a->capability = vout->fbuf.capability; 12208c2ecf20Sopenharmony_ci a->flags &= ~(V4L2_FBUF_FLAG_SRC_CHROMAKEY | V4L2_FBUF_FLAG_CHROMAKEY | 12218c2ecf20Sopenharmony_ci V4L2_FBUF_FLAG_LOCAL_ALPHA); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (ovl->manager && ovl->manager->get_manager_info) { 12248c2ecf20Sopenharmony_ci ovl->manager->get_manager_info(ovl->manager, &info); 12258c2ecf20Sopenharmony_ci if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC) 12268c2ecf20Sopenharmony_ci a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; 12278c2ecf20Sopenharmony_ci if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST) 12288c2ecf20Sopenharmony_ci a->flags |= V4L2_FBUF_FLAG_CHROMAKEY; 12298c2ecf20Sopenharmony_ci if (info.partial_alpha_enabled) 12308c2ecf20Sopenharmony_ci a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return 0; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int vidioc_enum_output(struct file *file, void *priv_fh, 12378c2ecf20Sopenharmony_ci struct v4l2_output *out) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci if (out->index) 12408c2ecf20Sopenharmony_ci return -EINVAL; 12418c2ecf20Sopenharmony_ci snprintf(out->name, sizeof(out->name), "Overlay"); 12428c2ecf20Sopenharmony_ci out->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; 12438c2ecf20Sopenharmony_ci return 0; 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cistatic int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci *i = 0; 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci return i ? -EINVAL : 0; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops vout_ioctl_ops = { 12588c2ecf20Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 12598c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, 12608c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, 12618c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, 12628c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, 12638c2ecf20Sopenharmony_ci .vidioc_s_fbuf = vidioc_s_fbuf, 12648c2ecf20Sopenharmony_ci .vidioc_g_fbuf = vidioc_g_fbuf, 12658c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_overlay, 12668c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_overlay, 12678c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay, 12688c2ecf20Sopenharmony_ci .vidioc_g_selection = vidioc_g_selection, 12698c2ecf20Sopenharmony_ci .vidioc_s_selection = vidioc_s_selection, 12708c2ecf20Sopenharmony_ci .vidioc_enum_output = vidioc_enum_output, 12718c2ecf20Sopenharmony_ci .vidioc_g_output = vidioc_g_output, 12728c2ecf20Sopenharmony_ci .vidioc_s_output = vidioc_s_output, 12738c2ecf20Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 12748c2ecf20Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 12758c2ecf20Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 12768c2ecf20Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 12778c2ecf20Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 12788c2ecf20Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 12798c2ecf20Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 12808c2ecf20Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 12818c2ecf20Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 12828c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 12838c2ecf20Sopenharmony_ci}; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations omap_vout_fops = { 12868c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12878c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 12888c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 12898c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 12908c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 12918c2ecf20Sopenharmony_ci .release = vb2_fop_release, 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic const struct vb2_ops omap_vout_vb2_ops = { 12958c2ecf20Sopenharmony_ci .queue_setup = omap_vout_vb2_queue_setup, 12968c2ecf20Sopenharmony_ci .buf_queue = omap_vout_vb2_queue, 12978c2ecf20Sopenharmony_ci .buf_prepare = omap_vout_vb2_prepare, 12988c2ecf20Sopenharmony_ci .start_streaming = omap_vout_vb2_start_streaming, 12998c2ecf20Sopenharmony_ci .stop_streaming = omap_vout_vb2_stop_streaming, 13008c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 13018c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 13028c2ecf20Sopenharmony_ci}; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci/* Init functions used during driver initialization */ 13058c2ecf20Sopenharmony_ci/* Initial setup of video_data */ 13068c2ecf20Sopenharmony_cistatic int __init omap_vout_setup_video_data(struct omap_vout_device *vout) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci struct video_device *vfd; 13098c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix; 13108c2ecf20Sopenharmony_ci struct omap_overlay *ovl = vout->vid_info.overlays[0]; 13118c2ecf20Sopenharmony_ci struct omap_dss_device *display = ovl->get_device(ovl); 13128c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl; 13138c2ecf20Sopenharmony_ci struct vb2_queue *vq; 13148c2ecf20Sopenharmony_ci int ret; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* set the default pix */ 13178c2ecf20Sopenharmony_ci pix = &vout->pix; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* Set the default picture of QVGA */ 13208c2ecf20Sopenharmony_ci pix->width = QQVGA_WIDTH; 13218c2ecf20Sopenharmony_ci pix->height = QQVGA_HEIGHT; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* Default pixel format is RGB 5-6-5 */ 13248c2ecf20Sopenharmony_ci pix->pixelformat = V4L2_PIX_FMT_RGB565; 13258c2ecf20Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 13268c2ecf20Sopenharmony_ci pix->bytesperline = pix->width * 2; 13278c2ecf20Sopenharmony_ci pix->sizeimage = pix->bytesperline * pix->height; 13288c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci vout->bpp = RGB565_BPP; 13318c2ecf20Sopenharmony_ci vout->fbuf.fmt.width = display->panel.timings.x_res; 13328c2ecf20Sopenharmony_ci vout->fbuf.fmt.height = display->panel.timings.y_res; 13338c2ecf20Sopenharmony_ci vout->cropped_offset = 0; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* Set the data structures for the overlay parameters*/ 13368c2ecf20Sopenharmony_ci vout->fbuf.flags = V4L2_FBUF_FLAG_OVERLAY; 13378c2ecf20Sopenharmony_ci vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA | 13388c2ecf20Sopenharmony_ci V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY | 13398c2ecf20Sopenharmony_ci V4L2_FBUF_CAP_EXTERNOVERLAY; 13408c2ecf20Sopenharmony_ci if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) { 13418c2ecf20Sopenharmony_ci vout->win.global_alpha = 255; 13428c2ecf20Sopenharmony_ci vout->fbuf.capability |= V4L2_FBUF_CAP_GLOBAL_ALPHA; 13438c2ecf20Sopenharmony_ci vout->fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; 13448c2ecf20Sopenharmony_ci } else { 13458c2ecf20Sopenharmony_ci vout->win.global_alpha = 0; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci vout->win.field = V4L2_FIELD_NONE; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci hdl = &vout->ctrl_handler; 13528c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 3); 13538c2ecf20Sopenharmony_ci if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) { 13548c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, 13558c2ecf20Sopenharmony_ci V4L2_CID_ROTATE, 0, 270, 90, 0); 13568c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, 13578c2ecf20Sopenharmony_ci V4L2_CID_VFLIP, 0, 1, 1, 0); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, 13608c2ecf20Sopenharmony_ci V4L2_CID_BG_COLOR, 0, 0xffffff, 1, 0); 13618c2ecf20Sopenharmony_ci if (hdl->error) 13628c2ecf20Sopenharmony_ci return hdl->error; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci vout->rotation = 0; 13658c2ecf20Sopenharmony_ci vout->mirror = false; 13668c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vout->dma_queue); 13678c2ecf20Sopenharmony_ci if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) 13688c2ecf20Sopenharmony_ci vout->vrfb_bpp = 2; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci /* initialize the video_device struct */ 13718c2ecf20Sopenharmony_ci vfd = vout->vfd = video_device_alloc(); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (!vfd) { 13748c2ecf20Sopenharmony_ci printk(KERN_ERR VOUT_NAME 13758c2ecf20Sopenharmony_ci ": could not allocate video device struct\n"); 13768c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 13778c2ecf20Sopenharmony_ci return -ENOMEM; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci vfd->ctrl_handler = hdl; 13808c2ecf20Sopenharmony_ci vfd->release = video_device_release; 13818c2ecf20Sopenharmony_ci vfd->ioctl_ops = &vout_ioctl_ops; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci strscpy(vfd->name, VOUT_NAME, sizeof(vfd->name)); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci vfd->fops = &omap_vout_fops; 13868c2ecf20Sopenharmony_ci vfd->v4l2_dev = &vout->vid_dev->v4l2_dev; 13878c2ecf20Sopenharmony_ci vfd->vfl_dir = VFL_DIR_TX; 13888c2ecf20Sopenharmony_ci vfd->minor = -1; 13898c2ecf20Sopenharmony_ci vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | 13908c2ecf20Sopenharmony_ci V4L2_CAP_VIDEO_OUTPUT_OVERLAY; 13918c2ecf20Sopenharmony_ci mutex_init(&vout->lock); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci vq = &vout->vq; 13948c2ecf20Sopenharmony_ci vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 13958c2ecf20Sopenharmony_ci vq->io_modes = VB2_MMAP | VB2_DMABUF; 13968c2ecf20Sopenharmony_ci vq->drv_priv = vout; 13978c2ecf20Sopenharmony_ci vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 13988c2ecf20Sopenharmony_ci vq->buf_struct_size = sizeof(struct omap_vout_buffer); 13998c2ecf20Sopenharmony_ci vq->dev = vfd->v4l2_dev->dev; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci vq->ops = &omap_vout_vb2_ops; 14028c2ecf20Sopenharmony_ci vq->mem_ops = &vb2_dma_contig_memops; 14038c2ecf20Sopenharmony_ci vq->lock = &vout->lock; 14048c2ecf20Sopenharmony_ci vq->min_buffers_needed = 1; 14058c2ecf20Sopenharmony_ci vfd->queue = vq; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci ret = vb2_queue_init(vq); 14088c2ecf20Sopenharmony_ci if (ret) { 14098c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 14108c2ecf20Sopenharmony_ci video_device_release(vfd); 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci return ret; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci/* Setup video buffers */ 14168c2ecf20Sopenharmony_cistatic int __init omap_vout_setup_video_bufs(struct platform_device *pdev, 14178c2ecf20Sopenharmony_ci int vid_num) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 14208c2ecf20Sopenharmony_ci struct omap_vout_device *vout; 14218c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 14228c2ecf20Sopenharmony_ci struct omap2video_device *vid_dev = 14238c2ecf20Sopenharmony_ci container_of(v4l2_dev, struct omap2video_device, v4l2_dev); 14248c2ecf20Sopenharmony_ci int ret = 0; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci vout = vid_dev->vouts[vid_num]; 14278c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci if (ovid->rotation_type == VOUT_ROT_VRFB) { 14308c2ecf20Sopenharmony_ci bool static_vrfb_allocation = (vid_num == 0) ? 14318c2ecf20Sopenharmony_ci vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; 14328c2ecf20Sopenharmony_ci ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, 14338c2ecf20Sopenharmony_ci static_vrfb_allocation); 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci return ret; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci/* Create video out devices */ 14398c2ecf20Sopenharmony_cistatic int __init omap_vout_create_video_devices(struct platform_device *pdev) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci int ret = 0, k; 14428c2ecf20Sopenharmony_ci struct omap_vout_device *vout; 14438c2ecf20Sopenharmony_ci struct video_device *vfd = NULL; 14448c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 14458c2ecf20Sopenharmony_ci struct omap2video_device *vid_dev = container_of(v4l2_dev, 14468c2ecf20Sopenharmony_ci struct omap2video_device, v4l2_dev); 14478c2ecf20Sopenharmony_ci struct omap_overlay *ovl = vid_dev->overlays[0]; 14488c2ecf20Sopenharmony_ci struct omap_overlay_info info; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci ovl->get_overlay_info(ovl, &info); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci for (k = 0; k < pdev->num_resources; k++) { 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL); 14558c2ecf20Sopenharmony_ci if (!vout) { 14568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, ": could not allocate memory\n"); 14578c2ecf20Sopenharmony_ci return -ENOMEM; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci vout->vid = k; 14618c2ecf20Sopenharmony_ci vid_dev->vouts[k] = vout; 14628c2ecf20Sopenharmony_ci vout->vid_dev = vid_dev; 14638c2ecf20Sopenharmony_ci /* Select video2 if only 1 overlay is controlled by V4L2 */ 14648c2ecf20Sopenharmony_ci if (pdev->num_resources == 1) 14658c2ecf20Sopenharmony_ci vout->vid_info.overlays[0] = vid_dev->overlays[k + 2]; 14668c2ecf20Sopenharmony_ci else 14678c2ecf20Sopenharmony_ci /* Else select video1 and video2 one by one. */ 14688c2ecf20Sopenharmony_ci vout->vid_info.overlays[0] = vid_dev->overlays[k + 1]; 14698c2ecf20Sopenharmony_ci vout->vid_info.num_overlays = 1; 14708c2ecf20Sopenharmony_ci vout->vid_info.id = k + 1; 14718c2ecf20Sopenharmony_ci spin_lock_init(&vout->vbq_lock); 14728c2ecf20Sopenharmony_ci /* 14738c2ecf20Sopenharmony_ci * Set the framebuffer base, this allows applications to find 14748c2ecf20Sopenharmony_ci * the fb corresponding to this overlay. 14758c2ecf20Sopenharmony_ci * 14768c2ecf20Sopenharmony_ci * To be precise: fbuf.base should match smem_start of 14778c2ecf20Sopenharmony_ci * struct fb_fix_screeninfo. 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci vout->fbuf.base = (void *)info.paddr; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci /* Set VRFB as rotation_type for omap2 and omap3 */ 14828c2ecf20Sopenharmony_ci if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx()) 14838c2ecf20Sopenharmony_ci vout->vid_info.rotation_type = VOUT_ROT_VRFB; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* Setup the default configuration for the video devices 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_ci if (omap_vout_setup_video_data(vout) != 0) { 14888c2ecf20Sopenharmony_ci ret = -ENOMEM; 14898c2ecf20Sopenharmony_ci goto error; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* Allocate default number of buffers for the video streaming 14938c2ecf20Sopenharmony_ci * and reserve the VRFB space for rotation 14948c2ecf20Sopenharmony_ci */ 14958c2ecf20Sopenharmony_ci if (omap_vout_setup_video_bufs(pdev, k) != 0) { 14968c2ecf20Sopenharmony_ci ret = -ENOMEM; 14978c2ecf20Sopenharmony_ci goto error1; 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* Register the Video device with V4L2 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_ci vfd = vout->vfd; 15038c2ecf20Sopenharmony_ci if (video_register_device(vfd, VFL_TYPE_VIDEO, -1) < 0) { 15048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 15058c2ecf20Sopenharmony_ci ": Could not register Video for Linux device\n"); 15068c2ecf20Sopenharmony_ci vfd->minor = -1; 15078c2ecf20Sopenharmony_ci ret = -ENODEV; 15088c2ecf20Sopenharmony_ci goto error2; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci video_set_drvdata(vfd, vout); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 15138c2ecf20Sopenharmony_ci ": registered and initialized video device %d\n", 15148c2ecf20Sopenharmony_ci vfd->minor); 15158c2ecf20Sopenharmony_ci if (k == (pdev->num_resources - 1)) 15168c2ecf20Sopenharmony_ci return 0; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci continue; 15198c2ecf20Sopenharmony_cierror2: 15208c2ecf20Sopenharmony_ci if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) 15218c2ecf20Sopenharmony_ci omap_vout_release_vrfb(vout); 15228c2ecf20Sopenharmony_cierror1: 15238c2ecf20Sopenharmony_ci video_device_release(vfd); 15248c2ecf20Sopenharmony_cierror: 15258c2ecf20Sopenharmony_ci kfree(vout); 15268c2ecf20Sopenharmony_ci return ret; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci return -ENODEV; 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci/* Driver functions */ 15328c2ecf20Sopenharmony_cistatic void omap_vout_cleanup_device(struct omap_vout_device *vout) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct video_device *vfd; 15358c2ecf20Sopenharmony_ci struct omapvideo_info *ovid; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (!vout) 15388c2ecf20Sopenharmony_ci return; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci vfd = vout->vfd; 15418c2ecf20Sopenharmony_ci ovid = &vout->vid_info; 15428c2ecf20Sopenharmony_ci if (vfd) { 15438c2ecf20Sopenharmony_ci if (!video_is_registered(vfd)) { 15448c2ecf20Sopenharmony_ci /* 15458c2ecf20Sopenharmony_ci * The device was never registered, so release the 15468c2ecf20Sopenharmony_ci * video_device struct directly. 15478c2ecf20Sopenharmony_ci */ 15488c2ecf20Sopenharmony_ci video_device_release(vfd); 15498c2ecf20Sopenharmony_ci } else { 15508c2ecf20Sopenharmony_ci /* 15518c2ecf20Sopenharmony_ci * The unregister function will release the video_device 15528c2ecf20Sopenharmony_ci * struct as well as unregistering it. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci video_unregister_device(vfd); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&vout->ctrl_handler); 15588c2ecf20Sopenharmony_ci if (ovid->rotation_type == VOUT_ROT_VRFB) { 15598c2ecf20Sopenharmony_ci omap_vout_release_vrfb(vout); 15608c2ecf20Sopenharmony_ci /* Free the VRFB buffer if allocated 15618c2ecf20Sopenharmony_ci * init time 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_ci if (vout->vrfb_static_allocation) 15648c2ecf20Sopenharmony_ci omap_vout_free_vrfb_buffers(vout); 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci kfree(vout); 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic int omap_vout_remove(struct platform_device *pdev) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci int k; 15738c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 15748c2ecf20Sopenharmony_ci struct omap2video_device *vid_dev = container_of(v4l2_dev, struct 15758c2ecf20Sopenharmony_ci omap2video_device, v4l2_dev); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci v4l2_device_unregister(v4l2_dev); 15788c2ecf20Sopenharmony_ci for (k = 0; k < pdev->num_resources; k++) 15798c2ecf20Sopenharmony_ci omap_vout_cleanup_device(vid_dev->vouts[k]); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci for (k = 0; k < vid_dev->num_displays; k++) { 15828c2ecf20Sopenharmony_ci if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED) 15838c2ecf20Sopenharmony_ci vid_dev->displays[k]->driver->disable(vid_dev->displays[k]); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci omap_dss_put_device(vid_dev->displays[k]); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci kfree(vid_dev); 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int __init omap_vout_probe(struct platform_device *pdev) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci int ret = 0, i; 15948c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 15958c2ecf20Sopenharmony_ci struct omap_dss_device *dssdev = NULL; 15968c2ecf20Sopenharmony_ci struct omap_dss_device *def_display; 15978c2ecf20Sopenharmony_ci struct omap2video_device *vid_dev = NULL; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (omapdss_is_initialized() == false) 16008c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci ret = omapdss_compat_init(); 16038c2ecf20Sopenharmony_ci if (ret) { 16048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to init dss\n"); 16058c2ecf20Sopenharmony_ci return ret; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (pdev->num_resources == 0) { 16098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "probed for an unknown device\n"); 16108c2ecf20Sopenharmony_ci ret = -ENODEV; 16118c2ecf20Sopenharmony_ci goto err_dss_init; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL); 16158c2ecf20Sopenharmony_ci if (vid_dev == NULL) { 16168c2ecf20Sopenharmony_ci ret = -ENOMEM; 16178c2ecf20Sopenharmony_ci goto err_dss_init; 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci vid_dev->num_displays = 0; 16218c2ecf20Sopenharmony_ci for_each_dss_dev(dssdev) { 16228c2ecf20Sopenharmony_ci omap_dss_get_device(dssdev); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (!dssdev->driver) { 16258c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "no driver for display: %s\n", 16268c2ecf20Sopenharmony_ci dssdev->name); 16278c2ecf20Sopenharmony_ci omap_dss_put_device(dssdev); 16288c2ecf20Sopenharmony_ci continue; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci vid_dev->displays[vid_dev->num_displays++] = dssdev; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if (vid_dev->num_displays == 0) { 16358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no displays\n"); 16368c2ecf20Sopenharmony_ci ret = -EINVAL; 16378c2ecf20Sopenharmony_ci goto probe_err0; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci vid_dev->num_overlays = omap_dss_get_num_overlays(); 16418c2ecf20Sopenharmony_ci for (i = 0; i < vid_dev->num_overlays; i++) 16428c2ecf20Sopenharmony_ci vid_dev->overlays[i] = omap_dss_get_overlay(i); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci vid_dev->num_managers = omap_dss_get_num_overlay_managers(); 16458c2ecf20Sopenharmony_ci for (i = 0; i < vid_dev->num_managers; i++) 16468c2ecf20Sopenharmony_ci vid_dev->managers[i] = omap_dss_get_overlay_manager(i); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* Get the Video1 overlay and video2 overlay. 16498c2ecf20Sopenharmony_ci * Setup the Display attached to that overlays 16508c2ecf20Sopenharmony_ci */ 16518c2ecf20Sopenharmony_ci for (i = 1; i < vid_dev->num_overlays; i++) { 16528c2ecf20Sopenharmony_ci ovl = omap_dss_get_overlay(i); 16538c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (dssdev) { 16568c2ecf20Sopenharmony_ci def_display = dssdev; 16578c2ecf20Sopenharmony_ci } else { 16588c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "cannot find display\n"); 16598c2ecf20Sopenharmony_ci def_display = NULL; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci if (def_display) { 16628c2ecf20Sopenharmony_ci struct omap_dss_driver *dssdrv = def_display->driver; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci ret = dssdrv->enable(def_display); 16658c2ecf20Sopenharmony_ci if (ret) { 16668c2ecf20Sopenharmony_ci /* Here we are not considering a error 16678c2ecf20Sopenharmony_ci * as display may be enabled by frame 16688c2ecf20Sopenharmony_ci * buffer driver 16698c2ecf20Sopenharmony_ci */ 16708c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 16718c2ecf20Sopenharmony_ci "'%s' Display already enabled\n", 16728c2ecf20Sopenharmony_ci def_display->name); 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) { 16788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "v4l2_device_register failed\n"); 16798c2ecf20Sopenharmony_ci ret = -ENODEV; 16808c2ecf20Sopenharmony_ci goto probe_err1; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci ret = omap_vout_create_video_devices(pdev); 16848c2ecf20Sopenharmony_ci if (ret) 16858c2ecf20Sopenharmony_ci goto probe_err2; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci for (i = 0; i < vid_dev->num_displays; i++) { 16888c2ecf20Sopenharmony_ci struct omap_dss_device *display = vid_dev->displays[i]; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (display->driver->update) 16918c2ecf20Sopenharmony_ci display->driver->update(display, 0, 0, 16928c2ecf20Sopenharmony_ci display->panel.timings.x_res, 16938c2ecf20Sopenharmony_ci display->panel.timings.y_res); 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ciprobe_err2: 16988c2ecf20Sopenharmony_ci v4l2_device_unregister(&vid_dev->v4l2_dev); 16998c2ecf20Sopenharmony_ciprobe_err1: 17008c2ecf20Sopenharmony_ci for (i = 1; i < vid_dev->num_overlays; i++) { 17018c2ecf20Sopenharmony_ci def_display = NULL; 17028c2ecf20Sopenharmony_ci ovl = omap_dss_get_overlay(i); 17038c2ecf20Sopenharmony_ci dssdev = ovl->get_device(ovl); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (dssdev) 17068c2ecf20Sopenharmony_ci def_display = dssdev; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (def_display && def_display->driver) 17098c2ecf20Sopenharmony_ci def_display->driver->disable(def_display); 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ciprobe_err0: 17128c2ecf20Sopenharmony_ci kfree(vid_dev); 17138c2ecf20Sopenharmony_cierr_dss_init: 17148c2ecf20Sopenharmony_ci omapdss_compat_uninit(); 17158c2ecf20Sopenharmony_ci return ret; 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic struct platform_driver omap_vout_driver = { 17198c2ecf20Sopenharmony_ci .driver = { 17208c2ecf20Sopenharmony_ci .name = VOUT_NAME, 17218c2ecf20Sopenharmony_ci }, 17228c2ecf20Sopenharmony_ci .remove = omap_vout_remove, 17238c2ecf20Sopenharmony_ci}; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_cistatic int __init omap_vout_init(void) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) { 17288c2ecf20Sopenharmony_ci printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); 17298c2ecf20Sopenharmony_ci return -EINVAL; 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci return 0; 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_cistatic void omap_vout_cleanup(void) 17358c2ecf20Sopenharmony_ci{ 17368c2ecf20Sopenharmony_ci platform_driver_unregister(&omap_vout_driver); 17378c2ecf20Sopenharmony_ci} 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_cilate_initcall(omap_vout_init); 17408c2ecf20Sopenharmony_cimodule_exit(omap_vout_cleanup); 1741