2016-04-26 10:22:19 -03:00
/*
* Driver for Renesas R - Car VIN
*
* Copyright ( C ) 2016 Renesas Electronics Corp .
* Copyright ( C ) 2011 - 2013 Renesas Solutions Corp .
* Copyright ( C ) 2013 Cogent Embedded , Inc . , < source @ cogentembedded . com >
* Copyright ( C ) 2008 Magnus Damm
*
* Based on the soc - camera rcar_vin driver
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <media/videobuf2-dma-contig.h>
# include "rcar-vin.h"
/* -----------------------------------------------------------------------------
* HW Functions
*/
/* Register offsets for R-Car VIN */
# define VNMC_REG 0x00 /* Video n Main Control Register */
# define VNMS_REG 0x04 /* Video n Module Status Register */
# define VNFC_REG 0x08 /* Video n Frame Capture Register */
# define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */
# define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */
# define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */
# define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */
# define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */
# define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */
# define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */
# define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */
# define VNIS_REG 0x2C /* Video n Image Stride Register */
# define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */
# define VNIE_REG 0x40 /* Video n Interrupt Enable Register */
# define VNINTS_REG 0x44 /* Video n Interrupt Status Register */
# define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */
# define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */
# define VNYS_REG 0x50 /* Video n Y Scale Register */
# define VNXS_REG 0x54 /* Video n X Scale Register */
# define VNDMR_REG 0x58 /* Video n Data Mode Register */
# define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */
# define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */
# define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */
# define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */
# define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */
# define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */
# define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */
# define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */
# define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */
# define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */
# define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */
# define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */
# define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */
# define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */
# define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */
# define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */
# define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */
# define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */
# define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */
# define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */
# define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */
# define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */
# define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */
# define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */
# define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */
# define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */
/* Register bit fields for R-Car VIN */
/* Video n Main Control Register bits */
# define VNMC_FOC (1 << 21)
# define VNMC_YCAL (1 << 19)
# define VNMC_INF_YUV8_BT656 (0 << 16)
# define VNMC_INF_YUV8_BT601 (1 << 16)
# define VNMC_INF_YUV10_BT656 (2 << 16)
# define VNMC_INF_YUV10_BT601 (3 << 16)
# define VNMC_INF_YUV16 (5 << 16)
# define VNMC_INF_RGB888 (6 << 16)
# define VNMC_VUP (1 << 10)
# define VNMC_IM_ODD (0 << 3)
# define VNMC_IM_ODD_EVEN (1 << 3)
# define VNMC_IM_EVEN (2 << 3)
# define VNMC_IM_FULL (3 << 3)
# define VNMC_BPS (1 << 1)
# define VNMC_ME (1 << 0)
/* Video n Module Status Register bits */
# define VNMS_FBS_MASK (3 << 3)
# define VNMS_FBS_SHIFT 3
# define VNMS_AV (1 << 1)
# define VNMS_CA (1 << 0)
/* Video n Frame Capture Register bits */
# define VNFC_C_FRAME (1 << 1)
# define VNFC_S_FRAME (1 << 0)
/* Video n Interrupt Enable Register bits */
# define VNIE_FIE (1 << 4)
# define VNIE_EFE (1 << 1)
/* Video n Data Mode Register bits */
# define VNDMR_EXRGB (1 << 8)
# define VNDMR_BPSM (1 << 4)
# define VNDMR_DTMD_YCSEP (1 << 1)
# define VNDMR_DTMD_ARGB1555 (1 << 0)
/* Video n Data Mode Register 2 bits */
# define VNDMR2_VPS (1 << 30)
# define VNDMR2_HPS (1 << 29)
# define VNDMR2_FTEV (1 << 17)
# define VNDMR2_VLV(n) ((n & 0xf) << 12)
static void rvin_write ( struct rvin_dev * vin , u32 value , u32 offset )
{
iowrite32 ( value , vin - > base + offset ) ;
}
static u32 rvin_read ( struct rvin_dev * vin , u32 offset )
{
return ioread32 ( vin - > base + offset ) ;
}
static int rvin_setup ( struct rvin_dev * vin )
{
u32 vnmc , dmr , dmr2 , interrupts ;
bool progressive = false , output_is_yuv = false , input_is_yuv = false ;
switch ( vin - > format . field ) {
case V4L2_FIELD_TOP :
vnmc = VNMC_IM_ODD ;
break ;
case V4L2_FIELD_BOTTOM :
vnmc = VNMC_IM_EVEN ;
break ;
case V4L2_FIELD_INTERLACED :
case V4L2_FIELD_INTERLACED_TB :
vnmc = VNMC_IM_FULL ;
break ;
case V4L2_FIELD_INTERLACED_BT :
vnmc = VNMC_IM_FULL | VNMC_FOC ;
break ;
case V4L2_FIELD_NONE :
if ( vin - > continuous ) {
vnmc = VNMC_IM_ODD_EVEN ;
progressive = true ;
} else {
vnmc = VNMC_IM_ODD ;
}
break ;
default :
vnmc = VNMC_IM_ODD ;
break ;
}
/*
* Input interface
*/
switch ( vin - > source . code ) {
case MEDIA_BUS_FMT_YUYV8_1X16 :
/* BT.601/BT.1358 16bit YCbCr422 */
vnmc | = VNMC_INF_YUV16 ;
input_is_yuv = true ;
break ;
case MEDIA_BUS_FMT_YUYV8_2X8 :
/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
vnmc | = vin - > mbus_cfg . type = = V4L2_MBUS_BT656 ?
VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601 ;
input_is_yuv = true ;
break ;
case MEDIA_BUS_FMT_RGB888_1X24 :
vnmc | = VNMC_INF_RGB888 ;
break ;
case MEDIA_BUS_FMT_YUYV10_2X10 :
/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
vnmc | = vin - > mbus_cfg . type = = V4L2_MBUS_BT656 ?
VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601 ;
input_is_yuv = true ;
break ;
default :
break ;
}
/* Enable VSYNC Field Toogle mode after one VSYNC input */
dmr2 = VNDMR2_FTEV | VNDMR2_VLV ( 1 ) ;
/* Hsync Signal Polarity Select */
if ( ! ( vin - > mbus_cfg . flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ) )
dmr2 | = VNDMR2_HPS ;
/* Vsync Signal Polarity Select */
if ( ! ( vin - > mbus_cfg . flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ) )
dmr2 | = VNDMR2_VPS ;
/*
* Output format
*/
switch ( vin - > format . pixelformat ) {
case V4L2_PIX_FMT_NV16 :
rvin_write ( vin ,
ALIGN ( vin - > format . width * vin - > format . height , 0x80 ) ,
VNUVAOF_REG ) ;
dmr = VNDMR_DTMD_YCSEP ;
output_is_yuv = true ;
break ;
case V4L2_PIX_FMT_YUYV :
dmr = VNDMR_BPSM ;
output_is_yuv = true ;
break ;
case V4L2_PIX_FMT_UYVY :
dmr = 0 ;
output_is_yuv = true ;
break ;
case V4L2_PIX_FMT_XRGB555 :
dmr = VNDMR_DTMD_ARGB1555 ;
break ;
case V4L2_PIX_FMT_RGB565 :
dmr = 0 ;
break ;
case V4L2_PIX_FMT_XBGR32 :
if ( vin - > chip = = RCAR_GEN2 | | vin - > chip = = RCAR_H1 ) {
dmr = VNDMR_EXRGB ;
break ;
}
/* fall through */
default :
vin_err ( vin , " Invalid pixelformat (0x%x) \n " ,
vin - > format . pixelformat ) ;
return - EINVAL ;
}
/* Always update on field change */
vnmc | = VNMC_VUP ;
/* If input and output use the same colorspace, use bypass mode */
if ( input_is_yuv = = output_is_yuv )
vnmc | = VNMC_BPS ;
/* Progressive or interlaced mode */
interrupts = progressive ? VNIE_FIE : VNIE_EFE ;
/* Ack interrupts */
rvin_write ( vin , interrupts , VNINTS_REG ) ;
/* Enable interrupts */
rvin_write ( vin , interrupts , VNIE_REG ) ;
/* Start capturing */
rvin_write ( vin , dmr , VNDMR_REG ) ;
rvin_write ( vin , dmr2 , VNDMR2_REG ) ;
/* Enable module */
rvin_write ( vin , vnmc | VNMC_ME , VNMC_REG ) ;
return 0 ;
}
static void rvin_capture_on ( struct rvin_dev * vin )
{
vin_dbg ( vin , " Capture on in %s mode \n " ,
vin - > continuous ? " continuous " : " single " ) ;
if ( vin - > continuous )
/* Continuous Frame Capture Mode */
rvin_write ( vin , VNFC_C_FRAME , VNFC_REG ) ;
else
/* Single Frame Capture Mode */
rvin_write ( vin , VNFC_S_FRAME , VNFC_REG ) ;
}
static void rvin_capture_off ( struct rvin_dev * vin )
{
/* Set continuous & single transfer off */
rvin_write ( vin , 0 , VNFC_REG ) ;
}
static int rvin_capture_start ( struct rvin_dev * vin )
{
int ret ;
rvin_crop_scale_comp ( vin ) ;
ret = rvin_setup ( vin ) ;
if ( ret )
return ret ;
rvin_capture_on ( vin ) ;
return 0 ;
}
static void rvin_capture_stop ( struct rvin_dev * vin )
{
rvin_capture_off ( vin ) ;
/* Disable module */
rvin_write ( vin , rvin_read ( vin , VNMC_REG ) & ~ VNMC_ME , VNMC_REG ) ;
}
static void rvin_disable_interrupts ( struct rvin_dev * vin )
{
rvin_write ( vin , 0 , VNIE_REG ) ;
}
static u32 rvin_get_interrupt_status ( struct rvin_dev * vin )
{
return rvin_read ( vin , VNINTS_REG ) ;
}
static void rvin_ack_interrupt ( struct rvin_dev * vin )
{
rvin_write ( vin , rvin_read ( vin , VNINTS_REG ) , VNINTS_REG ) ;
}
static bool rvin_capture_active ( struct rvin_dev * vin )
{
return rvin_read ( vin , VNMS_REG ) & VNMS_CA ;
}
static int rvin_get_active_slot ( struct rvin_dev * vin )
{
if ( vin - > continuous )
return ( rvin_read ( vin , VNMS_REG ) & VNMS_FBS_MASK )
> > VNMS_FBS_SHIFT ;
return 0 ;
}
static void rvin_set_slot_addr ( struct rvin_dev * vin , int slot , dma_addr_t addr )
{
const struct rvin_video_format * fmt ;
int offsetx , offsety ;
dma_addr_t offset ;
fmt = rvin_format_from_pixel ( vin - > format . pixelformat ) ;
/*
* There is no HW support for composition do the beast we can
* by modifying the buffer offset
*/
offsetx = vin - > compose . left * fmt - > bpp ;
offsety = vin - > compose . top * vin - > format . bytesperline ;
offset = addr + offsetx + offsety ;
/*
* The address needs to be 128 bytes aligned . Driver should never accept
* settings that do not satisfy this in the first place . . .
*/
if ( WARN_ON ( ( offsetx | offsety | offset ) & HW_BUFFER_MASK ) )
return ;
rvin_write ( vin , offset , VNMB_REG ( slot ) ) ;
}
/* -----------------------------------------------------------------------------
* Crop and Scaling Gen2
*/
struct vin_coeff {
unsigned short xs_value ;
u32 coeff_set [ 24 ] ;
} ;
static const struct vin_coeff vin_coeff_set [ ] = {
{ 0x0000 , {
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 } ,
} ,
{ 0x1000 , {
0x000fa400 , 0x000fa400 , 0x09625902 ,
0x000003f8 , 0x00000403 , 0x3de0d9f0 ,
0x001fffed , 0x00000804 , 0x3cc1f9c3 ,
0x001003de , 0x00000c01 , 0x3cb34d7f ,
0x002003d2 , 0x00000c00 , 0x3d24a92d ,
0x00200bca , 0x00000bff , 0x3df600d2 ,
0x002013cc , 0x000007ff , 0x3ed70c7e ,
0x00100fde , 0x00000000 , 0x3f87c036 } ,
} ,
{ 0x1200 , {
0x002ffff1 , 0x002ffff1 , 0x02a0a9c8 ,
0x002003e7 , 0x001ffffa , 0x000185bc ,
0x002007dc , 0x000003ff , 0x3e52859c ,
0x00200bd4 , 0x00000002 , 0x3d53996b ,
0x00100fd0 , 0x00000403 , 0x3d04ad2d ,
0x00000bd5 , 0x00000403 , 0x3d35ace7 ,
0x3ff003e4 , 0x00000801 , 0x3dc674a1 ,
0x3fffe800 , 0x00000800 , 0x3e76f461 } ,
} ,
{ 0x1400 , {
0x00100be3 , 0x00100be3 , 0x04d1359a ,
0x00000fdb , 0x002003ed , 0x0211fd93 ,
0x00000fd6 , 0x002003f4 , 0x0002d97b ,
0x000007d6 , 0x002ffffb , 0x3e93b956 ,
0x3ff003da , 0x001003ff , 0x3db49926 ,
0x3fffefe9 , 0x00100001 , 0x3d655cee ,
0x3fffd400 , 0x00000003 , 0x3d65f4b6 ,
0x000fb421 , 0x00000402 , 0x3dc6547e } ,
} ,
{ 0x1600 , {
0x00000bdd , 0x00000bdd , 0x06519578 ,
0x3ff007da , 0x00000be3 , 0x03c24973 ,
0x3ff003d9 , 0x00000be9 , 0x01b30d5f ,
0x3ffff7df , 0x001003f1 , 0x0003c542 ,
0x000fdfec , 0x001003f7 , 0x3ec4711d ,
0x000fc400 , 0x002ffffd , 0x3df504f1 ,
0x001fa81a , 0x002ffc00 , 0x3d957cc2 ,
0x002f8c3c , 0x00100000 , 0x3db5c891 } ,
} ,
{ 0x1800 , {
0x3ff003dc , 0x3ff003dc , 0x0791e558 ,
0x000ff7dd , 0x3ff007de , 0x05328554 ,
0x000fe7e3 , 0x3ff00be2 , 0x03232546 ,
0x000fd7ee , 0x000007e9 , 0x0143bd30 ,
0x001fb800 , 0x000007ee , 0x00044511 ,
0x002fa015 , 0x000007f4 , 0x3ef4bcee ,
0x002f8832 , 0x001003f9 , 0x3e4514c7 ,
0x001f7853 , 0x001003fd , 0x3de54c9f } ,
} ,
{ 0x1a00 , {
0x000fefe0 , 0x000fefe0 , 0x08721d3c ,
0x001fdbe7 , 0x000ffbde , 0x0652a139 ,
0x001fcbf0 , 0x000003df , 0x0463292e ,
0x002fb3ff , 0x3ff007e3 , 0x0293a91d ,
0x002f9c12 , 0x3ff00be7 , 0x01241905 ,
0x001f8c29 , 0x000007ed , 0x3fe470eb ,
0x000f7c46 , 0x000007f2 , 0x3f04b8ca ,
0x3fef7865 , 0x000007f6 , 0x3e74e4a8 } ,
} ,
{ 0x1c00 , {
0x001fd3e9 , 0x001fd3e9 , 0x08f23d26 ,
0x002fbff3 , 0x001fe3e4 , 0x0712ad23 ,
0x002fa800 , 0x000ff3e0 , 0x05631d1b ,
0x001f9810 , 0x000ffbe1 , 0x03b3890d ,
0x000f8c23 , 0x000003e3 , 0x0233e8fa ,
0x3fef843b , 0x000003e7 , 0x00f430e4 ,
0x3fbf8456 , 0x3ff00bea , 0x00046cc8 ,
0x3f8f8c72 , 0x3ff00bef , 0x3f3490ac } ,
} ,
{ 0x1e00 , {
0x001fbbf4 , 0x001fbbf4 , 0x09425112 ,
0x001fa800 , 0x002fc7ed , 0x0792b110 ,
0x000f980e , 0x001fdbe6 , 0x0613110a ,
0x3fff8c20 , 0x001fe7e3 , 0x04a368fd ,
0x3fcf8c33 , 0x000ff7e2 , 0x0343b8ed ,
0x3f9f8c4a , 0x000fffe3 , 0x0203f8da ,
0x3f5f9c61 , 0x000003e6 , 0x00e428c5 ,
0x3f1fb07b , 0x000003eb , 0x3fe440af } ,
} ,
{ 0x2000 , {
0x000fa400 , 0x000fa400 , 0x09625902 ,
0x3fff980c , 0x001fb7f5 , 0x0812b0ff ,
0x3fdf901c , 0x001fc7ed , 0x06b2fcfa ,
0x3faf902d , 0x001fd3e8 , 0x055348f1 ,
0x3f7f983f , 0x001fe3e5 , 0x04038ce3 ,
0x3f3fa454 , 0x001fefe3 , 0x02e3c8d1 ,
0x3f0fb86a , 0x001ff7e4 , 0x01c3e8c0 ,
0x3ecfd880 , 0x000fffe6 , 0x00c404ac } ,
} ,
{ 0x2200 , {
0x3fdf9c0b , 0x3fdf9c0b , 0x09725cf4 ,
0x3fbf9818 , 0x3fffa400 , 0x0842a8f1 ,
0x3f8f9827 , 0x000fb3f7 , 0x0702f0ec ,
0x3f5fa037 , 0x000fc3ef , 0x05d330e4 ,
0x3f2fac49 , 0x001fcfea , 0x04a364d9 ,
0x3effc05c , 0x001fdbe7 , 0x038394ca ,
0x3ecfdc6f , 0x001fe7e6 , 0x0273b0bb ,
0x3ea00083 , 0x001fefe6 , 0x0183c0a9 } ,
} ,
{ 0x2400 , {
0x3f9fa014 , 0x3f9fa014 , 0x098260e6 ,
0x3f7f9c23 , 0x3fcf9c0a , 0x08629ce5 ,
0x3f4fa431 , 0x3fefa400 , 0x0742d8e1 ,
0x3f1fb440 , 0x3fffb3f8 , 0x062310d9 ,
0x3eefc850 , 0x000fbbf2 , 0x050340d0 ,
0x3ecfe062 , 0x000fcbec , 0x041364c2 ,
0x3ea00073 , 0x001fd3ea , 0x03037cb5 ,
0x3e902086 , 0x001fdfe8 , 0x022388a5 } ,
} ,
{ 0x2600 , {
0x3f5fa81e , 0x3f5fa81e , 0x096258da ,
0x3f3fac2b , 0x3f8fa412 , 0x088290d8 ,
0x3f0fbc38 , 0x3fafa408 , 0x0772c8d5 ,
0x3eefcc47 , 0x3fcfa800 , 0x0672f4ce ,
0x3ecfe456 , 0x3fefaffa , 0x05531cc6 ,
0x3eb00066 , 0x3fffbbf3 , 0x047334bb ,
0x3ea01c77 , 0x000fc7ee , 0x039348ae ,
0x3ea04486 , 0x000fd3eb , 0x02b350a1 } ,
} ,
{ 0x2800 , {
0x3f2fb426 , 0x3f2fb426 , 0x094250ce ,
0x3f0fc032 , 0x3f4fac1b , 0x086284cd ,
0x3eefd040 , 0x3f7fa811 , 0x0782acc9 ,
0x3ecfe84c , 0x3f9fa807 , 0x06a2d8c4 ,
0x3eb0005b , 0x3fbfac00 , 0x05b2f4bc ,
0x3eb0186a , 0x3fdfb3fa , 0x04c308b4 ,
0x3eb04077 , 0x3fefbbf4 , 0x03f31ca8 ,
0x3ec06884 , 0x000fbff2 , 0x03031c9e } ,
} ,
{ 0x2a00 , {
0x3f0fc42d , 0x3f0fc42d , 0x090240c4 ,
0x3eefd439 , 0x3f2fb822 , 0x08526cc2 ,
0x3edfe845 , 0x3f4fb018 , 0x078294bf ,
0x3ec00051 , 0x3f6fac0f , 0x06b2b4bb ,
0x3ec0185f , 0x3f8fac07 , 0x05e2ccb4 ,
0x3ec0386b , 0x3fafac00 , 0x0502e8ac ,
0x3ed05c77 , 0x3fcfb3fb , 0x0432f0a3 ,
0x3ef08482 , 0x3fdfbbf6 , 0x0372f898 } ,
} ,
{ 0x2c00 , {
0x3eefdc31 , 0x3eefdc31 , 0x08e238b8 ,
0x3edfec3d , 0x3f0fc828 , 0x082258b9 ,
0x3ed00049 , 0x3f1fc01e , 0x077278b6 ,
0x3ed01455 , 0x3f3fb815 , 0x06c294b2 ,
0x3ed03460 , 0x3f5fb40d , 0x0602acac ,
0x3ef0506c , 0x3f7fb006 , 0x0542c0a4 ,
0x3f107476 , 0x3f9fb400 , 0x0472c89d ,
0x3f309c80 , 0x3fbfb7fc , 0x03b2cc94 } ,
} ,
{ 0x2e00 , {
0x3eefec37 , 0x3eefec37 , 0x088220b0 ,
0x3ee00041 , 0x3effdc2d , 0x07f244ae ,
0x3ee0144c , 0x3f0fd023 , 0x07625cad ,
0x3ef02c57 , 0x3f1fc81a , 0x06c274a9 ,
0x3f004861 , 0x3f3fbc13 , 0x060288a6 ,
0x3f20686b , 0x3f5fb80c , 0x05529c9e ,
0x3f408c74 , 0x3f6fb805 , 0x04b2ac96 ,
0x3f80ac7e , 0x3f8fb800 , 0x0402ac8e } ,
} ,
{ 0x3000 , {
0x3ef0003a , 0x3ef0003a , 0x084210a6 ,
0x3ef01045 , 0x3effec32 , 0x07b228a7 ,
0x3f00284e , 0x3f0fdc29 , 0x073244a4 ,
0x3f104058 , 0x3f0fd420 , 0x06a258a2 ,
0x3f305c62 , 0x3f2fc818 , 0x0612689d ,
0x3f508069 , 0x3f3fc011 , 0x05728496 ,
0x3f80a072 , 0x3f4fc00a , 0x04d28c90 ,
0x3fc0c07b , 0x3f6fbc04 , 0x04429088 } ,
} ,
{ 0x3200 , {
0x3f00103e , 0x3f00103e , 0x07f1fc9e ,
0x3f102447 , 0x3f000035 , 0x0782149d ,
0x3f203c4f , 0x3f0ff02c , 0x07122c9c ,
0x3f405458 , 0x3f0fe424 , 0x06924099 ,
0x3f607061 , 0x3f1fd41d , 0x06024c97 ,
0x3f909068 , 0x3f2fcc16 , 0x05726490 ,
0x3fc0b070 , 0x3f3fc80f , 0x04f26c8a ,
0x0000d077 , 0x3f4fc409 , 0x04627484 } ,
} ,
{ 0x3400 , {
0x3f202040 , 0x3f202040 , 0x07a1e898 ,
0x3f303449 , 0x3f100c38 , 0x0741fc98 ,
0x3f504c50 , 0x3f10002f , 0x06e21495 ,
0x3f706459 , 0x3f1ff028 , 0x06722492 ,
0x3fa08060 , 0x3f1fe421 , 0x05f2348f ,
0x3fd09c67 , 0x3f1fdc19 , 0x05824c89 ,
0x0000bc6e , 0x3f2fd014 , 0x04f25086 ,
0x0040dc74 , 0x3f3fcc0d , 0x04825c7f } ,
} ,
{ 0x3600 , {
0x3f403042 , 0x3f403042 , 0x0761d890 ,
0x3f504848 , 0x3f301c3b , 0x0701f090 ,
0x3f805c50 , 0x3f200c33 , 0x06a2008f ,
0x3fa07458 , 0x3f10002b , 0x06520c8d ,
0x3fd0905e , 0x3f1ff424 , 0x05e22089 ,
0x0000ac65 , 0x3f1fe81d , 0x05823483 ,
0x0030cc6a , 0x3f2fdc18 , 0x04f23c81 ,
0x0080e871 , 0x3f2fd412 , 0x0482407c } ,
} ,
{ 0x3800 , {
0x3f604043 , 0x3f604043 , 0x0721c88a ,
0x3f80544a , 0x3f502c3c , 0x06d1d88a ,
0x3fb06851 , 0x3f301c35 , 0x0681e889 ,
0x3fd08456 , 0x3f30082f , 0x0611fc88 ,
0x00009c5d , 0x3f200027 , 0x05d20884 ,
0x0030b863 , 0x3f2ff421 , 0x05621880 ,
0x0070d468 , 0x3f2fe81b , 0x0502247c ,
0x00c0ec6f , 0x3f2fe015 , 0x04a22877 } ,
} ,
{ 0x3a00 , {
0x3f904c44 , 0x3f904c44 , 0x06e1b884 ,
0x3fb0604a , 0x3f70383e , 0x0691c885 ,
0x3fe07451 , 0x3f502c36 , 0x0661d483 ,
0x00009055 , 0x3f401831 , 0x0601ec81 ,
0x0030a85b , 0x3f300c2a , 0x05b1f480 ,
0x0070c061 , 0x3f300024 , 0x0562047a ,
0x00b0d867 , 0x3f3ff41e , 0x05020c77 ,
0x00f0f46b , 0x3f2fec19 , 0x04a21474 } ,
} ,
{ 0x3c00 , {
0x3fb05c43 , 0x3fb05c43 , 0x06c1b07e ,
0x3fe06c4b , 0x3f902c3f , 0x0681c081 ,
0x0000844f , 0x3f703838 , 0x0631cc7d ,
0x00309855 , 0x3f602433 , 0x05d1d47e ,
0x0060b459 , 0x3f50142e , 0x0581e47b ,
0x00a0c85f , 0x3f400828 , 0x0531f078 ,
0x00e0e064 , 0x3f300021 , 0x0501fc73 ,
0x00b0fc6a , 0x3f3ff41d , 0x04a20873 } ,
} ,
{ 0x3e00 , {
0x3fe06444 , 0x3fe06444 , 0x0681a07a ,
0x00007849 , 0x3fc0503f , 0x0641b07a ,
0x0020904d , 0x3fa0403a , 0x05f1c07a ,
0x0060a453 , 0x3f803034 , 0x05c1c878 ,
0x0090b858 , 0x3f70202f , 0x0571d477 ,
0x00d0d05d , 0x3f501829 , 0x0531e073 ,
0x0110e462 , 0x3f500825 , 0x04e1e471 ,
0x01510065 , 0x3f40001f , 0x04a1f06d } ,
} ,
{ 0x4000 , {
0x00007044 , 0x00007044 , 0x06519476 ,
0x00208448 , 0x3fe05c3f , 0x0621a476 ,
0x0050984d , 0x3fc04c3a , 0x05e1b075 ,
0x0080ac52 , 0x3fa03c35 , 0x05a1b875 ,
0x00c0c056 , 0x3f803030 , 0x0561c473 ,
0x0100d45b , 0x3f70202b , 0x0521d46f ,
0x0140e860 , 0x3f601427 , 0x04d1d46e ,
0x01810064 , 0x3f500822 , 0x0491dc6b } ,
} ,
{ 0x5000 , {
0x0110a442 , 0x0110a442 , 0x0551545e ,
0x0140b045 , 0x00e0983f , 0x0531585f ,
0x0160c047 , 0x00c08c3c , 0x0511645e ,
0x0190cc4a , 0x00908039 , 0x04f1685f ,
0x01c0dc4c , 0x00707436 , 0x04d1705e ,
0x0200e850 , 0x00506833 , 0x04b1785b ,
0x0230f453 , 0x00305c30 , 0x0491805a ,
0x02710056 , 0x0010542d , 0x04718059 } ,
} ,
{ 0x6000 , {
0x01c0bc40 , 0x01c0bc40 , 0x04c13052 ,
0x01e0c841 , 0x01a0b43d , 0x04c13851 ,
0x0210cc44 , 0x0180a83c , 0x04a13453 ,
0x0230d845 , 0x0160a03a , 0x04913c52 ,
0x0260e047 , 0x01409838 , 0x04714052 ,
0x0280ec49 , 0x01208c37 , 0x04514c50 ,
0x02b0f44b , 0x01008435 , 0x04414c50 ,
0x02d1004c , 0x00e07c33 , 0x0431544f } ,
} ,
{ 0x7000 , {
0x0230c83e , 0x0230c83e , 0x04711c4c ,
0x0250d03f , 0x0210c43c , 0x0471204b ,
0x0270d840 , 0x0200b83c , 0x0451244b ,
0x0290dc42 , 0x01e0b43a , 0x0441244c ,
0x02b0e443 , 0x01c0b038 , 0x0441284b ,
0x02d0ec44 , 0x01b0a438 , 0x0421304a ,
0x02f0f445 , 0x0190a036 , 0x04213449 ,
0x0310f847 , 0x01709c34 , 0x04213848 } ,
} ,
{ 0x8000 , {
0x0280d03d , 0x0280d03d , 0x04310c48 ,
0x02a0d43e , 0x0270c83c , 0x04311047 ,
0x02b0dc3e , 0x0250c83a , 0x04311447 ,
0x02d0e040 , 0x0240c03a , 0x04211446 ,
0x02e0e840 , 0x0220bc39 , 0x04111847 ,
0x0300e842 , 0x0210b438 , 0x04012445 ,
0x0310f043 , 0x0200b037 , 0x04012045 ,
0x0330f444 , 0x01e0ac36 , 0x03f12445 } ,
} ,
{ 0xefff , {
0x0340dc3a , 0x0340dc3a , 0x03b0ec40 ,
0x0340e03a , 0x0330e039 , 0x03c0f03e ,
0x0350e03b , 0x0330dc39 , 0x03c0ec3e ,
0x0350e43a , 0x0320dc38 , 0x03c0f43e ,
0x0360e43b , 0x0320d839 , 0x03b0f03e ,
0x0360e83b , 0x0310d838 , 0x03c0fc3b ,
0x0370e83b , 0x0310d439 , 0x03a0f83d ,
0x0370e83c , 0x0300d438 , 0x03b0fc3c } ,
}
} ;
static void rvin_set_coeff ( struct rvin_dev * vin , unsigned short xs )
{
int i ;
const struct vin_coeff * p_prev_set = NULL ;
const struct vin_coeff * p_set = NULL ;
/* Look for suitable coefficient values */
for ( i = 0 ; i < ARRAY_SIZE ( vin_coeff_set ) ; i + + ) {
p_prev_set = p_set ;
p_set = & vin_coeff_set [ i ] ;
if ( xs < p_set - > xs_value )
break ;
}
/* Use previous value if its XS value is closer */
if ( p_prev_set & & p_set & &
xs - p_prev_set - > xs_value < p_set - > xs_value - xs )
p_set = p_prev_set ;
/* Set coefficient registers */
rvin_write ( vin , p_set - > coeff_set [ 0 ] , VNC1A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 1 ] , VNC1B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 2 ] , VNC1C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 3 ] , VNC2A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 4 ] , VNC2B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 5 ] , VNC2C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 6 ] , VNC3A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 7 ] , VNC3B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 8 ] , VNC3C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 9 ] , VNC4A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 10 ] , VNC4B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 11 ] , VNC4C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 12 ] , VNC5A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 13 ] , VNC5B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 14 ] , VNC5C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 15 ] , VNC6A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 16 ] , VNC6B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 17 ] , VNC6C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 18 ] , VNC7A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 19 ] , VNC7B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 20 ] , VNC7C_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 21 ] , VNC8A_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 22 ] , VNC8B_REG ) ;
rvin_write ( vin , p_set - > coeff_set [ 23 ] , VNC8C_REG ) ;
}
void rvin_crop_scale_comp ( struct rvin_dev * vin )
{
u32 xs , ys ;
/* Set Start/End Pixel/Line Pre-Clip */
rvin_write ( vin , vin - > crop . left , VNSPPRC_REG ) ;
rvin_write ( vin , vin - > crop . left + vin - > crop . width - 1 , VNEPPRC_REG ) ;
switch ( vin - > format . field ) {
case V4L2_FIELD_INTERLACED :
case V4L2_FIELD_INTERLACED_TB :
case V4L2_FIELD_INTERLACED_BT :
rvin_write ( vin , vin - > crop . top / 2 , VNSLPRC_REG ) ;
rvin_write ( vin , ( vin - > crop . top + vin - > crop . height ) / 2 - 1 ,
VNELPRC_REG ) ;
break ;
default :
rvin_write ( vin , vin - > crop . top , VNSLPRC_REG ) ;
rvin_write ( vin , vin - > crop . top + vin - > crop . height - 1 ,
VNELPRC_REG ) ;
break ;
}
/* Set scaling coefficient */
ys = 0 ;
if ( vin - > crop . height ! = vin - > compose . height )
ys = ( 4096 * vin - > crop . height ) / vin - > compose . height ;
rvin_write ( vin , ys , VNYS_REG ) ;
xs = 0 ;
if ( vin - > crop . width ! = vin - > compose . width )
xs = ( 4096 * vin - > crop . width ) / vin - > compose . width ;
/* Horizontal upscaling is up to double size */
if ( xs > 0 & & xs < 2048 )
xs = 2048 ;
rvin_write ( vin , xs , VNXS_REG ) ;
/* Horizontal upscaling is done out by scaling down from double size */
if ( xs < 4096 )
xs * = 2 ;
rvin_set_coeff ( vin , xs ) ;
/* Set Start/End Pixel/Line Post-Clip */
rvin_write ( vin , 0 , VNSPPOC_REG ) ;
rvin_write ( vin , 0 , VNSLPOC_REG ) ;
rvin_write ( vin , vin - > format . width - 1 , VNEPPOC_REG ) ;
switch ( vin - > format . field ) {
case V4L2_FIELD_INTERLACED :
case V4L2_FIELD_INTERLACED_TB :
case V4L2_FIELD_INTERLACED_BT :
rvin_write ( vin , vin - > format . height / 2 - 1 , VNELPOC_REG ) ;
break ;
default :
rvin_write ( vin , vin - > format . height - 1 , VNELPOC_REG ) ;
break ;
}
if ( vin - > format . pixelformat = = V4L2_PIX_FMT_NV16 )
rvin_write ( vin , ALIGN ( vin - > format . width , 0x20 ) , VNIS_REG ) ;
else
rvin_write ( vin , ALIGN ( vin - > format . width , 0x10 ) , VNIS_REG ) ;
vin_dbg ( vin ,
" Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u \n " ,
vin - > crop . width , vin - > crop . height , vin - > crop . left ,
vin - > crop . top , ys , xs , vin - > format . width , vin - > format . height ,
0 , 0 ) ;
}
void rvin_scale_try ( struct rvin_dev * vin , struct v4l2_pix_format * pix ,
u32 width , u32 height )
{
/* All VIN channels on Gen2 have scalers */
pix - > width = width ;
pix - > height = height ;
}
/* -----------------------------------------------------------------------------
* DMA Functions
*/
# define RVIN_TIMEOUT_MS 100
# define RVIN_RETRIES 10
struct rvin_buffer {
struct vb2_v4l2_buffer vb ;
struct list_head list ;
} ;
# define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
struct rvin_buffer , \
vb ) - > list )
/* Moves a buffer from the queue to the HW slots */
static bool rvin_fill_hw_slot ( struct rvin_dev * vin , int slot )
{
struct rvin_buffer * buf ;
struct vb2_v4l2_buffer * vbuf ;
dma_addr_t phys_addr_top ;
if ( vin - > queue_buf [ slot ] ! = NULL )
return true ;
if ( list_empty ( & vin - > buf_list ) )
return false ;
vin_dbg ( vin , " Filling HW slot: %d \n " , slot ) ;
/* Keep track of buffer we give to HW */
buf = list_entry ( vin - > buf_list . next , struct rvin_buffer , list ) ;
vbuf = & buf - > vb ;
list_del_init ( to_buf_list ( vbuf ) ) ;
vin - > queue_buf [ slot ] = vbuf ;
/* Setup DMA */
phys_addr_top = vb2_dma_contig_plane_dma_addr ( & vbuf - > vb2_buf , 0 ) ;
rvin_set_slot_addr ( vin , slot , phys_addr_top ) ;
return true ;
}
static bool rvin_fill_hw ( struct rvin_dev * vin )
{
int slot , limit ;
limit = vin - > continuous ? HW_BUFFER_NUM : 1 ;
for ( slot = 0 ; slot < limit ; slot + + )
if ( ! rvin_fill_hw_slot ( vin , slot ) )
return false ;
return true ;
}
static irqreturn_t rvin_irq ( int irq , void * data )
{
struct rvin_dev * vin = data ;
u32 int_status ;
int slot ;
unsigned int sequence , handled = 0 ;
unsigned long flags ;
spin_lock_irqsave ( & vin - > qlock , flags ) ;
int_status = rvin_get_interrupt_status ( vin ) ;
if ( ! int_status )
goto done ;
rvin_ack_interrupt ( vin ) ;
handled = 1 ;
/* Nothing to do if capture status is 'STOPPED' */
if ( vin - > state = = STOPPED ) {
vin_dbg ( vin , " IRQ while state stopped \n " ) ;
goto done ;
}
/* Nothing to do if capture status is 'STOPPING' */
if ( vin - > state = = STOPPING ) {
vin_dbg ( vin , " IRQ while state stopping \n " ) ;
goto done ;
}
/* Prepare for capture and update state */
slot = rvin_get_active_slot ( vin ) ;
sequence = vin - > sequence + + ;
vin_dbg ( vin , " IRQ %02d: %d \t buf0: %c buf1: %c buf2: %c \t more: %d \n " ,
sequence , slot ,
slot = = 0 ? ' x ' : vin - > queue_buf [ 0 ] ! = NULL ? ' 1 ' : ' 0 ' ,
slot = = 1 ? ' x ' : vin - > queue_buf [ 1 ] ! = NULL ? ' 1 ' : ' 0 ' ,
slot = = 2 ? ' x ' : vin - > queue_buf [ 2 ] ! = NULL ? ' 1 ' : ' 0 ' ,
! list_empty ( & vin - > buf_list ) ) ;
/* HW have written to a slot that is not prepared we are in trouble */
if ( WARN_ON ( ( vin - > queue_buf [ slot ] = = NULL ) ) )
goto done ;
/* Capture frame */
vin - > queue_buf [ slot ] - > field = vin - > format . field ;
vin - > queue_buf [ slot ] - > sequence = sequence ;
vin - > queue_buf [ slot ] - > vb2_buf . timestamp = ktime_get_ns ( ) ;
vb2_buffer_done ( & vin - > queue_buf [ slot ] - > vb2_buf , VB2_BUF_STATE_DONE ) ;
vin - > queue_buf [ slot ] = NULL ;
/* Prepare for next frame */
if ( ! rvin_fill_hw ( vin ) ) {
/*
* Can ' t supply HW with new buffers fast enough . Halt
* capture until more buffers are available .
*/
vin - > state = STALLED ;
/*
* The continuous capturing requires an explicit stop
* operation when there is no buffer to be set into
* the VnMBm registers .
*/
if ( vin - > continuous ) {
rvin_capture_off ( vin ) ;
vin_dbg ( vin , " IRQ %02d: hw not ready stop \n " , sequence ) ;
}
} else {
/*
* The single capturing requires an explicit capture
* operation to fetch the next frame .
*/
if ( ! vin - > continuous )
rvin_capture_on ( vin ) ;
}
done :
spin_unlock_irqrestore ( & vin - > qlock , flags ) ;
return IRQ_RETVAL ( handled ) ;
}
/* Need to hold qlock before calling */
static void return_all_buffers ( struct rvin_dev * vin ,
enum vb2_buffer_state state )
{
struct rvin_buffer * buf , * node ;
int i ;
for ( i = 0 ; i < HW_BUFFER_NUM ; i + + ) {
if ( vin - > queue_buf [ i ] ) {
vb2_buffer_done ( & vin - > queue_buf [ i ] - > vb2_buf ,
state ) ;
vin - > queue_buf [ i ] = NULL ;
}
}
list_for_each_entry_safe ( buf , node , & vin - > buf_list , list ) {
vb2_buffer_done ( & buf - > vb . vb2_buf , state ) ;
list_del ( & buf - > list ) ;
}
}
static int rvin_queue_setup ( struct vb2_queue * vq , unsigned int * nbuffers ,
unsigned int * nplanes , unsigned int sizes [ ] ,
2016-04-15 09:15:05 -03:00
struct device * alloc_devs [ ] )
2016-04-26 10:22:19 -03:00
{
struct rvin_dev * vin = vb2_get_drv_priv ( vq ) ;
/* Make sure the image size is large enough. */
if ( * nplanes )
return sizes [ 0 ] < vin - > format . sizeimage ? - EINVAL : 0 ;
* nplanes = 1 ;
sizes [ 0 ] = vin - > format . sizeimage ;
return 0 ;
} ;
static int rvin_buffer_prepare ( struct vb2_buffer * vb )
{
struct rvin_dev * vin = vb2_get_drv_priv ( vb - > vb2_queue ) ;
unsigned long size = vin - > format . sizeimage ;
if ( vb2_plane_size ( vb , 0 ) < size ) {
vin_err ( vin , " buffer too small (%lu < %lu) \n " ,
vb2_plane_size ( vb , 0 ) , size ) ;
return - EINVAL ;
}
vb2_set_plane_payload ( vb , 0 , size ) ;
return 0 ;
}
static void rvin_buffer_queue ( struct vb2_buffer * vb )
{
struct vb2_v4l2_buffer * vbuf = to_vb2_v4l2_buffer ( vb ) ;
struct rvin_dev * vin = vb2_get_drv_priv ( vb - > vb2_queue ) ;
unsigned long flags ;
spin_lock_irqsave ( & vin - > qlock , flags ) ;
list_add_tail ( to_buf_list ( vbuf ) , & vin - > buf_list ) ;
/*
* If capture is stalled add buffer to HW and restart
* capturing if HW is ready to continue .
*/
if ( vin - > state = = STALLED )
if ( rvin_fill_hw ( vin ) )
rvin_capture_on ( vin ) ;
spin_unlock_irqrestore ( & vin - > qlock , flags ) ;
}
static int rvin_start_streaming ( struct vb2_queue * vq , unsigned int count )
{
struct rvin_dev * vin = vb2_get_drv_priv ( vq ) ;
struct v4l2_subdev * sd ;
unsigned long flags ;
int ret ;
sd = vin_to_source ( vin ) ;
v4l2_subdev_call ( sd , video , s_stream , 1 ) ;
spin_lock_irqsave ( & vin - > qlock , flags ) ;
vin - > state = RUNNING ;
vin - > sequence = 0 ;
/* Continuous capture requires more buffers then there are HW slots */
vin - > continuous = count > HW_BUFFER_NUM ;
/*
* This should never happen but if we don ' t have enough
* buffers for HW bail out
*/
if ( ! rvin_fill_hw ( vin ) ) {
vin_err ( vin , " HW not ready to start, not enough buffers available \n " ) ;
ret = - EINVAL ;
goto out ;
}
ret = rvin_capture_start ( vin ) ;
out :
/* Return all buffers if something went wrong */
if ( ret ) {
return_all_buffers ( vin , VB2_BUF_STATE_QUEUED ) ;
v4l2_subdev_call ( sd , video , s_stream , 0 ) ;
}
spin_unlock_irqrestore ( & vin - > qlock , flags ) ;
return ret ;
}
static void rvin_stop_streaming ( struct vb2_queue * vq )
{
struct rvin_dev * vin = vb2_get_drv_priv ( vq ) ;
struct v4l2_subdev * sd ;
unsigned long flags ;
int retries = 0 ;
spin_lock_irqsave ( & vin - > qlock , flags ) ;
vin - > state = STOPPING ;
/* Wait for streaming to stop */
while ( retries + + < RVIN_RETRIES ) {
rvin_capture_stop ( vin ) ;
/* Check if HW is stopped */
if ( ! rvin_capture_active ( vin ) ) {
vin - > state = STOPPED ;
break ;
}
spin_unlock_irqrestore ( & vin - > qlock , flags ) ;
msleep ( RVIN_TIMEOUT_MS ) ;
spin_lock_irqsave ( & vin - > qlock , flags ) ;
}
if ( vin - > state ! = STOPPED ) {
/*
* If this happens something have gone horribly wrong .
* Set state to stopped to prevent the interrupt handler
* to make things worse . . .
*/
vin_err ( vin , " Failed stop HW, something is seriously broken \n " ) ;
vin - > state = STOPPED ;
}
/* Release all active buffers */
return_all_buffers ( vin , VB2_BUF_STATE_ERROR ) ;
spin_unlock_irqrestore ( & vin - > qlock , flags ) ;
sd = vin_to_source ( vin ) ;
v4l2_subdev_call ( sd , video , s_stream , 0 ) ;
/* disable interrupts */
rvin_disable_interrupts ( vin ) ;
}
static struct vb2_ops rvin_qops = {
. queue_setup = rvin_queue_setup ,
. buf_prepare = rvin_buffer_prepare ,
. buf_queue = rvin_buffer_queue ,
. start_streaming = rvin_start_streaming ,
. stop_streaming = rvin_stop_streaming ,
. wait_prepare = vb2_ops_wait_prepare ,
. wait_finish = vb2_ops_wait_finish ,
} ;
void rvin_dma_remove ( struct rvin_dev * vin )
{
mutex_destroy ( & vin - > lock ) ;
v4l2_device_unregister ( & vin - > v4l2_dev ) ;
}
int rvin_dma_probe ( struct rvin_dev * vin , int irq )
{
struct vb2_queue * q = & vin - > queue ;
int i , ret ;
/* Initialize the top-level structure */
ret = v4l2_device_register ( vin - > dev , & vin - > v4l2_dev ) ;
if ( ret )
return ret ;
mutex_init ( & vin - > lock ) ;
INIT_LIST_HEAD ( & vin - > buf_list ) ;
spin_lock_init ( & vin - > qlock ) ;
vin - > state = STOPPED ;
for ( i = 0 ; i < HW_BUFFER_NUM ; i + + )
vin - > queue_buf [ i ] = NULL ;
/* buffer queue */
q - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
q - > io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF ;
q - > lock = & vin - > lock ;
q - > drv_priv = vin ;
q - > buf_struct_size = sizeof ( struct rvin_buffer ) ;
q - > ops = & rvin_qops ;
q - > mem_ops = & vb2_dma_contig_memops ;
q - > timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC ;
q - > min_buffers_needed = 2 ;
2016-02-15 13:09:10 -02:00
q - > dev = vin - > dev ;
2016-04-26 10:22:19 -03:00
ret = vb2_queue_init ( q ) ;
if ( ret < 0 ) {
vin_err ( vin , " failed to initialize VB2 queue \n " ) ;
goto error ;
}
/* irq */
ret = devm_request_irq ( vin - > dev , irq , rvin_irq , IRQF_SHARED ,
KBUILD_MODNAME , vin ) ;
if ( ret ) {
vin_err ( vin , " failed to request irq \n " ) ;
goto error ;
}
return 0 ;
error :
rvin_dma_remove ( vin ) ;
return ret ;
}