2018-02-07 17:34:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2013-07-29 15:40:55 +04:00
/*
* v4l2 - dv - timings - dv - timings helper functions
*
* Copyright 2013 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/errno.h>
2016-07-14 13:59:12 +03:00
# include <linux/rational.h>
2013-07-29 15:40:55 +04:00
# include <linux/videodev2.h>
# include <linux/v4l2-dv-timings.h>
# include <media/v4l2-dv-timings.h>
2015-05-05 16:16:27 +03:00
# include <linux/math64.h>
2018-02-15 20:55:29 +03:00
# include <linux/hdmi.h>
2018-09-13 10:40:56 +03:00
# include <media/cec.h>
2013-07-29 15:40:55 +04:00
2014-03-04 11:51:50 +04:00
MODULE_AUTHOR ( " Hans Verkuil " ) ;
MODULE_DESCRIPTION ( " V4L2 DV Timings Helper Functions " ) ;
MODULE_LICENSE ( " GPL " ) ;
2013-08-19 17:19:54 +04:00
const struct v4l2_dv_timings v4l2_dv_timings_presets [ ] = {
2013-07-29 15:40:55 +04:00
V4L2_DV_BT_CEA_640X480P59_94 ,
V4L2_DV_BT_CEA_720X480I59_94 ,
V4L2_DV_BT_CEA_720X480P59_94 ,
V4L2_DV_BT_CEA_720X576I50 ,
V4L2_DV_BT_CEA_720X576P50 ,
V4L2_DV_BT_CEA_1280X720P24 ,
V4L2_DV_BT_CEA_1280X720P25 ,
V4L2_DV_BT_CEA_1280X720P30 ,
V4L2_DV_BT_CEA_1280X720P50 ,
V4L2_DV_BT_CEA_1280X720P60 ,
V4L2_DV_BT_CEA_1920X1080P24 ,
V4L2_DV_BT_CEA_1920X1080P25 ,
V4L2_DV_BT_CEA_1920X1080P30 ,
V4L2_DV_BT_CEA_1920X1080I50 ,
V4L2_DV_BT_CEA_1920X1080P50 ,
V4L2_DV_BT_CEA_1920X1080I60 ,
V4L2_DV_BT_CEA_1920X1080P60 ,
V4L2_DV_BT_DMT_640X350P85 ,
V4L2_DV_BT_DMT_640X400P85 ,
V4L2_DV_BT_DMT_720X400P85 ,
V4L2_DV_BT_DMT_640X480P72 ,
V4L2_DV_BT_DMT_640X480P75 ,
V4L2_DV_BT_DMT_640X480P85 ,
V4L2_DV_BT_DMT_800X600P56 ,
V4L2_DV_BT_DMT_800X600P60 ,
V4L2_DV_BT_DMT_800X600P72 ,
V4L2_DV_BT_DMT_800X600P75 ,
V4L2_DV_BT_DMT_800X600P85 ,
V4L2_DV_BT_DMT_800X600P120_RB ,
V4L2_DV_BT_DMT_848X480P60 ,
V4L2_DV_BT_DMT_1024X768I43 ,
V4L2_DV_BT_DMT_1024X768P60 ,
V4L2_DV_BT_DMT_1024X768P70 ,
V4L2_DV_BT_DMT_1024X768P75 ,
V4L2_DV_BT_DMT_1024X768P85 ,
V4L2_DV_BT_DMT_1024X768P120_RB ,
V4L2_DV_BT_DMT_1152X864P75 ,
V4L2_DV_BT_DMT_1280X768P60_RB ,
V4L2_DV_BT_DMT_1280X768P60 ,
V4L2_DV_BT_DMT_1280X768P75 ,
V4L2_DV_BT_DMT_1280X768P85 ,
V4L2_DV_BT_DMT_1280X768P120_RB ,
V4L2_DV_BT_DMT_1280X800P60_RB ,
V4L2_DV_BT_DMT_1280X800P60 ,
V4L2_DV_BT_DMT_1280X800P75 ,
V4L2_DV_BT_DMT_1280X800P85 ,
V4L2_DV_BT_DMT_1280X800P120_RB ,
V4L2_DV_BT_DMT_1280X960P60 ,
V4L2_DV_BT_DMT_1280X960P85 ,
V4L2_DV_BT_DMT_1280X960P120_RB ,
V4L2_DV_BT_DMT_1280X1024P60 ,
V4L2_DV_BT_DMT_1280X1024P75 ,
V4L2_DV_BT_DMT_1280X1024P85 ,
V4L2_DV_BT_DMT_1280X1024P120_RB ,
V4L2_DV_BT_DMT_1360X768P60 ,
V4L2_DV_BT_DMT_1360X768P120_RB ,
V4L2_DV_BT_DMT_1366X768P60 ,
V4L2_DV_BT_DMT_1366X768P60_RB ,
V4L2_DV_BT_DMT_1400X1050P60_RB ,
V4L2_DV_BT_DMT_1400X1050P60 ,
V4L2_DV_BT_DMT_1400X1050P75 ,
V4L2_DV_BT_DMT_1400X1050P85 ,
V4L2_DV_BT_DMT_1400X1050P120_RB ,
V4L2_DV_BT_DMT_1440X900P60_RB ,
V4L2_DV_BT_DMT_1440X900P60 ,
V4L2_DV_BT_DMT_1440X900P75 ,
V4L2_DV_BT_DMT_1440X900P85 ,
V4L2_DV_BT_DMT_1440X900P120_RB ,
V4L2_DV_BT_DMT_1600X900P60_RB ,
V4L2_DV_BT_DMT_1600X1200P60 ,
V4L2_DV_BT_DMT_1600X1200P65 ,
V4L2_DV_BT_DMT_1600X1200P70 ,
V4L2_DV_BT_DMT_1600X1200P75 ,
V4L2_DV_BT_DMT_1600X1200P85 ,
V4L2_DV_BT_DMT_1600X1200P120_RB ,
V4L2_DV_BT_DMT_1680X1050P60_RB ,
V4L2_DV_BT_DMT_1680X1050P60 ,
V4L2_DV_BT_DMT_1680X1050P75 ,
V4L2_DV_BT_DMT_1680X1050P85 ,
V4L2_DV_BT_DMT_1680X1050P120_RB ,
V4L2_DV_BT_DMT_1792X1344P60 ,
V4L2_DV_BT_DMT_1792X1344P75 ,
V4L2_DV_BT_DMT_1792X1344P120_RB ,
V4L2_DV_BT_DMT_1856X1392P60 ,
V4L2_DV_BT_DMT_1856X1392P75 ,
V4L2_DV_BT_DMT_1856X1392P120_RB ,
V4L2_DV_BT_DMT_1920X1200P60_RB ,
V4L2_DV_BT_DMT_1920X1200P60 ,
V4L2_DV_BT_DMT_1920X1200P75 ,
V4L2_DV_BT_DMT_1920X1200P85 ,
V4L2_DV_BT_DMT_1920X1200P120_RB ,
V4L2_DV_BT_DMT_1920X1440P60 ,
V4L2_DV_BT_DMT_1920X1440P75 ,
V4L2_DV_BT_DMT_1920X1440P120_RB ,
V4L2_DV_BT_DMT_2048X1152P60_RB ,
V4L2_DV_BT_DMT_2560X1600P60_RB ,
V4L2_DV_BT_DMT_2560X1600P60 ,
V4L2_DV_BT_DMT_2560X1600P75 ,
V4L2_DV_BT_DMT_2560X1600P85 ,
V4L2_DV_BT_DMT_2560X1600P120_RB ,
2014-04-08 12:01:52 +04:00
V4L2_DV_BT_CEA_3840X2160P24 ,
V4L2_DV_BT_CEA_3840X2160P25 ,
V4L2_DV_BT_CEA_3840X2160P30 ,
V4L2_DV_BT_CEA_3840X2160P50 ,
V4L2_DV_BT_CEA_3840X2160P60 ,
V4L2_DV_BT_CEA_4096X2160P24 ,
V4L2_DV_BT_CEA_4096X2160P25 ,
V4L2_DV_BT_CEA_4096X2160P30 ,
V4L2_DV_BT_CEA_4096X2160P50 ,
V4L2_DV_BT_DMT_4096X2160P59_94_RB ,
V4L2_DV_BT_CEA_4096X2160P60 ,
2013-08-19 17:19:54 +04:00
{ }
2013-07-29 15:40:55 +04:00
} ;
2013-08-19 17:19:54 +04:00
EXPORT_SYMBOL_GPL ( v4l2_dv_timings_presets ) ;
2013-07-29 15:40:55 +04:00
2013-08-19 17:23:33 +04:00
bool v4l2_valid_dv_timings ( const struct v4l2_dv_timings * t ,
2013-08-19 18:21:50 +04:00
const struct v4l2_dv_timings_cap * dvcap ,
v4l2_check_dv_timings_fnc fnc ,
void * fnc_handle )
2013-07-29 15:40:55 +04:00
{
const struct v4l2_bt_timings * bt = & t - > bt ;
const struct v4l2_bt_timings_cap * cap = & dvcap - > bt ;
u32 caps = cap - > capabilities ;
if ( t - > type ! = V4L2_DV_BT_656_1120 )
return false ;
if ( t - > type ! = dvcap - > type | |
bt - > height < cap - > min_height | |
bt - > height > cap - > max_height | |
bt - > width < cap - > min_width | |
bt - > width > cap - > max_width | |
bt - > pixelclock < cap - > min_pixelclock | |
bt - > pixelclock > cap - > max_pixelclock | |
2016-01-13 16:44:41 +03:00
( ! ( caps & V4L2_DV_BT_CAP_CUSTOM ) & &
cap - > standards & & bt - > standards & &
2014-09-20 14:36:38 +04:00
! ( bt - > standards & cap - > standards ) ) | |
2013-07-29 15:40:55 +04:00
( bt - > interlaced & & ! ( caps & V4L2_DV_BT_CAP_INTERLACED ) ) | |
( ! bt - > interlaced & & ! ( caps & V4L2_DV_BT_CAP_PROGRESSIVE ) ) )
return false ;
2013-08-19 18:21:50 +04:00
return fnc = = NULL | | fnc ( t , fnc_handle ) ;
2013-07-29 15:40:55 +04:00
}
2013-08-19 17:23:33 +04:00
EXPORT_SYMBOL_GPL ( v4l2_valid_dv_timings ) ;
2013-07-29 15:40:55 +04:00
int v4l2_enum_dv_timings_cap ( struct v4l2_enum_dv_timings * t ,
2013-08-19 18:21:50 +04:00
const struct v4l2_dv_timings_cap * cap ,
v4l2_check_dv_timings_fnc fnc ,
void * fnc_handle )
2013-07-29 15:40:55 +04:00
{
u32 i , idx ;
memset ( t - > reserved , 0 , sizeof ( t - > reserved ) ) ;
2013-08-19 17:19:54 +04:00
for ( i = idx = 0 ; v4l2_dv_timings_presets [ i ] . bt . width ; i + + ) {
2013-08-19 18:21:50 +04:00
if ( v4l2_valid_dv_timings ( v4l2_dv_timings_presets + i , cap ,
fnc , fnc_handle ) & &
2013-07-29 15:40:55 +04:00
idx + + = = t - > index ) {
2013-08-19 17:19:54 +04:00
t - > timings = v4l2_dv_timings_presets [ i ] ;
2013-07-29 15:40:55 +04:00
return 0 ;
}
}
return - EINVAL ;
}
EXPORT_SYMBOL_GPL ( v4l2_enum_dv_timings_cap ) ;
bool v4l2_find_dv_timings_cap ( struct v4l2_dv_timings * t ,
const struct v4l2_dv_timings_cap * cap ,
2013-08-19 18:21:50 +04:00
unsigned pclock_delta ,
v4l2_check_dv_timings_fnc fnc ,
void * fnc_handle )
2013-07-29 15:40:55 +04:00
{
int i ;
2013-08-19 18:21:50 +04:00
if ( ! v4l2_valid_dv_timings ( t , cap , fnc , fnc_handle ) )
2013-07-29 15:40:55 +04:00
return false ;
2013-08-19 17:19:54 +04:00
for ( i = 0 ; i < v4l2_dv_timings_presets [ i ] . bt . width ; i + + ) {
2013-08-19 18:21:50 +04:00
if ( v4l2_valid_dv_timings ( v4l2_dv_timings_presets + i , cap ,
fnc , fnc_handle ) & &
v4l2_match_dv_timings ( t , v4l2_dv_timings_presets + i ,
2015-11-13 14:46:26 +03:00
pclock_delta , false ) ) {
2015-09-22 17:27:28 +03:00
u32 flags = t - > bt . flags & V4L2_DV_FL_REDUCED_FPS ;
2013-08-19 17:19:54 +04:00
* t = v4l2_dv_timings_presets [ i ] ;
2015-09-22 17:27:28 +03:00
if ( can_reduce_fps ( & t - > bt ) )
t - > bt . flags | = flags ;
2013-07-29 15:40:55 +04:00
return true ;
}
}
return false ;
}
EXPORT_SYMBOL_GPL ( v4l2_find_dv_timings_cap ) ;
2013-07-29 15:40:56 +04:00
2016-07-14 13:59:12 +03:00
bool v4l2_find_dv_timings_cea861_vic ( struct v4l2_dv_timings * t , u8 vic )
{
unsigned int i ;
for ( i = 0 ; i < v4l2_dv_timings_presets [ i ] . bt . width ; i + + ) {
const struct v4l2_bt_timings * bt =
& v4l2_dv_timings_presets [ i ] . bt ;
if ( ( bt - > flags & V4L2_DV_FL_HAS_CEA861_VIC ) & &
bt - > cea861_vic = = vic ) {
* t = v4l2_dv_timings_presets [ i ] ;
return true ;
}
}
return false ;
}
EXPORT_SYMBOL_GPL ( v4l2_find_dv_timings_cea861_vic ) ;
2013-07-29 15:40:56 +04:00
/**
2013-08-15 15:28:47 +04:00
* v4l2_match_dv_timings - check if two timings match
2017-11-29 11:56:18 +03:00
* @ t1 : compare this v4l2_dv_timings struct . . .
* @ t2 : with this struct .
* @ pclock_delta : the allowed pixelclock deviation .
* @ match_reduced_fps : if true , then fail if V4L2_DV_FL_REDUCED_FPS does not
2018-01-04 14:47:28 +03:00
* match .
2013-07-29 15:40:56 +04:00
*
* Compare t1 with t2 with a given margin of error for the pixelclock .
*/
2013-08-15 15:28:47 +04:00
bool v4l2_match_dv_timings ( const struct v4l2_dv_timings * t1 ,
const struct v4l2_dv_timings * t2 ,
2015-11-13 14:46:26 +03:00
unsigned pclock_delta , bool match_reduced_fps )
2013-07-29 15:40:56 +04:00
{
if ( t1 - > type ! = t2 - > type | | t1 - > type ! = V4L2_DV_BT_656_1120 )
return false ;
if ( t1 - > bt . width = = t2 - > bt . width & &
t1 - > bt . height = = t2 - > bt . height & &
t1 - > bt . interlaced = = t2 - > bt . interlaced & &
t1 - > bt . polarities = = t2 - > bt . polarities & &
t1 - > bt . pixelclock > = t2 - > bt . pixelclock - pclock_delta & &
t1 - > bt . pixelclock < = t2 - > bt . pixelclock + pclock_delta & &
t1 - > bt . hfrontporch = = t2 - > bt . hfrontporch & &
2015-11-12 15:34:55 +03:00
t1 - > bt . hsync = = t2 - > bt . hsync & &
t1 - > bt . hbackporch = = t2 - > bt . hbackporch & &
2013-07-29 15:40:56 +04:00
t1 - > bt . vfrontporch = = t2 - > bt . vfrontporch & &
t1 - > bt . vsync = = t2 - > bt . vsync & &
t1 - > bt . vbackporch = = t2 - > bt . vbackporch & &
2015-11-13 14:46:26 +03:00
( ! match_reduced_fps | |
( t1 - > bt . flags & V4L2_DV_FL_REDUCED_FPS ) = =
( t2 - > bt . flags & V4L2_DV_FL_REDUCED_FPS ) ) & &
2013-07-29 15:40:56 +04:00
( ! t1 - > bt . interlaced | |
( t1 - > bt . il_vfrontporch = = t2 - > bt . il_vfrontporch & &
t1 - > bt . il_vsync = = t2 - > bt . il_vsync & &
t1 - > bt . il_vbackporch = = t2 - > bt . il_vbackporch ) ) )
return true ;
return false ;
}
2013-08-15 15:28:47 +04:00
EXPORT_SYMBOL_GPL ( v4l2_match_dv_timings ) ;
2013-07-29 15:40:56 +04:00
2013-08-15 15:02:40 +04:00
void v4l2_print_dv_timings ( const char * dev_prefix , const char * prefix ,
const struct v4l2_dv_timings * t , bool detailed )
{
const struct v4l2_bt_timings * bt = & t - > bt ;
u32 htot , vtot ;
2015-06-12 14:48:10 +03:00
u32 fps ;
2013-08-15 15:02:40 +04:00
if ( t - > type ! = V4L2_DV_BT_656_1120 )
return ;
htot = V4L2_DV_BT_FRAME_WIDTH ( bt ) ;
vtot = V4L2_DV_BT_FRAME_HEIGHT ( bt ) ;
2015-06-05 11:30:02 +03:00
if ( bt - > interlaced )
vtot / = 2 ;
2013-08-15 15:02:40 +04:00
2015-06-12 14:48:10 +03:00
fps = ( htot * vtot ) > 0 ? div_u64 ( ( 100 * ( u64 ) bt - > pixelclock ) ,
( htot * vtot ) ) : 0 ;
2013-08-15 15:02:40 +04:00
if ( prefix = = NULL )
prefix = " " ;
2015-06-12 14:48:10 +03:00
pr_info ( " %s: %s%ux%u%s%u.%u (%ux%u) \n " , dev_prefix , prefix ,
2013-08-15 15:02:40 +04:00
bt - > width , bt - > height , bt - > interlaced ? " i " : " p " ,
2015-06-12 14:48:10 +03:00
fps / 100 , fps % 100 , htot , vtot ) ;
2013-08-15 15:02:40 +04:00
if ( ! detailed )
return ;
pr_info ( " %s: horizontal: fp = %u, %ssync = %u, bp = %u \n " ,
dev_prefix , bt - > hfrontporch ,
( bt - > polarities & V4L2_DV_HSYNC_POS_POL ) ? " + " : " - " ,
bt - > hsync , bt - > hbackporch ) ;
pr_info ( " %s: vertical: fp = %u, %ssync = %u, bp = %u \n " ,
dev_prefix , bt - > vfrontporch ,
( bt - > polarities & V4L2_DV_VSYNC_POS_POL ) ? " + " : " - " ,
bt - > vsync , bt - > vbackporch ) ;
2015-06-05 11:30:02 +03:00
if ( bt - > interlaced )
pr_info ( " %s: vertical bottom field: fp = %u, %ssync = %u, bp = %u \n " ,
dev_prefix , bt - > il_vfrontporch ,
( bt - > polarities & V4L2_DV_VSYNC_POS_POL ) ? " + " : " - " ,
bt - > il_vsync , bt - > il_vbackporch ) ;
2013-08-15 15:02:40 +04:00
pr_info ( " %s: pixelclock: %llu \n " , dev_prefix , bt - > pixelclock ) ;
2016-07-14 13:59:12 +03:00
pr_info ( " %s: flags (0x%x):%s%s%s%s%s%s%s%s%s%s \n " ,
dev_prefix , bt - > flags ,
2013-08-15 15:02:40 +04:00
( bt - > flags & V4L2_DV_FL_REDUCED_BLANKING ) ?
" REDUCED_BLANKING " : " " ,
2015-06-12 09:52:54 +03:00
( ( bt - > flags & V4L2_DV_FL_REDUCED_BLANKING ) & &
bt - > vsync = = 8 ) ? " (V2) " : " " ,
2013-08-15 15:02:40 +04:00
( bt - > flags & V4L2_DV_FL_CAN_REDUCE_FPS ) ?
" CAN_REDUCE_FPS " : " " ,
( bt - > flags & V4L2_DV_FL_REDUCED_FPS ) ?
" REDUCED_FPS " : " " ,
( bt - > flags & V4L2_DV_FL_HALF_LINE ) ?
2015-04-03 12:27:02 +03:00
" HALF_LINE " : " " ,
( bt - > flags & V4L2_DV_FL_IS_CE_VIDEO ) ?
2016-09-15 18:29:50 +03:00
" CE_VIDEO " : " " ,
( bt - > flags & V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE ) ?
2016-07-14 13:59:12 +03:00
" FIRST_FIELD_EXTRA_LINE " : " " ,
( bt - > flags & V4L2_DV_FL_HAS_PICTURE_ASPECT ) ?
" HAS_PICTURE_ASPECT " : " " ,
( bt - > flags & V4L2_DV_FL_HAS_CEA861_VIC ) ?
" HAS_CEA861_VIC " : " " ,
( bt - > flags & V4L2_DV_FL_HAS_HDMI_VIC ) ?
" HAS_HDMI_VIC " : " " ) ;
2016-09-15 18:29:50 +03:00
pr_info ( " %s: standards (0x%x):%s%s%s%s%s \n " , dev_prefix , bt - > standards ,
2013-08-15 15:02:40 +04:00
( bt - > standards & V4L2_DV_BT_STD_CEA861 ) ? " CEA " : " " ,
( bt - > standards & V4L2_DV_BT_STD_DMT ) ? " DMT " : " " ,
( bt - > standards & V4L2_DV_BT_STD_CVT ) ? " CVT " : " " ,
2016-09-15 18:29:50 +03:00
( bt - > standards & V4L2_DV_BT_STD_GTF ) ? " GTF " : " " ,
( bt - > standards & V4L2_DV_BT_STD_SDI ) ? " SDI " : " " ) ;
2016-07-14 13:59:12 +03:00
if ( bt - > flags & V4L2_DV_FL_HAS_PICTURE_ASPECT )
pr_info ( " %s: picture aspect (hor:vert): %u:%u \n " , dev_prefix ,
bt - > picture_aspect . numerator ,
bt - > picture_aspect . denominator ) ;
if ( bt - > flags & V4L2_DV_FL_HAS_CEA861_VIC )
pr_info ( " %s: CEA-861 VIC: %u \n " , dev_prefix , bt - > cea861_vic ) ;
if ( bt - > flags & V4L2_DV_FL_HAS_HDMI_VIC )
pr_info ( " %s: HDMI VIC: %u \n " , dev_prefix , bt - > hdmi_vic ) ;
2013-08-15 15:02:40 +04:00
}
EXPORT_SYMBOL_GPL ( v4l2_print_dv_timings ) ;
2016-07-14 13:59:12 +03:00
struct v4l2_fract v4l2_dv_timings_aspect_ratio ( const struct v4l2_dv_timings * t )
{
struct v4l2_fract ratio = { 1 , 1 } ;
unsigned long n , d ;
if ( t - > type ! = V4L2_DV_BT_656_1120 )
return ratio ;
if ( ! ( t - > bt . flags & V4L2_DV_FL_HAS_PICTURE_ASPECT ) )
return ratio ;
ratio . numerator = t - > bt . width * t - > bt . picture_aspect . denominator ;
ratio . denominator = t - > bt . height * t - > bt . picture_aspect . numerator ;
rational_best_approximation ( ratio . numerator , ratio . denominator ,
ratio . numerator , ratio . denominator , & n , & d ) ;
ratio . numerator = n ;
ratio . denominator = d ;
return ratio ;
}
EXPORT_SYMBOL_GPL ( v4l2_dv_timings_aspect_ratio ) ;
2017-03-21 14:49:17 +03:00
/** v4l2_calc_timeperframe - helper function to calculate timeperframe based
* v4l2_dv_timings fields .
* @ t - Timings for the video mode .
*
* Calculates the expected timeperframe using the pixel clock value and
* horizontal / vertical measures . This means that v4l2_dv_timings structure
* must be correctly and fully filled .
*/
struct v4l2_fract v4l2_calc_timeperframe ( const struct v4l2_dv_timings * t )
{
const struct v4l2_bt_timings * bt = & t - > bt ;
struct v4l2_fract fps_fract = { 1 , 1 } ;
unsigned long n , d ;
u32 htot , vtot , fps ;
u64 pclk ;
if ( t - > type ! = V4L2_DV_BT_656_1120 )
return fps_fract ;
htot = V4L2_DV_BT_FRAME_WIDTH ( bt ) ;
vtot = V4L2_DV_BT_FRAME_HEIGHT ( bt ) ;
pclk = bt - > pixelclock ;
if ( ( bt - > flags & V4L2_DV_FL_CAN_DETECT_REDUCED_FPS ) & &
( bt - > flags & V4L2_DV_FL_REDUCED_FPS ) )
pclk = div_u64 ( pclk * 1000ULL , 1001 ) ;
fps = ( htot * vtot ) > 0 ? div_u64 ( ( 100 * pclk ) , ( htot * vtot ) ) : 0 ;
if ( ! fps )
return fps_fract ;
rational_best_approximation ( fps , 100 , fps , 100 , & n , & d ) ;
fps_fract . numerator = d ;
fps_fract . denominator = n ;
return fps_fract ;
}
EXPORT_SYMBOL_GPL ( v4l2_calc_timeperframe ) ;
2013-07-29 15:40:56 +04:00
/*
* CVT defines
* Based on Coordinated Video Timings Standard
* version 1.1 September 10 , 2003
*/
# define CVT_PXL_CLK_GRAN 250000 /* pixel clock granularity */
2015-06-10 19:51:42 +03:00
# define CVT_PXL_CLK_GRAN_RB_V2 1000 /* granularity for reduced blanking v2*/
2013-07-29 15:40:56 +04:00
/* Normal blanking */
# define CVT_MIN_V_BPORCH 7 /* lines */
# define CVT_MIN_V_PORCH_RND 3 /* lines */
# define CVT_MIN_VSYNC_BP 550 /* min time of vsync + back porch (us) */
2015-04-22 20:32:37 +03:00
# define CVT_HSYNC_PERCENT 8 /* nominal hsync as percentage of line */
2013-07-29 15:40:56 +04:00
/* Normal blanking for CVT uses GTF to calculate horizontal blanking */
# define CVT_CELL_GRAN 8 /* character cell granularity */
# define CVT_M 600 /* blanking formula gradient */
# define CVT_C 40 /* blanking formula offset */
# define CVT_K 128 /* blanking formula scaling factor */
# define CVT_J 20 /* blanking formula scaling factor */
# define CVT_C_PRIME (((CVT_C - CVT_J) * CVT_K / 256) + CVT_J)
# define CVT_M_PRIME (CVT_K * CVT_M / 256)
/* Reduced Blanking */
# define CVT_RB_MIN_V_BPORCH 7 /* lines */
# define CVT_RB_V_FPORCH 3 /* lines */
2015-06-10 19:51:42 +03:00
# define CVT_RB_MIN_V_BLANK 460 /* us */
2013-07-29 15:40:56 +04:00
# define CVT_RB_H_SYNC 32 /* pixels */
# define CVT_RB_H_BLANK 160 /* pixels */
2015-06-10 19:51:42 +03:00
/* Reduce blanking Version 2 */
# define CVT_RB_V2_H_BLANK 80 /* pixels */
# define CVT_RB_MIN_V_FPORCH 3 /* lines */
# define CVT_RB_V2_MIN_V_FPORCH 1 /* lines */
# define CVT_RB_V_BPORCH 6 /* lines */
2013-07-29 15:40:56 +04:00
/** v4l2_detect_cvt - detect if the given timings follow the CVT standard
* @ frame_height - the total height of the frame ( including blanking ) in lines .
* @ hfreq - the horizontal frequency in Hz .
* @ vsync - the height of the vertical sync in lines .
2015-06-10 19:51:42 +03:00
* @ active_width - active width of image ( does not include blanking ) . This
* information is needed only in case of version 2 of reduced blanking .
* In other cases , this parameter does not have any effect on timings .
2013-07-29 15:40:56 +04:00
* @ polarities - the horizontal and vertical polarities ( same as struct
* v4l2_bt_timings polarities ) .
2015-05-22 08:27:34 +03:00
* @ interlaced - if this flag is true , it indicates interlaced format
2013-07-29 15:40:56 +04:00
* @ fmt - the resulting timings .
*
* This function will attempt to detect if the given values correspond to a
* valid CVT format . If so , then it will return true , and fmt will be filled
* in with the found CVT timings .
*/
2015-06-10 19:51:42 +03:00
bool v4l2_detect_cvt ( unsigned frame_height ,
unsigned hfreq ,
unsigned vsync ,
unsigned active_width ,
u32 polarities ,
bool interlaced ,
struct v4l2_dv_timings * fmt )
2013-07-29 15:40:56 +04:00
{
int v_fp , v_bp , h_fp , h_bp , hsync ;
int frame_width , image_height , image_width ;
bool reduced_blanking ;
2015-06-10 19:51:42 +03:00
bool rb_v2 = false ;
2013-07-29 15:40:56 +04:00
unsigned pix_clk ;
2015-06-10 19:51:42 +03:00
if ( vsync < 4 | | vsync > 8 )
2013-07-29 15:40:56 +04:00
return false ;
if ( polarities = = V4L2_DV_VSYNC_POS_POL )
reduced_blanking = false ;
else if ( polarities = = V4L2_DV_HSYNC_POS_POL )
reduced_blanking = true ;
else
return false ;
2015-06-10 19:51:42 +03:00
if ( reduced_blanking & & vsync = = 8 )
rb_v2 = true ;
if ( rb_v2 & & active_width = = 0 )
return false ;
if ( ! rb_v2 & & vsync > 7 )
return false ;
2015-04-22 20:32:36 +03:00
if ( hfreq = = 0 )
return false ;
2013-07-29 15:40:56 +04:00
/* Vertical */
if ( reduced_blanking ) {
2015-06-10 19:51:42 +03:00
if ( rb_v2 ) {
v_bp = CVT_RB_V_BPORCH ;
v_fp = ( CVT_RB_MIN_V_BLANK * hfreq ) / 1000000 + 1 ;
v_fp - = vsync + v_bp ;
if ( v_fp < CVT_RB_V2_MIN_V_FPORCH )
v_fp = CVT_RB_V2_MIN_V_FPORCH ;
} else {
v_fp = CVT_RB_V_FPORCH ;
v_bp = ( CVT_RB_MIN_V_BLANK * hfreq ) / 1000000 + 1 ;
v_bp - = vsync + v_fp ;
if ( v_bp < CVT_RB_MIN_V_BPORCH )
v_bp = CVT_RB_MIN_V_BPORCH ;
}
2013-07-29 15:40:56 +04:00
} else {
v_fp = CVT_MIN_V_PORCH_RND ;
2015-04-22 20:32:34 +03:00
v_bp = ( CVT_MIN_VSYNC_BP * hfreq ) / 1000000 + 1 - vsync ;
2013-07-29 15:40:56 +04:00
if ( v_bp < CVT_MIN_V_BPORCH )
v_bp = CVT_MIN_V_BPORCH ;
}
2015-05-22 08:27:34 +03:00
if ( interlaced )
image_height = ( frame_height - 2 * v_fp - 2 * vsync - 2 * v_bp ) & ~ 0x1 ;
else
image_height = ( frame_height - v_fp - vsync - v_bp + 1 ) & ~ 0x1 ;
2013-07-29 15:40:56 +04:00
2015-04-22 20:32:36 +03:00
if ( image_height < 0 )
return false ;
2013-07-29 15:40:56 +04:00
/* Aspect ratio based on vsync */
switch ( vsync ) {
case 4 :
image_width = ( image_height * 4 ) / 3 ;
break ;
case 5 :
image_width = ( image_height * 16 ) / 9 ;
break ;
case 6 :
image_width = ( image_height * 16 ) / 10 ;
break ;
case 7 :
/* special case */
if ( image_height = = 1024 )
image_width = ( image_height * 5 ) / 4 ;
else if ( image_height = = 768 )
image_width = ( image_height * 15 ) / 9 ;
else
return false ;
break ;
2015-06-10 19:51:42 +03:00
case 8 :
image_width = active_width ;
break ;
2013-07-29 15:40:56 +04:00
default :
return false ;
}
2015-06-10 19:51:42 +03:00
if ( ! rb_v2 )
image_width = image_width & ~ 7 ;
2013-07-29 15:40:56 +04:00
/* Horizontal */
if ( reduced_blanking ) {
2015-06-10 19:51:42 +03:00
int h_blank ;
int clk_gran ;
h_blank = rb_v2 ? CVT_RB_V2_H_BLANK : CVT_RB_H_BLANK ;
clk_gran = rb_v2 ? CVT_PXL_CLK_GRAN_RB_V2 : CVT_PXL_CLK_GRAN ;
pix_clk = ( image_width + h_blank ) * hfreq ;
pix_clk = ( pix_clk / clk_gran ) * clk_gran ;
2013-07-29 15:40:56 +04:00
2015-06-10 19:51:42 +03:00
h_bp = h_blank / 2 ;
2013-07-29 15:40:56 +04:00
hsync = CVT_RB_H_SYNC ;
2015-06-10 19:51:42 +03:00
h_fp = h_blank - h_bp - hsync ;
2013-07-29 15:40:56 +04:00
2015-06-10 19:51:42 +03:00
frame_width = image_width + h_blank ;
2013-07-29 15:40:56 +04:00
} else {
2013-08-14 11:58:38 +04:00
unsigned ideal_duty_cycle_per_myriad =
100 * CVT_C_PRIME - ( CVT_M_PRIME * 100000 ) / hfreq ;
2013-07-29 15:40:56 +04:00
int h_blank ;
2013-08-14 11:58:38 +04:00
if ( ideal_duty_cycle_per_myriad < 2000 )
ideal_duty_cycle_per_myriad = 2000 ;
2013-07-29 15:40:56 +04:00
2013-08-14 11:58:38 +04:00
h_blank = image_width * ideal_duty_cycle_per_myriad /
( 10000 - ideal_duty_cycle_per_myriad ) ;
h_blank = ( h_blank / ( 2 * CVT_CELL_GRAN ) ) * 2 * CVT_CELL_GRAN ;
2013-07-29 15:40:56 +04:00
pix_clk = ( image_width + h_blank ) * hfreq ;
pix_clk = ( pix_clk / CVT_PXL_CLK_GRAN ) * CVT_PXL_CLK_GRAN ;
h_bp = h_blank / 2 ;
frame_width = image_width + h_blank ;
2015-04-22 20:32:37 +03:00
hsync = frame_width * CVT_HSYNC_PERCENT / 100 ;
2015-04-22 20:32:35 +03:00
hsync = ( hsync / CVT_CELL_GRAN ) * CVT_CELL_GRAN ;
2013-07-29 15:40:56 +04:00
h_fp = h_blank - hsync - h_bp ;
}
2013-08-19 15:38:29 +04:00
fmt - > type = V4L2_DV_BT_656_1120 ;
2013-07-29 15:40:56 +04:00
fmt - > bt . polarities = polarities ;
fmt - > bt . width = image_width ;
fmt - > bt . height = image_height ;
fmt - > bt . hfrontporch = h_fp ;
fmt - > bt . vfrontporch = v_fp ;
fmt - > bt . hsync = hsync ;
fmt - > bt . vsync = vsync ;
fmt - > bt . hbackporch = frame_width - image_width - h_fp - hsync ;
2015-05-22 08:27:34 +03:00
if ( ! interlaced ) {
fmt - > bt . vbackporch = frame_height - image_height - v_fp - vsync ;
fmt - > bt . interlaced = V4L2_DV_PROGRESSIVE ;
} else {
fmt - > bt . vbackporch = ( frame_height - image_height - 2 * v_fp -
2 * vsync ) / 2 ;
fmt - > bt . il_vbackporch = frame_height - image_height - 2 * v_fp -
2 * vsync - fmt - > bt . vbackporch ;
fmt - > bt . il_vfrontporch = v_fp ;
fmt - > bt . il_vsync = vsync ;
fmt - > bt . flags | = V4L2_DV_FL_HALF_LINE ;
fmt - > bt . interlaced = V4L2_DV_INTERLACED ;
}
2013-07-29 15:40:56 +04:00
fmt - > bt . pixelclock = pix_clk ;
fmt - > bt . standards = V4L2_DV_BT_STD_CVT ;
2015-05-22 08:27:34 +03:00
2013-07-29 15:40:56 +04:00
if ( reduced_blanking )
fmt - > bt . flags | = V4L2_DV_FL_REDUCED_BLANKING ;
2015-05-22 08:27:34 +03:00
2013-07-29 15:40:56 +04:00
return true ;
}
EXPORT_SYMBOL_GPL ( v4l2_detect_cvt ) ;
/*
* GTF defines
* Based on Generalized Timing Formula Standard
* Version 1.1 September 2 , 1999
*/
# define GTF_PXL_CLK_GRAN 250000 /* pixel clock granularity */
# define GTF_MIN_VSYNC_BP 550 /* min time of vsync + back porch (us) */
# define GTF_V_FP 1 /* vertical front porch (lines) */
# define GTF_CELL_GRAN 8 /* character cell granularity */
/* Default */
# define GTF_D_M 600 /* blanking formula gradient */
# define GTF_D_C 40 /* blanking formula offset */
# define GTF_D_K 128 /* blanking formula scaling factor */
# define GTF_D_J 20 /* blanking formula scaling factor */
# define GTF_D_C_PRIME ((((GTF_D_C - GTF_D_J) * GTF_D_K) / 256) + GTF_D_J)
# define GTF_D_M_PRIME ((GTF_D_K * GTF_D_M) / 256)
/* Secondary */
# define GTF_S_M 3600 /* blanking formula gradient */
# define GTF_S_C 40 /* blanking formula offset */
# define GTF_S_K 128 /* blanking formula scaling factor */
# define GTF_S_J 35 /* blanking formula scaling factor */
# define GTF_S_C_PRIME ((((GTF_S_C - GTF_S_J) * GTF_S_K) / 256) + GTF_S_J)
# define GTF_S_M_PRIME ((GTF_S_K * GTF_S_M) / 256)
/** v4l2_detect_gtf - detect if the given timings follow the GTF standard
* @ frame_height - the total height of the frame ( including blanking ) in lines .
* @ hfreq - the horizontal frequency in Hz .
* @ vsync - the height of the vertical sync in lines .
* @ polarities - the horizontal and vertical polarities ( same as struct
* v4l2_bt_timings polarities ) .
2015-05-22 08:27:34 +03:00
* @ interlaced - if this flag is true , it indicates interlaced format
2013-07-29 15:40:56 +04:00
* @ aspect - preferred aspect ratio . GTF has no method of determining the
* aspect ratio in order to derive the image width from the
* image height , so it has to be passed explicitly . Usually
* the native screen aspect ratio is used for this . If it
* is not filled in correctly , then 16 : 9 will be assumed .
* @ fmt - the resulting timings .
*
* This function will attempt to detect if the given values correspond to a
* valid GTF format . If so , then it will return true , and fmt will be filled
* in with the found GTF timings .
*/
bool v4l2_detect_gtf ( unsigned frame_height ,
unsigned hfreq ,
unsigned vsync ,
u32 polarities ,
2015-05-22 08:27:34 +03:00
bool interlaced ,
2013-07-29 15:40:56 +04:00
struct v4l2_fract aspect ,
struct v4l2_dv_timings * fmt )
{
int pix_clk ;
int v_fp , v_bp , h_fp , hsync ;
int frame_width , image_height , image_width ;
bool default_gtf ;
int h_blank ;
if ( vsync ! = 3 )
return false ;
if ( polarities = = V4L2_DV_VSYNC_POS_POL )
default_gtf = true ;
else if ( polarities = = V4L2_DV_HSYNC_POS_POL )
default_gtf = false ;
else
return false ;
2015-04-22 20:32:36 +03:00
if ( hfreq = = 0 )
return false ;
2013-07-29 15:40:56 +04:00
/* Vertical */
v_fp = GTF_V_FP ;
2015-04-22 20:32:34 +03:00
v_bp = ( GTF_MIN_VSYNC_BP * hfreq + 500000 ) / 1000000 - vsync ;
2015-05-22 08:27:34 +03:00
if ( interlaced )
image_height = ( frame_height - 2 * v_fp - 2 * vsync - 2 * v_bp ) & ~ 0x1 ;
else
image_height = ( frame_height - v_fp - vsync - v_bp + 1 ) & ~ 0x1 ;
2013-07-29 15:40:56 +04:00
2015-04-22 20:32:36 +03:00
if ( image_height < 0 )
return false ;
2013-07-29 15:40:56 +04:00
if ( aspect . numerator = = 0 | | aspect . denominator = = 0 ) {
aspect . numerator = 16 ;
aspect . denominator = 9 ;
}
image_width = ( ( image_height * aspect . numerator ) / aspect . denominator ) ;
2014-01-23 13:40:00 +04:00
image_width = ( image_width + GTF_CELL_GRAN / 2 ) & ~ ( GTF_CELL_GRAN - 1 ) ;
2013-07-29 15:40:56 +04:00
/* Horizontal */
2015-05-05 16:16:27 +03:00
if ( default_gtf ) {
u64 num ;
u32 den ;
num = ( ( image_width * GTF_D_C_PRIME * ( u64 ) hfreq ) -
( ( u64 ) image_width * GTF_D_M_PRIME * 1000 ) ) ;
2015-06-05 11:13:31 +03:00
den = ( hfreq * ( 100 - GTF_D_C_PRIME ) + GTF_D_M_PRIME * 1000 ) *
( 2 * GTF_CELL_GRAN ) ;
2015-05-05 16:16:27 +03:00
h_blank = div_u64 ( ( num + ( den > > 1 ) ) , den ) ;
2015-06-05 11:13:31 +03:00
h_blank * = ( 2 * GTF_CELL_GRAN ) ;
2015-05-05 16:16:27 +03:00
} else {
u64 num ;
u32 den ;
num = ( ( image_width * GTF_S_C_PRIME * ( u64 ) hfreq ) -
( ( u64 ) image_width * GTF_S_M_PRIME * 1000 ) ) ;
2015-06-05 11:13:31 +03:00
den = ( hfreq * ( 100 - GTF_S_C_PRIME ) + GTF_S_M_PRIME * 1000 ) *
( 2 * GTF_CELL_GRAN ) ;
2015-05-05 16:16:27 +03:00
h_blank = div_u64 ( ( num + ( den > > 1 ) ) , den ) ;
2015-06-05 11:13:31 +03:00
h_blank * = ( 2 * GTF_CELL_GRAN ) ;
2015-05-05 16:16:27 +03:00
}
2013-07-29 15:40:56 +04:00
frame_width = image_width + h_blank ;
pix_clk = ( image_width + h_blank ) * hfreq ;
pix_clk = pix_clk / GTF_PXL_CLK_GRAN * GTF_PXL_CLK_GRAN ;
hsync = ( frame_width * 8 + 50 ) / 100 ;
2015-04-22 20:32:35 +03:00
hsync = ( ( hsync + GTF_CELL_GRAN / 2 ) / GTF_CELL_GRAN ) * GTF_CELL_GRAN ;
2013-07-29 15:40:56 +04:00
h_fp = h_blank / 2 - hsync ;
2013-08-19 15:38:29 +04:00
fmt - > type = V4L2_DV_BT_656_1120 ;
2013-07-29 15:40:56 +04:00
fmt - > bt . polarities = polarities ;
fmt - > bt . width = image_width ;
fmt - > bt . height = image_height ;
fmt - > bt . hfrontporch = h_fp ;
fmt - > bt . vfrontporch = v_fp ;
fmt - > bt . hsync = hsync ;
fmt - > bt . vsync = vsync ;
fmt - > bt . hbackporch = frame_width - image_width - h_fp - hsync ;
2015-05-22 08:27:34 +03:00
if ( ! interlaced ) {
fmt - > bt . vbackporch = frame_height - image_height - v_fp - vsync ;
fmt - > bt . interlaced = V4L2_DV_PROGRESSIVE ;
} else {
fmt - > bt . vbackporch = ( frame_height - image_height - 2 * v_fp -
2 * vsync ) / 2 ;
fmt - > bt . il_vbackporch = frame_height - image_height - 2 * v_fp -
2 * vsync - fmt - > bt . vbackporch ;
fmt - > bt . il_vfrontporch = v_fp ;
fmt - > bt . il_vsync = vsync ;
fmt - > bt . flags | = V4L2_DV_FL_HALF_LINE ;
fmt - > bt . interlaced = V4L2_DV_INTERLACED ;
}
2013-07-29 15:40:56 +04:00
fmt - > bt . pixelclock = pix_clk ;
fmt - > bt . standards = V4L2_DV_BT_STD_GTF ;
2015-05-22 08:27:34 +03:00
2013-07-29 15:40:56 +04:00
if ( ! default_gtf )
fmt - > bt . flags | = V4L2_DV_FL_REDUCED_BLANKING ;
2015-05-22 08:27:34 +03:00
2013-07-29 15:40:56 +04:00
return true ;
}
EXPORT_SYMBOL_GPL ( v4l2_detect_gtf ) ;
/** v4l2_calc_aspect_ratio - calculate the aspect ratio based on bytes
* 0x15 and 0x16 from the EDID .
* @ hor_landscape - byte 0x15 from the EDID .
* @ vert_portrait - byte 0x16 from the EDID .
*
* Determines the aspect ratio from the EDID .
* See VESA Enhanced EDID standard , release A , rev 2 , section 3.6 .2 :
* " Horizontal and Vertical Screen Size or Aspect Ratio "
*/
struct v4l2_fract v4l2_calc_aspect_ratio ( u8 hor_landscape , u8 vert_portrait )
{
struct v4l2_fract aspect = { 16 , 9 } ;
u8 ratio ;
/* Nothing filled in, fallback to 16:9 */
if ( ! hor_landscape & & ! vert_portrait )
return aspect ;
/* Both filled in, so they are interpreted as the screen size in cm */
if ( hor_landscape & & vert_portrait ) {
aspect . numerator = hor_landscape ;
aspect . denominator = vert_portrait ;
return aspect ;
}
/* Only one is filled in, so interpret them as a ratio:
( val + 99 ) / 100 */
ratio = hor_landscape | vert_portrait ;
/* Change some rounded values into the exact aspect ratio */
if ( ratio = = 79 ) {
aspect . numerator = 16 ;
aspect . denominator = 9 ;
} else if ( ratio = = 34 ) {
aspect . numerator = 4 ;
2014-06-14 15:37:09 +04:00
aspect . denominator = 3 ;
2013-07-29 15:40:56 +04:00
} else if ( ratio = = 68 ) {
aspect . numerator = 15 ;
2014-06-14 15:37:09 +04:00
aspect . denominator = 9 ;
2013-07-29 15:40:56 +04:00
} else {
aspect . numerator = hor_landscape + 99 ;
aspect . denominator = 100 ;
}
if ( hor_landscape )
return aspect ;
/* The aspect ratio is for portrait, so swap numerator and denominator */
2015-06-10 19:32:33 +03:00
swap ( aspect . denominator , aspect . numerator ) ;
2013-07-29 15:40:56 +04:00
return aspect ;
}
EXPORT_SYMBOL_GPL ( v4l2_calc_aspect_ratio ) ;
2018-02-15 20:55:29 +03:00
/** v4l2_hdmi_rx_colorimetry - determine HDMI colorimetry information
* based on various InfoFrames .
* @ avi : the AVI InfoFrame
* @ hdmi : the HDMI Vendor InfoFrame , may be NULL
* @ height : the frame height
*
* Determines the HDMI colorimetry information , i . e . how the HDMI
* pixel color data should be interpreted .
*
* Note that some of the newer features ( DCI - P3 , HDR ) are not yet
* implemented : the hdmi . h header needs to be updated to the HDMI 2.0
* and CTA - 861 - G standards .
*/
struct v4l2_hdmi_colorimetry
v4l2_hdmi_rx_colorimetry ( const struct hdmi_avi_infoframe * avi ,
const struct hdmi_vendor_infoframe * hdmi ,
unsigned int height )
{
struct v4l2_hdmi_colorimetry c = {
V4L2_COLORSPACE_SRGB ,
V4L2_YCBCR_ENC_DEFAULT ,
V4L2_QUANTIZATION_FULL_RANGE ,
V4L2_XFER_FUNC_SRGB
} ;
bool is_ce = avi - > video_code | | ( hdmi & & hdmi - > vic ) ;
bool is_sdtv = height < = 576 ;
bool default_is_lim_range_rgb = avi - > video_code > 1 ;
switch ( avi - > colorspace ) {
case HDMI_COLORSPACE_RGB :
/* RGB pixel encoding */
switch ( avi - > colorimetry ) {
case HDMI_COLORIMETRY_EXTENDED :
switch ( avi - > extended_colorimetry ) {
2018-09-13 14:47:29 +03:00
case HDMI_EXTENDED_COLORIMETRY_OPRGB :
2018-09-14 11:58:03 +03:00
c . colorspace = V4L2_COLORSPACE_OPRGB ;
c . xfer_func = V4L2_XFER_FUNC_OPRGB ;
2018-02-15 20:55:29 +03:00
break ;
case HDMI_EXTENDED_COLORIMETRY_BT2020 :
c . colorspace = V4L2_COLORSPACE_BT2020 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
default :
break ;
}
break ;
default :
break ;
}
switch ( avi - > quantization_range ) {
case HDMI_QUANTIZATION_RANGE_LIMITED :
c . quantization = V4L2_QUANTIZATION_LIM_RANGE ;
break ;
case HDMI_QUANTIZATION_RANGE_FULL :
break ;
default :
if ( default_is_lim_range_rgb )
c . quantization = V4L2_QUANTIZATION_LIM_RANGE ;
break ;
}
break ;
default :
/* YCbCr pixel encoding */
c . quantization = V4L2_QUANTIZATION_LIM_RANGE ;
switch ( avi - > colorimetry ) {
case HDMI_COLORIMETRY_NONE :
if ( ! is_ce )
break ;
if ( is_sdtv ) {
c . colorspace = V4L2_COLORSPACE_SMPTE170M ;
c . ycbcr_enc = V4L2_YCBCR_ENC_601 ;
} else {
c . colorspace = V4L2_COLORSPACE_REC709 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_709 ;
}
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
case HDMI_COLORIMETRY_ITU_601 :
c . colorspace = V4L2_COLORSPACE_SMPTE170M ;
c . ycbcr_enc = V4L2_YCBCR_ENC_601 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
case HDMI_COLORIMETRY_ITU_709 :
c . colorspace = V4L2_COLORSPACE_REC709 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_709 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
case HDMI_COLORIMETRY_EXTENDED :
switch ( avi - > extended_colorimetry ) {
case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 :
c . colorspace = V4L2_COLORSPACE_REC709 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_XV709 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709 :
c . colorspace = V4L2_COLORSPACE_REC709 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_XV601 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
case HDMI_EXTENDED_COLORIMETRY_S_YCC_601 :
c . colorspace = V4L2_COLORSPACE_SRGB ;
c . ycbcr_enc = V4L2_YCBCR_ENC_601 ;
c . xfer_func = V4L2_XFER_FUNC_SRGB ;
break ;
2018-09-13 14:47:29 +03:00
case HDMI_EXTENDED_COLORIMETRY_OPYCC_601 :
2018-09-14 11:58:03 +03:00
c . colorspace = V4L2_COLORSPACE_OPRGB ;
2018-02-15 20:55:29 +03:00
c . ycbcr_enc = V4L2_YCBCR_ENC_601 ;
2018-09-14 11:58:03 +03:00
c . xfer_func = V4L2_XFER_FUNC_OPRGB ;
2018-02-15 20:55:29 +03:00
break ;
case HDMI_EXTENDED_COLORIMETRY_BT2020 :
c . colorspace = V4L2_COLORSPACE_BT2020 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_BT2020 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM :
c . colorspace = V4L2_COLORSPACE_BT2020 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_BT2020_CONST_LUM ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
default : /* fall back to ITU_709 */
c . colorspace = V4L2_COLORSPACE_REC709 ;
c . ycbcr_enc = V4L2_YCBCR_ENC_709 ;
c . xfer_func = V4L2_XFER_FUNC_709 ;
break ;
}
break ;
default :
break ;
}
/*
* YCC Quantization Range signaling is more - or - less broken ,
* let ' s just ignore this .
*/
break ;
}
return c ;
}
EXPORT_SYMBOL_GPL ( v4l2_hdmi_rx_colorimetry ) ;
2018-09-13 10:40:56 +03:00
/**
* v4l2_get_edid_phys_addr ( ) - find and return the physical address
*
* @ edid : pointer to the EDID data
* @ size : size in bytes of the EDID data
* @ offset : If not % NULL then the location of the physical address
* bytes in the EDID will be returned here . This is set to 0
* if there is no physical address found .
*
* Return : the physical address or CEC_PHYS_ADDR_INVALID if there is none .
*/
u16 v4l2_get_edid_phys_addr ( const u8 * edid , unsigned int size ,
unsigned int * offset )
{
unsigned int loc = cec_get_edid_spa_location ( edid , size ) ;
if ( offset )
* offset = loc ;
if ( loc = = 0 )
return CEC_PHYS_ADDR_INVALID ;
return ( edid [ loc ] < < 8 ) | edid [ loc + 1 ] ;
}
EXPORT_SYMBOL_GPL ( v4l2_get_edid_phys_addr ) ;
/**
* v4l2_set_edid_phys_addr ( ) - find and set the physical address
*
* @ edid : pointer to the EDID data
* @ size : size in bytes of the EDID data
* @ phys_addr : the new physical address
*
* This function finds the location of the physical address in the EDID
* and fills in the given physical address and updates the checksum
* at the end of the EDID block . It does nothing if the EDID doesn ' t
* contain a physical address .
*/
void v4l2_set_edid_phys_addr ( u8 * edid , unsigned int size , u16 phys_addr )
{
unsigned int loc = cec_get_edid_spa_location ( edid , size ) ;
u8 sum = 0 ;
unsigned int i ;
if ( loc = = 0 )
return ;
edid [ loc ] = phys_addr > > 8 ;
edid [ loc + 1 ] = phys_addr & 0xff ;
loc & = ~ 0x7f ;
/* update the checksum */
for ( i = loc ; i < loc + 127 ; i + + )
sum + = edid [ i ] ;
edid [ i ] = 256 - sum ;
}
EXPORT_SYMBOL_GPL ( v4l2_set_edid_phys_addr ) ;
/**
* v4l2_phys_addr_for_input ( ) - calculate the PA for an input
*
* @ phys_addr : the physical address of the parent
* @ input : the number of the input port , must be between 1 and 15
*
* This function calculates a new physical address based on the input
* port number . For example :
*
* PA = 0.0 .0 .0 and input = 2 becomes 2.0 .0 .0
*
* PA = 3.0 .0 .0 and input = 1 becomes 3.1 .0 .0
*
* PA = 3.2 .1 .0 and input = 5 becomes 3.2 .1 .5
*
* PA = 3.2 .1 .3 and input = 5 becomes f . f . f . f since it maxed out the depth .
*
* Return : the new physical address or CEC_PHYS_ADDR_INVALID .
*/
u16 v4l2_phys_addr_for_input ( u16 phys_addr , u8 input )
{
/* Check if input is sane */
if ( WARN_ON ( input = = 0 | | input > 0xf ) )
return CEC_PHYS_ADDR_INVALID ;
if ( phys_addr = = 0 )
return input < < 12 ;
if ( ( phys_addr & 0x0fff ) = = 0 )
return phys_addr | ( input < < 8 ) ;
if ( ( phys_addr & 0x00ff ) = = 0 )
return phys_addr | ( input < < 4 ) ;
if ( ( phys_addr & 0x000f ) = = 0 )
return phys_addr | input ;
/*
* All nibbles are used so no valid physical addresses can be assigned
* to the input .
*/
return CEC_PHYS_ADDR_INVALID ;
}
EXPORT_SYMBOL_GPL ( v4l2_phys_addr_for_input ) ;
/**
* v4l2_phys_addr_validate ( ) - validate a physical address from an EDID
*
* @ phys_addr : the physical address to validate
* @ parent : if not % NULL , then this is filled with the parents PA .
* @ port : if not % NULL , then this is filled with the input port .
*
* This validates a physical address as read from an EDID . If the
* PA is invalid ( such as 1.0 .1 .0 since ' 0 ' is only allowed at the end ) ,
* then it will return - EINVAL .
*
* The parent PA is passed into % parent and the input port is passed into
* % port . For example :
*
* PA = 0.0 .0 .0 : has parent 0.0 .0 .0 and input port 0.
*
* PA = 1.0 .0 .0 : has parent 0.0 .0 .0 and input port 1.
*
* PA = 3.2 .0 .0 : has parent 3.0 .0 .0 and input port 2.
*
* PA = f . f . f . f : has parent f . f . f . f and input port 0.
*
* Return : 0 if the PA is valid , - EINVAL if not .
*/
int v4l2_phys_addr_validate ( u16 phys_addr , u16 * parent , u16 * port )
{
int i ;
if ( parent )
* parent = phys_addr ;
if ( port )
* port = 0 ;
if ( phys_addr = = CEC_PHYS_ADDR_INVALID )
return 0 ;
for ( i = 0 ; i < 16 ; i + = 4 )
if ( phys_addr & ( 0xf < < i ) )
break ;
if ( i = = 16 )
return 0 ;
if ( parent )
* parent = phys_addr & ( 0xfff0 < < i ) ;
if ( port )
* port = ( phys_addr > > i ) & 0xf ;
for ( i + = 4 ; i < 16 ; i + = 4 )
if ( ( phys_addr & ( 0xf < < i ) ) = = 0 )
return - EINVAL ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_phys_addr_validate ) ;