2008-11-07 14:05:41 -08:00
/*
* Copyright ( c ) 2006 Luc Verhaegen ( quirks list )
* Copyright ( c ) 2007 - 2008 Intel Corporation
* Jesse Barnes < jesse . barnes @ intel . com >
2010-03-29 21:43:18 +00:00
* Copyright 2010 Red Hat , Inc .
2008-11-07 14:05:41 -08:00
*
* DDC probing routines ( drm_ddc_read & drm_do_probe_ddc_edid ) originally from
* FB layer .
* Copyright ( C ) 2006 Dennis Munsie < dmunsie @ cecropia . com >
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sub license ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial portions
* of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NON - INFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
*/
2019-05-06 12:52:48 +03:00
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
# include <linux/bitfield.h>
2012-11-21 15:31:35 +01:00
# include <linux/hdmi.h>
2008-11-07 14:05:41 -08:00
# include <linux/i2c.h>
2019-05-06 12:52:48 +03:00
# include <linux/kernel.h>
2012-05-30 16:42:39 -04:00
# include <linux/module.h>
2021-01-18 14:14:15 +01:00
# include <linux/pci.h>
2019-05-06 12:52:48 +03:00
# include <linux/slab.h>
drm/edid: Switch DDC when reading the EDID
Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
Some dual graphics machines support muxing the DDC separately from
the display, so make use of this functionality when reading the EDID
on the inactive GPU. Also serialize drm_get_edid() with a mutex to
avoid races on the DDC mux state.
Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
I can't figure out why I didn't like this, but I rewrote this [...]
to lock/unlock the ddc lines [...]. I think I'd prefer something
like that otherwise the interface got really ugly.
Modified by Lukas Wunner <lukas@wunner.de>, 2015-04 - 2015-09:
v3: Move vga_switcheroo calls to a wrapper around drm_get_edid()
which drivers can call on muxed machines. This avoids other
drivers having to go through the vga_switcheroo motions even
though they are never used on a muxed platform
(Thierry Reding, Daniel Vetter, Alex Deucher)
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina 15"]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina 15"]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina 15"]
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Dave Airlie <airlied@gmail.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/b898d0da4c134f2642d0122479006863e1830723.1452525860.git.lukas@wunner.de
2016-01-11 20:09:20 +01:00
# include <linux/vga_switcheroo.h>
2019-05-06 12:52:48 +03:00
# include <drm/drm_displayid.h>
# include <drm/drm_drv.h>
2012-10-02 18:01:07 +01:00
# include <drm/drm_edid.h>
2016-11-28 20:51:09 +02:00
# include <drm/drm_encoder.h>
2019-05-06 12:52:48 +03:00
# include <drm/drm_print.h>
2008-11-07 14:05:41 -08:00
2017-01-17 17:43:29 +01:00
# include "drm_crtc_internal.h"
2021-08-31 17:17:32 +03:00
static int oui ( u8 first , u8 second , u8 third )
{
return ( first < < 16 ) | ( second < < 8 ) | third ;
}
2010-03-29 21:43:26 +00:00
# define EDID_EST_TIMINGS 16
# define EDID_STD_TIMINGS 8
# define EDID_DETAILED_TIMINGS 4
2008-11-07 14:05:41 -08:00
/*
* EDID blocks out in the wild have a variety of bugs , try to collect
* them here ( note that userspace may work around broken monitors first ,
* but fixes should make their way here so that the kernel " just works "
* on as many displays as possible ) .
*/
/* First detailed mode wrong, use largest 60Hz mode */
# define EDID_QUIRK_PREFER_LARGE_60 (1 << 0)
/* Reported 135MHz pixel clock is too high, needs adjustment */
# define EDID_QUIRK_135_CLOCK_TOO_HIGH (1 << 1)
/* Prefer the largest mode at 75 Hz */
# define EDID_QUIRK_PREFER_LARGE_75 (1 << 2)
/* Detail timing is in cm not mm */
# define EDID_QUIRK_DETAILED_IN_CM (1 << 3)
/* Detailed timing descriptors have bogus size values, so just take the
* maximum size and use that .
*/
# define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE (1 << 4)
/* use +hsync +vsync for detailed mode */
# define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
2012-05-23 16:26:54 -04:00
/* Force reduced-blanking timings for detailed modes */
# define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7)
2013-12-07 13:22:42 +01:00
/* Force 8bpc */
# define EDID_QUIRK_FORCE_8BPC (1 << 8)
2014-05-23 21:40:55 +02:00
/* Force 12bpc */
# define EDID_QUIRK_FORCE_12BPC (1 << 9)
2016-07-06 12:05:44 +02:00
/* Force 6bpc */
# define EDID_QUIRK_FORCE_6BPC (1 << 10)
2017-04-21 17:05:08 +02:00
/* Force 10bpc */
# define EDID_QUIRK_FORCE_10BPC (1 << 11)
2017-10-16 05:08:09 +01:00
/* Non desktop display (i.e. HMD) */
# define EDID_QUIRK_NON_DESKTOP (1 << 12)
2010-02-05 04:21:19 -05:00
2022-01-23 11:16:52 +01:00
# define MICROSOFT_IEEE_OUI 0xca125c
2010-08-03 14:38:19 -04:00
struct detailed_mode_closure {
struct drm_connector * connector ;
2022-05-09 15:03:07 +03:00
const struct drm_edid * drm_edid ;
2010-08-03 14:38:19 -04:00
bool preferred ;
u32 quirks ;
int modes ;
} ;
2008-11-07 14:05:41 -08:00
2009-06-22 13:17:10 +08:00
# define LEVEL_DMT 0
# define LEVEL_GTF 1
2010-03-29 21:43:30 +00:00
# define LEVEL_GTF2 2
# define LEVEL_CVT 3
2009-06-22 13:17:10 +08:00
2021-09-24 07:53:21 -07:00
# define EDID_QUIRK(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _quirks) \
2021-09-14 13:21:51 -07:00
{ \
2021-09-24 07:53:21 -07:00
. panel_id = drm_edid_encode_panel_id ( vend_chr_0 , vend_chr_1 , vend_chr_2 , \
product_id ) , \
2021-09-14 13:21:51 -07:00
. quirks = _quirks \
}
2016-12-28 13:06:26 +02:00
static const struct edid_quirk {
2021-09-14 13:21:51 -07:00
u32 panel_id ;
2008-11-07 14:05:41 -08:00
u32 quirks ;
} edid_quirk_list [ ] = {
/* Acer AL1706 */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' A ' , ' C ' , ' R ' , 44358 , EDID_QUIRK_PREFER_LARGE_60 ) ,
2008-11-07 14:05:41 -08:00
/* Acer F51 */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' A ' , ' P ' , ' I ' , 0x7602 , EDID_QUIRK_PREFER_LARGE_60 ) ,
2008-11-07 14:05:41 -08:00
2016-07-06 12:05:44 +02:00
/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' A ' , ' E ' , ' O ' , 0 , EDID_QUIRK_FORCE_6BPC ) ,
2016-07-06 12:05:44 +02:00
2018-10-02 23:29:11 +08:00
/* BOE model on HP Pavilion 15-n233sl reports 8 bpc, but is a 6 bpc panel */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' B ' , ' O ' , ' E ' , 0x78b , EDID_QUIRK_FORCE_6BPC ) ,
2018-10-02 23:29:11 +08:00
2018-02-18 16:53:59 +08:00
/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' C ' , ' P ' , ' T ' , 0x17df , EDID_QUIRK_FORCE_6BPC ) ,
2018-02-18 16:53:59 +08:00
2018-08-23 05:53:32 +00:00
/* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' D ' , ' C ' , 0x3652 , EDID_QUIRK_FORCE_6BPC ) ,
2018-08-23 05:53:32 +00:00
2018-10-28 22:49:33 -07:00
/* BOE model 0x0771 reports 8 bpc, but is a 6 bpc panel */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' B ' , ' O ' , ' E ' , 0x0771 , EDID_QUIRK_FORCE_6BPC ) ,
2018-10-28 22:49:33 -07:00
2008-11-07 14:05:41 -08:00
/* Belinea 10 15 55 */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' M ' , ' A ' , ' X ' , 1516 , EDID_QUIRK_PREFER_LARGE_60 ) ,
EDID_QUIRK ( ' M ' , ' A ' , ' X ' , 0x77e , EDID_QUIRK_PREFER_LARGE_60 ) ,
2008-11-07 14:05:41 -08:00
/* Envision Peripherals, Inc. EN-7100e */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' E ' , ' P ' , ' I ' , 59264 , EDID_QUIRK_135_CLOCK_TOO_HIGH ) ,
2010-04-06 16:11:00 +00:00
/* Envision EN2028 */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' E ' , ' P ' , ' I ' , 8232 , EDID_QUIRK_PREFER_LARGE_60 ) ,
2008-11-07 14:05:41 -08:00
/* Funai Electronics PM36B */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' F ' , ' C ' , ' M ' , 13600 , EDID_QUIRK_PREFER_LARGE_75 |
2021-09-14 13:21:51 -07:00
EDID_QUIRK_DETAILED_IN_CM ) ,
2008-11-07 14:05:41 -08:00
2017-04-21 17:05:08 +02:00
/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' L ' , ' G ' , ' D ' , 764 , EDID_QUIRK_FORCE_10BPC ) ,
2017-04-21 17:05:08 +02:00
2008-11-07 14:05:41 -08:00
/* LG Philips LCD LP154W01-A5 */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' L ' , ' P ' , ' L ' , 0 , EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE ) ,
EDID_QUIRK ( ' L ' , ' P ' , ' L ' , 0x2a00 , EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE ) ,
2008-11-07 14:05:41 -08:00
/* Samsung SyncMaster 205BW. Note: irony */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' A ' , ' M ' , 541 , EDID_QUIRK_DETAILED_SYNC_PP ) ,
2008-11-07 14:05:41 -08:00
/* Samsung SyncMaster 22[5-6]BW */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' A ' , ' M ' , 596 , EDID_QUIRK_PREFER_LARGE_60 ) ,
EDID_QUIRK ( ' S ' , ' A ' , ' M ' , 638 , EDID_QUIRK_PREFER_LARGE_60 ) ,
2012-05-23 16:26:54 -04:00
2014-05-23 21:40:55 +02:00
/* Sony PVM-2541A does up to 12 bpc, but only reports max 8 bpc */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' N ' , ' Y ' , 0x2541 , EDID_QUIRK_FORCE_12BPC ) ,
2014-05-23 21:40:55 +02:00
2012-05-23 16:26:54 -04:00
/* ViewSonic VA2026w */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' V ' , ' S ' , ' C ' , 5020 , EDID_QUIRK_FORCE_REDUCED_BLANKING ) ,
2013-08-12 11:04:29 -04:00
/* Medion MD 30217 PG */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' M ' , ' E ' , ' D ' , 0x7b8 , EDID_QUIRK_PREFER_LARGE_75 ) ,
2013-12-07 13:22:42 +01:00
2019-04-02 11:30:37 +08:00
/* Lenovo G50 */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' D ' , ' C ' , 18514 , EDID_QUIRK_FORCE_6BPC ) ,
2019-04-02 11:30:37 +08:00
2013-12-07 13:22:42 +01:00
/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' E ' , ' C ' , 0xd033 , EDID_QUIRK_FORCE_8BPC ) ,
2017-02-20 16:25:45 +01:00
/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' E ' , ' T ' , ' R ' , 13896 , EDID_QUIRK_FORCE_8BPC ) ,
2017-10-16 05:26:19 +01:00
2019-05-02 15:31:57 -04:00
/* Valve Index Headset */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91a8 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b0 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b1 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b2 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b3 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b4 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b5 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b6 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b7 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b8 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91b9 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91ba , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91bb , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91bc , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91bd , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91be , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' V ' , ' L ' , ' V ' , 0x91bf , EDID_QUIRK_NON_DESKTOP ) ,
2019-05-02 15:31:57 -04:00
2018-05-29 13:52:15 +02:00
/* HTC Vive and Vive Pro VR Headsets */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' H ' , ' V ' , ' R ' , 0xaa01 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' H ' , ' V ' , ' R ' , 0xaa02 , EDID_QUIRK_NON_DESKTOP ) ,
2018-02-19 18:59:36 +01:00
2020-05-08 04:06:28 +10:00
/* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' O ' , ' V ' , ' R ' , 0x0001 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' O ' , ' V ' , ' R ' , 0x0003 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' O ' , ' V ' , ' R ' , 0x0004 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' O ' , ' V ' , ' R ' , 0x0012 , EDID_QUIRK_NON_DESKTOP ) ,
2018-02-19 18:59:37 +01:00
/* Windows Mixed Reality Headsets */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' A ' , ' C ' , ' R ' , 0x7fce , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' L ' , ' E ' , ' N ' , 0x0408 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' F ' , ' U ' , ' J ' , 0x1970 , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' D ' , ' E ' , ' L ' , 0x7fce , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' S ' , ' E ' , ' C ' , 0x144a , EDID_QUIRK_NON_DESKTOP ) ,
EDID_QUIRK ( ' A ' , ' U ' , ' S ' , 0xc102 , EDID_QUIRK_NON_DESKTOP ) ,
2018-02-19 18:59:38 +01:00
/* Sony PlayStation VR Headset */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' N ' , ' Y ' , 0x0704 , EDID_QUIRK_NON_DESKTOP ) ,
2018-12-03 10:46:44 -06:00
/* Sensics VR Headsets */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' E ' , ' N ' , 0x1019 , EDID_QUIRK_NON_DESKTOP ) ,
2018-12-03 10:46:44 -06:00
/* OSVR HDK and HDK2 VR Headsets */
2021-09-24 07:53:21 -07:00
EDID_QUIRK ( ' S ' , ' V ' , ' R ' , 0x1019 , EDID_QUIRK_NON_DESKTOP ) ,
2008-11-07 14:05:41 -08:00
} ;
2012-11-23 15:01:42 +01:00
/*
* Autogenerated from the DMT spec .
* This table is copied from xfree86 / modes / xf86EdidModes . c .
*/
static const struct drm_display_mode drm_dmt_modes [ ] = {
2015-04-02 17:02:10 +03:00
/* 0x01 - 640x350@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x350 " , DRM_MODE_TYPE_DRIVER , 31500 , 640 , 672 ,
736 , 832 , 0 , 350 , 382 , 385 , 445 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x02 - 640x400@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x400 " , DRM_MODE_TYPE_DRIVER , 31500 , 640 , 672 ,
736 , 832 , 0 , 400 , 401 , 404 , 445 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x03 - 720x400@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x400 " , DRM_MODE_TYPE_DRIVER , 35500 , 720 , 756 ,
828 , 936 , 0 , 400 , 401 , 404 , 446 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x04 - 640x480@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 25175 , 640 , 656 ,
2015-04-02 17:02:09 +03:00
752 , 800 , 0 , 480 , 490 , 492 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x05 - 640x480@72Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 31500 , 640 , 664 ,
704 , 832 , 0 , 480 , 489 , 492 , 520 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x06 - 640x480@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 31500 , 640 , 656 ,
720 , 840 , 0 , 480 , 481 , 484 , 500 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x07 - 640x480@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 36000 , 640 , 696 ,
752 , 832 , 0 , 480 , 481 , 484 , 509 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x08 - 800x600@56Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 36000 , 800 , 824 ,
896 , 1024 , 0 , 600 , 601 , 603 , 625 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x09 - 800x600@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 40000 , 800 , 840 ,
968 , 1056 , 0 , 600 , 601 , 605 , 628 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x0a - 800x600@72Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 50000 , 800 , 856 ,
976 , 1040 , 0 , 600 , 637 , 643 , 666 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x0b - 800x600@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 49500 , 800 , 816 ,
896 , 1056 , 0 , 600 , 601 , 604 , 625 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x0c - 800x600@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 56250 , 800 , 832 ,
896 , 1048 , 0 , 600 , 601 , 604 , 631 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x0d - 800x600@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 73250 , 800 , 848 ,
880 , 960 , 0 , 600 , 603 , 607 , 636 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x0e - 848x480@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 848x480 " , DRM_MODE_TYPE_DRIVER , 33750 , 848 , 864 ,
976 , 1088 , 0 , 480 , 486 , 494 , 517 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x0f - 1024x768@43Hz, interlace */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1024x768i " , DRM_MODE_TYPE_DRIVER , 44900 , 1024 , 1032 ,
2016-04-04 20:36:34 +01:00
1208 , 1264 , 0 , 768 , 768 , 776 , 817 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
2015-04-02 17:02:09 +03:00
DRM_MODE_FLAG_INTERLACE ) } ,
2015-04-02 17:02:10 +03:00
/* 0x10 - 1024x768@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 65000 , 1024 , 1048 ,
1184 , 1344 , 0 , 768 , 771 , 777 , 806 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x11 - 1024x768@70Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 75000 , 1024 , 1048 ,
1184 , 1328 , 0 , 768 , 771 , 777 , 806 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x12 - 1024x768@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 78750 , 1024 , 1040 ,
1136 , 1312 , 0 , 768 , 769 , 772 , 800 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x13 - 1024x768@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 94500 , 1024 , 1072 ,
1168 , 1376 , 0 , 768 , 769 , 772 , 808 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x14 - 1024x768@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 115500 , 1024 , 1072 ,
1104 , 1184 , 0 , 768 , 771 , 775 , 813 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x15 - 1152x864@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1152x864 " , DRM_MODE_TYPE_DRIVER , 108000 , 1152 , 1216 ,
1344 , 1600 , 0 , 864 , 865 , 868 , 900 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:11 +03:00
/* 0x55 - 1280x720@60Hz */
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 1390 ,
1430 , 1650 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x16 - 1280x768@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x768 " , DRM_MODE_TYPE_DRIVER , 68250 , 1280 , 1328 ,
1360 , 1440 , 0 , 768 , 771 , 778 , 790 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x17 - 1280x768@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x768 " , DRM_MODE_TYPE_DRIVER , 79500 , 1280 , 1344 ,
1472 , 1664 , 0 , 768 , 771 , 778 , 798 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x18 - 1280x768@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x768 " , DRM_MODE_TYPE_DRIVER , 102250 , 1280 , 1360 ,
1488 , 1696 , 0 , 768 , 771 , 778 , 805 , 0 ,
2015-04-02 17:02:09 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x19 - 1280x768@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x768 " , DRM_MODE_TYPE_DRIVER , 117500 , 1280 , 1360 ,
1496 , 1712 , 0 , 768 , 771 , 778 , 809 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x1a - 1280x768@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x768 " , DRM_MODE_TYPE_DRIVER , 140250 , 1280 , 1328 ,
1360 , 1440 , 0 , 768 , 771 , 778 , 813 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x1b - 1280x800@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x800 " , DRM_MODE_TYPE_DRIVER , 71000 , 1280 , 1328 ,
1360 , 1440 , 0 , 800 , 803 , 809 , 823 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x1c - 1280x800@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x800 " , DRM_MODE_TYPE_DRIVER , 83500 , 1280 , 1352 ,
1480 , 1680 , 0 , 800 , 803 , 809 , 831 , 0 ,
2015-04-02 17:02:09 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x1d - 1280x800@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x800 " , DRM_MODE_TYPE_DRIVER , 106500 , 1280 , 1360 ,
1488 , 1696 , 0 , 800 , 803 , 809 , 838 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x1e - 1280x800@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x800 " , DRM_MODE_TYPE_DRIVER , 122500 , 1280 , 1360 ,
1496 , 1712 , 0 , 800 , 803 , 809 , 843 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x1f - 1280x800@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x800 " , DRM_MODE_TYPE_DRIVER , 146250 , 1280 , 1328 ,
1360 , 1440 , 0 , 800 , 803 , 809 , 847 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x20 - 1280x960@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x960 " , DRM_MODE_TYPE_DRIVER , 108000 , 1280 , 1376 ,
1488 , 1800 , 0 , 960 , 961 , 964 , 1000 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x21 - 1280x960@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x960 " , DRM_MODE_TYPE_DRIVER , 148500 , 1280 , 1344 ,
1504 , 1728 , 0 , 960 , 961 , 964 , 1011 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x22 - 1280x960@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x960 " , DRM_MODE_TYPE_DRIVER , 175500 , 1280 , 1328 ,
1360 , 1440 , 0 , 960 , 963 , 967 , 1017 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x23 - 1280x1024@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x1024 " , DRM_MODE_TYPE_DRIVER , 108000 , 1280 , 1328 ,
1440 , 1688 , 0 , 1024 , 1025 , 1028 , 1066 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x24 - 1280x1024@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x1024 " , DRM_MODE_TYPE_DRIVER , 135000 , 1280 , 1296 ,
1440 , 1688 , 0 , 1024 , 1025 , 1028 , 1066 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x25 - 1280x1024@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x1024 " , DRM_MODE_TYPE_DRIVER , 157500 , 1280 , 1344 ,
1504 , 1728 , 0 , 1024 , 1025 , 1028 , 1072 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x26 - 1280x1024@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x1024 " , DRM_MODE_TYPE_DRIVER , 187250 , 1280 , 1328 ,
1360 , 1440 , 0 , 1024 , 1027 , 1034 , 1084 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x27 - 1360x768@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1360x768 " , DRM_MODE_TYPE_DRIVER , 85500 , 1360 , 1424 ,
1536 , 1792 , 0 , 768 , 771 , 777 , 795 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x28 - 1360x768@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1360x768 " , DRM_MODE_TYPE_DRIVER , 148250 , 1360 , 1408 ,
1440 , 1520 , 0 , 768 , 771 , 776 , 813 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:11 +03:00
/* 0x51 - 1366x768@60Hz */
{ DRM_MODE ( " 1366x768 " , DRM_MODE_TYPE_DRIVER , 85500 , 1366 , 1436 ,
1579 , 1792 , 0 , 768 , 771 , 774 , 798 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 0x56 - 1366x768@60Hz */
{ DRM_MODE ( " 1366x768 " , DRM_MODE_TYPE_DRIVER , 72000 , 1366 , 1380 ,
1436 , 1500 , 0 , 768 , 769 , 772 , 800 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x29 - 1400x1050@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1400x1050 " , DRM_MODE_TYPE_DRIVER , 101000 , 1400 , 1448 ,
1480 , 1560 , 0 , 1050 , 1053 , 1057 , 1080 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x2a - 1400x1050@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1400x1050 " , DRM_MODE_TYPE_DRIVER , 121750 , 1400 , 1488 ,
1632 , 1864 , 0 , 1050 , 1053 , 1057 , 1089 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x2b - 1400x1050@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1400x1050 " , DRM_MODE_TYPE_DRIVER , 156000 , 1400 , 1504 ,
1648 , 1896 , 0 , 1050 , 1053 , 1057 , 1099 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x2c - 1400x1050@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1400x1050 " , DRM_MODE_TYPE_DRIVER , 179500 , 1400 , 1504 ,
1656 , 1912 , 0 , 1050 , 1053 , 1057 , 1105 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x2d - 1400x1050@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1400x1050 " , DRM_MODE_TYPE_DRIVER , 208000 , 1400 , 1448 ,
1480 , 1560 , 0 , 1050 , 1053 , 1057 , 1112 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x2e - 1440x900@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x900 " , DRM_MODE_TYPE_DRIVER , 88750 , 1440 , 1488 ,
1520 , 1600 , 0 , 900 , 903 , 909 , 926 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x2f - 1440x900@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x900 " , DRM_MODE_TYPE_DRIVER , 106500 , 1440 , 1520 ,
1672 , 1904 , 0 , 900 , 903 , 909 , 934 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x30 - 1440x900@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x900 " , DRM_MODE_TYPE_DRIVER , 136750 , 1440 , 1536 ,
1688 , 1936 , 0 , 900 , 903 , 909 , 942 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x31 - 1440x900@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x900 " , DRM_MODE_TYPE_DRIVER , 157000 , 1440 , 1544 ,
1696 , 1952 , 0 , 900 , 903 , 909 , 948 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x32 - 1440x900@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x900 " , DRM_MODE_TYPE_DRIVER , 182750 , 1440 , 1488 ,
1520 , 1600 , 0 , 900 , 903 , 909 , 953 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:11 +03:00
/* 0x53 - 1600x900@60Hz */
{ DRM_MODE ( " 1600x900 " , DRM_MODE_TYPE_DRIVER , 108000 , 1600 , 1624 ,
1704 , 1800 , 0 , 900 , 901 , 904 , 1000 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x33 - 1600x1200@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 162000 , 1600 , 1664 ,
1856 , 2160 , 0 , 1200 , 1201 , 1204 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x34 - 1600x1200@65Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 175500 , 1600 , 1664 ,
1856 , 2160 , 0 , 1200 , 1201 , 1204 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x35 - 1600x1200@70Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 189000 , 1600 , 1664 ,
1856 , 2160 , 0 , 1200 , 1201 , 1204 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x36 - 1600x1200@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 202500 , 1600 , 1664 ,
1856 , 2160 , 0 , 1200 , 1201 , 1204 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x37 - 1600x1200@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 229500 , 1600 , 1664 ,
1856 , 2160 , 0 , 1200 , 1201 , 1204 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x38 - 1600x1200@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 268250 , 1600 , 1648 ,
1680 , 1760 , 0 , 1200 , 1203 , 1207 , 1271 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x39 - 1680x1050@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1680x1050 " , DRM_MODE_TYPE_DRIVER , 119000 , 1680 , 1728 ,
1760 , 1840 , 0 , 1050 , 1053 , 1059 , 1080 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x3a - 1680x1050@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1680x1050 " , DRM_MODE_TYPE_DRIVER , 146250 , 1680 , 1784 ,
1960 , 2240 , 0 , 1050 , 1053 , 1059 , 1089 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x3b - 1680x1050@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1680x1050 " , DRM_MODE_TYPE_DRIVER , 187000 , 1680 , 1800 ,
1976 , 2272 , 0 , 1050 , 1053 , 1059 , 1099 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x3c - 1680x1050@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1680x1050 " , DRM_MODE_TYPE_DRIVER , 214750 , 1680 , 1808 ,
1984 , 2288 , 0 , 1050 , 1053 , 1059 , 1105 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x3d - 1680x1050@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1680x1050 " , DRM_MODE_TYPE_DRIVER , 245500 , 1680 , 1728 ,
1760 , 1840 , 0 , 1050 , 1053 , 1059 , 1112 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x3e - 1792x1344@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1792x1344 " , DRM_MODE_TYPE_DRIVER , 204750 , 1792 , 1920 ,
2120 , 2448 , 0 , 1344 , 1345 , 1348 , 1394 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x3f - 1792x1344@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1792x1344 " , DRM_MODE_TYPE_DRIVER , 261000 , 1792 , 1888 ,
2104 , 2456 , 0 , 1344 , 1345 , 1348 , 1417 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x40 - 1792x1344@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1792x1344 " , DRM_MODE_TYPE_DRIVER , 333250 , 1792 , 1840 ,
1872 , 1952 , 0 , 1344 , 1347 , 1351 , 1423 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x41 - 1856x1392@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1856x1392 " , DRM_MODE_TYPE_DRIVER , 218250 , 1856 , 1952 ,
2176 , 2528 , 0 , 1392 , 1393 , 1396 , 1439 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x42 - 1856x1392@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1856x1392 " , DRM_MODE_TYPE_DRIVER , 288000 , 1856 , 1984 ,
2015-04-02 17:02:09 +03:00
2208 , 2560 , 0 , 1392 , 1393 , 1396 , 1500 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x43 - 1856x1392@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1856x1392 " , DRM_MODE_TYPE_DRIVER , 356500 , 1856 , 1904 ,
1936 , 2016 , 0 , 1392 , 1395 , 1399 , 1474 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:11 +03:00
/* 0x52 - 1920x1080@60Hz */
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x44 - 1920x1200@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1200 " , DRM_MODE_TYPE_DRIVER , 154000 , 1920 , 1968 ,
2000 , 2080 , 0 , 1200 , 1203 , 1209 , 1235 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x45 - 1920x1200@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1200 " , DRM_MODE_TYPE_DRIVER , 193250 , 1920 , 2056 ,
2256 , 2592 , 0 , 1200 , 1203 , 1209 , 1245 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x46 - 1920x1200@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1200 " , DRM_MODE_TYPE_DRIVER , 245250 , 1920 , 2056 ,
2264 , 2608 , 0 , 1200 , 1203 , 1209 , 1255 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x47 - 1920x1200@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1200 " , DRM_MODE_TYPE_DRIVER , 281250 , 1920 , 2064 ,
2272 , 2624 , 0 , 1200 , 1203 , 1209 , 1262 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x48 - 1920x1200@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1200 " , DRM_MODE_TYPE_DRIVER , 317000 , 1920 , 1968 ,
2000 , 2080 , 0 , 1200 , 1203 , 1209 , 1271 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x49 - 1920x1440@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1440 " , DRM_MODE_TYPE_DRIVER , 234000 , 1920 , 2048 ,
2256 , 2600 , 0 , 1440 , 1441 , 1444 , 1500 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x4a - 1920x1440@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1440 " , DRM_MODE_TYPE_DRIVER , 297000 , 1920 , 2064 ,
2288 , 2640 , 0 , 1440 , 1441 , 1444 , 1500 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x4b - 1920x1440@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1440 " , DRM_MODE_TYPE_DRIVER , 380500 , 1920 , 1968 ,
2000 , 2080 , 0 , 1440 , 1443 , 1447 , 1525 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:11 +03:00
/* 0x54 - 2048x1152@60Hz */
{ DRM_MODE ( " 2048x1152 " , DRM_MODE_TYPE_DRIVER , 162000 , 2048 , 2074 ,
2154 , 2250 , 0 , 1152 , 1153 , 1156 , 1200 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x4c - 2560x1600@60Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2560x1600 " , DRM_MODE_TYPE_DRIVER , 268500 , 2560 , 2608 ,
2640 , 2720 , 0 , 1600 , 1603 , 1609 , 1646 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x4d - 2560x1600@60Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2560x1600 " , DRM_MODE_TYPE_DRIVER , 348500 , 2560 , 2752 ,
3032 , 3504 , 0 , 1600 , 1603 , 1609 , 1658 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x4e - 2560x1600@75Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2560x1600 " , DRM_MODE_TYPE_DRIVER , 443250 , 2560 , 2768 ,
3048 , 3536 , 0 , 1600 , 1603 , 1609 , 1672 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x4f - 2560x1600@85Hz */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2560x1600 " , DRM_MODE_TYPE_DRIVER , 505250 , 2560 , 2768 ,
3048 , 3536 , 0 , 1600 , 1603 , 1609 , 1682 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
2015-04-02 17:02:10 +03:00
/* 0x50 - 2560x1600@120Hz RB */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2560x1600 " , DRM_MODE_TYPE_DRIVER , 552750 , 2560 , 2608 ,
2640 , 2720 , 0 , 1600 , 1603 , 1609 , 1694 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2015-04-02 17:02:11 +03:00
/* 0x57 - 4096x2160@60Hz RB */
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 556744 , 4096 , 4104 ,
4136 , 4176 , 0 , 2160 , 2208 , 2216 , 2222 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
/* 0x58 - 4096x2160@59.94Hz RB */
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 556188 , 4096 , 4104 ,
4136 , 4176 , 0 , 2160 , 2208 , 2216 , 2222 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
2012-11-23 15:01:42 +01:00
} ;
2013-10-14 16:44:27 +03:00
/*
* These more or less come from the DMT spec . The 720 x400 modes are
* inferred from historical 80 x25 practice . The 640 x480 @ 67 and 832 x624 @ 75
* modes are old - school Mac modes . The EDID spec says the 1152 x864 @ 75 mode
* should be 1152 x870 , again for the Mac , but instead we use the x864 DMT
* mode .
*
* The DMT modes have been fact - checked ; the rest are mild guesses .
*/
2012-11-23 15:01:42 +01:00
static const struct drm_display_mode edid_est_modes [ ] = {
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 40000 , 800 , 840 ,
968 , 1056 , 0 , 600 , 601 , 605 , 628 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 800x600@60Hz */
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 36000 , 800 , 824 ,
896 , 1024 , 0 , 600 , 601 , 603 , 625 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 800x600@56Hz */
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 31500 , 640 , 656 ,
720 , 840 , 0 , 480 , 481 , 484 , 500 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 640x480@75Hz */
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 31500 , 640 , 664 ,
2016-04-02 11:08:06 +01:00
704 , 832 , 0 , 480 , 489 , 492 , 520 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 640x480@72Hz */
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 30240 , 640 , 704 ,
768 , 864 , 0 , 480 , 483 , 486 , 525 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 640x480@67Hz */
2016-04-02 11:08:06 +01:00
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 25175 , 640 , 656 ,
2012-11-23 15:01:42 +01:00
752 , 800 , 0 , 480 , 490 , 492 , 525 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 640x480@60Hz */
{ DRM_MODE ( " 720x400 " , DRM_MODE_TYPE_DRIVER , 35500 , 720 , 738 ,
846 , 900 , 0 , 400 , 421 , 423 , 449 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 720x400@88Hz */
{ DRM_MODE ( " 720x400 " , DRM_MODE_TYPE_DRIVER , 28320 , 720 , 738 ,
846 , 900 , 0 , 400 , 412 , 414 , 449 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 720x400@70Hz */
{ DRM_MODE ( " 1280x1024 " , DRM_MODE_TYPE_DRIVER , 135000 , 1280 , 1296 ,
1440 , 1688 , 0 , 1024 , 1025 , 1028 , 1066 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 1280x1024@75Hz */
2016-04-02 11:08:06 +01:00
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 78750 , 1024 , 1040 ,
2012-11-23 15:01:42 +01:00
1136 , 1312 , 0 , 768 , 769 , 772 , 800 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 1024x768@75Hz */
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 75000 , 1024 , 1048 ,
1184 , 1328 , 0 , 768 , 771 , 777 , 806 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 1024x768@70Hz */
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 65000 , 1024 , 1048 ,
1184 , 1344 , 0 , 768 , 771 , 777 , 806 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 1024x768@60Hz */
{ DRM_MODE ( " 1024x768i " , DRM_MODE_TYPE_DRIVER , 44900 , 1024 , 1032 ,
1208 , 1264 , 0 , 768 , 768 , 776 , 817 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE ) } , /* 1024x768@43Hz */
{ DRM_MODE ( " 832x624 " , DRM_MODE_TYPE_DRIVER , 57284 , 832 , 864 ,
928 , 1152 , 0 , 624 , 625 , 628 , 667 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } , /* 832x624@75Hz */
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 49500 , 800 , 816 ,
896 , 1056 , 0 , 600 , 601 , 604 , 625 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 800x600@75Hz */
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 50000 , 800 , 856 ,
976 , 1040 , 0 , 600 , 637 , 643 , 666 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 800x600@72Hz */
{ DRM_MODE ( " 1152x864 " , DRM_MODE_TYPE_DRIVER , 108000 , 1152 , 1216 ,
1344 , 1600 , 0 , 864 , 865 , 868 , 900 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } , /* 1152x864@75Hz */
} ;
struct minimode {
short w ;
short h ;
short r ;
short rb ;
} ;
static const struct minimode est3_modes [ ] = {
/* byte 6 */
{ 640 , 350 , 85 , 0 } ,
{ 640 , 400 , 85 , 0 } ,
{ 720 , 400 , 85 , 0 } ,
{ 640 , 480 , 85 , 0 } ,
{ 848 , 480 , 60 , 0 } ,
{ 800 , 600 , 85 , 0 } ,
{ 1024 , 768 , 85 , 0 } ,
{ 1152 , 864 , 75 , 0 } ,
/* byte 7 */
{ 1280 , 768 , 60 , 1 } ,
{ 1280 , 768 , 60 , 0 } ,
{ 1280 , 768 , 75 , 0 } ,
{ 1280 , 768 , 85 , 0 } ,
{ 1280 , 960 , 60 , 0 } ,
{ 1280 , 960 , 85 , 0 } ,
{ 1280 , 1024 , 60 , 0 } ,
{ 1280 , 1024 , 85 , 0 } ,
/* byte 8 */
{ 1360 , 768 , 60 , 0 } ,
{ 1440 , 900 , 60 , 1 } ,
{ 1440 , 900 , 60 , 0 } ,
{ 1440 , 900 , 75 , 0 } ,
{ 1440 , 900 , 85 , 0 } ,
{ 1400 , 1050 , 60 , 1 } ,
{ 1400 , 1050 , 60 , 0 } ,
{ 1400 , 1050 , 75 , 0 } ,
/* byte 9 */
{ 1400 , 1050 , 85 , 0 } ,
{ 1680 , 1050 , 60 , 1 } ,
{ 1680 , 1050 , 60 , 0 } ,
{ 1680 , 1050 , 75 , 0 } ,
{ 1680 , 1050 , 85 , 0 } ,
{ 1600 , 1200 , 60 , 0 } ,
{ 1600 , 1200 , 65 , 0 } ,
{ 1600 , 1200 , 70 , 0 } ,
/* byte 10 */
{ 1600 , 1200 , 75 , 0 } ,
{ 1600 , 1200 , 85 , 0 } ,
{ 1792 , 1344 , 60 , 0 } ,
2013-10-14 16:44:25 +03:00
{ 1792 , 1344 , 75 , 0 } ,
2012-11-23 15:01:42 +01:00
{ 1856 , 1392 , 60 , 0 } ,
{ 1856 , 1392 , 75 , 0 } ,
{ 1920 , 1200 , 60 , 1 } ,
{ 1920 , 1200 , 60 , 0 } ,
/* byte 11 */
{ 1920 , 1200 , 75 , 0 } ,
{ 1920 , 1200 , 85 , 0 } ,
{ 1920 , 1440 , 60 , 0 } ,
{ 1920 , 1440 , 75 , 0 } ,
} ;
static const struct minimode extra_modes [ ] = {
{ 1024 , 576 , 60 , 0 } ,
{ 1366 , 768 , 60 , 0 } ,
{ 1600 , 900 , 60 , 0 } ,
{ 1680 , 945 , 60 , 0 } ,
{ 1920 , 1080 , 60 , 0 } ,
{ 2048 , 1152 , 60 , 0 } ,
{ 2048 , 1536 , 60 , 0 } ,
} ;
/*
2019-12-13 19:43:45 +02:00
* From CEA / CTA - 861 spec .
2016-01-08 13:21:51 +02:00
*
2019-12-13 19:43:45 +02:00
* Do not access directly , instead always use cea_mode_for_vic ( ) .
2012-11-23 15:01:42 +01:00
*/
2019-12-13 19:43:47 +02:00
static const struct drm_display_mode edid_cea_modes_1 [ ] = {
2018-05-24 22:20:35 +03:00
/* 1 - 640x480@60Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 25175 , 640 , 656 ,
752 , 800 , 0 , 480 , 490 , 492 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 2 - 720x480@60Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x480 " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 736 ,
798 , 858 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 3 - 720x480@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x480 " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 736 ,
798 , 858 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 4 - 1280x720@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 1390 ,
1430 , 1650 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 5 - 1920x1080i@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080i " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1094 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 6 - 720(1440)x480i@60Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x480i " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 739 ,
801 , 858 , 0 , 480 , 488 , 494 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 7 - 720(1440)x480i@60Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x480i " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 739 ,
801 , 858 , 0 , 480 , 488 , 494 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 8 - 720(1440)x240@60Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x240 " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 739 ,
801 , 858 , 0 , 240 , 244 , 247 , 262 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 9 - 720(1440)x240@60Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x240 " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 739 ,
801 , 858 , 0 , 240 , 244 , 247 , 262 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 10 - 2880x480i@60Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x480i " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2956 ,
3204 , 3432 , 0 , 480 , 488 , 494 , 525 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 11 - 2880x480i@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x480i " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2956 ,
3204 , 3432 , 0 , 480 , 488 , 494 , 525 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 12 - 2880x240@60Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x240 " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2956 ,
3204 , 3432 , 0 , 240 , 244 , 247 , 262 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 13 - 2880x240@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x240 " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2956 ,
3204 , 3432 , 0 , 240 , 244 , 247 , 262 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 14 - 1440x480@60Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x480 " , DRM_MODE_TYPE_DRIVER , 54000 , 1440 , 1472 ,
1596 , 1716 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 15 - 1440x480@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x480 " , DRM_MODE_TYPE_DRIVER , 54000 , 1440 , 1472 ,
1596 , 1716 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 16 - 1920x1080@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 17 - 720x576@50Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x576 " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 732 ,
796 , 864 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 18 - 720x576@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x576 " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 732 ,
796 , 864 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 19 - 1280x720@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 1720 ,
1760 , 1980 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 20 - 1920x1080i@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080i " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1094 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 21 - 720(1440)x576i@50Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x576i " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 732 ,
795 , 864 , 0 , 576 , 580 , 586 , 625 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 22 - 720(1440)x576i@50Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x576i " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 732 ,
795 , 864 , 0 , 576 , 580 , 586 , 625 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 23 - 720(1440)x288@50Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x288 " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 732 ,
795 , 864 , 0 , 288 , 290 , 293 , 312 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 24 - 720(1440)x288@50Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x288 " , DRM_MODE_TYPE_DRIVER , 13500 , 720 , 732 ,
795 , 864 , 0 , 288 , 290 , 293 , 312 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 25 - 2880x576i@50Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x576i " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2928 ,
3180 , 3456 , 0 , 576 , 580 , 586 , 625 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 26 - 2880x576i@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x576i " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2928 ,
3180 , 3456 , 0 , 576 , 580 , 586 , 625 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 27 - 2880x288@50Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x288 " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2928 ,
3180 , 3456 , 0 , 288 , 290 , 293 , 312 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 28 - 2880x288@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x288 " , DRM_MODE_TYPE_DRIVER , 54000 , 2880 , 2928 ,
3180 , 3456 , 0 , 288 , 290 , 293 , 312 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 29 - 1440x576@50Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x576 " , DRM_MODE_TYPE_DRIVER , 54000 , 1440 , 1464 ,
1592 , 1728 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 30 - 1440x576@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1440x576 " , DRM_MODE_TYPE_DRIVER , 54000 , 1440 , 1464 ,
1592 , 1728 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 31 - 1920x1080@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 32 - 1920x1080@24Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2558 ,
2602 , 2750 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 33 - 1920x1080@25Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 34 - 1920x1080@30Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 35 - 2880x480@60Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x480 " , DRM_MODE_TYPE_DRIVER , 108000 , 2880 , 2944 ,
3192 , 3432 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 36 - 2880x480@60Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x480 " , DRM_MODE_TYPE_DRIVER , 108000 , 2880 , 2944 ,
3192 , 3432 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 37 - 2880x576@50Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x576 " , DRM_MODE_TYPE_DRIVER , 108000 , 2880 , 2928 ,
3184 , 3456 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 38 - 2880x576@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 2880x576 " , DRM_MODE_TYPE_DRIVER , 108000 , 2880 , 2928 ,
3184 , 3456 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 39 - 1920x1080i@50Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080i " , DRM_MODE_TYPE_DRIVER , 72000 , 1920 , 1952 ,
2120 , 2304 , 0 , 1080 , 1126 , 1136 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 40 - 1920x1080i@100Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080i " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1094 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 41 - 1280x720@100Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 148500 , 1280 , 1720 ,
1760 , 1980 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 42 - 720x576@100Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x576 " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 732 ,
796 , 864 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 43 - 720x576@100Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x576 " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 732 ,
796 , 864 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 44 - 720(1440)x576i@100Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x576i " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 732 ,
795 , 864 , 0 , 576 , 580 , 586 , 625 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 45 - 720(1440)x576i@100Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x576i " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 732 ,
795 , 864 , 0 , 576 , 580 , 586 , 625 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 46 - 1920x1080i@120Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080i " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1094 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 47 - 1280x720@120Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 148500 , 1280 , 1390 ,
1430 , 1650 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 48 - 720x480@120Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x480 " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 736 ,
798 , 858 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 49 - 720x480@120Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x480 " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 736 ,
798 , 858 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 50 - 720(1440)x480i@120Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x480i " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 739 ,
801 , 858 , 0 , 480 , 488 , 494 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 51 - 720(1440)x480i@120Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x480i " , DRM_MODE_TYPE_DRIVER , 27000 , 720 , 739 ,
801 , 858 , 0 , 480 , 488 , 494 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 52 - 720x576@200Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x576 " , DRM_MODE_TYPE_DRIVER , 108000 , 720 , 732 ,
796 , 864 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 53 - 720x576@200Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x576 " , DRM_MODE_TYPE_DRIVER , 108000 , 720 , 732 ,
796 , 864 , 0 , 576 , 581 , 586 , 625 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 54 - 720(1440)x576i@200Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x576i " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 732 ,
795 , 864 , 0 , 576 , 580 , 586 , 625 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 55 - 720(1440)x576i@200Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x576i " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 732 ,
795 , 864 , 0 , 576 , 580 , 586 , 625 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 56 - 720x480@240Hz 4:3 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x480 " , DRM_MODE_TYPE_DRIVER , 108000 , 720 , 736 ,
798 , 858 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 57 - 720x480@240Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 720x480 " , DRM_MODE_TYPE_DRIVER , 108000 , 720 , 736 ,
798 , 858 , 0 , 480 , 489 , 495 , 525 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 58 - 720(1440)x480i@240Hz 4:3 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x480i " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 739 ,
801 , 858 , 0 , 480 , 488 , 494 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3 , } ,
2018-05-24 22:20:35 +03:00
/* 59 - 720(1440)x480i@240Hz 16:9 */
2014-09-02 17:03:35 -07:00
{ DRM_MODE ( " 720x480i " , DRM_MODE_TYPE_DRIVER , 54000 , 720 , 739 ,
801 , 858 , 0 , 480 , 488 , 494 , 525 , 0 ,
2012-11-23 15:01:42 +01:00
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
2018-05-24 22:20:35 +03:00
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 60 - 1280x720@24Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 59400 , 1280 , 3040 ,
3080 , 3300 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 61 - 1280x720@25Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 3700 ,
3740 , 3960 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 62 - 1280x720@30Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 3040 ,
3080 , 3300 , 0 , 720 , 725 , 730 , 750 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 63 - 1920x1080@120Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 297000 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 64 - 1920x1080@100Hz 16:9 */
2012-11-23 15:01:42 +01:00
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 297000 , 1920 , 2448 ,
2016-08-15 10:31:28 -07:00
2492 , 2640 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
2013-04-24 19:07:17 +03:00
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 65 - 1280x720@24Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 59400 , 1280 , 3040 ,
3080 , 3300 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 66 - 1280x720@25Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 3700 ,
3740 , 3960 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 67 - 1280x720@30Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 3040 ,
3080 , 3300 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 68 - 1280x720@50Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 1720 ,
1760 , 1980 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 69 - 1280x720@60Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 74250 , 1280 , 1390 ,
1430 , 1650 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 70 - 1280x720@100Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 148500 , 1280 , 1720 ,
1760 , 1980 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 71 - 1280x720@120Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 148500 , 1280 , 1390 ,
1430 , 1650 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 72 - 1920x1080@24Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2558 ,
2602 , 2750 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 73 - 1920x1080@25Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 74 - 1920x1080@30Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 74250 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 75 - 1920x1080@50Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 76 - 1920x1080@60Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 77 - 1920x1080@100Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 297000 , 1920 , 2448 ,
2492 , 2640 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 78 - 1920x1080@120Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 297000 , 1920 , 2008 ,
2052 , 2200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 79 - 1680x720@24Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 59400 , 1680 , 3040 ,
3080 , 3300 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 80 - 1680x720@25Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 59400 , 1680 , 2908 ,
2948 , 3168 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 81 - 1680x720@30Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 59400 , 1680 , 2380 ,
2420 , 2640 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 82 - 1680x720@50Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 82500 , 1680 , 1940 ,
1980 , 2200 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 83 - 1680x720@60Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 99000 , 1680 , 1940 ,
1980 , 2200 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 84 - 1680x720@100Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 165000 , 1680 , 1740 ,
1780 , 2000 , 0 , 720 , 725 , 730 , 825 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 85 - 1680x720@120Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 198000 , 1680 , 1740 ,
1780 , 2000 , 0 , 720 , 725 , 730 , 825 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 86 - 2560x1080@24Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 99000 , 2560 , 3558 ,
3602 , 3750 , 0 , 1080 , 1084 , 1089 , 1100 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 87 - 2560x1080@25Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 90000 , 2560 , 3008 ,
3052 , 3200 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 88 - 2560x1080@30Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 118800 , 2560 , 3328 ,
3372 , 3520 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 89 - 2560x1080@50Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 185625 , 2560 , 3108 ,
3152 , 3300 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 90 - 2560x1080@60Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 198000 , 2560 , 2808 ,
2852 , 3000 , 0 , 1080 , 1084 , 1089 , 1100 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 91 - 2560x1080@100Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 371250 , 2560 , 2778 ,
2822 , 2970 , 0 , 1080 , 1084 , 1089 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 92 - 2560x1080@120Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 495000 , 2560 , 3108 ,
3152 , 3300 , 0 , 1080 , 1084 , 1089 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 93 - 3840x2160@24Hz 16:9 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 3840 , 5116 ,
5204 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 94 - 3840x2160@25Hz 16:9 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 3840 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 95 - 3840x2160@30Hz 16:9 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 3840 , 4016 ,
4104 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 96 - 3840x2160@50Hz 16:9 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 3840 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 97 - 3840x2160@60Hz 16:9 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 3840 , 4016 ,
4104 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2018-05-24 22:20:35 +03:00
/* 98 - 4096x2160@24Hz 256:135 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 4096 , 5116 ,
5204 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2018-05-24 22:20:35 +03:00
/* 99 - 4096x2160@25Hz 256:135 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 4096 , 5064 ,
5152 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2018-05-24 22:20:35 +03:00
/* 100 - 4096x2160@30Hz 256:135 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 4096 , 4184 ,
4272 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2018-05-24 22:20:35 +03:00
/* 101 - 4096x2160@50Hz 256:135 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 4096 , 5064 ,
5152 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2018-05-24 22:20:35 +03:00
/* 102 - 4096x2160@60Hz 256:135 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 4096 , 4184 ,
4272 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2018-05-24 22:20:35 +03:00
/* 103 - 3840x2160@24Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 3840 , 5116 ,
5204 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 104 - 3840x2160@25Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 3840 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 105 - 3840x2160@30Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 , 3840 , 4016 ,
4104 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 106 - 3840x2160@50Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 3840 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2018-05-24 22:20:35 +03:00
/* 107 - 3840x2160@60Hz 64:27 */
2017-07-13 21:03:08 +05:30
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 3840 , 4016 ,
4104 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 108 - 1280x720@48Hz 16:9 */
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 90000 , 1280 , 2240 ,
2280 , 2500 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-07-11 13:32:30 +03:00
/* 109 - 1280x720@48Hz 64:27 */
{ DRM_MODE ( " 1280x720 " , DRM_MODE_TYPE_DRIVER , 90000 , 1280 , 2240 ,
2280 , 2500 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 110 - 1680x720@48Hz 64:27 */
{ DRM_MODE ( " 1680x720 " , DRM_MODE_TYPE_DRIVER , 99000 , 1680 , 2490 ,
2530 , 2750 , 0 , 720 , 725 , 730 , 750 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 111 - 1920x1080@48Hz 16:9 */
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2558 ,
2602 , 2750 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-07-11 13:32:30 +03:00
/* 112 - 1920x1080@48Hz 64:27 */
{ DRM_MODE ( " 1920x1080 " , DRM_MODE_TYPE_DRIVER , 148500 , 1920 , 2558 ,
2602 , 2750 , 0 , 1080 , 1084 , 1089 , 1125 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 113 - 2560x1080@48Hz 64:27 */
{ DRM_MODE ( " 2560x1080 " , DRM_MODE_TYPE_DRIVER , 198000 , 2560 , 3558 ,
3602 , 3750 , 0 , 1080 , 1084 , 1089 , 1100 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 114 - 3840x2160@48Hz 16:9 */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 3840 , 5116 ,
5204 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-07-11 13:32:30 +03:00
/* 115 - 4096x2160@48Hz 256:135 */
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 4096 , 5116 ,
5204 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2019-07-11 13:32:30 +03:00
/* 116 - 3840x2160@48Hz 64:27 */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 594000 , 3840 , 5116 ,
5204 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 117 - 3840x2160@100Hz 16:9 */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 1188000 , 3840 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-07-11 13:32:30 +03:00
/* 118 - 3840x2160@120Hz 16:9 */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 1188000 , 3840 , 4016 ,
4104 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-07-11 13:32:30 +03:00
/* 119 - 3840x2160@100Hz 64:27 */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 1188000 , 3840 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 120 - 3840x2160@120Hz 64:27 */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 1188000 , 3840 , 4016 ,
4104 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 121 - 5120x2160@24Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 396000 , 5120 , 7116 ,
7204 , 7500 , 0 , 2160 , 2168 , 2178 , 2200 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 122 - 5120x2160@25Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 396000 , 5120 , 6816 ,
6904 , 7200 , 0 , 2160 , 2168 , 2178 , 2200 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 123 - 5120x2160@30Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 396000 , 5120 , 5784 ,
5872 , 6000 , 0 , 2160 , 2168 , 2178 , 2200 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 124 - 5120x2160@48Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 742500 , 5120 , 5866 ,
5954 , 6250 , 0 , 2160 , 2168 , 2178 , 2475 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 125 - 5120x2160@50Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 742500 , 5120 , 6216 ,
6304 , 6600 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 126 - 5120x2160@60Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 742500 , 5120 , 5284 ,
5372 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-07-11 13:32:30 +03:00
/* 127 - 5120x2160@100Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 1485000 , 5120 , 6216 ,
6304 , 6600 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2012-11-23 15:01:42 +01:00
} ;
2019-12-13 19:43:46 +02:00
/*
* From CEA / CTA - 861 spec .
*
* Do not access directly , instead always use cea_mode_for_vic ( ) .
*/
static const struct drm_display_mode edid_cea_modes_193 [ ] = {
/* 193 - 5120x2160@120Hz 64:27 */
{ DRM_MODE ( " 5120x2160 " , DRM_MODE_TYPE_DRIVER , 1485000 , 5120 , 5284 ,
5372 , 5500 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 194 - 7680x4320@24Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 1188000 , 7680 , 10232 ,
10408 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 195 - 7680x4320@25Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 1188000 , 7680 , 10032 ,
10208 , 10800 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 196 - 7680x4320@30Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 1188000 , 7680 , 8232 ,
8408 , 9000 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 197 - 7680x4320@48Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 2376000 , 7680 , 10232 ,
10408 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 198 - 7680x4320@50Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 2376000 , 7680 , 10032 ,
10208 , 10800 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 199 - 7680x4320@60Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 2376000 , 7680 , 8232 ,
8408 , 9000 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 200 - 7680x4320@100Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 4752000 , 7680 , 9792 ,
9968 , 10560 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 201 - 7680x4320@120Hz 16:9 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 4752000 , 7680 , 8032 ,
8208 , 8800 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2019-12-13 19:43:46 +02:00
/* 202 - 7680x4320@24Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 1188000 , 7680 , 10232 ,
10408 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 203 - 7680x4320@25Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 1188000 , 7680 , 10032 ,
10208 , 10800 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 204 - 7680x4320@30Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 1188000 , 7680 , 8232 ,
8408 , 9000 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 205 - 7680x4320@48Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 2376000 , 7680 , 10232 ,
10408 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 206 - 7680x4320@50Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 2376000 , 7680 , 10032 ,
10208 , 10800 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 207 - 7680x4320@60Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 2376000 , 7680 , 8232 ,
8408 , 9000 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 208 - 7680x4320@100Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 4752000 , 7680 , 9792 ,
9968 , 10560 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 209 - 7680x4320@120Hz 64:27 */
{ DRM_MODE ( " 7680x4320 " , DRM_MODE_TYPE_DRIVER , 4752000 , 7680 , 8032 ,
8208 , 8800 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 210 - 10240x4320@24Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 1485000 , 10240 , 11732 ,
11908 , 12500 , 0 , 4320 , 4336 , 4356 , 4950 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 211 - 10240x4320@25Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 1485000 , 10240 , 12732 ,
12908 , 13500 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 212 - 10240x4320@30Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 1485000 , 10240 , 10528 ,
10704 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 213 - 10240x4320@48Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 2970000 , 10240 , 11732 ,
11908 , 12500 , 0 , 4320 , 4336 , 4356 , 4950 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 214 - 10240x4320@50Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 2970000 , 10240 , 12732 ,
12908 , 13500 , 0 , 4320 , 4336 , 4356 , 4400 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 215 - 10240x4320@60Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 2970000 , 10240 , 10528 ,
10704 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 216 - 10240x4320@100Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 5940000 , 10240 , 12432 ,
12608 , 13200 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 217 - 10240x4320@120Hz 64:27 */
{ DRM_MODE ( " 10240x4320 " , DRM_MODE_TYPE_DRIVER , 5940000 , 10240 , 10528 ,
10704 , 11000 , 0 , 4320 , 4336 , 4356 , 4500 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27 , } ,
2019-12-13 19:43:46 +02:00
/* 218 - 4096x2160@100Hz 256:135 */
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 1188000 , 4096 , 4896 ,
4984 , 5280 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2019-12-13 19:43:46 +02:00
/* 219 - 4096x2160@120Hz 256:135 */
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 1188000 , 4096 , 4184 ,
4272 , 4400 , 0 , 2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2019-12-13 19:43:46 +02:00
} ;
2013-08-19 16:58:54 +01:00
/*
2016-01-08 13:21:51 +02:00
* HDMI 1.4 4 k modes . Index using the VIC .
2013-08-19 16:58:54 +01:00
*/
static const struct drm_display_mode edid_4k_modes [ ] = {
2016-01-08 13:21:51 +02:00
/* 0 - dummy, VICs start at 1 */
{ } ,
2013-08-19 16:58:54 +01:00
/* 1 - 3840x2160@30Hz */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 ,
3840 , 4016 , 4104 , 4400 , 0 ,
2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2013-08-19 16:58:54 +01:00
/* 2 - 3840x2160@25Hz */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 ,
3840 , 4896 , 4984 , 5280 , 0 ,
2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2013-08-19 16:58:54 +01:00
/* 3 - 3840x2160@24Hz */
{ DRM_MODE ( " 3840x2160 " , DRM_MODE_TYPE_DRIVER , 297000 ,
3840 , 5116 , 5204 , 5500 , 0 ,
2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9 , } ,
2013-08-19 16:58:54 +01:00
/* 4 - 4096x2160@24Hz (SMPTE) */
{ DRM_MODE ( " 4096x2160 " , DRM_MODE_TYPE_DRIVER , 297000 ,
4096 , 5116 , 5204 , 5500 , 0 ,
2160 , 2168 , 2178 , 2250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) ,
2020-04-28 20:19:27 +03:00
. picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135 , } ,
2013-08-19 16:58:54 +01:00
} ;
2010-03-29 21:43:18 +00:00
/*** DDC fetch and block validation ***/
2008-11-07 14:05:41 -08:00
drm/edid: add struct drm_edid container
Introduce new opaque type struct drm_edid to encapsulate the EDID data
and the size allocated for it. The contents will be private to
drm_edid.c.
There are a number of reasons for adding a container around struct edid:
* struct edid is a raw blob pointer to data that usually originates
outside of the kernel. Its size is contained within the structure.
* There's no way to attach meta information (such as allocated memory
size) to struct edid.
* Validation of the EDID blob and its size become crucial, and it's
spread all over the subsystem, with varying levels of accuracy.
* HDMI Forum has introduced an HF-EEODB extension that defines an
override EDID size within an EDID extension. The size allocated for an
EDID depends on whether the allocator understands the HF-EEODB
extension. Given a struct edid *, it's impossible to know how much
memory was actually allocated for it.
There are also some reasons for making the container type struct
drm_edid opaque and private to drm_edid.c:
* Have only one place for creating and parsing the EDID, to avoid
duplicating bugs.
* Prepare for reading a pure DisplayID 2.0 from its own DDC address, and
adding it within the same struct drm_edid container, transparently,
and for all drivers.
* With the idea that the drm_edid objects are immutable during their
lifetimes, it will be possible to refcount them and reduce EDID
copying everywhere (this is left for future work).
Initially, just add the type. In follow-up, we'll start converting the
guts of drm_edid.c to use it, and finally add interfaces around it.
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/f3ecabd8a219aea678ad00f7bcdecf77b27b3c78.1652097712.git.jani.nikula@intel.com
2022-05-09 15:03:02 +03:00
/*
* The opaque EDID type , internal to drm_edid . c .
*/
struct drm_edid {
/* Size allocated for edid */
size_t size ;
const struct edid * edid ;
} ;
2022-05-09 15:03:24 +03:00
static bool version_greater ( const struct drm_edid * drm_edid ,
u8 version , u8 revision )
{
const struct edid * edid = drm_edid - > edid ;
return edid - > version > version | |
( edid - > version = = version & & edid - > revision > revision ) ;
}
2022-06-29 12:27:54 +03:00
static int edid_hfeeodb_extension_block_count ( const struct edid * edid ) ;
static int edid_hfeeodb_block_count ( const struct edid * edid )
{
int eeodb = edid_hfeeodb_extension_block_count ( edid ) ;
return eeodb ? eeodb + 1 : 0 ;
}
2022-04-11 17:00:35 +03:00
static int edid_extension_block_count ( const struct edid * edid )
{
return edid - > extensions ;
}
static int edid_block_count ( const struct edid * edid )
{
return edid_extension_block_count ( edid ) + 1 ;
}
static int edid_size_by_blocks ( int num_blocks )
{
return num_blocks * EDID_LENGTH ;
}
static int edid_size ( const struct edid * edid )
{
return edid_size_by_blocks ( edid_block_count ( edid ) ) ;
}
static const void * edid_block_data ( const struct edid * edid , int index )
{
BUILD_BUG_ON ( sizeof ( * edid ) ! = EDID_LENGTH ) ;
return edid + index ;
}
static const void * edid_extension_block_data ( const struct edid * edid , int index )
{
return edid_block_data ( edid , index + 1 ) ;
}
2022-06-08 10:50:33 +03:00
static int drm_edid_block_count ( const struct drm_edid * drm_edid )
{
int num_blocks ;
/* Starting point */
num_blocks = edid_block_count ( drm_edid - > edid ) ;
2022-06-29 12:27:55 +03:00
/* HF-EEODB override */
if ( drm_edid - > size > = edid_size_by_blocks ( 2 ) ) {
int eeodb ;
/*
* Note : HF - EEODB may specify a smaller extension count than the
* regular one . Unlike in buffer allocation , here we can use it .
*/
eeodb = edid_hfeeodb_block_count ( drm_edid - > edid ) ;
if ( eeodb )
num_blocks = eeodb ;
}
2022-06-08 10:50:33 +03:00
/* Limit by allocated size */
num_blocks = min ( num_blocks , ( int ) drm_edid - > size / EDID_LENGTH ) ;
return num_blocks ;
}
static int drm_edid_extension_block_count ( const struct drm_edid * drm_edid )
{
return drm_edid_block_count ( drm_edid ) - 1 ;
}
static const void * drm_edid_block_data ( const struct drm_edid * drm_edid , int index )
{
return edid_block_data ( drm_edid - > edid , index ) ;
}
static const void * drm_edid_extension_block_data ( const struct drm_edid * drm_edid ,
int index )
{
return edid_extension_block_data ( drm_edid - > edid , index ) ;
}
2022-05-09 15:03:03 +03:00
/*
* Initializer helper for legacy interfaces , where we have no choice but to
* trust edid size . Not for general purpose use .
*/
static const struct drm_edid * drm_edid_legacy_init ( struct drm_edid * drm_edid ,
const struct edid * edid )
{
if ( ! edid )
return NULL ;
memset ( drm_edid , 0 , sizeof ( * drm_edid ) ) ;
drm_edid - > edid = edid ;
drm_edid - > size = edid_size ( edid ) ;
return drm_edid ;
}
2022-05-03 12:23:50 +03:00
/*
* EDID base and extension block iterator .
*
* struct drm_edid_iter iter ;
* const u8 * block ;
*
2022-05-09 15:03:21 +03:00
* drm_edid_iter_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:50 +03:00
* drm_edid_iter_for_each ( block , & iter ) {
* // do stuff with block
* }
* drm_edid_iter_end ( & iter ) ;
*/
struct drm_edid_iter {
2022-05-09 15:03:21 +03:00
const struct drm_edid * drm_edid ;
2022-05-03 12:23:50 +03:00
/* Current block index. */
int index ;
} ;
2022-05-09 15:03:21 +03:00
static void drm_edid_iter_begin ( const struct drm_edid * drm_edid ,
2022-05-03 12:23:50 +03:00
struct drm_edid_iter * iter )
{
memset ( iter , 0 , sizeof ( * iter ) ) ;
2022-05-09 15:03:21 +03:00
iter - > drm_edid = drm_edid ;
2022-05-03 12:23:50 +03:00
}
static const void * __drm_edid_iter_next ( struct drm_edid_iter * iter )
{
const void * block = NULL ;
2022-05-09 15:03:21 +03:00
if ( ! iter - > drm_edid )
2022-05-03 12:23:50 +03:00
return NULL ;
2022-06-08 10:50:33 +03:00
if ( iter - > index < drm_edid_block_count ( iter - > drm_edid ) )
block = drm_edid_block_data ( iter - > drm_edid , iter - > index + + ) ;
2022-05-03 12:23:50 +03:00
return block ;
}
# define drm_edid_iter_for_each(__block, __iter) \
while ( ( ( __block ) = __drm_edid_iter_next ( __iter ) ) )
static void drm_edid_iter_end ( struct drm_edid_iter * iter )
{
memset ( iter , 0 , sizeof ( * iter ) ) ;
}
2009-09-23 17:30:45 -04:00
static const u8 edid_header [ ] = {
0x00 , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x00
} ;
2008-11-07 14:05:41 -08:00
2022-03-31 21:45:03 +03:00
static void edid_header_fix ( void * edid )
{
memcpy ( edid , edid_header , sizeof ( edid_header ) ) ;
}
2014-04-29 11:44:34 +02:00
/**
* drm_edid_header_is_valid - sanity check the header of the base EDID block
2022-04-26 12:19:12 +03:00
* @ _edid : pointer to raw base EDID block
2014-04-29 11:44:34 +02:00
*
* Sanity check the header of the base EDID block .
*
* Return : 8 if the header is perfect , down to 0 if it ' s totally wrong .
2011-07-29 14:28:57 +00:00
*/
2022-03-31 21:45:01 +03:00
int drm_edid_header_is_valid ( const void * _edid )
2011-07-29 14:28:57 +00:00
{
2022-03-31 21:45:01 +03:00
const struct edid * edid = _edid ;
2011-07-29 14:28:57 +00:00
int i , score = 0 ;
2022-03-31 21:45:01 +03:00
for ( i = 0 ; i < sizeof ( edid_header ) ; i + + ) {
if ( edid - > header [ i ] = = edid_header [ i ] )
2011-07-29 14:28:57 +00:00
score + + ;
2022-03-31 21:45:01 +03:00
}
2011-07-29 14:28:57 +00:00
return score ;
}
EXPORT_SYMBOL ( drm_edid_header_is_valid ) ;
2012-05-30 16:42:39 -04:00
static int edid_fixup __read_mostly = 6 ;
module_param_named ( edid_fixup , edid_fixup , int , 0400 ) ;
MODULE_PARM_DESC ( edid_fixup ,
" Minimum number of valid EDID header bytes (0-8, default 6) " ) ;
2011-07-29 14:28:57 +00:00
2022-03-31 21:44:59 +03:00
static int edid_block_compute_checksum ( const void * _block )
2014-11-30 19:57:43 +01:00
{
2022-03-31 21:44:59 +03:00
const u8 * block = _block ;
2014-11-30 19:57:43 +01:00
int i ;
2020-02-11 11:08:32 -05:00
u8 csum = 0 , crc = 0 ;
for ( i = 0 ; i < EDID_LENGTH - 1 ; i + + )
2022-03-31 21:44:59 +03:00
csum + = block [ i ] ;
2014-11-30 19:57:43 +01:00
2020-02-11 11:08:32 -05:00
crc = 0x100 - csum ;
return crc ;
}
2022-03-31 21:44:59 +03:00
static int edid_block_get_checksum ( const void * _block )
2020-02-11 11:08:32 -05:00
{
2022-03-31 21:44:59 +03:00
const struct edid * block = _block ;
return block - > checksum ;
2014-11-30 19:57:43 +01:00
}
2022-03-31 21:45:00 +03:00
static int edid_block_tag ( const void * _block )
{
const u8 * block = _block ;
return block [ 0 ] ;
}
2022-04-11 17:00:24 +03:00
static bool edid_block_is_zero ( const void * edid )
2014-11-30 19:57:41 +01:00
{
2022-04-11 17:00:24 +03:00
return ! memchr_inv ( edid , 0 , EDID_LENGTH ) ;
2014-11-30 19:57:41 +01:00
}
2020-06-30 05:56:58 +05:30
/**
* drm_edid_are_equal - compare two edid blobs .
* @ edid1 : pointer to first blob
* @ edid2 : pointer to second blob
* This helper can be used during probing to determine if
* edid had changed .
*/
bool drm_edid_are_equal ( const struct edid * edid1 , const struct edid * edid2 )
{
int edid1_len , edid2_len ;
bool edid1_present = edid1 ! = NULL ;
bool edid2_present = edid2 ! = NULL ;
if ( edid1_present ! = edid2_present )
return false ;
if ( edid1 ) {
2022-04-11 17:00:35 +03:00
edid1_len = edid_size ( edid1 ) ;
edid2_len = edid_size ( edid2 ) ;
2020-06-30 05:56:58 +05:30
if ( edid1_len ! = edid2_len )
return false ;
if ( memcmp ( edid1 , edid2 , edid1_len ) )
return false ;
}
return true ;
}
EXPORT_SYMBOL ( drm_edid_are_equal ) ;
2022-03-31 21:45:04 +03:00
enum edid_block_status {
EDID_BLOCK_OK = 0 ,
2022-04-11 17:00:30 +03:00
EDID_BLOCK_READ_FAIL ,
2022-03-31 21:45:04 +03:00
EDID_BLOCK_NULL ,
2022-04-11 17:00:25 +03:00
EDID_BLOCK_ZERO ,
2022-03-31 21:45:04 +03:00
EDID_BLOCK_HEADER_CORRUPT ,
EDID_BLOCK_HEADER_REPAIR ,
EDID_BLOCK_HEADER_FIXED ,
EDID_BLOCK_CHECKSUM ,
EDID_BLOCK_VERSION ,
} ;
static enum edid_block_status edid_block_check ( const void * _block ,
bool is_base_block )
{
const struct edid * block = _block ;
if ( ! block )
return EDID_BLOCK_NULL ;
if ( is_base_block ) {
int score = drm_edid_header_is_valid ( block ) ;
2022-04-11 17:00:25 +03:00
if ( score < clamp ( edid_fixup , 0 , 8 ) ) {
if ( edid_block_is_zero ( block ) )
return EDID_BLOCK_ZERO ;
else
return EDID_BLOCK_HEADER_CORRUPT ;
}
2022-03-31 21:45:04 +03:00
if ( score < 8 )
return EDID_BLOCK_HEADER_REPAIR ;
}
2022-04-11 17:00:25 +03:00
if ( edid_block_compute_checksum ( block ) ! = edid_block_get_checksum ( block ) ) {
if ( edid_block_is_zero ( block ) )
return EDID_BLOCK_ZERO ;
else
return EDID_BLOCK_CHECKSUM ;
}
2022-03-31 21:45:04 +03:00
if ( is_base_block ) {
if ( block - > version ! = 1 )
return EDID_BLOCK_VERSION ;
}
return EDID_BLOCK_OK ;
}
static bool edid_block_status_valid ( enum edid_block_status status , int tag )
{
return status = = EDID_BLOCK_OK | |
status = = EDID_BLOCK_HEADER_FIXED | |
( status = = EDID_BLOCK_CHECKSUM & & tag = = CEA_EXT ) ;
}
2022-03-31 21:45:06 +03:00
static bool edid_block_valid ( const void * block , bool base )
{
return edid_block_status_valid ( edid_block_check ( block , base ) ,
edid_block_tag ( block ) ) ;
}
2022-04-11 17:00:26 +03:00
static void edid_block_status_print ( enum edid_block_status status ,
const struct edid * block ,
int block_num )
{
switch ( status ) {
case EDID_BLOCK_OK :
break ;
2022-04-11 17:00:30 +03:00
case EDID_BLOCK_READ_FAIL :
pr_debug ( " EDID block %d read failed \n " , block_num ) ;
break ;
2022-04-11 17:00:26 +03:00
case EDID_BLOCK_NULL :
pr_debug ( " EDID block %d pointer is NULL \n " , block_num ) ;
break ;
case EDID_BLOCK_ZERO :
pr_notice ( " EDID block %d is all zeroes \n " , block_num ) ;
break ;
case EDID_BLOCK_HEADER_CORRUPT :
pr_notice ( " EDID has corrupt header \n " ) ;
break ;
case EDID_BLOCK_HEADER_REPAIR :
pr_debug ( " EDID corrupt header needs repair \n " ) ;
break ;
case EDID_BLOCK_HEADER_FIXED :
pr_debug ( " EDID corrupt header fixed \n " ) ;
break ;
case EDID_BLOCK_CHECKSUM :
if ( edid_block_status_valid ( status , edid_block_tag ( block ) ) ) {
pr_debug ( " EDID block %d (tag 0x%02x) checksum is invalid, remainder is %d, ignoring \n " ,
block_num , edid_block_tag ( block ) ,
edid_block_compute_checksum ( block ) ) ;
} else {
pr_notice ( " EDID block %d (tag 0x%02x) checksum is invalid, remainder is %d \n " ,
block_num , edid_block_tag ( block ) ,
edid_block_compute_checksum ( block ) ) ;
}
break ;
case EDID_BLOCK_VERSION :
pr_notice ( " EDID has major version %d, instead of 1 \n " ,
block - > version ) ;
break ;
default :
WARN ( 1 , " EDID block %d unknown edid block status code %d \n " ,
block_num , status ) ;
break ;
}
}
2022-04-11 17:00:27 +03:00
static void edid_block_dump ( const char * level , const void * block , int block_num )
{
enum edid_block_status status ;
char prefix [ 20 ] ;
status = edid_block_check ( block , block_num = = 0 ) ;
if ( status = = EDID_BLOCK_ZERO )
sprintf ( prefix , " \t [%02x] ZERO " , block_num ) ;
else if ( ! edid_block_status_valid ( status , edid_block_tag ( block ) ) )
sprintf ( prefix , " \t [%02x] BAD " , block_num ) ;
else
sprintf ( prefix , " \t [%02x] GOOD " , block_num ) ;
print_hex_dump ( level , prefix , DUMP_PREFIX_NONE , 16 , 1 ,
block , EDID_LENGTH , false ) ;
}
2014-04-29 11:44:34 +02:00
/**
* drm_edid_block_valid - Sanity check the EDID block ( base or extension )
2022-04-26 12:19:12 +03:00
* @ _block : pointer to raw EDID block
2022-03-31 21:45:04 +03:00
* @ block_num : type of block to validate ( 0 for base , extension otherwise )
2014-04-29 11:44:34 +02:00
* @ print_bad_edid : if true , dump bad EDID blocks to the console
2015-04-21 11:09:41 -07:00
* @ edid_corrupt : if true , the header or checksum is invalid
2014-04-29 11:44:34 +02:00
*
* Validate a base or extension EDID block and optionally dump bad blocks to
* the console .
*
* Return : True if the block is valid , false otherwise .
2008-11-07 14:05:41 -08:00
*/
2022-03-31 21:45:04 +03:00
bool drm_edid_block_valid ( u8 * _block , int block_num , bool print_bad_edid ,
2015-04-21 11:09:41 -07:00
bool * edid_corrupt )
2008-11-07 14:05:41 -08:00
{
2022-03-31 21:45:04 +03:00
struct edid * block = ( struct edid * ) _block ;
enum edid_block_status status ;
bool is_base_block = block_num = = 0 ;
bool valid ;
2008-11-07 14:05:41 -08:00
2022-03-31 21:45:04 +03:00
if ( WARN_ON ( ! block ) )
2013-07-02 17:57:04 +09:00
return false ;
2022-03-31 21:45:04 +03:00
status = edid_block_check ( block , is_base_block ) ;
if ( status = = EDID_BLOCK_HEADER_REPAIR ) {
DRM_DEBUG ( " Fixing EDID header, your hardware may be failing \n " ) ;
edid_header_fix ( block ) ;
/* Retry with fixed header, update status if that worked. */
status = edid_block_check ( block , is_base_block ) ;
if ( status = = EDID_BLOCK_OK )
status = EDID_BLOCK_HEADER_FIXED ;
2010-03-29 21:43:18 +00:00
}
2008-11-07 14:05:41 -08:00
2022-03-31 21:45:04 +03:00
if ( edid_corrupt ) {
/*
* Unknown major version isn ' t corrupt but we can ' t use it . Only
* the base block can reset edid_corrupt to false .
*/
if ( is_base_block & &
( status = = EDID_BLOCK_OK | | status = = EDID_BLOCK_VERSION ) )
* edid_corrupt = false ;
else if ( status ! = EDID_BLOCK_OK )
2015-05-08 16:15:41 +02:00
* edid_corrupt = true ;
2008-11-07 14:05:41 -08:00
}
2022-04-11 17:00:26 +03:00
edid_block_status_print ( status , block , block_num ) ;
2022-03-31 21:45:04 +03:00
/* Determine whether we can use this block with this status. */
valid = edid_block_status_valid ( status , edid_block_tag ( block ) ) ;
2022-04-11 17:00:26 +03:00
if ( ! valid & & print_bad_edid & & status ! = EDID_BLOCK_ZERO ) {
pr_notice ( " Raw EDID: \n " ) ;
2022-04-11 17:00:27 +03:00
edid_block_dump ( KERN_NOTICE , block , block_num ) ;
2008-11-07 14:05:41 -08:00
}
2022-03-31 21:45:04 +03:00
return valid ;
2008-11-07 14:05:41 -08:00
}
2012-03-18 22:37:33 +01:00
EXPORT_SYMBOL ( drm_edid_block_valid ) ;
2010-03-29 21:43:18 +00:00
/**
* drm_edid_is_valid - sanity check EDID data
* @ edid : EDID data
*
* Sanity - check an entire EDID record ( including extensions )
2014-04-29 11:44:34 +02:00
*
* Return : True if the EDID data is valid , false otherwise .
2010-03-29 21:43:18 +00:00
*/
bool drm_edid_is_valid ( struct edid * edid )
{
int i ;
if ( ! edid )
return false ;
2022-04-11 17:00:35 +03:00
for ( i = 0 ; i < edid_block_count ( edid ) ; i + + ) {
void * block = ( void * ) edid_block_data ( edid , i ) ;
if ( ! drm_edid_block_valid ( block , i , true , NULL ) )
2010-03-29 21:43:18 +00:00
return false ;
2022-04-11 17:00:35 +03:00
}
2010-03-29 21:43:18 +00:00
return true ;
}
2010-02-05 04:21:19 -05:00
EXPORT_SYMBOL ( drm_edid_is_valid ) ;
2008-11-07 14:05:41 -08:00
2022-06-29 12:27:53 +03:00
static struct edid * edid_filter_invalid_blocks ( struct edid * edid ,
2022-06-08 10:50:34 +03:00
size_t * alloc_size )
2022-03-31 21:45:07 +03:00
{
2022-06-29 12:27:53 +03:00
struct edid * new ;
int i , valid_blocks = 0 ;
2022-03-31 21:45:07 +03:00
2022-06-29 12:27:54 +03:00
/*
* Note : If the EDID uses HF - EEODB , but has invalid blocks , we ' ll revert
* back to regular extension count here . We don ' t want to start
* modifying the HF - EEODB extension too .
*/
2022-06-29 12:27:53 +03:00
for ( i = 0 ; i < edid_block_count ( edid ) ; i + + ) {
const void * src_block = edid_block_data ( edid , i ) ;
2022-06-08 10:50:34 +03:00
2022-06-29 12:27:53 +03:00
if ( edid_block_valid ( src_block , i = = 0 ) ) {
void * dst_block = ( void * ) edid_block_data ( edid , valid_blocks ) ;
2022-03-31 21:45:07 +03:00
2022-06-29 12:27:53 +03:00
memmove ( dst_block , src_block , EDID_LENGTH ) ;
valid_blocks + + ;
}
}
2022-03-31 21:45:07 +03:00
2022-06-29 12:27:53 +03:00
/* We already trusted the base block to be valid here... */
if ( WARN_ON ( ! valid_blocks ) ) {
kfree ( edid ) ;
return NULL ;
2022-03-31 21:45:07 +03:00
}
2022-06-29 12:27:53 +03:00
edid - > extensions = valid_blocks - 1 ;
edid - > checksum = edid_block_compute_checksum ( edid ) ;
2022-03-31 21:45:07 +03:00
2022-06-29 12:27:53 +03:00
* alloc_size = edid_size_by_blocks ( valid_blocks ) ;
new = krealloc ( edid , * alloc_size , GFP_KERNEL ) ;
if ( ! new )
kfree ( edid ) ;
2022-03-31 21:45:07 +03:00
return new ;
}
2010-03-29 21:43:18 +00:00
# define DDC_SEGMENT_ADDR 0x30
/**
2014-04-29 11:44:34 +02:00
* drm_do_probe_ddc_edid ( ) - get EDID information via I2C
2014-12-03 16:52:18 +01:00
* @ data : I2C device adapter
2014-01-21 12:02:26 +01:00
* @ buf : EDID data buffer to be filled
* @ block : 128 byte EDID block to start fetching from
* @ len : EDID data buffer length to fetch
*
2014-04-29 11:44:34 +02:00
* Try to fetch EDID information by calling I2C driver functions .
2010-03-29 21:43:18 +00:00
*
2014-04-29 11:44:34 +02:00
* Return : 0 on success or - 1 on failure .
2010-03-29 21:43:18 +00:00
*/
static int
2012-04-27 11:11:58 +02:00
drm_do_probe_ddc_edid ( void * data , u8 * buf , unsigned int block , size_t len )
2010-03-29 21:43:18 +00:00
{
2012-04-27 11:11:58 +02:00
struct i2c_adapter * adapter = data ;
2010-03-29 21:43:18 +00:00
unsigned char start = block * EDID_LENGTH ;
2012-08-30 07:04:06 +00:00
unsigned char segment = block > > 1 ;
unsigned char xfers = segment ? 3 : 2 ;
2011-03-15 11:04:41 +00:00
int ret , retries = 5 ;
2014-04-29 11:44:34 +02:00
/*
* The core I2C driver will automatically retry the transfer if the
2011-03-15 11:04:41 +00:00
* adapter reports EAGAIN . However , we find that bit - banging transfers
* are susceptible to errors under a heavily loaded machine and
* generate spurious NAKs and timeouts . Retrying the transfer
* of the individual block a few times seems to overcome this .
*/
do {
struct i2c_msg msgs [ ] = {
{
2012-08-30 07:04:06 +00:00
. addr = DDC_SEGMENT_ADDR ,
. flags = 0 ,
. len = 1 ,
. buf = & segment ,
} , {
2011-03-15 11:04:41 +00:00
. addr = DDC_ADDR ,
. flags = 0 ,
. len = 1 ,
. buf = & start ,
} , {
. addr = DDC_ADDR ,
. flags = I2C_M_RD ,
. len = len ,
. buf = buf ,
}
} ;
2012-08-30 07:04:06 +00:00
2014-04-29 11:44:34 +02:00
/*
* Avoid sending the segment addr to not upset non - compliant
* DDC monitors .
*/
2012-08-30 07:04:06 +00:00
ret = i2c_transfer ( adapter , & msgs [ 3 - xfers ] , xfers ) ;
2012-01-05 09:34:28 -02:00
if ( ret = = - ENXIO ) {
DRM_DEBUG_KMS ( " drm: skipping non-existent adapter %s \n " ,
adapter - > name ) ;
break ;
}
2012-08-30 07:04:06 +00:00
} while ( ret ! = xfers & & - - retries ) ;
2011-03-15 11:04:41 +00:00
2012-08-30 07:04:06 +00:00
return ret = = xfers ? 0 : - 1 ;
2010-03-29 21:43:18 +00:00
}
2016-10-24 12:38:21 +01:00
static void connector_bad_edid ( struct drm_connector * connector ,
2022-04-11 17:00:28 +03:00
const struct edid * edid , int num_blocks )
2016-10-24 12:38:21 +01:00
{
int i ;
2021-10-05 19:29:08 -07:00
u8 last_block ;
/*
* 0x7e in the EDID is the number of extension blocks . The EDID
* is 1 ( base block ) + num_ext_blocks big . That means we can think
* of 0x7e in the EDID of the _index_ of the last block in the
* combined chunk of memory .
*/
2022-04-11 17:00:28 +03:00
last_block = edid - > extensions ;
2020-02-11 11:08:32 -05:00
/* Calculate real checksum for the last edid extension block data */
2021-10-05 19:29:08 -07:00
if ( last_block < num_blocks )
connector - > real_edid_checksum =
2022-04-11 17:00:28 +03:00
edid_block_compute_checksum ( edid + last_block ) ;
2016-10-24 12:38:21 +01:00
2019-10-01 17:06:14 +03:00
if ( connector - > bad_edid_counter + + & & ! drm_debug_enabled ( DRM_UT_KMS ) )
2016-10-24 12:38:21 +01:00
return ;
2020-10-29 21:30:42 +00:00
drm_dbg_kms ( connector - > dev , " %s: EDID is invalid: \n " , connector - > name ) ;
2022-04-11 17:00:28 +03:00
for ( i = 0 ; i < num_blocks ; i + + )
edid_block_dump ( KERN_DEBUG , edid + i , i ) ;
2016-10-24 12:38:21 +01:00
}
2019-06-07 14:05:12 +03:00
/* Get override or firmware EDID */
2022-06-08 10:50:34 +03:00
static struct edid * drm_get_override_edid ( struct drm_connector * connector ,
size_t * alloc_size )
2019-06-07 14:05:12 +03:00
{
struct edid * override = NULL ;
if ( connector - > override_edid )
override = drm_edid_duplicate ( connector - > edid_blob_ptr - > data ) ;
if ( ! override )
override = drm_load_edid_firmware ( connector ) ;
2022-06-08 10:50:34 +03:00
/* FIXME: Get alloc size from deeper down the stack */
if ( ! IS_ERR_OR_NULL ( override ) & & alloc_size )
* alloc_size = edid_size ( override ) ;
2019-06-07 14:05:12 +03:00
return IS_ERR ( override ) ? NULL : override ;
}
2022-06-29 12:27:49 +03:00
/* For debugfs edid_override implementation */
int drm_edid_override_set ( struct drm_connector * connector , const void * edid ,
size_t size )
{
int ret ;
if ( size < EDID_LENGTH | | edid_size ( edid ) > size )
return - EINVAL ;
connector - > override_edid = false ;
ret = drm_connector_update_edid_property ( connector , edid ) ;
if ( ! ret )
connector - > override_edid = true ;
return ret ;
}
/* For debugfs edid_override implementation */
int drm_edid_override_reset ( struct drm_connector * connector )
{
connector - > override_edid = false ;
return drm_connector_update_edid_property ( connector , NULL ) ;
}
drm: add fallback override/firmware EDID modes workaround
We've moved the override and firmware EDID (simply "override EDID" from
now on) handling to the low level drm_do_get_edid() function in order to
transparently use the override throughout the stack. The idea is that
you get the override EDID via the ->get_modes() hook.
Unfortunately, there are scenarios where the DDC probe in drm_get_edid()
called via ->get_modes() fails, although the preceding ->detect()
succeeds.
In the case reported by Paul Wise, the ->detect() hook,
intel_crt_detect(), relies on hotplug detect, bypassing the DDC. In the
case reported by Ilpo Järvinen, there is no ->detect() hook, which is
interpreted as connected. The subsequent DDC probe reached via
->get_modes() fails, and we don't even look at the override EDID,
resulting in no modes being added.
Because drm_get_edid() is used via ->detect() all over the place, we
can't trivially remove the DDC probe, as it leads to override EDID
effectively meaning connector forcing. The goal is that connector
forcing and override EDID remain orthogonal.
Generally, the underlying problem here is the conflation of ->detect()
and ->get_modes() via drm_get_edid(). The former should just detect, and
the latter should just get the modes, typically via reading the EDID. As
long as drm_get_edid() is used in ->detect(), it needs to retain the DDC
probe. Or such users need to have a separate DDC probe step first.
The EDID caching between ->detect() and ->get_modes() done by some
drivers is a further complication that prevents us from making
drm_do_get_edid() adapt to the two cases.
Work around the regression by falling back to a separate attempt at
getting the override EDID at drm_helper_probe_single_connector_modes()
level. With a working DDC and override EDID, it'll never be called; the
override EDID will come via ->get_modes(). There will still be a failing
DDC probe attempt in the cases that require the fallback.
v2:
- Call drm_connector_update_edid_property (Paul)
- Update commit message about EDID caching (Daniel)
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107583
Reported-by: Paul Wise <pabs3@bonedaddy.net>
Cc: Paul Wise <pabs3@bonedaddy.net>
References: http://mid.mail-archive.com/alpine.DEB.2.20.1905262211270.24390@whs-18.cs.helsinki.fi
Reported-by: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
Cc: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
References: 15f080f08d48 ("drm/edid: respect connector force for drm_get_edid ddc probe")
Fixes: 53fd40a90f3c ("drm: handle override and firmware EDID at drm_do_get_edid() level")
Cc: <stable@vger.kernel.org> # v4.15+ 56a2b7f2a39a drm/edid: abstract override/firmware EDID retrieval
Cc: <stable@vger.kernel.org> # v4.15+
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harish Chegondi <harish.chegondi@intel.com>
Tested-by: Paul Wise <pabs3@bonedaddy.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190610093054.28445-1-jani.nikula@intel.com
2019-06-10 12:30:54 +03:00
/**
* drm_add_override_edid_modes - add modes from override / firmware EDID
* @ connector : connector we ' re probing
*
* Add modes from the override / firmware EDID , if available . Only to be used from
* drm_helper_probe_single_connector_modes ( ) as a fallback for when DDC probe
* failed during drm_get_edid ( ) and caused the override / firmware EDID to be
* skipped .
*
* Return : The number of modes added or 0 if we couldn ' t find any .
*/
int drm_add_override_edid_modes ( struct drm_connector * connector )
{
struct edid * override ;
int num_modes = 0 ;
2022-06-08 10:50:34 +03:00
override = drm_get_override_edid ( connector , NULL ) ;
drm: add fallback override/firmware EDID modes workaround
We've moved the override and firmware EDID (simply "override EDID" from
now on) handling to the low level drm_do_get_edid() function in order to
transparently use the override throughout the stack. The idea is that
you get the override EDID via the ->get_modes() hook.
Unfortunately, there are scenarios where the DDC probe in drm_get_edid()
called via ->get_modes() fails, although the preceding ->detect()
succeeds.
In the case reported by Paul Wise, the ->detect() hook,
intel_crt_detect(), relies on hotplug detect, bypassing the DDC. In the
case reported by Ilpo Järvinen, there is no ->detect() hook, which is
interpreted as connected. The subsequent DDC probe reached via
->get_modes() fails, and we don't even look at the override EDID,
resulting in no modes being added.
Because drm_get_edid() is used via ->detect() all over the place, we
can't trivially remove the DDC probe, as it leads to override EDID
effectively meaning connector forcing. The goal is that connector
forcing and override EDID remain orthogonal.
Generally, the underlying problem here is the conflation of ->detect()
and ->get_modes() via drm_get_edid(). The former should just detect, and
the latter should just get the modes, typically via reading the EDID. As
long as drm_get_edid() is used in ->detect(), it needs to retain the DDC
probe. Or such users need to have a separate DDC probe step first.
The EDID caching between ->detect() and ->get_modes() done by some
drivers is a further complication that prevents us from making
drm_do_get_edid() adapt to the two cases.
Work around the regression by falling back to a separate attempt at
getting the override EDID at drm_helper_probe_single_connector_modes()
level. With a working DDC and override EDID, it'll never be called; the
override EDID will come via ->get_modes(). There will still be a failing
DDC probe attempt in the cases that require the fallback.
v2:
- Call drm_connector_update_edid_property (Paul)
- Update commit message about EDID caching (Daniel)
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107583
Reported-by: Paul Wise <pabs3@bonedaddy.net>
Cc: Paul Wise <pabs3@bonedaddy.net>
References: http://mid.mail-archive.com/alpine.DEB.2.20.1905262211270.24390@whs-18.cs.helsinki.fi
Reported-by: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
Cc: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
References: 15f080f08d48 ("drm/edid: respect connector force for drm_get_edid ddc probe")
Fixes: 53fd40a90f3c ("drm: handle override and firmware EDID at drm_do_get_edid() level")
Cc: <stable@vger.kernel.org> # v4.15+ 56a2b7f2a39a drm/edid: abstract override/firmware EDID retrieval
Cc: <stable@vger.kernel.org> # v4.15+
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harish Chegondi <harish.chegondi@intel.com>
Tested-by: Paul Wise <pabs3@bonedaddy.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190610093054.28445-1-jani.nikula@intel.com
2019-06-10 12:30:54 +03:00
if ( override ) {
drm_connector_update_edid_property ( connector , override ) ;
num_modes = drm_add_edid_modes ( connector , override ) ;
kfree ( override ) ;
DRM_DEBUG_KMS ( " [CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID \n " ,
connector - > base . id , connector - > name , num_modes ) ;
}
return num_modes ;
}
EXPORT_SYMBOL ( drm_add_override_edid_modes ) ;
2022-04-11 17:00:29 +03:00
typedef int read_block_fn ( void * context , u8 * buf , unsigned int block , size_t len ) ;
2022-04-11 17:00:30 +03:00
static enum edid_block_status edid_block_read ( void * block , unsigned int block_num ,
read_block_fn read_block ,
void * context )
{
enum edid_block_status status ;
bool is_base_block = block_num = = 0 ;
int try ;
for ( try = 0 ; try < 4 ; try + + ) {
if ( read_block ( context , block , block_num , EDID_LENGTH ) )
return EDID_BLOCK_READ_FAIL ;
status = edid_block_check ( block , is_base_block ) ;
if ( status = = EDID_BLOCK_HEADER_REPAIR ) {
edid_header_fix ( block ) ;
/* Retry with fixed header, update status if that worked. */
status = edid_block_check ( block , is_base_block ) ;
if ( status = = EDID_BLOCK_OK )
status = EDID_BLOCK_HEADER_FIXED ;
}
if ( edid_block_status_valid ( status , edid_block_tag ( block ) ) )
break ;
/* Fail early for unrepairable base block all zeros. */
if ( try = = 0 & & is_base_block & & status = = EDID_BLOCK_ZERO )
break ;
}
return status ;
}
2022-06-08 10:50:35 +03:00
static struct edid * _drm_do_get_edid ( struct drm_connector * connector ,
read_block_fn read_block , void * context ,
size_t * size )
2010-03-29 21:43:18 +00:00
{
2022-04-11 17:00:31 +03:00
enum edid_block_status status ;
2022-06-29 12:27:54 +03:00
int i , num_blocks , invalid_blocks = 0 ;
2022-04-11 17:00:33 +03:00
struct edid * edid , * new ;
2022-06-08 10:50:34 +03:00
size_t alloc_size = EDID_LENGTH ;
drm: handle override and firmware EDID at drm_do_get_edid() level
Handle debugfs override edid and firmware edid at the low level to
transparently and completely replace the real edid. Previously, we
practically only used the modes from the override EDID, and none of the
other data, such as audio parameters.
This change also prevents actual EDID reads when the EDID is to be
overridden, but retains the DDC probe. This is useful if the reason for
preferring override EDID are problems with reading the data, or
corruption of the data.
Move firmware EDID loading from helper to core, as the functionality
moves to lower level as well. This will result in a change of module
parameter from drm_kms_helper.edid_firmware to drm.edid_firmware, which
arguably makes more sense anyway.
Some future work remains related to override and firmware EDID
validation. Like before, no validation is done for override EDID. The
firmware EDID is validated separately in the loader. Some unification
and deduplication would be in order, to validate all of them at the
drm_do_get_edid() level, like "real" EDIDs.
v2: move firmware loading to core
v3: rebase, commit message refresh
Cc: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Tested-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Dave Airlie <airlied@gmail.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1e8a710bcac46e5136c1a7b430074893c81f364a.1505203831.git.jani.nikula@intel.com
2017-09-12 11:19:26 +03:00
2022-06-08 10:50:34 +03:00
edid = drm_get_override_edid ( connector , & alloc_size ) ;
2022-04-11 17:00:33 +03:00
if ( edid )
2022-04-11 17:00:34 +03:00
goto ok ;
2010-03-29 21:43:18 +00:00
2022-06-08 10:50:34 +03:00
edid = kmalloc ( alloc_size , GFP_KERNEL ) ;
2021-10-04 09:21:27 -07:00
if ( ! edid )
2010-03-29 21:43:18 +00:00
return NULL ;
2022-04-11 17:00:31 +03:00
status = edid_block_read ( edid , 0 , read_block , context ) ;
edid_block_status_print ( status , edid , 0 ) ;
if ( status = = EDID_BLOCK_READ_FAIL )
2022-04-11 17:00:34 +03:00
goto fail ;
2022-04-11 17:00:31 +03:00
/* FIXME: Clarify what a corrupt EDID actually means. */
if ( status = = EDID_BLOCK_OK | | status = = EDID_BLOCK_VERSION )
connector - > edid_corrupt = false ;
else
connector - > edid_corrupt = true ;
if ( ! edid_block_status_valid ( status , edid_block_tag ( edid ) ) ) {
if ( status = = EDID_BLOCK_ZERO )
connector - > null_edid_counter + + ;
connector_bad_edid ( connector , edid , 1 ) ;
2022-04-11 17:00:34 +03:00
goto fail ;
2022-04-11 17:00:31 +03:00
}
2022-04-11 17:00:35 +03:00
if ( ! edid_extension_block_count ( edid ) )
2022-04-11 17:00:34 +03:00
goto ok ;
2010-03-29 21:43:18 +00:00
2022-06-08 10:50:34 +03:00
alloc_size = edid_size ( edid ) ;
new = krealloc ( edid , alloc_size , GFP_KERNEL ) ;
2010-03-29 21:43:18 +00:00
if ( ! new )
2022-04-11 17:00:34 +03:00
goto fail ;
2016-10-17 09:35:12 +01:00
edid = new ;
2010-03-29 21:43:18 +00:00
2022-06-29 12:27:54 +03:00
num_blocks = edid_block_count ( edid ) ;
for ( i = 1 ; i < num_blocks ; i + + ) {
2022-04-11 17:00:35 +03:00
void * block = ( void * ) edid_block_data ( edid , i ) ;
2016-10-17 09:35:13 +01:00
2022-04-11 17:00:35 +03:00
status = edid_block_read ( block , i , read_block , context ) ;
2022-04-11 17:00:32 +03:00
2022-04-11 17:00:35 +03:00
edid_block_status_print ( status , block , i ) ;
2013-01-29 14:27:39 +01:00
2022-04-11 17:00:32 +03:00
if ( ! edid_block_status_valid ( status , edid_block_tag ( block ) ) ) {
if ( status = = EDID_BLOCK_READ_FAIL )
2022-04-11 17:00:34 +03:00
goto fail ;
2022-03-31 21:45:08 +03:00
invalid_blocks + + ;
2022-06-29 12:27:54 +03:00
} else if ( i = = 1 ) {
/*
* If the first EDID extension is a CTA extension , and
* the first Data Block is HF - EEODB , override the
* extension block count .
*
* Note : HF - EEODB could specify a smaller extension
* count too , but we can ' t risk allocating a smaller
* amount .
*/
int eeodb = edid_hfeeodb_block_count ( edid ) ;
if ( eeodb > num_blocks ) {
num_blocks = eeodb ;
alloc_size = edid_size_by_blocks ( num_blocks ) ;
new = krealloc ( edid , alloc_size , GFP_KERNEL ) ;
if ( ! new )
goto fail ;
edid = new ;
}
2022-04-11 17:00:32 +03:00
}
2010-09-23 10:11:01 +01:00
}
2022-03-31 21:45:08 +03:00
if ( invalid_blocks ) {
2022-06-29 12:27:54 +03:00
connector_bad_edid ( connector , edid , num_blocks ) ;
2016-10-24 12:38:21 +01:00
2022-06-29 12:27:53 +03:00
edid = edid_filter_invalid_blocks ( edid , & alloc_size ) ;
2010-03-29 21:43:18 +00:00
}
2022-04-11 17:00:34 +03:00
ok :
2022-06-08 10:50:35 +03:00
if ( size )
* size = alloc_size ;
2022-03-31 21:44:58 +03:00
return edid ;
2010-03-29 21:43:18 +00:00
2022-04-11 17:00:34 +03:00
fail :
2016-10-17 09:35:12 +01:00
kfree ( edid ) ;
2010-03-29 21:43:18 +00:00
return NULL ;
}
2022-06-08 10:50:35 +03:00
/**
* drm_do_get_edid - get EDID data using a custom EDID block read function
* @ connector : connector we ' re probing
* @ read_block : EDID block read function
* @ context : private data passed to the block read function
*
* When the I2C adapter connected to the DDC bus is hidden behind a device that
* exposes a different interface to read EDID blocks this function can be used
* to get EDID data using a custom block read function .
*
* As in the general case the DDC bus is accessible by the kernel at the I2C
* level , drivers must make all reasonable efforts to expose it as an I2C
* adapter and use drm_get_edid ( ) instead of abusing this function .
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
* ( drm_load_edid_firmware ( ) and drm . edid_firmware parameter ) , in this priority
* order . Having either of them bypasses actual EDID reads .
*
* Return : Pointer to valid EDID or NULL if we couldn ' t find any .
*/
struct edid * drm_do_get_edid ( struct drm_connector * connector ,
read_block_fn read_block ,
void * context )
{
return _drm_do_get_edid ( connector , read_block , context , NULL ) ;
}
2012-04-27 11:11:58 +02:00
EXPORT_SYMBOL_GPL ( drm_do_get_edid ) ;
2010-03-29 21:43:18 +00:00
2022-06-29 12:27:52 +03:00
/**
* drm_edid_raw - Get a pointer to the raw EDID data .
* @ drm_edid : drm_edid container
*
* Get a pointer to the raw EDID data .
*
* This is for transition only . Avoid using this like the plague .
*
* Return : Pointer to raw EDID data .
*/
const struct edid * drm_edid_raw ( const struct drm_edid * drm_edid )
{
if ( ! drm_edid | | ! drm_edid - > size )
return NULL ;
/*
* Do not return pointers where relying on EDID extension count would
* lead to buffer overflow .
*/
if ( WARN_ON ( edid_size ( drm_edid - > edid ) > drm_edid - > size ) )
return NULL ;
return drm_edid - > edid ;
}
EXPORT_SYMBOL ( drm_edid_raw ) ;
2022-06-08 10:50:35 +03:00
/* Allocate struct drm_edid container *without* duplicating the edid data */
static const struct drm_edid * _drm_edid_alloc ( const void * edid , size_t size )
{
struct drm_edid * drm_edid ;
if ( ! edid | | ! size | | size < EDID_LENGTH )
return NULL ;
drm_edid = kzalloc ( sizeof ( * drm_edid ) , GFP_KERNEL ) ;
if ( drm_edid ) {
drm_edid - > edid = edid ;
drm_edid - > size = size ;
}
return drm_edid ;
}
/**
* drm_edid_alloc - Allocate a new drm_edid container
* @ edid : Pointer to raw EDID data
* @ size : Size of memory allocated for EDID
*
* Allocate a new drm_edid container . Do not calculate edid size from edid , pass
* the actual size that has been allocated for the data . There is no validation
* of the raw EDID data against the size , but at least the EDID base block must
* fit in the buffer .
*
* The returned pointer must be freed using drm_edid_free ( ) .
*
* Return : drm_edid container , or NULL on errors
*/
const struct drm_edid * drm_edid_alloc ( const void * edid , size_t size )
{
const struct drm_edid * drm_edid ;
if ( ! edid | | ! size | | size < EDID_LENGTH )
return NULL ;
edid = kmemdup ( edid , size , GFP_KERNEL ) ;
if ( ! edid )
return NULL ;
drm_edid = _drm_edid_alloc ( edid , size ) ;
if ( ! drm_edid )
kfree ( edid ) ;
return drm_edid ;
}
EXPORT_SYMBOL ( drm_edid_alloc ) ;
/**
* drm_edid_dup - Duplicate a drm_edid container
* @ drm_edid : EDID to duplicate
*
* The returned pointer must be freed using drm_edid_free ( ) .
*
* Returns : drm_edid container copy , or NULL on errors
*/
const struct drm_edid * drm_edid_dup ( const struct drm_edid * drm_edid )
{
if ( ! drm_edid )
return NULL ;
return drm_edid_alloc ( drm_edid - > edid , drm_edid - > size ) ;
}
EXPORT_SYMBOL ( drm_edid_dup ) ;
/**
* drm_edid_free - Free the drm_edid container
* @ drm_edid : EDID to free
*/
void drm_edid_free ( const struct drm_edid * drm_edid )
{
if ( ! drm_edid )
return ;
kfree ( drm_edid - > edid ) ;
kfree ( drm_edid ) ;
}
EXPORT_SYMBOL ( drm_edid_free ) ;
2010-03-29 21:43:18 +00:00
/**
2014-04-29 11:44:34 +02:00
* drm_probe_ddc ( ) - probe DDC presence
* @ adapter : I2C adapter to probe
2014-01-21 12:02:26 +01:00
*
2014-04-29 11:44:34 +02:00
* Return : True on success , false on failure .
2010-03-29 21:43:18 +00:00
*/
2012-09-18 10:58:47 -04:00
bool
2010-03-29 21:43:18 +00:00
drm_probe_ddc ( struct i2c_adapter * adapter )
{
unsigned char out ;
return ( drm_do_probe_ddc_edid ( adapter , & out , 0 , 1 ) = = 0 ) ;
}
2012-09-18 10:58:47 -04:00
EXPORT_SYMBOL ( drm_probe_ddc ) ;
2010-03-29 21:43:18 +00:00
/**
* drm_get_edid - get EDID data , if available
* @ connector : connector we ' re probing
2014-04-29 11:44:34 +02:00
* @ adapter : I2C adapter to use for DDC
2010-03-29 21:43:18 +00:00
*
2014-04-29 11:44:34 +02:00
* Poke the given I2C channel to grab EDID data if possible . If found ,
2010-03-29 21:43:18 +00:00
* attach it to the connector .
*
2014-04-29 11:44:34 +02:00
* Return : Pointer to valid EDID or NULL if we couldn ' t find any .
2010-03-29 21:43:18 +00:00
*/
struct edid * drm_get_edid ( struct drm_connector * connector ,
struct i2c_adapter * adapter )
{
2020-06-30 05:56:59 +05:30
struct edid * edid ;
2017-02-17 17:20:53 +02:00
if ( connector - > force = = DRM_FORCE_OFF )
return NULL ;
if ( connector - > force = = DRM_FORCE_UNSPECIFIED & & ! drm_probe_ddc ( adapter ) )
2012-04-27 11:11:58 +02:00
return NULL ;
2010-03-29 21:43:18 +00:00
2022-06-08 10:50:35 +03:00
edid = _drm_do_get_edid ( connector , drm_do_probe_ddc_edid , adapter , NULL ) ;
2020-06-30 05:56:59 +05:30
drm_connector_update_edid_property ( connector , edid ) ;
return edid ;
2010-03-29 21:43:18 +00:00
}
EXPORT_SYMBOL ( drm_get_edid ) ;
2022-06-08 10:50:35 +03:00
/**
* drm_edid_read_custom - Read EDID data using given EDID block read function
* @ connector : Connector to use
* @ read_block : EDID block read function
* @ context : Private data passed to the block read function
*
* When the I2C adapter connected to the DDC bus is hidden behind a device that
* exposes a different interface to read EDID blocks this function can be used
* to get EDID data using a custom block read function .
*
* As in the general case the DDC bus is accessible by the kernel at the I2C
* level , drivers must make all reasonable efforts to expose it as an I2C
* adapter and use drm_edid_read ( ) or drm_edid_read_ddc ( ) instead of abusing
* this function .
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
* ( drm_load_edid_firmware ( ) and drm . edid_firmware parameter ) , in this priority
* order . Having either of them bypasses actual EDID reads .
*
* The returned pointer must be freed using drm_edid_free ( ) .
*
* Return : Pointer to EDID , or NULL if probe / read failed .
*/
const struct drm_edid * drm_edid_read_custom ( struct drm_connector * connector ,
read_block_fn read_block ,
void * context )
{
const struct drm_edid * drm_edid ;
struct edid * edid ;
size_t size = 0 ;
edid = _drm_do_get_edid ( connector , read_block , context , & size ) ;
if ( ! edid )
return NULL ;
/* Sanity check for now */
drm_WARN_ON ( connector - > dev , ! size ) ;
drm_edid = _drm_edid_alloc ( edid , size ) ;
if ( ! drm_edid )
kfree ( edid ) ;
return drm_edid ;
}
EXPORT_SYMBOL ( drm_edid_read_custom ) ;
/**
* drm_edid_read_ddc - Read EDID data using given I2C adapter
* @ connector : Connector to use
* @ adapter : I2C adapter to use for DDC
*
* Read EDID using the given I2C adapter .
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
* ( drm_load_edid_firmware ( ) and drm . edid_firmware parameter ) , in this priority
* order . Having either of them bypasses actual EDID reads .
*
* Prefer initializing connector - > ddc with drm_connector_init_with_ddc ( ) and
* using drm_edid_read ( ) instead of this function .
*
* The returned pointer must be freed using drm_edid_free ( ) .
*
* Return : Pointer to EDID , or NULL if probe / read failed .
*/
const struct drm_edid * drm_edid_read_ddc ( struct drm_connector * connector ,
struct i2c_adapter * adapter )
{
const struct drm_edid * drm_edid ;
if ( connector - > force = = DRM_FORCE_OFF )
return NULL ;
if ( connector - > force = = DRM_FORCE_UNSPECIFIED & & ! drm_probe_ddc ( adapter ) )
return NULL ;
drm_edid = drm_edid_read_custom ( connector , drm_do_probe_ddc_edid , adapter ) ;
/* Note: Do *not* call connector updates here. */
return drm_edid ;
}
EXPORT_SYMBOL ( drm_edid_read_ddc ) ;
/**
* drm_edid_read - Read EDID data using connector ' s I2C adapter
* @ connector : Connector to use
*
* Read EDID using the connector ' s I2C adapter .
*
* The EDID may be overridden using debugfs override_edid or firmware EDID
* ( drm_load_edid_firmware ( ) and drm . edid_firmware parameter ) , in this priority
* order . Having either of them bypasses actual EDID reads .
*
* The returned pointer must be freed using drm_edid_free ( ) .
*
* Return : Pointer to EDID , or NULL if probe / read failed .
*/
const struct drm_edid * drm_edid_read ( struct drm_connector * connector )
{
if ( drm_WARN_ON ( connector - > dev , ! connector - > ddc ) )
return NULL ;
return drm_edid_read_ddc ( connector , connector - > ddc ) ;
}
EXPORT_SYMBOL ( drm_edid_read ) ;
2021-09-14 13:21:50 -07:00
static u32 edid_extract_panel_id ( const struct edid * edid )
{
/*
2021-09-14 13:21:51 -07:00
* We represent the ID as a 32 - bit number so it can easily be compared
* with " == " .
2021-09-14 13:21:50 -07:00
*
* NOTE that we deal with endianness differently for the top half
* of this ID than for the bottom half . The bottom half ( the product
* id ) gets decoded as little endian by the EDID_PRODUCT_ID because
* that ' s how everyone seems to interpret it . The top half ( the mfg_id )
* gets stored as big endian because that makes
* drm_edid_encode_panel_id ( ) and drm_edid_decode_panel_id ( ) easier
* to write ( it ' s easier to extract the ASCII ) . It doesn ' t really
* matter , though , as long as the number here is unique .
*/
return ( u32 ) edid - > mfg_id [ 0 ] < < 24 |
( u32 ) edid - > mfg_id [ 1 ] < < 16 |
( u32 ) EDID_PRODUCT_ID ( edid ) ;
}
/**
* drm_edid_get_panel_id - Get a panel ' s ID through DDC
* @ adapter : I2C adapter to use for DDC
*
* This function reads the first block of the EDID of a panel and ( assuming
* that the EDID is valid ) extracts the ID out of it . The ID is a 32 - bit value
* ( 16 bits of manufacturer ID and 16 bits of per - manufacturer ID ) that ' s
* supposed to be different for each different modem of panel .
*
* This function is intended to be used during early probing on devices where
* more than one panel might be present . Because of its intended use it must
* assume that the EDID of the panel is correct , at least as far as the ID
* is concerned ( in other words , we don ' t process any overrides here ) .
*
* NOTE : it ' s expected that this function and drm_do_get_edid ( ) will both
* be read the EDID , but there is no caching between them . Since we ' re only
* reading the first block , hopefully this extra overhead won ' t be too big .
*
* Return : A 32 - bit ID that should be different for each make / model of panel .
* See the functions drm_edid_encode_panel_id ( ) and
* drm_edid_decode_panel_id ( ) for some details on the structure of this
* ID .
*/
u32 drm_edid_get_panel_id ( struct i2c_adapter * adapter )
{
2022-04-11 17:00:30 +03:00
enum edid_block_status status ;
void * base_block ;
u32 panel_id = 0 ;
2021-09-14 13:21:50 -07:00
/*
* There are no manufacturer IDs of 0 , so if there is a problem reading
* the EDID then we ' ll just return 0.
*/
2022-04-11 17:00:30 +03:00
base_block = kmalloc ( EDID_LENGTH , GFP_KERNEL ) ;
if ( ! base_block )
2021-09-14 13:21:50 -07:00
return 0 ;
2022-04-11 17:00:30 +03:00
status = edid_block_read ( base_block , 0 , drm_do_probe_ddc_edid , adapter ) ;
edid_block_status_print ( status , base_block , 0 ) ;
if ( edid_block_status_valid ( status , edid_block_tag ( base_block ) ) )
panel_id = edid_extract_panel_id ( base_block ) ;
kfree ( base_block ) ;
2021-09-14 13:21:50 -07:00
return panel_id ;
}
EXPORT_SYMBOL ( drm_edid_get_panel_id ) ;
drm/edid: Switch DDC when reading the EDID
Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
Some dual graphics machines support muxing the DDC separately from
the display, so make use of this functionality when reading the EDID
on the inactive GPU. Also serialize drm_get_edid() with a mutex to
avoid races on the DDC mux state.
Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
I can't figure out why I didn't like this, but I rewrote this [...]
to lock/unlock the ddc lines [...]. I think I'd prefer something
like that otherwise the interface got really ugly.
Modified by Lukas Wunner <lukas@wunner.de>, 2015-04 - 2015-09:
v3: Move vga_switcheroo calls to a wrapper around drm_get_edid()
which drivers can call on muxed machines. This avoids other
drivers having to go through the vga_switcheroo motions even
though they are never used on a muxed platform
(Thierry Reding, Daniel Vetter, Alex Deucher)
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina 15"]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina 15"]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina 15"]
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Dave Airlie <airlied@gmail.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/b898d0da4c134f2642d0122479006863e1830723.1452525860.git.lukas@wunner.de
2016-01-11 20:09:20 +01:00
/**
* drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
* @ connector : connector we ' re probing
* @ adapter : I2C adapter to use for DDC
*
* Wrapper around drm_get_edid ( ) for laptops with dual GPUs using one set of
* outputs . The wrapper adds the requisite vga_switcheroo calls to temporarily
* switch DDC to the GPU which is retrieving EDID .
*
* Return : Pointer to valid EDID or % NULL if we couldn ' t find any .
*/
struct edid * drm_get_edid_switcheroo ( struct drm_connector * connector ,
struct i2c_adapter * adapter )
{
2021-01-18 14:14:15 +01:00
struct drm_device * dev = connector - > dev ;
struct pci_dev * pdev = to_pci_dev ( dev - > dev ) ;
drm/edid: Switch DDC when reading the EDID
Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
Some dual graphics machines support muxing the DDC separately from
the display, so make use of this functionality when reading the EDID
on the inactive GPU. Also serialize drm_get_edid() with a mutex to
avoid races on the DDC mux state.
Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
I can't figure out why I didn't like this, but I rewrote this [...]
to lock/unlock the ddc lines [...]. I think I'd prefer something
like that otherwise the interface got really ugly.
Modified by Lukas Wunner <lukas@wunner.de>, 2015-04 - 2015-09:
v3: Move vga_switcheroo calls to a wrapper around drm_get_edid()
which drivers can call on muxed machines. This avoids other
drivers having to go through the vga_switcheroo motions even
though they are never used on a muxed platform
(Thierry Reding, Daniel Vetter, Alex Deucher)
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina 15"]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina 15"]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina 15"]
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Dave Airlie <airlied@gmail.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/b898d0da4c134f2642d0122479006863e1830723.1452525860.git.lukas@wunner.de
2016-01-11 20:09:20 +01:00
struct edid * edid ;
2021-01-18 14:14:15 +01:00
if ( drm_WARN_ON_ONCE ( dev , ! dev_is_pci ( dev - > dev ) ) )
return NULL ;
drm/edid: Switch DDC when reading the EDID
Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
Some dual graphics machines support muxing the DDC separately from
the display, so make use of this functionality when reading the EDID
on the inactive GPU. Also serialize drm_get_edid() with a mutex to
avoid races on the DDC mux state.
Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
I can't figure out why I didn't like this, but I rewrote this [...]
to lock/unlock the ddc lines [...]. I think I'd prefer something
like that otherwise the interface got really ugly.
Modified by Lukas Wunner <lukas@wunner.de>, 2015-04 - 2015-09:
v3: Move vga_switcheroo calls to a wrapper around drm_get_edid()
which drivers can call on muxed machines. This avoids other
drivers having to go through the vga_switcheroo motions even
though they are never used on a muxed platform
(Thierry Reding, Daniel Vetter, Alex Deucher)
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina 15"]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina 15"]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina 15"]
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Dave Airlie <airlied@gmail.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/b898d0da4c134f2642d0122479006863e1830723.1452525860.git.lukas@wunner.de
2016-01-11 20:09:20 +01:00
vga_switcheroo_lock_ddc ( pdev ) ;
edid = drm_get_edid ( connector , adapter ) ;
vga_switcheroo_unlock_ddc ( pdev ) ;
return edid ;
}
EXPORT_SYMBOL ( drm_get_edid_switcheroo ) ;
2013-09-27 15:08:27 +03:00
/**
* drm_edid_duplicate - duplicate an EDID and the extensions
* @ edid : EDID to duplicate
*
2014-04-29 11:44:34 +02:00
* Return : Pointer to duplicated EDID or NULL on allocation failure .
2013-09-27 15:08:27 +03:00
*/
struct edid * drm_edid_duplicate ( const struct edid * edid )
{
2022-04-11 17:00:35 +03:00
return kmemdup ( edid , edid_size ( edid ) , GFP_KERNEL ) ;
2013-09-27 15:08:27 +03:00
}
EXPORT_SYMBOL ( drm_edid_duplicate ) ;
2010-03-29 21:43:18 +00:00
/*** EDID parsing ***/
2008-11-07 14:05:41 -08:00
/**
* edid_get_quirks - return quirk flags for a given EDID
2022-05-11 12:21:04 +03:00
* @ drm_edid : EDID to process
2008-11-07 14:05:41 -08:00
*
* This tells subsequent routines what fixes they need to apply .
*/
2022-05-11 12:21:04 +03:00
static u32 edid_get_quirks ( const struct drm_edid * drm_edid )
2008-11-07 14:05:41 -08:00
{
2022-05-11 12:21:04 +03:00
u32 panel_id = edid_extract_panel_id ( drm_edid - > edid ) ;
2016-12-28 13:06:26 +02:00
const struct edid_quirk * quirk ;
2008-11-07 14:05:41 -08:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( edid_quirk_list ) ; i + + ) {
quirk = & edid_quirk_list [ i ] ;
2021-09-14 13:21:51 -07:00
if ( quirk - > panel_id = = panel_id )
2008-11-07 14:05:41 -08:00
return quirk - > quirks ;
}
return 0 ;
}
# define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
2013-08-15 11:42:14 -04:00
# define MODE_REFRESH_DIFF(c,t) (abs((c) - (t)))
2008-11-07 14:05:41 -08:00
2022-04-26 12:19:13 +03:00
/*
* Walk the mode list for connector , clearing the preferred status on existing
* modes and setting it anew for the right mode ala quirks .
2008-11-07 14:05:41 -08:00
*/
static void edid_fixup_preferred ( struct drm_connector * connector ,
u32 quirks )
{
struct drm_display_mode * t , * cur_mode , * preferred_mode ;
2008-12-18 16:59:02 +10:00
int target_refresh = 0 ;
2013-08-15 11:42:14 -04:00
int cur_vrefresh , preferred_vrefresh ;
2008-11-07 14:05:41 -08:00
if ( list_empty ( & connector - > probed_modes ) )
return ;
if ( quirks & EDID_QUIRK_PREFER_LARGE_60 )
target_refresh = 60 ;
if ( quirks & EDID_QUIRK_PREFER_LARGE_75 )
target_refresh = 75 ;
preferred_mode = list_first_entry ( & connector - > probed_modes ,
struct drm_display_mode , head ) ;
list_for_each_entry_safe ( cur_mode , t , & connector - > probed_modes , head ) {
cur_mode - > type & = ~ DRM_MODE_TYPE_PREFERRED ;
if ( cur_mode = = preferred_mode )
continue ;
/* Largest mode is preferred */
if ( MODE_SIZE ( cur_mode ) > MODE_SIZE ( preferred_mode ) )
preferred_mode = cur_mode ;
2020-04-28 20:19:27 +03:00
cur_vrefresh = drm_mode_vrefresh ( cur_mode ) ;
preferred_vrefresh = drm_mode_vrefresh ( preferred_mode ) ;
2008-11-07 14:05:41 -08:00
/* At a given size, try to get closest to target refresh */
if ( ( MODE_SIZE ( cur_mode ) = = MODE_SIZE ( preferred_mode ) ) & &
2013-08-15 11:42:14 -04:00
MODE_REFRESH_DIFF ( cur_vrefresh , target_refresh ) <
MODE_REFRESH_DIFF ( preferred_vrefresh , target_refresh ) ) {
2008-11-07 14:05:41 -08:00
preferred_mode = cur_mode ;
}
}
preferred_mode - > type | = DRM_MODE_TYPE_PREFERRED ;
}
2012-04-13 16:33:31 -04:00
static bool
mode_is_rb ( const struct drm_display_mode * mode )
{
return ( mode - > htotal - mode - > hdisplay = = 160 ) & &
( mode - > hsync_end - mode - > hdisplay = = 80 ) & &
( mode - > hsync_end - mode - > hsync_start = = 32 ) & &
( mode - > vsync_start - mode - > vdisplay = = 3 ) ;
}
2012-04-13 16:33:29 -04:00
/*
* drm_mode_find_dmt - Create a copy of a mode if present in DMT
* @ dev : Device to duplicate against
* @ hsize : Mode width
* @ vsize : Mode height
* @ fresh : Mode refresh rate
2012-04-13 16:33:31 -04:00
* @ rb : Mode reduced - blanking - ness
2012-04-13 16:33:29 -04:00
*
* Walk the DMT mode list looking for a match for the given parameters .
2014-04-29 11:44:34 +02:00
*
* Return : A newly allocated copy of the mode , or NULL if not found .
2012-04-13 16:33:29 -04:00
*/
2010-05-07 05:02:30 +00:00
struct drm_display_mode * drm_mode_find_dmt ( struct drm_device * dev ,
2012-04-13 16:33:31 -04:00
int hsize , int vsize , int fresh ,
bool rb )
2009-09-03 09:33:47 +08:00
{
2009-12-03 17:44:38 -05:00
int i ;
2009-09-03 09:33:47 +08:00
2012-11-23 15:01:42 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( drm_dmt_modes ) ; i + + ) {
2011-01-26 09:49:47 +00:00
const struct drm_display_mode * ptr = & drm_dmt_modes [ i ] ;
2020-07-02 18:53:32 +05:30
2012-04-13 16:33:30 -04:00
if ( hsize ! = ptr - > hdisplay )
continue ;
if ( vsize ! = ptr - > vdisplay )
continue ;
if ( fresh ! = drm_mode_vrefresh ( ptr ) )
continue ;
2012-04-13 16:33:31 -04:00
if ( rb ! = mode_is_rb ( ptr ) )
continue ;
2012-04-13 16:33:30 -04:00
return drm_mode_duplicate ( dev , ptr ) ;
2009-09-03 09:33:47 +08:00
}
2012-04-13 16:33:30 -04:00
return NULL ;
2009-09-03 09:33:47 +08:00
}
2010-05-07 05:02:30 +00:00
EXPORT_SYMBOL ( drm_mode_find_dmt ) ;
2009-09-23 17:30:58 -04:00
2022-03-28 17:34:24 +03:00
static bool is_display_descriptor ( const struct detailed_timing * descriptor , u8 type )
2020-01-24 22:02:25 +02:00
{
2022-03-28 17:34:24 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , pixel_clock ) ! = 0 ) ;
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . pad1 ) ! = 2 ) ;
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . type ) ! = 3 ) ;
return descriptor - > pixel_clock = = 0 & &
descriptor - > data . other_data . pad1 = = 0 & &
descriptor - > data . other_data . type = = type ;
2020-01-24 22:02:25 +02:00
}
2022-03-28 17:34:25 +03:00
static bool is_detailed_timing_descriptor ( const struct detailed_timing * descriptor )
2020-01-24 22:02:26 +02:00
{
2022-03-28 17:34:25 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , pixel_clock ) ! = 0 ) ;
return descriptor - > pixel_clock ! = 0 ;
2020-01-24 22:02:26 +02:00
}
2022-03-28 17:34:29 +03:00
typedef void detailed_cb ( const struct detailed_timing * timing , void * closure ) ;
2010-03-29 21:43:26 +00:00
2010-08-03 14:38:17 -04:00
static void
2022-03-28 17:34:30 +03:00
cea_for_each_detailed_block ( const u8 * ext , detailed_cb * cb , void * closure )
2010-08-03 14:38:17 -04:00
{
2020-01-24 22:02:24 +02:00
int i , n ;
2011-12-19 20:03:43 +01:00
u8 d = ext [ 0x02 ] ;
2022-03-28 17:34:30 +03:00
const u8 * det_base = ext + d ;
2010-08-03 14:38:17 -04:00
2020-01-24 22:02:24 +02:00
if ( d < 4 | | d > 127 )
return ;
2011-12-19 20:03:43 +01:00
n = ( 127 - d ) / 18 ;
2010-08-03 14:38:17 -04:00
for ( i = 0 ; i < n ; i + + )
2022-03-28 17:34:30 +03:00
cb ( ( const struct detailed_timing * ) ( det_base + 18 * i ) , closure ) ;
2010-08-03 14:38:17 -04:00
}
2010-08-03 14:38:18 -04:00
static void
2022-03-28 17:34:30 +03:00
vtb_for_each_detailed_block ( const u8 * ext , detailed_cb * cb , void * closure )
2010-08-03 14:38:18 -04:00
{
unsigned int i , n = min ( ( int ) ext [ 0x02 ] , 6 ) ;
2022-03-28 17:34:30 +03:00
const u8 * det_base = ext + 5 ;
2010-08-03 14:38:18 -04:00
if ( ext [ 0x01 ] ! = 1 )
return ; /* unknown version */
for ( i = 0 ; i < n ; i + + )
2022-03-28 17:34:30 +03:00
cb ( ( const struct detailed_timing * ) ( det_base + 18 * i ) , closure ) ;
2010-08-03 14:38:18 -04:00
}
2022-05-09 15:03:15 +03:00
static void drm_for_each_detailed_block ( const struct drm_edid * drm_edid ,
detailed_cb * cb , void * closure )
2010-03-29 21:43:26 +00:00
{
2022-05-09 15:03:01 +03:00
struct drm_edid_iter edid_iter ;
const u8 * ext ;
2010-03-29 21:43:26 +00:00
int i ;
2022-05-09 15:03:15 +03:00
if ( ! drm_edid )
2010-03-29 21:43:26 +00:00
return ;
for ( i = 0 ; i < EDID_DETAILED_TIMINGS ; i + + )
2022-05-09 15:03:15 +03:00
cb ( & drm_edid - > edid - > detailed_timings [ i ] , closure ) ;
2010-03-29 21:43:26 +00:00
2022-05-09 15:03:21 +03:00
drm_edid_iter_begin ( drm_edid , & edid_iter ) ;
2022-05-09 15:03:01 +03:00
drm_edid_iter_for_each ( ext , & edid_iter ) {
2010-08-03 14:38:17 -04:00
switch ( * ext ) {
case CEA_EXT :
cea_for_each_detailed_block ( ext , cb , closure ) ;
break ;
2010-08-03 14:38:18 -04:00
case VTB_EXT :
vtb_for_each_detailed_block ( ext , cb , closure ) ;
break ;
2010-08-03 14:38:17 -04:00
default :
break ;
}
}
2022-05-09 15:03:01 +03:00
drm_edid_iter_end ( & edid_iter ) ;
2010-03-29 21:43:26 +00:00
}
static void
2022-03-28 17:34:29 +03:00
is_rb ( const struct detailed_timing * descriptor , void * data )
2010-03-29 21:43:26 +00:00
{
2022-03-28 17:34:26 +03:00
bool * res = data ;
2020-01-24 22:02:25 +02:00
2022-03-28 17:34:26 +03:00
if ( ! is_display_descriptor ( descriptor , EDID_DETAIL_MONITOR_RANGE ) )
2020-01-24 22:02:25 +02:00
return ;
2022-03-28 17:34:26 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . flags ) ! = 10 ) ;
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . formula . cvt . flags ) ! = 15 ) ;
if ( descriptor - > data . other_data . data . range . flags = = DRM_EDID_CVT_SUPPORT_FLAG & &
descriptor - > data . other_data . data . range . formula . cvt . flags & 0x10 )
* res = true ;
2010-03-29 21:43:26 +00:00
}
/* EDID 1.4 defines this explicitly. For EDID 1.3, we guess, badly. */
static bool
2022-05-09 15:03:13 +03:00
drm_monitor_supports_rb ( const struct drm_edid * drm_edid )
2010-03-29 21:43:26 +00:00
{
2022-05-09 15:03:13 +03:00
if ( drm_edid - > edid - > revision > = 4 ) {
2012-06-19 11:33:06 +02:00
bool ret = false ;
2020-07-02 18:53:32 +05:30
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , is_rb , & ret ) ;
2010-03-29 21:43:26 +00:00
return ret ;
}
2022-05-09 15:03:13 +03:00
return ( ( drm_edid - > edid - > input & DRM_EDID_INPUT_DIGITAL ) ! = 0 ) ;
2010-03-29 21:43:26 +00:00
}
2010-03-29 21:43:30 +00:00
static void
2022-03-28 17:34:29 +03:00
find_gtf2 ( const struct detailed_timing * descriptor , void * data )
2010-03-29 21:43:30 +00:00
{
2022-03-28 17:34:29 +03:00
const struct detailed_timing * * res = data ;
2020-01-24 22:02:25 +02:00
2022-03-28 17:34:27 +03:00
if ( ! is_display_descriptor ( descriptor , EDID_DETAIL_MONITOR_RANGE ) )
2020-01-24 22:02:25 +02:00
return ;
2022-03-28 17:34:27 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . flags ) ! = 10 ) ;
if ( descriptor - > data . other_data . data . range . flags = = 0x02 )
* res = descriptor ;
2010-03-29 21:43:30 +00:00
}
/* Secondary GTF curve kicks in above some break frequency */
static int
2022-05-09 15:03:12 +03:00
drm_gtf2_hbreak ( const struct drm_edid * drm_edid )
2010-03-29 21:43:30 +00:00
{
2022-03-28 17:34:29 +03:00
const struct detailed_timing * descriptor = NULL ;
2022-03-28 17:34:27 +03:00
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , find_gtf2 , & descriptor ) ;
2020-07-02 18:53:32 +05:30
2022-03-28 17:34:27 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . formula . gtf2 . hfreq_start_khz ) ! = 12 ) ;
return descriptor ? descriptor - > data . other_data . data . range . formula . gtf2 . hfreq_start_khz * 2 : 0 ;
2010-03-29 21:43:30 +00:00
}
static int
2022-05-09 15:03:12 +03:00
drm_gtf2_2c ( const struct drm_edid * drm_edid )
2010-03-29 21:43:30 +00:00
{
2022-03-28 17:34:29 +03:00
const struct detailed_timing * descriptor = NULL ;
2022-03-28 17:34:27 +03:00
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , find_gtf2 , & descriptor ) ;
2022-03-28 17:34:27 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . formula . gtf2 . c ) ! = 13 ) ;
2020-07-02 18:53:32 +05:30
2022-03-28 17:34:27 +03:00
return descriptor ? descriptor - > data . other_data . data . range . formula . gtf2 . c : 0 ;
2010-03-29 21:43:30 +00:00
}
static int
2022-05-09 15:03:12 +03:00
drm_gtf2_m ( const struct drm_edid * drm_edid )
2010-03-29 21:43:30 +00:00
{
2022-03-28 17:34:29 +03:00
const struct detailed_timing * descriptor = NULL ;
2020-07-02 18:53:32 +05:30
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , find_gtf2 , & descriptor ) ;
2022-03-28 17:34:27 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . formula . gtf2 . m ) ! = 14 ) ;
return descriptor ? le16_to_cpu ( descriptor - > data . other_data . data . range . formula . gtf2 . m ) : 0 ;
2010-03-29 21:43:30 +00:00
}
static int
2022-05-09 15:03:12 +03:00
drm_gtf2_k ( const struct drm_edid * drm_edid )
2010-03-29 21:43:30 +00:00
{
2022-03-28 17:34:29 +03:00
const struct detailed_timing * descriptor = NULL ;
2022-03-28 17:34:27 +03:00
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , find_gtf2 , & descriptor ) ;
2020-07-02 18:53:32 +05:30
2022-03-28 17:34:27 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . formula . gtf2 . k ) ! = 16 ) ;
return descriptor ? descriptor - > data . other_data . data . range . formula . gtf2 . k : 0 ;
2010-03-29 21:43:30 +00:00
}
static int
2022-05-09 15:03:12 +03:00
drm_gtf2_2j ( const struct drm_edid * drm_edid )
2010-03-29 21:43:30 +00:00
{
2022-03-28 17:34:29 +03:00
const struct detailed_timing * descriptor = NULL ;
2022-03-28 17:34:27 +03:00
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , find_gtf2 , & descriptor ) ;
2022-03-28 17:34:27 +03:00
BUILD_BUG_ON ( offsetof ( typeof ( * descriptor ) , data . other_data . data . range . formula . gtf2 . j ) ! = 17 ) ;
2020-07-02 18:53:32 +05:30
2022-03-28 17:34:27 +03:00
return descriptor ? descriptor - > data . other_data . data . range . formula . gtf2 . j : 0 ;
2010-03-29 21:43:30 +00:00
}
2022-04-26 12:19:13 +03:00
/* Get standard timing level (CVT/GTF/DMT). */
2022-05-09 15:03:12 +03:00
static int standard_timing_level ( const struct drm_edid * drm_edid )
2010-03-29 21:43:30 +00:00
{
2022-05-09 15:03:12 +03:00
const struct edid * edid = drm_edid - > edid ;
2010-03-29 21:43:30 +00:00
if ( edid - > revision > = 2 ) {
if ( edid - > revision > = 4 & & ( edid - > features & DRM_EDID_FEATURE_DEFAULT_GTF ) )
return LEVEL_CVT ;
2022-05-09 15:03:12 +03:00
if ( drm_gtf2_hbreak ( drm_edid ) )
2010-03-29 21:43:30 +00:00
return LEVEL_GTF2 ;
2019-10-07 21:51:27 +08:00
if ( edid - > features & DRM_EDID_FEATURE_DEFAULT_GTF )
return LEVEL_GTF ;
2010-03-29 21:43:30 +00:00
}
return LEVEL_DMT ;
}
2009-09-23 17:30:58 -04:00
/*
* 0 is reserved . The spec says 0x01 fill for unused timings . Some old
* monitors fill with ascii space ( 0x20 ) instead .
*/
static int
bad_std_timing ( u8 a , u8 b )
{
return ( a = = 0x00 & & b = = 0x00 ) | |
( a = = 0x01 & & b = = 0x01 ) | |
( a = = 0x20 & & b = = 0x20 ) ;
}
2020-04-28 20:19:25 +03:00
static int drm_mode_hsync ( const struct drm_display_mode * mode )
{
if ( mode - > htotal < = 0 )
return 0 ;
return DIV_ROUND_CLOSEST ( mode - > clock , mode - > htotal ) ;
}
2022-04-26 12:19:13 +03:00
/*
2008-11-07 14:05:41 -08:00
* Take the standard timing params ( in this case width , aspect , and refresh )
2009-06-22 13:17:10 +08:00
* and convert them into a real mode using CVT / GTF / DMT .
2008-11-07 14:05:41 -08:00
*/
2022-05-09 15:03:12 +03:00
static struct drm_display_mode * drm_mode_std ( struct drm_connector * connector ,
const struct drm_edid * drm_edid ,
const struct std_timing * t )
2008-11-07 14:05:41 -08:00
{
2010-03-29 21:43:29 +00:00
struct drm_device * dev = connector - > dev ;
struct drm_display_mode * m , * mode = NULL ;
2009-06-22 13:17:10 +08:00
int hsize , vsize ;
int vrefresh_rate ;
2009-06-15 16:56:07 +02:00
unsigned aspect_ratio = ( t - > vfreq_aspect & EDID_TIMING_ASPECT_MASK )
> > EDID_TIMING_ASPECT_SHIFT ;
2009-06-22 13:17:10 +08:00
unsigned vfreq = ( t - > vfreq_aspect & EDID_TIMING_VFREQ_MASK )
> > EDID_TIMING_VFREQ_SHIFT ;
2022-05-09 15:03:12 +03:00
int timing_level = standard_timing_level ( drm_edid ) ;
2009-06-22 13:17:10 +08:00
2009-09-23 17:30:58 -04:00
if ( bad_std_timing ( t - > hsize , t - > vfreq_aspect ) )
return NULL ;
2009-06-22 13:17:10 +08:00
/* According to the EDID spec, the hdisplay = hsize * 8 + 248 */
hsize = t - > hsize * 8 + 248 ;
/* vrefresh_rate = vfreq + 60 */
vrefresh_rate = vfreq + 60 ;
/* the vdisplay is calculated based on the aspect ratio */
2009-09-23 17:31:21 -04:00
if ( aspect_ratio = = 0 ) {
2022-05-09 15:03:12 +03:00
if ( drm_edid - > edid - > revision < 3 )
2009-09-23 17:31:21 -04:00
vsize = hsize ;
else
vsize = ( hsize * 10 ) / 16 ;
} else if ( aspect_ratio = = 1 )
2008-11-07 14:05:41 -08:00
vsize = ( hsize * 3 ) / 4 ;
2009-06-15 16:56:07 +02:00
else if ( aspect_ratio = = 2 )
2008-11-07 14:05:41 -08:00
vsize = ( hsize * 4 ) / 5 ;
else
vsize = ( hsize * 9 ) / 16 ;
2010-03-29 21:43:28 +00:00
/* HDTV hack, part 1 */
if ( vrefresh_rate = = 60 & &
( ( hsize = = 1360 & & vsize = = 765 ) | |
( hsize = = 1368 & & vsize = = 769 ) ) ) {
hsize = 1366 ;
vsize = 768 ;
}
2010-03-29 21:43:29 +00:00
/*
* If this connector already has a mode for this size and refresh
* rate ( because it came from detailed or CVT info ) , use that
* instead . This way we don ' t have to guess at interlace or
* reduced blanking .
*/
2010-04-09 16:52:49 +00:00
list_for_each_entry ( m , & connector - > probed_modes , head )
2010-03-29 21:43:29 +00:00
if ( m - > hdisplay = = hsize & & m - > vdisplay = = vsize & &
drm_mode_vrefresh ( m ) = = vrefresh_rate )
return NULL ;
2010-03-29 21:43:28 +00:00
/* HDTV hack, part 2 */
if ( hsize = = 1366 & & vsize = = 768 & & vrefresh_rate = = 60 ) {
mode = drm_cvt_mode ( dev , 1366 , 768 , vrefresh_rate , 0 , 0 ,
drm/kms: start adding command line interface using fb.
[note this requires an fb patch posted to linux-fbdev-devel already]
This uses the normal video= command line option to control the kms
output setup at boot time. It is used to override the autodetection
done by kms.
video= normally takes a framebuffer as the first parameter, in kms
it will take a connector name, DVI-I-1, or LVDS-1 etc. If no output
connector is specified the mode string will apply to all connectors.
The mode specification used will match down the probed modes, and if
no mode is found it will add a CVT mode that matches.
video=1024x768 - all connectors match a 1024x768 mode or add a CVT on
video=VGA-1:1024x768, VGA-1 connector gets mode only.
The same strings as used in current fb modedb.c are used, except I've
added three more letters, e, D, d, e = enable, D = enable Digital,
d = disable, which allow a connector to be forced into a certain state.
Signed-off-by: Dave Airlie <airlied@redhat.com>
2009-09-23 14:44:08 +10:00
false ) ;
2018-02-12 14:51:43 -05:00
if ( ! mode )
return NULL ;
2009-09-03 09:33:47 +08:00
mode - > hdisplay = 1366 ;
2010-07-28 07:40:32 +10:00
mode - > hsync_start = mode - > hsync_start - 1 ;
mode - > hsync_end = mode - > hsync_end - 1 ;
2009-09-03 09:33:47 +08:00
return mode ;
}
2010-03-29 21:43:28 +00:00
2009-09-03 09:33:47 +08:00
/* check whether it can be found in default mode table */
2022-05-09 15:03:13 +03:00
if ( drm_monitor_supports_rb ( drm_edid ) ) {
2012-04-13 16:33:31 -04:00
mode = drm_mode_find_dmt ( dev , hsize , vsize , vrefresh_rate ,
true ) ;
if ( mode )
return mode ;
}
mode = drm_mode_find_dmt ( dev , hsize , vsize , vrefresh_rate , false ) ;
2009-09-03 09:33:47 +08:00
if ( mode )
return mode ;
2012-04-13 16:33:31 -04:00
/* okay, generate it */
2009-06-22 13:17:10 +08:00
switch ( timing_level ) {
case LEVEL_DMT :
break ;
case LEVEL_GTF :
mode = drm_gtf_mode ( dev , hsize , vsize , vrefresh_rate , 0 , 0 ) ;
break ;
2010-03-29 21:43:30 +00:00
case LEVEL_GTF2 :
/*
* This is potentially wrong if there ' s ever a monitor with
* more than one ranges section , each claiming a different
* secondary GTF curve . Please don ' t do that .
*/
mode = drm_gtf_mode ( dev , hsize , vsize , vrefresh_rate , 0 , 0 ) ;
2012-04-20 12:59:33 +01:00
if ( ! mode )
return NULL ;
2022-05-09 15:03:12 +03:00
if ( drm_mode_hsync ( mode ) > drm_gtf2_hbreak ( drm_edid ) ) {
2012-02-01 11:38:21 +01:00
drm_mode_destroy ( dev , mode ) ;
2010-03-29 21:43:30 +00:00
mode = drm_gtf_mode_complex ( dev , hsize , vsize ,
vrefresh_rate , 0 , 0 ,
2022-05-09 15:03:12 +03:00
drm_gtf2_m ( drm_edid ) ,
drm_gtf2_2c ( drm_edid ) ,
drm_gtf2_k ( drm_edid ) ,
drm_gtf2_2j ( drm_edid ) ) ;
2010-03-29 21:43:30 +00:00
}
break ;
2009-06-22 13:17:10 +08:00
case LEVEL_CVT :
drm/kms: start adding command line interface using fb.
[note this requires an fb patch posted to linux-fbdev-devel already]
This uses the normal video= command line option to control the kms
output setup at boot time. It is used to override the autodetection
done by kms.
video= normally takes a framebuffer as the first parameter, in kms
it will take a connector name, DVI-I-1, or LVDS-1 etc. If no output
connector is specified the mode string will apply to all connectors.
The mode specification used will match down the probed modes, and if
no mode is found it will add a CVT mode that matches.
video=1024x768 - all connectors match a 1024x768 mode or add a CVT on
video=VGA-1:1024x768, VGA-1 connector gets mode only.
The same strings as used in current fb modedb.c are used, except I've
added three more letters, e, D, d, e = enable, D = enable Digital,
d = disable, which allow a connector to be forced into a certain state.
Signed-off-by: Dave Airlie <airlied@redhat.com>
2009-09-23 14:44:08 +10:00
mode = drm_cvt_mode ( dev , hsize , vsize , vrefresh_rate , 0 , 0 ,
false ) ;
2009-06-22 13:17:10 +08:00
break ;
}
2008-11-07 14:05:41 -08:00
return mode ;
}
2010-02-15 22:15:39 +00:00
/*
* EDID is delightfully ambiguous about how interlaced modes are to be
* encoded . Our internal representation is of frame height , but some
* HDTV detailed timings are encoded as field height .
*
* The format list here is from CEA , in frame size . Technically we
* should be checking refresh rate too . Whatever .
*/
static void
drm_mode_do_interlace_quirk ( struct drm_display_mode * mode ,
2022-03-28 17:34:28 +03:00
const struct detailed_pixel_timing * pt )
2010-02-15 22:15:39 +00:00
{
int i ;
static const struct {
int w , h ;
} cea_interlaced [ ] = {
{ 1920 , 1080 } ,
{ 720 , 480 } ,
{ 1440 , 480 } ,
{ 2880 , 480 } ,
{ 720 , 576 } ,
{ 1440 , 576 } ,
{ 2880 , 576 } ,
} ;
if ( ! ( pt - > misc & DRM_EDID_PT_INTERLACED ) )
return ;
2010-06-28 15:54:52 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( cea_interlaced ) ; i + + ) {
2010-02-15 22:15:39 +00:00
if ( ( mode - > hdisplay = = cea_interlaced [ i ] . w ) & &
( mode - > vdisplay = = cea_interlaced [ i ] . h / 2 ) ) {
mode - > vdisplay * = 2 ;
mode - > vsync_start * = 2 ;
mode - > vsync_end * = 2 ;
mode - > vtotal * = 2 ;
mode - > vtotal | = 1 ;
}
}
mode - > flags | = DRM_MODE_FLAG_INTERLACE ;
}
2022-04-26 12:19:13 +03:00
/*
* Create a new mode from an EDID detailed timing section . An EDID detailed
* timing block contains enough info for us to create and return a new struct
* drm_display_mode .
2008-11-07 14:05:41 -08:00
*/
static struct drm_display_mode * drm_mode_detailed ( struct drm_device * dev ,
2022-05-09 15:03:08 +03:00
const struct drm_edid * drm_edid ,
2022-03-28 17:34:28 +03:00
const struct detailed_timing * timing ,
2008-11-07 14:05:41 -08:00
u32 quirks )
{
struct drm_display_mode * mode ;
2022-03-28 17:34:28 +03:00
const struct detailed_pixel_timing * pt = & timing - > data . pixel_data ;
2009-06-15 16:56:07 +02:00
unsigned hactive = ( pt - > hactive_hblank_hi & 0xf0 ) < < 4 | pt - > hactive_lo ;
unsigned vactive = ( pt - > vactive_vblank_hi & 0xf0 ) < < 4 | pt - > vactive_lo ;
unsigned hblank = ( pt - > hactive_hblank_hi & 0xf ) < < 8 | pt - > hblank_lo ;
unsigned vblank = ( pt - > vactive_vblank_hi & 0xf ) < < 8 | pt - > vblank_lo ;
2009-06-23 12:36:32 +02:00
unsigned hsync_offset = ( pt - > hsync_vsync_offset_pulse_width_hi & 0xc0 ) < < 2 | pt - > hsync_offset_lo ;
unsigned hsync_pulse_width = ( pt - > hsync_vsync_offset_pulse_width_hi & 0x30 ) < < 4 | pt - > hsync_pulse_width_lo ;
2013-03-23 15:38:22 +01:00
unsigned vsync_offset = ( pt - > hsync_vsync_offset_pulse_width_hi & 0xc ) < < 2 | pt - > vsync_offset_pulse_width_lo > > 4 ;
2009-06-23 12:36:32 +02:00
unsigned vsync_pulse_width = ( pt - > hsync_vsync_offset_pulse_width_hi & 0x3 ) < < 4 | ( pt - > vsync_offset_pulse_width_lo & 0xf ) ;
2008-11-07 14:05:41 -08:00
2009-06-04 10:20:34 +10:00
/* ignore tiny modes */
2009-06-15 16:56:07 +02:00
if ( hactive < 64 | | vactive < 64 )
2009-06-04 10:20:34 +10:00
return NULL ;
2009-06-15 16:56:07 +02:00
if ( pt - > misc & DRM_EDID_PT_STEREO ) {
2013-06-13 21:01:19 +02:00
DRM_DEBUG_KMS ( " stereo mode not supported \n " ) ;
2008-11-07 14:05:41 -08:00
return NULL ;
}
2009-06-15 16:56:07 +02:00
if ( ! ( pt - > misc & DRM_EDID_PT_SEPARATE_SYNC ) ) {
2013-06-13 21:01:19 +02:00
DRM_DEBUG_KMS ( " composite sync not supported \n " ) ;
2008-11-07 14:05:41 -08:00
}
2009-10-14 09:11:25 +08:00
/* it is incorrect if hsync/vsync width is zero */
if ( ! hsync_pulse_width | | ! vsync_pulse_width ) {
DRM_DEBUG_KMS ( " Incorrect Detailed timing. "
" Wrong Hsync/Vsync pulse width \n " ) ;
return NULL ;
}
2012-05-23 16:26:54 -04:00
if ( quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING ) {
mode = drm_cvt_mode ( dev , hactive , vactive , 60 , true , false , false ) ;
if ( ! mode )
return NULL ;
goto set_size ;
}
2008-11-07 14:05:41 -08:00
mode = drm_mode_create ( dev ) ;
if ( ! mode )
return NULL ;
if ( quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH )
2022-03-28 17:34:22 +03:00
mode - > clock = 1088 * 10 ;
else
mode - > clock = le16_to_cpu ( timing - > pixel_clock ) * 10 ;
2009-06-15 16:56:07 +02:00
mode - > hdisplay = hactive ;
mode - > hsync_start = mode - > hdisplay + hsync_offset ;
mode - > hsync_end = mode - > hsync_start + hsync_pulse_width ;
mode - > htotal = mode - > hdisplay + hblank ;
mode - > vdisplay = vactive ;
mode - > vsync_start = mode - > vdisplay + vsync_offset ;
mode - > vsync_end = mode - > vsync_start + vsync_pulse_width ;
mode - > vtotal = mode - > vdisplay + vblank ;
2008-11-07 14:05:41 -08:00
2009-11-05 10:12:54 -08:00
/* Some EDIDs have bogus h/vtotal values */
if ( mode - > hsync_end > mode - > htotal )
mode - > htotal = mode - > hsync_end + 1 ;
if ( mode - > vsync_end > mode - > vtotal )
mode - > vtotal = mode - > vsync_end + 1 ;
2010-02-15 22:15:39 +00:00
drm_mode_do_interlace_quirk ( mode , pt ) ;
2008-11-07 14:05:41 -08:00
if ( quirks & EDID_QUIRK_DETAILED_SYNC_PP ) {
2022-03-28 17:34:22 +03:00
mode - > flags | = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ;
} else {
mode - > flags | = ( pt - > misc & DRM_EDID_PT_HSYNC_POSITIVE ) ?
DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC ;
mode - > flags | = ( pt - > misc & DRM_EDID_PT_VSYNC_POSITIVE ) ?
DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC ;
2008-11-07 14:05:41 -08:00
}
2012-05-23 16:26:54 -04:00
set_size :
2009-06-23 12:36:32 +02:00
mode - > width_mm = pt - > width_mm_lo | ( pt - > width_height_mm_hi & 0xf0 ) < < 4 ;
mode - > height_mm = pt - > height_mm_lo | ( pt - > width_height_mm_hi & 0xf ) < < 8 ;
2008-11-07 14:05:41 -08:00
if ( quirks & EDID_QUIRK_DETAILED_IN_CM ) {
mode - > width_mm * = 10 ;
mode - > height_mm * = 10 ;
}
if ( quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE ) {
2022-05-09 15:03:08 +03:00
mode - > width_mm = drm_edid - > edid - > width_cm * 10 ;
mode - > height_mm = drm_edid - > edid - > height_cm * 10 ;
2008-11-07 14:05:41 -08:00
}
2012-05-23 16:26:54 -04:00
mode - > type = DRM_MODE_TYPE_DRIVER ;
drm_mode_set_name ( mode ) ;
2008-11-07 14:05:41 -08:00
return mode ;
}
2010-03-29 21:43:27 +00:00
static bool
2011-01-26 09:49:47 +00:00
mode_in_hsync_range ( const struct drm_display_mode * mode ,
2022-03-28 17:34:31 +03:00
const struct edid * edid , const u8 * t )
2010-03-29 21:43:27 +00:00
{
int hsync , hmin , hmax ;
hmin = t [ 7 ] ;
if ( edid - > revision > = 4 )
hmin + = ( ( t [ 4 ] & 0x04 ) ? 255 : 0 ) ;
hmax = t [ 8 ] ;
if ( edid - > revision > = 4 )
hmax + = ( ( t [ 4 ] & 0x08 ) ? 255 : 0 ) ;
2009-12-03 17:44:38 -05:00
hsync = drm_mode_hsync ( mode ) ;
2010-03-29 21:43:27 +00:00
return ( hsync < = hmax & & hsync > = hmin ) ;
}
static bool
2011-01-26 09:49:47 +00:00
mode_in_vsync_range ( const struct drm_display_mode * mode ,
2022-03-28 17:34:31 +03:00
const struct edid * edid , const u8 * t )
2010-03-29 21:43:27 +00:00
{
int vsync , vmin , vmax ;
vmin = t [ 5 ] ;
if ( edid - > revision > = 4 )
vmin + = ( ( t [ 4 ] & 0x01 ) ? 255 : 0 ) ;
vmax = t [ 6 ] ;
if ( edid - > revision > = 4 )
vmax + = ( ( t [ 4 ] & 0x02 ) ? 255 : 0 ) ;
vsync = drm_mode_vrefresh ( mode ) ;
return ( vsync < = vmax & & vsync > = vmin ) ;
}
static u32
2022-03-28 17:34:31 +03:00
range_pixel_clock ( const struct edid * edid , const u8 * t )
2010-03-29 21:43:27 +00:00
{
/* unspecified */
if ( t [ 9 ] = = 0 | | t [ 9 ] = = 255 )
return 0 ;
/* 1.4 with CVT support gives us real precision, yay */
if ( edid - > revision > = 4 & & t [ 10 ] = = 0x04 )
return ( t [ 9 ] * 10000 ) - ( ( t [ 12 ] > > 2 ) * 250 ) ;
/* 1.3 is pathetic, so fuzz up a bit */
return t [ 9 ] * 10000 + 5001 ;
}
2022-05-09 15:03:13 +03:00
static bool mode_in_range ( const struct drm_display_mode * mode ,
const struct drm_edid * drm_edid ,
const struct detailed_timing * timing )
2010-03-29 21:43:27 +00:00
{
2022-05-09 15:03:13 +03:00
const struct edid * edid = drm_edid - > edid ;
2010-03-29 21:43:27 +00:00
u32 max_clock ;
2022-03-28 17:34:28 +03:00
const u8 * t = ( const u8 * ) timing ;
2010-03-29 21:43:27 +00:00
if ( ! mode_in_hsync_range ( mode , edid , t ) )
2009-12-03 17:44:38 -05:00
return false ;
2010-03-29 21:43:27 +00:00
if ( ! mode_in_vsync_range ( mode , edid , t ) )
2009-12-03 17:44:38 -05:00
return false ;
2010-03-29 21:43:27 +00:00
if ( ( max_clock = range_pixel_clock ( edid , t ) ) )
2009-12-03 17:44:38 -05:00
if ( mode - > clock > max_clock )
return false ;
2010-03-29 21:43:27 +00:00
/* 1.4 max horizontal check */
if ( edid - > revision > = 4 & & t [ 10 ] = = 0x04 )
if ( t [ 13 ] & & mode - > hdisplay > 8 * ( t [ 13 ] + ( 256 * ( t [ 12 ] & 0x3 ) ) ) )
return false ;
2022-05-09 15:03:13 +03:00
if ( mode_is_rb ( mode ) & & ! drm_monitor_supports_rb ( drm_edid ) )
2010-03-29 21:43:27 +00:00
return false ;
2009-12-03 17:44:38 -05:00
return true ;
}
2012-07-03 11:22:11 +02:00
static bool valid_inferred_mode ( const struct drm_connector * connector ,
const struct drm_display_mode * mode )
{
2015-09-07 18:22:56 +03:00
const struct drm_display_mode * m ;
2012-07-03 11:22:11 +02:00
bool ok = false ;
list_for_each_entry ( m , & connector - > probed_modes , head ) {
if ( mode - > hdisplay = = m - > hdisplay & &
mode - > vdisplay = = m - > vdisplay & &
drm_mode_vrefresh ( mode ) = = drm_mode_vrefresh ( m ) )
return false ; /* duplicated */
if ( mode - > hdisplay < = m - > hdisplay & &
mode - > vdisplay < = m - > vdisplay )
ok = true ;
}
return ok ;
}
2022-05-09 15:03:09 +03:00
static int drm_dmt_modes_for_range ( struct drm_connector * connector ,
const struct drm_edid * drm_edid ,
const struct detailed_timing * timing )
2009-12-03 17:44:38 -05:00
{
int i , modes = 0 ;
struct drm_display_mode * newmode ;
struct drm_device * dev = connector - > dev ;
2012-11-23 15:01:42 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( drm_dmt_modes ) ; i + + ) {
2022-05-09 15:03:13 +03:00
if ( mode_in_range ( drm_dmt_modes + i , drm_edid , timing ) & &
2012-07-03 11:22:11 +02:00
valid_inferred_mode ( connector , drm_dmt_modes + i ) ) {
2009-12-03 17:44:38 -05:00
newmode = drm_mode_duplicate ( dev , & drm_dmt_modes [ i ] ) ;
if ( newmode ) {
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
}
return modes ;
}
2012-04-23 17:40:33 +01:00
/* fix up 1366x768 mode from 1368x768;
* GFT / CVT can ' t express 1366 width which isn ' t dividable by 8
*/
2017-01-17 17:43:29 +01:00
void drm_mode_fixup_1366x768 ( struct drm_display_mode * mode )
2012-04-23 17:40:33 +01:00
{
if ( mode - > hdisplay = = 1368 & & mode - > vdisplay = = 768 ) {
mode - > hdisplay = 1366 ;
mode - > hsync_start - - ;
mode - > hsync_end - - ;
drm_mode_set_name ( mode ) ;
}
}
2022-05-09 15:03:10 +03:00
static int drm_gtf_modes_for_range ( struct drm_connector * connector ,
const struct drm_edid * drm_edid ,
const struct detailed_timing * timing )
2012-04-13 16:33:40 -04:00
{
int i , modes = 0 ;
struct drm_display_mode * newmode ;
struct drm_device * dev = connector - > dev ;
2012-11-23 15:01:42 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( extra_modes ) ; i + + ) {
2012-04-13 16:33:40 -04:00
const struct minimode * m = & extra_modes [ i ] ;
2020-07-02 18:53:32 +05:30
2012-04-13 16:33:40 -04:00
newmode = drm_gtf_mode ( dev , m - > w , m - > h , m - > r , 0 , 0 ) ;
2012-04-20 12:59:33 +01:00
if ( ! newmode )
return modes ;
2012-04-13 16:33:40 -04:00
2017-01-17 17:43:29 +01:00
drm_mode_fixup_1366x768 ( newmode ) ;
2022-05-09 15:03:13 +03:00
if ( ! mode_in_range ( newmode , drm_edid , timing ) | |
2012-07-03 11:22:11 +02:00
! valid_inferred_mode ( connector , newmode ) ) {
2012-04-13 16:33:40 -04:00
drm_mode_destroy ( dev , newmode ) ;
continue ;
}
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
return modes ;
}
2022-05-09 15:03:11 +03:00
static int drm_cvt_modes_for_range ( struct drm_connector * connector ,
const struct drm_edid * drm_edid ,
const struct detailed_timing * timing )
2012-04-13 16:33:40 -04:00
{
int i , modes = 0 ;
struct drm_display_mode * newmode ;
struct drm_device * dev = connector - > dev ;
2022-05-09 15:03:13 +03:00
bool rb = drm_monitor_supports_rb ( drm_edid ) ;
2012-04-13 16:33:40 -04:00
2012-11-23 15:01:42 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( extra_modes ) ; i + + ) {
2012-04-13 16:33:40 -04:00
const struct minimode * m = & extra_modes [ i ] ;
2020-07-02 18:53:32 +05:30
2012-04-13 16:33:40 -04:00
newmode = drm_cvt_mode ( dev , m - > w , m - > h , m - > r , rb , 0 , 0 ) ;
2012-04-20 12:59:33 +01:00
if ( ! newmode )
return modes ;
2012-04-13 16:33:40 -04:00
2017-01-17 17:43:29 +01:00
drm_mode_fixup_1366x768 ( newmode ) ;
2022-05-09 15:03:13 +03:00
if ( ! mode_in_range ( newmode , drm_edid , timing ) | |
2012-07-03 11:22:11 +02:00
! valid_inferred_mode ( connector , newmode ) ) {
2012-04-13 16:33:40 -04:00
drm_mode_destroy ( dev , newmode ) ;
continue ;
}
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
return modes ;
}
2010-08-03 14:38:19 -04:00
static void
2022-03-28 17:34:29 +03:00
do_inferred_modes ( const struct detailed_timing * timing , void * c )
2009-12-03 17:44:40 -05:00
{
2010-08-03 14:38:19 -04:00
struct detailed_mode_closure * closure = c ;
2022-03-28 17:34:28 +03:00
const struct detailed_non_pixel * data = & timing - > data . other_data ;
const struct detailed_data_monitor_range * range = & data - > data . range ;
2009-12-03 17:44:40 -05:00
2022-03-28 17:34:24 +03:00
if ( ! is_display_descriptor ( timing , EDID_DETAIL_MONITOR_RANGE ) )
2012-04-13 16:33:36 -04:00
return ;
closure - > modes + = drm_dmt_modes_for_range ( closure - > connector ,
2022-05-09 15:03:09 +03:00
closure - > drm_edid ,
2012-04-13 16:33:36 -04:00
timing ) ;
2020-01-24 22:02:27 +02:00
2022-05-09 15:03:24 +03:00
if ( ! version_greater ( closure - > drm_edid , 1 , 1 ) )
2012-04-13 16:33:40 -04:00
return ; /* GTF not defined yet */
switch ( range - > flags ) {
case 0x02 : /* secondary gtf, XXX could do more */
case 0x00 : /* default gtf */
closure - > modes + = drm_gtf_modes_for_range ( closure - > connector ,
2022-05-09 15:03:10 +03:00
closure - > drm_edid ,
2012-04-13 16:33:40 -04:00
timing ) ;
break ;
case 0x04 : /* cvt, only in 1.4+ */
2022-05-09 15:03:24 +03:00
if ( ! version_greater ( closure - > drm_edid , 1 , 3 ) )
2012-04-13 16:33:40 -04:00
break ;
closure - > modes + = drm_cvt_modes_for_range ( closure - > connector ,
2022-05-09 15:03:11 +03:00
closure - > drm_edid ,
2012-04-13 16:33:40 -04:00
timing ) ;
break ;
case 0x01 : /* just the ranges, no formula */
default :
break ;
}
2010-08-03 14:38:19 -04:00
}
2010-01-04 17:53:06 -05:00
2022-05-11 12:26:50 +03:00
static int add_inferred_modes ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2010-08-03 14:38:19 -04:00
{
struct detailed_mode_closure closure = {
2014-08-23 18:09:56 +02:00
. connector = connector ,
2022-05-09 15:03:07 +03:00
. drm_edid = drm_edid ,
2010-08-03 14:38:19 -04:00
} ;
2009-12-03 17:44:40 -05:00
2022-05-09 15:03:24 +03:00
if ( version_greater ( drm_edid , 1 , 0 ) )
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , do_inferred_modes , & closure ) ;
2009-12-03 17:44:40 -05:00
2010-08-03 14:38:19 -04:00
return closure . modes ;
2009-12-03 17:44:40 -05:00
}
2010-03-29 21:43:22 +00:00
static int
2022-03-28 17:34:28 +03:00
drm_est3_modes ( struct drm_connector * connector , const struct detailed_timing * timing )
2010-03-29 21:43:22 +00:00
{
int i , j , m , modes = 0 ;
struct drm_display_mode * mode ;
2022-03-28 17:34:28 +03:00
const u8 * est = ( ( const u8 * ) timing ) + 6 ;
2010-03-29 21:43:22 +00:00
for ( i = 0 ; i < 6 ; i + + ) {
2013-10-14 16:44:26 +03:00
for ( j = 7 ; j > = 0 ; j - - ) {
2010-03-29 21:43:22 +00:00
m = ( i * 8 ) + ( 7 - j ) ;
2010-06-28 15:54:52 +04:00
if ( m > = ARRAY_SIZE ( est3_modes ) )
2010-03-29 21:43:22 +00:00
break ;
if ( est [ i ] & ( 1 < < j ) ) {
2010-05-07 05:02:30 +00:00
mode = drm_mode_find_dmt ( connector - > dev ,
est3_modes [ m ] . w ,
est3_modes [ m ] . h ,
2012-04-13 16:33:31 -04:00
est3_modes [ m ] . r ,
est3_modes [ m ] . rb ) ;
2010-03-29 21:43:22 +00:00
if ( mode ) {
drm_mode_probed_add ( connector , mode ) ;
modes + + ;
}
}
}
}
return modes ;
}
2010-08-03 14:38:19 -04:00
static void
2022-03-28 17:34:29 +03:00
do_established_modes ( const struct detailed_timing * timing , void * c )
2009-12-03 17:44:36 -05:00
{
2010-08-03 14:38:19 -04:00
struct detailed_mode_closure * closure = c ;
2009-12-03 17:44:36 -05:00
2022-03-28 17:34:24 +03:00
if ( ! is_display_descriptor ( timing , EDID_DETAIL_EST_TIMINGS ) )
2020-01-24 22:02:25 +02:00
return ;
closure - > modes + = drm_est3_modes ( closure - > connector , timing ) ;
2010-08-03 14:38:19 -04:00
}
2009-12-03 17:44:36 -05:00
2022-04-26 12:19:13 +03:00
/*
* Get established modes from EDID and add them . Each EDID block contains a
* bitmap of the supported " established modes " list ( defined above ) . Tease them
* out and add them to the global modes list .
2010-08-03 14:38:19 -04:00
*/
2022-05-11 12:26:50 +03:00
static int add_established_modes ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2010-08-03 14:38:19 -04:00
{
struct drm_device * dev = connector - > dev ;
2022-05-11 12:26:50 +03:00
const struct edid * edid = drm_edid - > edid ;
2010-08-03 14:38:19 -04:00
unsigned long est_bits = edid - > established_timings . t1 |
( edid - > established_timings . t2 < < 8 ) |
( ( edid - > established_timings . mfg_rsvd & 0x80 ) < < 9 ) ;
int i , modes = 0 ;
struct detailed_mode_closure closure = {
2014-08-23 18:09:56 +02:00
. connector = connector ,
2022-05-09 15:03:07 +03:00
. drm_edid = drm_edid ,
2010-08-03 14:38:19 -04:00
} ;
2009-12-03 17:44:36 -05:00
2010-08-03 14:38:19 -04:00
for ( i = 0 ; i < = EDID_EST_TIMINGS ; i + + ) {
if ( est_bits & ( 1 < < i ) ) {
struct drm_display_mode * newmode ;
2020-07-02 18:53:32 +05:30
2010-08-03 14:38:19 -04:00
newmode = drm_mode_duplicate ( dev , & edid_est_modes [ i ] ) ;
if ( newmode ) {
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
2009-12-03 17:44:36 -05:00
}
2022-05-09 15:03:24 +03:00
if ( version_greater ( drm_edid , 1 , 0 ) )
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , do_established_modes ,
2022-03-28 17:34:30 +03:00
& closure ) ;
2010-08-03 14:38:19 -04:00
return modes + closure . modes ;
}
static void
2022-03-28 17:34:29 +03:00
do_standard_modes ( const struct detailed_timing * timing , void * c )
2010-08-03 14:38:19 -04:00
{
struct detailed_mode_closure * closure = c ;
2022-03-28 17:34:28 +03:00
const struct detailed_non_pixel * data = & timing - > data . other_data ;
2010-08-03 14:38:19 -04:00
struct drm_connector * connector = closure - > connector ;
2020-01-24 22:02:25 +02:00
int i ;
2010-08-03 14:38:19 -04:00
2022-03-28 17:34:24 +03:00
if ( ! is_display_descriptor ( timing , EDID_DETAIL_STD_MODES ) )
2020-01-24 22:02:25 +02:00
return ;
2009-12-03 17:44:36 -05:00
2020-01-24 22:02:25 +02:00
for ( i = 0 ; i < 6 ; i + + ) {
2022-03-28 17:34:28 +03:00
const struct std_timing * std = & data - > data . timings [ i ] ;
2020-01-24 22:02:25 +02:00
struct drm_display_mode * newmode ;
2022-05-09 15:03:12 +03:00
newmode = drm_mode_std ( connector , closure - > drm_edid , std ) ;
2020-01-24 22:02:25 +02:00
if ( newmode ) {
drm_mode_probed_add ( connector , newmode ) ;
closure - > modes + + ;
2009-12-03 17:44:36 -05:00
}
}
}
2022-04-26 12:19:13 +03:00
/*
* Get standard modes from EDID and add them . Standard modes can be calculated
* using the appropriate standard ( DMT , GTF , or CVT ) . Grab them from EDID and
* add them to the list .
2008-11-07 14:05:41 -08:00
*/
2022-05-11 12:26:50 +03:00
static int add_standard_modes ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2008-11-07 14:05:41 -08:00
{
2009-12-03 17:44:36 -05:00
int i , modes = 0 ;
2010-08-03 14:38:19 -04:00
struct detailed_mode_closure closure = {
2014-08-23 18:09:56 +02:00
. connector = connector ,
2022-05-09 15:03:07 +03:00
. drm_edid = drm_edid ,
2010-08-03 14:38:19 -04:00
} ;
for ( i = 0 ; i < EDID_STD_TIMINGS ; i + + ) {
struct drm_display_mode * newmode ;
2022-05-09 15:03:12 +03:00
newmode = drm_mode_std ( connector , drm_edid ,
2022-05-11 12:26:50 +03:00
& drm_edid - > edid - > standard_timings [ i ] ) ;
2010-08-03 14:38:19 -04:00
if ( newmode ) {
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
2022-05-09 15:03:24 +03:00
if ( version_greater ( drm_edid , 1 , 0 ) )
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , do_standard_modes ,
2010-08-03 14:38:19 -04:00
& closure ) ;
/* XXX should also look for standard codes in VTB blocks */
return modes + closure . modes ;
}
2008-11-07 14:05:41 -08:00
2010-08-03 14:38:19 -04:00
static int drm_cvt_modes ( struct drm_connector * connector ,
2022-03-28 17:34:28 +03:00
const struct detailed_timing * timing )
2010-08-03 14:38:19 -04:00
{
int i , j , modes = 0 ;
struct drm_display_mode * newmode ;
struct drm_device * dev = connector - > dev ;
2022-03-28 17:34:28 +03:00
const struct cvt_timing * cvt ;
2010-08-03 14:38:19 -04:00
const int rates [ ] = { 60 , 85 , 75 , 60 , 50 } ;
const u8 empty [ 3 ] = { 0 , 0 , 0 } ;
2010-03-29 21:43:25 +00:00
2010-08-03 14:38:19 -04:00
for ( i = 0 ; i < 4 ; i + + ) {
treewide: Remove uninitialized_var() usage
Using uninitialized_var() is dangerous as it papers over real bugs[1]
(or can in the future), and suppresses unrelated compiler warnings
(e.g. "unused variable"). If the compiler thinks it is uninitialized,
either simply initialize the variable or make compiler changes.
In preparation for removing[2] the[3] macro[4], remove all remaining
needless uses with the following script:
git grep '\buninitialized_var\b' | cut -d: -f1 | sort -u | \
xargs perl -pi -e \
's/\buninitialized_var\(([^\)]+)\)/\1/g;
s:\s*/\* (GCC be quiet|to make compiler happy) \*/$::g;'
drivers/video/fbdev/riva/riva_hw.c was manually tweaked to avoid
pathological white-space.
No outstanding warnings were found building allmodconfig with GCC 9.3.0
for x86_64, i386, arm64, arm, powerpc, powerpc64le, s390x, mips, sparc64,
alpha, and m68k.
[1] https://lore.kernel.org/lkml/20200603174714.192027-1-glider@google.com/
[2] https://lore.kernel.org/lkml/CA+55aFw+Vbj0i=1TGqCR5vQkCzWJ0QxK6CernOU6eedsudAixw@mail.gmail.com/
[3] https://lore.kernel.org/lkml/CA+55aFwgbgqhbp1fkxvRKEpzyR5J8n1vKT1VZdz9knmPuXhOeg@mail.gmail.com/
[4] https://lore.kernel.org/lkml/CA+55aFz2500WfbKXAx8s67wrm9=yVJu65TpLgN_ybYNv0VEOKA@mail.gmail.com/
Reviewed-by: Leon Romanovsky <leonro@mellanox.com> # drivers/infiniband and mlx4/mlx5
Acked-by: Jason Gunthorpe <jgg@mellanox.com> # IB
Acked-by: Kalle Valo <kvalo@codeaurora.org> # wireless drivers
Reviewed-by: Chao Yu <yuchao0@huawei.com> # erofs
Signed-off-by: Kees Cook <keescook@chromium.org>
2020-06-03 13:09:38 -07:00
int width , height ;
2020-07-02 18:53:32 +05:30
2010-08-03 14:38:19 -04:00
cvt = & ( timing - > data . other_data . data . cvt [ i ] ) ;
2008-11-07 14:05:41 -08:00
2010-08-03 14:38:19 -04:00
if ( ! memcmp ( cvt - > code , empty , 3 ) )
2009-12-03 17:44:36 -05:00
continue ;
2008-11-07 14:05:41 -08:00
2010-08-03 14:38:19 -04:00
height = ( cvt - > code [ 0 ] + ( ( cvt - > code [ 1 ] & 0xf0 ) < < 4 ) + 1 ) * 2 ;
switch ( cvt - > code [ 1 ] & 0x0c ) {
drm/edid: fix objtool warning in drm_cvt_modes()
Commit 991fcb77f490 ("drm/edid: Fix uninitialized variable in
drm_cvt_modes()") just replaced one warning with another.
The original warning about a possibly uninitialized variable was due to
the compiler not being smart enough to see that the case statement
actually enumerated all possible cases. And the initial fix was just to
add a "default" case that had a single "unreachable()", just to tell the
compiler that that situation cannot happen.
However, that doesn't actually fix the fundamental reason for the
problem: the compiler still doesn't see that the existing case
statements enumerate all possibilities, so the compiler will still
generate code to jump to that unreachable case statement. It just won't
complain about an uninitialized variable any more.
So now the compiler generates code to our inline asm marker that we told
it would not fall through, and end end result is basically random. We
have created a bridge to nowhere.
And then, depending on the random details of just exactly what the
compiler ends up doing, 'objtool' might end up complaining about the
conditional branches (for conditions that cannot happen, and that thus
will never be taken - but if the compiler was not smart enough to figure
that out, we can't expect objtool to do so) going off in the weeds.
So depending on how the compiler has laid out the result, you might see
something like this:
drivers/gpu/drm/drm_edid.o: warning: objtool: do_cvt_mode() falls through to next function drm_mode_detailed.isra.0()
and now you have a truly inscrutable warning that makes no sense at all
unless you start looking at whatever random code the compiler happened
to generate for our bare "unreachable()" statement.
IOW, don't use "unreachable()" unless you have an _active_ operation
that generates code that actually makes it obvious that something is not
reachable (ie an UD instruction or similar).
Solve the "compiler isn't smart enough" problem by just marking one of
the cases as "default", so that even when the compiler doesn't otherwise
see that we've enumerated all cases, the compiler will feel happy and
safe about there always being a valid case that initializes the 'width'
variable.
This also generates better code, since now the compiler doesn't generate
comparisons for five different possibilities (the four real ones and the
one that can't happen), but just for the three real ones and "the rest"
(which is that last one).
A smart enough compiler that sees that we cover all the cases won't care.
Cc: Lyude Paul <lyude@redhat.com>
Cc: Ilia Mirkin <imirkin@alum.mit.edu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-12-17 09:27:57 -08:00
/* default - because compiler doesn't see that we've enumerated all cases */
default :
2010-08-03 14:38:19 -04:00
case 0x00 :
width = height * 4 / 3 ;
break ;
case 0x04 :
width = height * 16 / 9 ;
break ;
case 0x08 :
width = height * 16 / 10 ;
break ;
case 0x0c :
width = height * 15 / 9 ;
break ;
}
for ( j = 1 ; j < 5 ; j + + ) {
if ( cvt - > code [ 2 ] & ( 1 < < j ) ) {
newmode = drm_cvt_mode ( dev , width , height ,
rates [ j ] , j = = 0 ,
false , false ) ;
if ( newmode ) {
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
}
2008-11-07 14:05:41 -08:00
}
return modes ;
}
2009-12-03 17:44:36 -05:00
2010-08-03 14:38:19 -04:00
static void
2022-03-28 17:34:29 +03:00
do_cvt_mode ( const struct detailed_timing * timing , void * c )
2009-08-26 18:20:49 +08:00
{
2010-08-03 14:38:19 -04:00
struct detailed_mode_closure * closure = c ;
2009-08-26 18:20:49 +08:00
2022-03-28 17:34:24 +03:00
if ( ! is_display_descriptor ( timing , EDID_DETAIL_CVT_3BYTE ) )
2020-01-24 22:02:25 +02:00
return ;
closure - > modes + = drm_cvt_modes ( closure - > connector , timing ) ;
2010-08-03 14:38:19 -04:00
}
2009-08-26 18:20:49 +08:00
2010-08-03 14:38:19 -04:00
static int
2022-05-11 12:26:50 +03:00
add_cvt_modes ( struct drm_connector * connector , const struct drm_edid * drm_edid )
2020-01-24 22:02:27 +02:00
{
2010-08-03 14:38:19 -04:00
struct detailed_mode_closure closure = {
2014-08-23 18:09:56 +02:00
. connector = connector ,
2022-05-09 15:03:07 +03:00
. drm_edid = drm_edid ,
2010-08-03 14:38:19 -04:00
} ;
2009-08-26 18:20:49 +08:00
2022-05-09 15:03:24 +03:00
if ( version_greater ( drm_edid , 1 , 2 ) )
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , do_cvt_mode , & closure ) ;
2009-08-26 18:20:49 +08:00
2010-08-03 14:38:19 -04:00
/* XXX should also look for CVT codes in VTB blocks */
2009-08-26 18:20:49 +08:00
2010-08-03 14:38:19 -04:00
return closure . modes ;
}
2015-10-08 11:43:32 +03:00
static void fixup_detailed_cea_mode_clock ( struct drm_display_mode * mode ) ;
2010-08-03 14:38:19 -04:00
static void
2022-03-28 17:34:29 +03:00
do_detailed_mode ( const struct detailed_timing * timing , void * c )
2010-08-03 14:38:19 -04:00
{
struct detailed_mode_closure * closure = c ;
struct drm_display_mode * newmode ;
2022-03-28 17:34:25 +03:00
if ( ! is_detailed_timing_descriptor ( timing ) )
2020-01-24 22:02:26 +02:00
return ;
newmode = drm_mode_detailed ( closure - > connector - > dev ,
2022-05-09 15:03:08 +03:00
closure - > drm_edid , timing ,
2020-01-24 22:02:26 +02:00
closure - > quirks ) ;
if ( ! newmode )
return ;
2010-08-03 14:38:19 -04:00
2020-01-24 22:02:26 +02:00
if ( closure - > preferred )
newmode - > type | = DRM_MODE_TYPE_PREFERRED ;
2010-08-03 14:38:19 -04:00
2020-01-24 22:02:26 +02:00
/*
* Detailed modes are limited to 10 kHz pixel clock resolution ,
* so fix up anything that looks like CEA / HDMI mode , but the clock
* is just slightly off .
*/
fixup_detailed_cea_mode_clock ( newmode ) ;
2015-10-08 11:43:32 +03:00
2020-01-24 22:02:26 +02:00
drm_mode_probed_add ( closure - > connector , newmode ) ;
closure - > modes + + ;
closure - > preferred = false ;
2010-08-03 14:38:19 -04:00
}
2009-08-26 18:20:49 +08:00
2010-08-03 14:38:19 -04:00
/*
* add_detailed_modes - Add modes from detailed timings
* @ connector : attached connector
2022-05-11 12:26:50 +03:00
* @ drm_edid : EDID block to scan
2010-08-03 14:38:19 -04:00
* @ quirks : quirks to apply
*/
2022-05-11 12:26:50 +03:00
static int add_detailed_modes ( struct drm_connector * connector ,
const struct drm_edid * drm_edid , u32 quirks )
2010-08-03 14:38:19 -04:00
{
struct detailed_mode_closure closure = {
2014-08-23 18:09:56 +02:00
. connector = connector ,
2022-05-09 15:03:07 +03:00
. drm_edid = drm_edid ,
2018-01-30 04:05:28 -06:00
. preferred = true ,
2014-08-23 18:09:56 +02:00
. quirks = quirks ,
2010-08-03 14:38:19 -04:00
} ;
2022-05-09 15:03:24 +03:00
if ( closure . preferred & & ! version_greater ( drm_edid , 1 , 3 ) )
2010-08-03 14:38:19 -04:00
closure . preferred =
2022-05-11 12:26:50 +03:00
( drm_edid - > edid - > features & DRM_EDID_FEATURE_PREFERRED_TIMING ) ;
2010-08-03 14:38:19 -04:00
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , do_detailed_mode , & closure ) ;
2010-08-03 14:38:19 -04:00
return closure . modes ;
2009-08-26 18:20:49 +08:00
}
2008-11-07 14:05:41 -08:00
2022-05-03 12:23:49 +03:00
/* CTA-861-H Table 60 - CTA Tag Codes */
# define CTA_DB_AUDIO 1
# define CTA_DB_VIDEO 2
# define CTA_DB_VENDOR 3
# define CTA_DB_SPEAKER 4
# define CTA_DB_EXTENDED_TAG 7
/* CTA-861-H Table 62 - CTA Extended Tag Codes */
# define CTA_EXT_DB_VIDEO_CAP 0
# define CTA_EXT_DB_VENDOR 1
# define CTA_EXT_DB_HDR_STATIC_METADATA 6
# define CTA_EXT_DB_420_VIDEO_DATA 14
# define CTA_EXT_DB_420_VIDEO_CAP_MAP 15
2022-06-29 12:27:54 +03:00
# define CTA_EXT_DB_HF_EEODB 0x78
2022-05-03 12:23:49 +03:00
# define CTA_EXT_DB_HF_SCDB 0x79
2010-09-19 14:27:28 +08:00
# define EDID_BASIC_AUDIO (1 << 6)
2012-04-16 15:16:19 +02:00
# define EDID_CEA_YCRCB444 (1 << 5)
# define EDID_CEA_YCRCB422 (1 << 4)
2013-01-17 16:31:30 +02:00
# define EDID_CEA_VCDB_QS (1 << 6)
2010-09-19 14:27:28 +08:00
2013-08-19 16:58:52 +01:00
/*
2010-09-19 14:27:28 +08:00
* Search EDID for CEA extension block .
2022-05-09 15:03:23 +03:00
*
* FIXME : Prefer not returning pointers to raw EDID data .
2009-03-26 19:26:23 +08:00
*/
2022-05-09 15:03:23 +03:00
const u8 * drm_find_edid_extension ( const struct drm_edid * drm_edid ,
2021-03-29 16:37:16 +03:00
int ext_id , int * ext_index )
2009-03-26 19:26:23 +08:00
{
2021-03-29 16:37:15 +03:00
const u8 * edid_ext = NULL ;
2010-09-19 14:27:28 +08:00
int i ;
2009-03-26 19:26:23 +08:00
/* No EDID or EDID extensions */
2022-06-08 10:50:33 +03:00
if ( ! drm_edid | | ! drm_edid_extension_block_count ( drm_edid ) )
2010-09-19 14:27:28 +08:00
return NULL ;
2009-03-26 19:26:23 +08:00
/* Find CEA extension */
2022-06-08 10:50:33 +03:00
for ( i = * ext_index ; i < drm_edid_extension_block_count ( drm_edid ) ; i + + ) {
edid_ext = drm_edid_extension_block_data ( drm_edid , i ) ;
2022-03-31 21:45:00 +03:00
if ( edid_block_tag ( edid_ext ) = = ext_id )
2009-03-26 19:26:23 +08:00
break ;
}
2022-06-08 10:50:33 +03:00
if ( i > = drm_edid_extension_block_count ( drm_edid ) )
2010-09-19 14:27:28 +08:00
return NULL ;
2020-05-27 16:03:08 +03:00
* ext_index = i + 1 ;
2010-09-19 14:27:28 +08:00
return edid_ext ;
}
2022-05-03 12:24:05 +03:00
/* Return true if the EDID has a CTA extension or a DisplayID CTA data block */
2022-05-11 12:26:50 +03:00
static bool drm_edid_has_cta_extension ( const struct drm_edid * drm_edid )
2019-06-19 14:09:01 -04:00
{
2021-03-29 16:37:15 +03:00
const struct displayid_block * block ;
2021-03-29 16:37:19 +03:00
struct displayid_iter iter ;
int ext_index = 0 ;
2022-05-03 12:24:05 +03:00
bool found = false ;
2019-06-19 14:09:01 -04:00
/* Look for a top level CEA extension block */
2022-05-09 15:03:23 +03:00
if ( drm_find_edid_extension ( drm_edid , CEA_EXT , & ext_index ) )
2022-05-03 12:24:05 +03:00
return true ;
2019-06-19 14:09:01 -04:00
/* CEA blocks can also be found embedded in a DisplayID block */
2022-05-09 15:03:23 +03:00
displayid_iter_edid_begin ( drm_edid , & iter ) ;
2021-03-29 16:37:19 +03:00
displayid_iter_for_each ( block , & iter ) {
if ( block - > tag = = DATA_BLOCK_CTA ) {
2022-05-03 12:24:05 +03:00
found = true ;
2021-03-29 16:37:19 +03:00
break ;
2019-06-19 14:09:01 -04:00
}
}
2021-03-29 16:37:19 +03:00
displayid_iter_end ( & iter ) ;
2019-06-19 14:09:01 -04:00
2022-05-03 12:24:05 +03:00
return found ;
2019-06-19 14:09:01 -04:00
}
2020-02-03 22:31:13 +01:00
static __always_inline const struct drm_display_mode * cea_mode_for_vic ( u8 vic )
2019-12-13 19:43:45 +02:00
{
2019-12-13 19:43:48 +02:00
BUILD_BUG_ON ( 1 + ARRAY_SIZE ( edid_cea_modes_1 ) - 1 ! = 127 ) ;
BUILD_BUG_ON ( 193 + ARRAY_SIZE ( edid_cea_modes_193 ) - 1 ! = 219 ) ;
2019-12-13 19:43:47 +02:00
if ( vic > = 1 & & vic < 1 + ARRAY_SIZE ( edid_cea_modes_1 ) )
return & edid_cea_modes_1 [ vic - 1 ] ;
2019-12-13 19:43:46 +02:00
if ( vic > = 193 & & vic < 193 + ARRAY_SIZE ( edid_cea_modes_193 ) )
return & edid_cea_modes_193 [ vic - 193 ] ;
2019-12-13 19:43:45 +02:00
return NULL ;
}
static u8 cea_num_vics ( void )
{
2019-12-13 19:43:46 +02:00
return 193 + ARRAY_SIZE ( edid_cea_modes_193 ) ;
2019-12-13 19:43:45 +02:00
}
static u8 cea_next_vic ( u8 vic )
{
2019-12-13 19:43:47 +02:00
if ( + + vic = = 1 + ARRAY_SIZE ( edid_cea_modes_1 ) )
2019-12-13 19:43:46 +02:00
vic = 193 ;
return vic ;
2019-12-13 19:43:45 +02:00
}
2013-05-31 15:23:41 +03:00
/*
* Calculate the alternate clock for the CEA mode
* ( 60 Hz vs . 59.94 Hz etc . )
*/
static unsigned int
cea_mode_alternate_clock ( const struct drm_display_mode * cea_mode )
{
unsigned int clock = cea_mode - > clock ;
2020-04-28 20:19:27 +03:00
if ( drm_mode_vrefresh ( cea_mode ) % 6 ! = 0 )
2013-05-31 15:23:41 +03:00
return clock ;
/*
* edid_cea_modes contains the 59.94 Hz
* variant for 240 and 480 line modes ,
* and the 60 Hz variant otherwise .
*/
if ( cea_mode - > vdisplay = = 240 | | cea_mode - > vdisplay = = 480 )
2015-10-08 11:43:33 +03:00
clock = DIV_ROUND_CLOSEST ( clock * 1001 , 1000 ) ;
2013-05-31 15:23:41 +03:00
else
2015-10-08 11:43:33 +03:00
clock = DIV_ROUND_CLOSEST ( clock * 1000 , 1001 ) ;
2013-05-31 15:23:41 +03:00
return clock ;
}
2016-11-03 14:53:29 +02:00
static bool
cea_mode_alternate_timings ( u8 vic , struct drm_display_mode * mode )
{
/*
* For certain VICs the spec allows the vertical
* front porch to vary by one or two lines .
*
* cea_modes [ ] stores the variant with the shortest
* vertical front porch . We can adjust the mode to
* get the other variants by simply increasing the
* vertical front porch length .
*/
2019-12-13 19:43:45 +02:00
BUILD_BUG_ON ( cea_mode_for_vic ( 8 ) - > vtotal ! = 262 | |
cea_mode_for_vic ( 9 ) - > vtotal ! = 262 | |
cea_mode_for_vic ( 12 ) - > vtotal ! = 262 | |
cea_mode_for_vic ( 13 ) - > vtotal ! = 262 | |
cea_mode_for_vic ( 23 ) - > vtotal ! = 312 | |
cea_mode_for_vic ( 24 ) - > vtotal ! = 312 | |
cea_mode_for_vic ( 27 ) - > vtotal ! = 312 | |
cea_mode_for_vic ( 28 ) - > vtotal ! = 312 ) ;
2016-11-03 14:53:29 +02:00
if ( ( ( vic = = 8 | | vic = = 9 | |
vic = = 12 | | vic = = 13 ) & & mode - > vtotal < 263 ) | |
( ( vic = = 23 | | vic = = 24 | |
vic = = 27 | | vic = = 28 ) & & mode - > vtotal < 314 ) ) {
mode - > vsync_start + + ;
mode - > vsync_end + + ;
mode - > vtotal + + ;
return true ;
}
return false ;
}
2015-11-16 21:05:12 +02:00
static u8 drm_match_cea_mode_clock_tolerance ( const struct drm_display_mode * to_match ,
unsigned int clock_tolerance )
{
2018-05-08 16:39:38 +05:30
unsigned int match_flags = DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_FLAGS ;
2016-01-08 13:21:51 +02:00
u8 vic ;
2015-11-16 21:05:12 +02:00
if ( ! to_match - > clock )
return 0 ;
2018-05-08 16:39:38 +05:30
if ( to_match - > picture_aspect_ratio )
match_flags | = DRM_MODE_MATCH_ASPECT_RATIO ;
2019-12-13 19:43:45 +02:00
for ( vic = 1 ; vic < cea_num_vics ( ) ; vic = cea_next_vic ( vic ) ) {
2022-02-18 12:04:02 +02:00
struct drm_display_mode cea_mode ;
2015-11-16 21:05:12 +02:00
unsigned int clock1 , clock2 ;
2022-02-18 12:04:02 +02:00
drm_mode_init ( & cea_mode , cea_mode_for_vic ( vic ) ) ;
2015-11-16 21:05:12 +02:00
/* Check both 60Hz and 59.94Hz */
2016-11-03 14:53:29 +02:00
clock1 = cea_mode . clock ;
clock2 = cea_mode_alternate_clock ( & cea_mode ) ;
2015-11-16 21:05:12 +02:00
if ( abs ( to_match - > clock - clock1 ) > clock_tolerance & &
abs ( to_match - > clock - clock2 ) > clock_tolerance )
continue ;
2016-11-03 14:53:29 +02:00
do {
2018-05-08 16:39:38 +05:30
if ( drm_mode_match ( to_match , & cea_mode , match_flags ) )
2016-11-03 14:53:29 +02:00
return vic ;
} while ( cea_mode_alternate_timings ( vic , & cea_mode ) ) ;
2015-11-16 21:05:12 +02:00
}
return 0 ;
}
2012-12-20 15:41:44 +01:00
/**
* drm_match_cea_mode - look for a CEA mode matching given mode
* @ to_match : display mode
*
2014-04-29 11:44:34 +02:00
* Return : The CEA Video ID ( VIC ) of the mode or 0 if it isn ' t a CEA - 861
2012-12-20 15:41:44 +01:00
* mode .
2012-11-09 16:21:05 +00:00
*/
2012-12-20 15:41:44 +01:00
u8 drm_match_cea_mode ( const struct drm_display_mode * to_match )
2012-11-09 16:21:05 +00:00
{
2018-05-08 16:39:38 +05:30
unsigned int match_flags = DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_FLAGS ;
2016-01-08 13:21:51 +02:00
u8 vic ;
2012-11-09 16:21:05 +00:00
2013-04-24 19:07:18 +03:00
if ( ! to_match - > clock )
return 0 ;
2018-05-08 16:39:38 +05:30
if ( to_match - > picture_aspect_ratio )
match_flags | = DRM_MODE_MATCH_ASPECT_RATIO ;
2019-12-13 19:43:45 +02:00
for ( vic = 1 ; vic < cea_num_vics ( ) ; vic = cea_next_vic ( vic ) ) {
2022-02-18 12:04:02 +02:00
struct drm_display_mode cea_mode ;
2013-04-24 19:07:18 +03:00
unsigned int clock1 , clock2 ;
2022-02-18 12:04:02 +02:00
drm_mode_init ( & cea_mode , cea_mode_for_vic ( vic ) ) ;
2013-04-24 19:07:18 +03:00
/* Check both 60Hz and 59.94Hz */
2016-11-03 14:53:29 +02:00
clock1 = cea_mode . clock ;
clock2 = cea_mode_alternate_clock ( & cea_mode ) ;
2012-11-09 16:21:05 +00:00
2016-11-03 14:53:29 +02:00
if ( KHZ2PICOS ( to_match - > clock ) ! = KHZ2PICOS ( clock1 ) & &
KHZ2PICOS ( to_match - > clock ) ! = KHZ2PICOS ( clock2 ) )
continue ;
do {
2018-05-08 16:39:38 +05:30
if ( drm_mode_match ( to_match , & cea_mode , match_flags ) )
2016-11-03 14:53:29 +02:00
return vic ;
} while ( cea_mode_alternate_timings ( vic , & cea_mode ) ) ;
2012-11-09 16:21:05 +00:00
}
2016-11-03 14:53:29 +02:00
2012-11-09 16:21:05 +00:00
return 0 ;
}
EXPORT_SYMBOL ( drm_match_cea_mode ) ;
2016-01-08 13:21:51 +02:00
static bool drm_valid_cea_vic ( u8 vic )
{
2019-12-13 19:43:45 +02:00
return cea_mode_for_vic ( vic ) ! = NULL ;
2016-01-08 13:21:51 +02:00
}
2019-10-04 17:19:11 +03:00
static enum hdmi_picture_aspect drm_get_cea_aspect_ratio ( const u8 video_code )
2014-04-01 16:26:59 +05:30
{
2019-12-13 19:43:45 +02:00
const struct drm_display_mode * mode = cea_mode_for_vic ( video_code ) ;
if ( mode )
return mode - > picture_aspect_ratio ;
return HDMI_PICTURE_ASPECT_NONE ;
2014-04-01 16:26:59 +05:30
}
2019-11-18 18:18:31 +08:00
static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio ( const u8 video_code )
{
return edid_4k_modes [ video_code ] . picture_aspect_ratio ;
}
2013-08-19 16:58:55 +01:00
/*
* Calculate the alternate clock for HDMI modes ( those from the HDMI vendor
* specific block ) .
*/
static unsigned int
hdmi_mode_alternate_clock ( const struct drm_display_mode * hdmi_mode )
{
return cea_mode_alternate_clock ( hdmi_mode ) ;
}
2015-11-16 21:05:12 +02:00
static u8 drm_match_hdmi_mode_clock_tolerance ( const struct drm_display_mode * to_match ,
unsigned int clock_tolerance )
{
2018-05-08 16:39:38 +05:30
unsigned int match_flags = DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_FLAGS ;
2016-01-08 13:21:51 +02:00
u8 vic ;
2015-11-16 21:05:12 +02:00
if ( ! to_match - > clock )
return 0 ;
2019-11-18 18:18:31 +08:00
if ( to_match - > picture_aspect_ratio )
match_flags | = DRM_MODE_MATCH_ASPECT_RATIO ;
2016-01-08 13:21:51 +02:00
for ( vic = 1 ; vic < ARRAY_SIZE ( edid_4k_modes ) ; vic + + ) {
const struct drm_display_mode * hdmi_mode = & edid_4k_modes [ vic ] ;
2015-11-16 21:05:12 +02:00
unsigned int clock1 , clock2 ;
/* Make sure to also match alternate clocks */
clock1 = hdmi_mode - > clock ;
clock2 = hdmi_mode_alternate_clock ( hdmi_mode ) ;
if ( abs ( to_match - > clock - clock1 ) > clock_tolerance & &
abs ( to_match - > clock - clock2 ) > clock_tolerance )
continue ;
2018-05-08 16:39:38 +05:30
if ( drm_mode_match ( to_match , hdmi_mode , match_flags ) )
2016-01-08 13:21:51 +02:00
return vic ;
2015-11-16 21:05:12 +02:00
}
return 0 ;
}
2013-08-19 16:58:55 +01:00
/*
* drm_match_hdmi_mode - look for a HDMI mode matching given mode
* @ to_match : display mode
*
* An HDMI mode is one defined in the HDMI vendor specific block .
*
* Returns the HDMI Video ID ( VIC ) of the mode or 0 if it isn ' t one .
*/
static u8 drm_match_hdmi_mode ( const struct drm_display_mode * to_match )
{
2018-05-08 16:39:38 +05:30
unsigned int match_flags = DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_FLAGS ;
2016-01-08 13:21:51 +02:00
u8 vic ;
2013-08-19 16:58:55 +01:00
if ( ! to_match - > clock )
return 0 ;
2019-11-18 18:18:31 +08:00
if ( to_match - > picture_aspect_ratio )
match_flags | = DRM_MODE_MATCH_ASPECT_RATIO ;
2016-01-08 13:21:51 +02:00
for ( vic = 1 ; vic < ARRAY_SIZE ( edid_4k_modes ) ; vic + + ) {
const struct drm_display_mode * hdmi_mode = & edid_4k_modes [ vic ] ;
2013-08-19 16:58:55 +01:00
unsigned int clock1 , clock2 ;
/* Make sure to also match alternate clocks */
clock1 = hdmi_mode - > clock ;
clock2 = hdmi_mode_alternate_clock ( hdmi_mode ) ;
if ( ( KHZ2PICOS ( to_match - > clock ) = = KHZ2PICOS ( clock1 ) | |
KHZ2PICOS ( to_match - > clock ) = = KHZ2PICOS ( clock2 ) ) & &
2018-05-08 16:39:38 +05:30
drm_mode_match ( to_match , hdmi_mode , match_flags ) )
2016-01-08 13:21:51 +02:00
return vic ;
2013-08-19 16:58:55 +01:00
}
return 0 ;
}
2016-01-08 13:21:51 +02:00
static bool drm_valid_hdmi_vic ( u8 vic )
{
return vic > 0 & & vic < ARRAY_SIZE ( edid_4k_modes ) ;
}
2022-05-11 12:26:50 +03:00
static int add_alternate_cea_modes ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2013-05-31 15:23:41 +03:00
{
struct drm_device * dev = connector - > dev ;
struct drm_display_mode * mode , * tmp ;
LIST_HEAD ( list ) ;
int modes = 0 ;
2022-05-03 12:24:05 +03:00
/* Don't add CTA modes if the CTA extension block is missing */
2022-05-11 12:26:50 +03:00
if ( ! drm_edid_has_cta_extension ( drm_edid ) )
2013-05-31 15:23:41 +03:00
return 0 ;
/*
* Go through all probed modes and create a new mode
* with the alternate clock for certain CEA modes .
*/
list_for_each_entry ( mode , & connector - > probed_modes , head ) {
2013-08-19 16:58:55 +01:00
const struct drm_display_mode * cea_mode = NULL ;
2013-05-31 15:23:41 +03:00
struct drm_display_mode * newmode ;
2016-01-08 13:21:51 +02:00
u8 vic = drm_match_cea_mode ( mode ) ;
2013-05-31 15:23:41 +03:00
unsigned int clock1 , clock2 ;
2016-01-08 13:21:51 +02:00
if ( drm_valid_cea_vic ( vic ) ) {
2019-12-13 19:43:45 +02:00
cea_mode = cea_mode_for_vic ( vic ) ;
2013-08-19 16:58:55 +01:00
clock2 = cea_mode_alternate_clock ( cea_mode ) ;
} else {
2016-01-08 13:21:51 +02:00
vic = drm_match_hdmi_mode ( mode ) ;
if ( drm_valid_hdmi_vic ( vic ) ) {
cea_mode = & edid_4k_modes [ vic ] ;
2013-08-19 16:58:55 +01:00
clock2 = hdmi_mode_alternate_clock ( cea_mode ) ;
}
}
2013-05-31 15:23:41 +03:00
2013-08-19 16:58:55 +01:00
if ( ! cea_mode )
continue ;
2013-05-31 15:23:41 +03:00
clock1 = cea_mode - > clock ;
if ( clock1 = = clock2 )
continue ;
if ( mode - > clock ! = clock1 & & mode - > clock ! = clock2 )
continue ;
newmode = drm_mode_duplicate ( dev , cea_mode ) ;
if ( ! newmode )
continue ;
2013-09-25 16:45:28 +01:00
/* Carry over the stereo flags */
newmode - > flags | = mode - > flags & DRM_MODE_FLAG_3D_MASK ;
2013-05-31 15:23:41 +03:00
/*
* The current mode could be either variant . Make
* sure to pick the " other " clock for the new mode .
*/
if ( mode - > clock ! = clock1 )
newmode - > clock = clock1 ;
else
newmode - > clock = clock2 ;
list_add_tail ( & newmode - > head , & list ) ;
}
list_for_each_entry_safe ( mode , tmp , & list , head ) {
list_del ( & mode - > head ) ;
drm_mode_probed_add ( connector , mode ) ;
modes + + ;
}
return modes ;
}
2012-11-09 16:21:05 +00:00
2017-07-13 21:03:08 +05:30
static u8 svd_to_vic ( u8 svd )
{
/* 0-6 bit vic, 7th bit native mode indicator */
if ( ( svd > = 1 & & svd < = 64 ) | | ( svd > = 129 & & svd < = 192 ) )
return svd & 127 ;
return svd ;
}
2013-11-29 15:33:27 +00:00
static struct drm_display_mode *
drm_display_mode_from_vic_index ( struct drm_connector * connector ,
const u8 * video_db , u8 video_len ,
u8 video_index )
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
{
struct drm_device * dev = connector - > dev ;
2013-11-29 15:33:27 +00:00
struct drm_display_mode * newmode ;
2016-01-08 13:21:51 +02:00
u8 vic ;
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
2013-11-29 15:33:27 +00:00
if ( video_db = = NULL | | video_index > = video_len )
return NULL ;
/* CEA modes are numbered 1..127 */
2017-07-13 21:03:08 +05:30
vic = svd_to_vic ( video_db [ video_index ] ) ;
2016-01-08 13:21:51 +02:00
if ( ! drm_valid_cea_vic ( vic ) )
2013-11-29 15:33:27 +00:00
return NULL ;
2019-12-13 19:43:45 +02:00
newmode = drm_mode_duplicate ( dev , cea_mode_for_vic ( vic ) ) ;
2014-03-03 23:59:07 +00:00
if ( ! newmode )
return NULL ;
2013-11-29 15:33:27 +00:00
return newmode ;
}
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
/*
* do_y420vdb_modes - Parse YCBCR 420 only modes
* @ connector : connector corresponding to the HDMI sink
* @ svds : start of the data block of CEA YCBCR 420 VDB
* @ len : length of the CEA YCBCR 420 VDB
*
* Parse the CEA - 861 - F YCBCR 420 Video Data Block ( Y420VDB )
* which contains modes which can be supported in YCBCR 420
* output format only .
*/
static int do_y420vdb_modes ( struct drm_connector * connector ,
const u8 * svds , u8 svds_len )
{
int modes = 0 , i ;
struct drm_device * dev = connector - > dev ;
struct drm_display_info * info = & connector - > display_info ;
struct drm_hdmi_info * hdmi = & info - > hdmi ;
for ( i = 0 ; i < svds_len ; i + + ) {
u8 vic = svd_to_vic ( svds [ i ] ) ;
struct drm_display_mode * newmode ;
if ( ! drm_valid_cea_vic ( vic ) )
continue ;
2019-12-13 19:43:45 +02:00
newmode = drm_mode_duplicate ( dev , cea_mode_for_vic ( vic ) ) ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
if ( ! newmode )
break ;
bitmap_set ( hdmi - > y420_vdb_modes , vic , 1 ) ;
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
if ( modes > 0 )
2022-01-20 16:16:13 +01:00
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR420 ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
return modes ;
}
/*
* drm_add_cmdb_modes - Add a YCBCR 420 mode into bitmap
* @ connector : connector corresponding to the HDMI sink
* @ vic : CEA vic for the video mode to be added in the map
*
* Makes an entry for a videomode in the YCBCR 420 bitmap
*/
static void
drm_add_cmdb_modes ( struct drm_connector * connector , u8 svd )
{
u8 vic = svd_to_vic ( svd ) ;
struct drm_hdmi_info * hdmi = & connector - > display_info . hdmi ;
if ( ! drm_valid_cea_vic ( vic ) )
return ;
bitmap_set ( hdmi - > y420_cmdb_modes , vic , 1 ) ;
}
2020-09-04 14:53:49 +03:00
/**
* drm_display_mode_from_cea_vic ( ) - return a mode for CEA VIC
* @ dev : DRM device
2020-10-27 10:51:16 +01:00
* @ video_code : CEA VIC of the mode
2020-09-04 14:53:49 +03:00
*
* Creates a new mode matching the specified CEA VIC .
*
* Returns : A new drm_display_mode on success or NULL on failure
*/
struct drm_display_mode *
drm_display_mode_from_cea_vic ( struct drm_device * dev ,
u8 video_code )
{
const struct drm_display_mode * cea_mode ;
struct drm_display_mode * newmode ;
cea_mode = cea_mode_for_vic ( video_code ) ;
if ( ! cea_mode )
return NULL ;
newmode = drm_mode_duplicate ( dev , cea_mode ) ;
if ( ! newmode )
return NULL ;
return newmode ;
}
EXPORT_SYMBOL ( drm_display_mode_from_cea_vic ) ;
2013-11-29 15:33:27 +00:00
static int
do_cea_modes ( struct drm_connector * connector , const u8 * db , u8 len )
{
int i , modes = 0 ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
struct drm_hdmi_info * hdmi = & connector - > display_info . hdmi ;
2013-11-29 15:33:27 +00:00
for ( i = 0 ; i < len ; i + + ) {
struct drm_display_mode * mode ;
2020-07-02 18:53:32 +05:30
2013-11-29 15:33:27 +00:00
mode = drm_display_mode_from_vic_index ( connector , db , len , i ) ;
if ( mode ) {
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
/*
* YCBCR420 capability block contains a bitmap which
* gives the index of CEA modes from CEA VDB , which
* can support YCBCR 420 sampling output also ( apart
* from RGB / YCBCR444 etc ) .
* For example , if the bit 0 in bitmap is set ,
* first mode in VDB can support YCBCR420 output too .
* Add YCBCR420 modes only if sink is HDMI 2.0 capable .
*/
if ( i < 64 & & hdmi - > y420_cmdb_map & ( 1ULL < < i ) )
drm_add_cmdb_modes ( connector , db [ i ] ) ;
2013-11-29 15:33:27 +00:00
drm_mode_probed_add ( connector , mode ) ;
modes + + ;
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
}
}
return modes ;
}
2013-09-25 16:45:23 +01:00
struct stereo_mandatory_mode {
int width , height , vrefresh ;
unsigned int flags ;
} ;
static const struct stereo_mandatory_mode stereo_mandatory_modes [ ] = {
2013-09-27 12:11:48 +01:00
{ 1920 , 1080 , 24 , DRM_MODE_FLAG_3D_TOP_AND_BOTTOM } ,
{ 1920 , 1080 , 24 , DRM_MODE_FLAG_3D_FRAME_PACKING } ,
2013-09-25 16:45:23 +01:00
{ 1920 , 1080 , 50 ,
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF } ,
{ 1920 , 1080 , 60 ,
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF } ,
2013-09-27 12:11:48 +01:00
{ 1280 , 720 , 50 , DRM_MODE_FLAG_3D_TOP_AND_BOTTOM } ,
{ 1280 , 720 , 50 , DRM_MODE_FLAG_3D_FRAME_PACKING } ,
{ 1280 , 720 , 60 , DRM_MODE_FLAG_3D_TOP_AND_BOTTOM } ,
{ 1280 , 720 , 60 , DRM_MODE_FLAG_3D_FRAME_PACKING }
2013-09-25 16:45:23 +01:00
} ;
static bool
stereo_match_mandatory ( const struct drm_display_mode * mode ,
const struct stereo_mandatory_mode * stereo_mode )
{
unsigned int interlaced = mode - > flags & DRM_MODE_FLAG_INTERLACE ;
return mode - > hdisplay = = stereo_mode - > width & &
mode - > vdisplay = = stereo_mode - > height & &
interlaced = = ( stereo_mode - > flags & DRM_MODE_FLAG_INTERLACE ) & &
drm_mode_vrefresh ( mode ) = = stereo_mode - > vrefresh ;
}
static int add_hdmi_mandatory_stereo_modes ( struct drm_connector * connector )
{
struct drm_device * dev = connector - > dev ;
const struct drm_display_mode * mode ;
struct list_head stereo_modes ;
2013-09-27 12:11:48 +01:00
int modes = 0 , i ;
2013-09-25 16:45:23 +01:00
INIT_LIST_HEAD ( & stereo_modes ) ;
list_for_each_entry ( mode , & connector - > probed_modes , head ) {
2013-09-27 12:11:48 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( stereo_mandatory_modes ) ; i + + ) {
const struct stereo_mandatory_mode * mandatory ;
2013-09-25 16:45:23 +01:00
struct drm_display_mode * new_mode ;
2013-09-27 12:11:48 +01:00
if ( ! stereo_match_mandatory ( mode ,
& stereo_mandatory_modes [ i ] ) )
continue ;
2013-09-25 16:45:23 +01:00
2013-09-27 12:11:48 +01:00
mandatory = & stereo_mandatory_modes [ i ] ;
2013-09-25 16:45:23 +01:00
new_mode = drm_mode_duplicate ( dev , mode ) ;
if ( ! new_mode )
continue ;
2013-09-27 12:11:48 +01:00
new_mode - > flags | = mandatory - > flags ;
2013-09-25 16:45:23 +01:00
list_add_tail ( & new_mode - > head , & stereo_modes ) ;
modes + + ;
2013-09-27 12:11:48 +01:00
}
2013-09-25 16:45:23 +01:00
}
list_splice_tail ( & stereo_modes , & connector - > probed_modes ) ;
return modes ;
}
2013-09-25 16:45:24 +01:00
static int add_hdmi_mode ( struct drm_connector * connector , u8 vic )
{
struct drm_device * dev = connector - > dev ;
struct drm_display_mode * newmode ;
2016-01-08 13:21:51 +02:00
if ( ! drm_valid_hdmi_vic ( vic ) ) {
2013-09-25 16:45:24 +01:00
DRM_ERROR ( " Unknown HDMI VIC: %d \n " , vic ) ;
return 0 ;
}
newmode = drm_mode_duplicate ( dev , & edid_4k_modes [ vic ] ) ;
if ( ! newmode )
return 0 ;
drm_mode_probed_add ( connector , newmode ) ;
return 1 ;
}
2013-10-16 15:58:50 +01:00
static int add_3d_struct_modes ( struct drm_connector * connector , u16 structure ,
const u8 * video_db , u8 video_len , u8 video_index )
{
struct drm_display_mode * newmode ;
int modes = 0 ;
if ( structure & ( 1 < < 0 ) ) {
2013-11-29 15:33:27 +00:00
newmode = drm_display_mode_from_vic_index ( connector , video_db ,
video_len ,
video_index ) ;
2013-10-16 15:58:50 +01:00
if ( newmode ) {
newmode - > flags | = DRM_MODE_FLAG_3D_FRAME_PACKING ;
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
if ( structure & ( 1 < < 6 ) ) {
2013-11-29 15:33:27 +00:00
newmode = drm_display_mode_from_vic_index ( connector , video_db ,
video_len ,
video_index ) ;
2013-10-16 15:58:50 +01:00
if ( newmode ) {
newmode - > flags | = DRM_MODE_FLAG_3D_TOP_AND_BOTTOM ;
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
if ( structure & ( 1 < < 8 ) ) {
2013-11-29 15:33:27 +00:00
newmode = drm_display_mode_from_vic_index ( connector , video_db ,
video_len ,
video_index ) ;
2013-10-16 15:58:50 +01:00
if ( newmode ) {
2013-11-28 15:35:04 +00:00
newmode - > flags | = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF ;
2013-10-16 15:58:50 +01:00
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
return modes ;
}
2013-08-19 16:58:54 +01:00
/*
* do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
* @ connector : connector corresponding to the HDMI sink
* @ db : start of the CEA vendor specific block
* @ len : length of the CEA block payload , ie . one can access up to db [ len ]
*
2013-09-25 16:45:23 +01:00
* Parses the HDMI VSDB looking for modes to add to @ connector . This function
* also adds the stereo 3 d modes when applicable .
2013-08-19 16:58:54 +01:00
*/
static int
2013-10-16 15:58:50 +01:00
do_hdmi_vsdb_modes ( struct drm_connector * connector , const u8 * db , u8 len ,
const u8 * video_db , u8 video_len )
2013-08-19 16:58:54 +01:00
{
2017-11-13 19:04:19 +02:00
struct drm_display_info * info = & connector - > display_info ;
2013-11-29 18:18:58 +00:00
int modes = 0 , offset = 0 , i , multi_present = 0 , multi_len ;
2013-10-16 15:58:50 +01:00
u8 vic_len , hdmi_3d_len = 0 ;
u16 mask ;
u16 structure_all ;
2013-08-19 16:58:54 +01:00
if ( len < 8 )
goto out ;
/* no HDMI_Video_Present */
if ( ! ( db [ 8 ] & ( 1 < < 5 ) ) )
goto out ;
/* Latency_Fields_Present */
if ( db [ 8 ] & ( 1 < < 7 ) )
offset + = 2 ;
/* I_Latency_Fields_Present */
if ( db [ 8 ] & ( 1 < < 6 ) )
offset + = 2 ;
/* the declared length is not long enough for the 2 first bytes
* of additional video format capabilities */
2013-09-25 16:45:23 +01:00
if ( len < ( 8 + offset + 2 ) )
2013-08-19 16:58:54 +01:00
goto out ;
2013-09-25 16:45:23 +01:00
/* 3D_Present */
offset + + ;
2013-10-16 15:58:50 +01:00
if ( db [ 8 + offset ] & ( 1 < < 7 ) ) {
2013-09-25 16:45:23 +01:00
modes + = add_hdmi_mandatory_stereo_modes ( connector ) ;
2013-10-16 15:58:50 +01:00
/* 3D_Multi_present */
multi_present = ( db [ 8 + offset ] & 0x60 ) > > 5 ;
}
2013-09-25 16:45:23 +01:00
offset + + ;
2013-08-19 16:58:54 +01:00
vic_len = db [ 8 + offset ] > > 5 ;
2013-10-16 15:58:50 +01:00
hdmi_3d_len = db [ 8 + offset ] & 0x1f ;
2013-08-19 16:58:54 +01:00
for ( i = 0 ; i < vic_len & & len > = ( 9 + offset + i ) ; i + + ) {
u8 vic ;
vic = db [ 9 + offset + i ] ;
2013-09-25 16:45:24 +01:00
modes + = add_hdmi_mode ( connector , vic ) ;
2013-08-19 16:58:54 +01:00
}
2013-10-16 15:58:50 +01:00
offset + = 1 + vic_len ;
2013-11-29 18:18:58 +00:00
if ( multi_present = = 1 )
multi_len = 2 ;
else if ( multi_present = = 2 )
multi_len = 4 ;
else
multi_len = 0 ;
2013-10-16 15:58:50 +01:00
2013-11-29 18:18:58 +00:00
if ( len < ( 8 + offset + hdmi_3d_len - 1 ) )
2013-10-16 15:58:50 +01:00
goto out ;
2013-11-29 18:18:58 +00:00
if ( hdmi_3d_len < multi_len )
2013-10-16 15:58:50 +01:00
goto out ;
2013-11-29 18:18:58 +00:00
if ( multi_present = = 1 | | multi_present = = 2 ) {
/* 3D_Structure_ALL */
structure_all = ( db [ 8 + offset ] < < 8 ) | db [ 9 + offset ] ;
2013-10-16 15:58:50 +01:00
2013-11-29 18:18:58 +00:00
/* check if 3D_MASK is present */
if ( multi_present = = 2 )
mask = ( db [ 10 + offset ] < < 8 ) | db [ 11 + offset ] ;
else
mask = 0xffff ;
for ( i = 0 ; i < 16 ; i + + ) {
if ( mask & ( 1 < < i ) )
modes + = add_3d_struct_modes ( connector ,
structure_all ,
video_db ,
video_len , i ) ;
}
}
offset + = multi_len ;
for ( i = 0 ; i < ( hdmi_3d_len - multi_len ) ; i + + ) {
int vic_index ;
struct drm_display_mode * newmode = NULL ;
unsigned int newflag = 0 ;
bool detail_present ;
detail_present = ( ( db [ 8 + offset + i ] & 0x0f ) > 7 ) ;
if ( detail_present & & ( i + 1 = = hdmi_3d_len - multi_len ) )
break ;
/* 2D_VIC_order_X */
vic_index = db [ 8 + offset + i ] > > 4 ;
/* 3D_Structure_X */
switch ( db [ 8 + offset + i ] & 0x0f ) {
case 0 :
newflag = DRM_MODE_FLAG_3D_FRAME_PACKING ;
break ;
case 6 :
newflag = DRM_MODE_FLAG_3D_TOP_AND_BOTTOM ;
break ;
case 8 :
/* 3D_Detail_X */
if ( ( db [ 9 + offset + i ] > > 4 ) = = 1 )
newflag = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF ;
break ;
}
if ( newflag ! = 0 ) {
newmode = drm_display_mode_from_vic_index ( connector ,
video_db ,
video_len ,
vic_index ) ;
if ( newmode ) {
newmode - > flags | = newflag ;
drm_mode_probed_add ( connector , newmode ) ;
modes + + ;
}
}
if ( detail_present )
i + + ;
2013-10-16 15:58:50 +01:00
}
2013-08-19 16:58:54 +01:00
out :
2017-11-13 19:04:19 +02:00
if ( modes > 0 )
info - > has_hdmi_infoframe = true ;
2013-08-19 16:58:54 +01:00
return modes ;
}
2012-08-16 14:55:04 +00:00
static int
cea_revision ( const u8 * cea )
{
2020-01-24 22:02:29 +02:00
/*
* FIXME is this correct for the DispID variant ?
* The DispID spec doesn ' t really specify whether
* this is the revision of the CEA extension or
* the DispID CEA data block . And the only value
* given as an example is 0.
*/
2012-08-16 14:55:04 +00:00
return cea [ 1 ] ;
}
2022-05-03 12:23:51 +03:00
/*
* CTA Data Block iterator .
*
* Iterate through all CTA Data Blocks in both EDID CTA Extensions and DisplayID
* CTA Data Blocks .
*
* struct cea_db * db :
* struct cea_db_iter iter ;
*
* cea_db_iter_edid_begin ( edid , & iter ) ;
* cea_db_iter_for_each ( db , & iter ) {
* // do stuff with db
* }
* cea_db_iter_end ( & iter ) ;
*/
struct cea_db_iter {
struct drm_edid_iter edid_iter ;
struct displayid_iter displayid_iter ;
/* Current Data Block Collection. */
const u8 * collection ;
/* Current Data Block index in current collection. */
int index ;
/* End index in current collection. */
int end ;
} ;
/* CTA-861-H section 7.4 CTA Data BLock Collection */
struct cea_db {
u8 tag_length ;
u8 data [ ] ;
} __packed ;
2022-05-03 12:24:01 +03:00
static int cea_db_tag ( const struct cea_db * db )
2022-05-03 12:23:51 +03:00
{
return db - > tag_length > > 5 ;
}
static int cea_db_payload_len ( const void * _db )
{
/* FIXME: Transition to passing struct cea_db * everywhere. */
const struct cea_db * db = _db ;
return db - > tag_length & 0x1f ;
}
static const void * cea_db_data ( const struct cea_db * db )
{
return db - > data ;
}
2022-05-03 12:23:52 +03:00
static bool cea_db_is_extended_tag ( const struct cea_db * db , int tag )
{
return cea_db_tag ( db ) = = CTA_DB_EXTENDED_TAG & &
cea_db_payload_len ( db ) > = 1 & &
db - > data [ 0 ] = = tag ;
}
static bool cea_db_is_vendor ( const struct cea_db * db , int vendor_oui )
{
const u8 * data = cea_db_data ( db ) ;
return cea_db_tag ( db ) = = CTA_DB_VENDOR & &
cea_db_payload_len ( db ) > = 3 & &
oui ( data [ 2 ] , data [ 1 ] , data [ 0 ] ) = = vendor_oui ;
}
2022-05-09 15:03:20 +03:00
static void cea_db_iter_edid_begin ( const struct drm_edid * drm_edid ,
struct cea_db_iter * iter )
2022-05-03 12:23:51 +03:00
{
memset ( iter , 0 , sizeof ( * iter ) ) ;
2022-05-09 15:03:21 +03:00
drm_edid_iter_begin ( drm_edid , & iter - > edid_iter ) ;
2022-05-09 15:03:23 +03:00
displayid_iter_edid_begin ( drm_edid , & iter - > displayid_iter ) ;
2022-05-03 12:23:51 +03:00
}
static const struct cea_db *
__cea_db_iter_current_block ( const struct cea_db_iter * iter )
{
const struct cea_db * db ;
if ( ! iter - > collection )
return NULL ;
db = ( const struct cea_db * ) & iter - > collection [ iter - > index ] ;
if ( iter - > index + sizeof ( * db ) < = iter - > end & &
iter - > index + sizeof ( * db ) + cea_db_payload_len ( db ) < = iter - > end )
return db ;
return NULL ;
}
2022-06-08 10:50:32 +03:00
/*
* References :
* - CTA - 861 - H section 7.3 .3 CTA Extension Version 3
*/
static int cea_db_collection_size ( const u8 * cta )
{
u8 d = cta [ 2 ] ;
if ( d < 4 | | d > 127 )
return 0 ;
return d - 4 ;
}
2022-05-03 12:23:51 +03:00
/*
* References :
* - VESA E - EDID v1 .4
* - CTA - 861 - H section 7.3 .3 CTA Extension Version 3
*/
static const void * __cea_db_iter_edid_next ( struct cea_db_iter * iter )
{
const u8 * ext ;
drm_edid_iter_for_each ( ext , & iter - > edid_iter ) {
2022-06-08 10:50:32 +03:00
int size ;
2022-05-03 12:23:51 +03:00
/* Only support CTA Extension revision 3+ */
if ( ext [ 0 ] ! = CEA_EXT | | cea_revision ( ext ) < 3 )
continue ;
2022-06-08 10:50:32 +03:00
size = cea_db_collection_size ( ext ) ;
if ( ! size )
2022-05-03 12:23:51 +03:00
continue ;
2022-06-08 10:50:32 +03:00
iter - > index = 4 ;
iter - > end = iter - > index + size ;
2022-05-03 12:23:51 +03:00
return ext ;
}
return NULL ;
}
/*
* References :
* - DisplayID v1 .3 Appendix C : CEA Data Block within a DisplayID Data Block
* - DisplayID v2 .0 section 4.10 CTA DisplayID Data Block
*
* Note that the above do not specify any connection between DisplayID Data
* Block revision and CTA Extension versions .
*/
static const void * __cea_db_iter_displayid_next ( struct cea_db_iter * iter )
{
const struct displayid_block * block ;
displayid_iter_for_each ( block , & iter - > displayid_iter ) {
if ( block - > tag ! = DATA_BLOCK_CTA )
continue ;
/*
* The displayid iterator has already verified the block bounds
* in displayid_iter_block ( ) .
*/
iter - > index = sizeof ( * block ) ;
iter - > end = iter - > index + block - > num_bytes ;
return block ;
}
return NULL ;
}
static const struct cea_db * __cea_db_iter_next ( struct cea_db_iter * iter )
{
const struct cea_db * db ;
if ( iter - > collection ) {
/* Current collection should always be valid. */
db = __cea_db_iter_current_block ( iter ) ;
if ( WARN_ON ( ! db ) ) {
iter - > collection = NULL ;
return NULL ;
}
/* Next block in CTA Data Block Collection */
iter - > index + = sizeof ( * db ) + cea_db_payload_len ( db ) ;
db = __cea_db_iter_current_block ( iter ) ;
if ( db )
return db ;
}
for ( ; ; ) {
/*
* Find the next CTA Data Block Collection . First iterate all
* the EDID CTA Extensions , then all the DisplayID CTA blocks .
*
* Per DisplayID v1 .3 Appendix B : DisplayID as an EDID
* Extension , it ' s recommended that DisplayID extensions are
* exposed after all of the CTA Extensions .
*/
iter - > collection = __cea_db_iter_edid_next ( iter ) ;
if ( ! iter - > collection )
iter - > collection = __cea_db_iter_displayid_next ( iter ) ;
if ( ! iter - > collection )
return NULL ;
db = __cea_db_iter_current_block ( iter ) ;
if ( db )
return db ;
}
}
# define cea_db_iter_for_each(__db, __iter) \
while ( ( ( __db ) = __cea_db_iter_next ( __iter ) ) )
static void cea_db_iter_end ( struct cea_db_iter * iter )
{
displayid_iter_end ( & iter - > displayid_iter ) ;
drm_edid_iter_end ( & iter - > edid_iter ) ;
memset ( iter , 0 , sizeof ( * iter ) ) ;
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_hdmi_vsdb ( const struct cea_db * db )
2013-08-19 16:58:54 +01:00
{
2022-05-03 12:23:52 +03:00
return cea_db_is_vendor ( db , HDMI_IEEE_OUI ) & &
cea_db_payload_len ( db ) > = 5 ;
2013-08-19 16:58:54 +01:00
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_hdmi_forum_vsdb ( const struct cea_db * db )
2017-03-13 16:54:00 +05:30
{
2022-05-03 12:23:52 +03:00
return cea_db_is_vendor ( db , HDMI_FORUM_IEEE_OUI ) & &
cea_db_payload_len ( db ) > = 7 ;
2017-03-13 16:54:00 +05:30
}
2022-06-29 12:27:54 +03:00
static bool cea_db_is_hdmi_forum_eeodb ( const void * db )
{
return cea_db_is_extended_tag ( db , CTA_EXT_DB_HF_EEODB ) & &
cea_db_payload_len ( db ) > = 2 ;
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_microsoft_vsdb ( const struct cea_db * db )
2022-01-23 11:16:52 +01:00
{
2022-05-03 12:23:52 +03:00
return cea_db_is_vendor ( db , MICROSOFT_IEEE_OUI ) & &
cea_db_payload_len ( db ) = = 21 ;
2022-01-23 11:16:52 +01:00
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_vcdb ( const struct cea_db * db )
2019-01-08 19:28:28 +02:00
{
2022-05-03 12:23:52 +03:00
return cea_db_is_extended_tag ( db , CTA_EXT_DB_VIDEO_CAP ) & &
cea_db_payload_len ( db ) = = 2 ;
2019-01-08 19:28:28 +02:00
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_hdmi_forum_scdb ( const struct cea_db * db )
2022-05-03 12:23:47 +03:00
{
2022-05-03 12:23:52 +03:00
return cea_db_is_extended_tag ( db , CTA_EXT_DB_HF_SCDB ) & &
cea_db_payload_len ( db ) > = 7 ;
2022-05-03 12:23:47 +03:00
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_y420cmdb ( const struct cea_db * db )
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
{
2022-05-03 12:23:52 +03:00
return cea_db_is_extended_tag ( db , CTA_EXT_DB_420_VIDEO_CAP_MAP ) ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
}
2022-05-03 12:24:01 +03:00
static bool cea_db_is_y420vdb ( const struct cea_db * db )
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
{
2022-05-03 12:23:52 +03:00
return cea_db_is_extended_tag ( db , CTA_EXT_DB_420_VIDEO_DATA ) ;
}
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
2022-05-03 12:24:01 +03:00
static bool cea_db_is_hdmi_hdr_metadata_block ( const struct cea_db * db )
2022-05-03 12:23:52 +03:00
{
return cea_db_is_extended_tag ( db , CTA_EXT_DB_HDR_STATIC_METADATA ) & &
cea_db_payload_len ( db ) > = 3 ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
}
2022-06-29 12:27:54 +03:00
/*
* Get the HF - EEODB override extension block count from EDID .
*
* The passed in EDID may be partially read , as long as it has at least two
* blocks ( base block and one extension block ) if EDID extension count is > 0.
*
* Note that this is * not * how you should parse CTA Data Blocks in general ; this
* is only to handle partially read EDIDs . Normally , use the CTA Data Block
* iterators instead .
*
* References :
* - HDMI 2.1 section 10.3 .6 HDMI Forum EDID Extension Override Data Block
*/
static int edid_hfeeodb_extension_block_count ( const struct edid * edid )
{
const u8 * cta ;
/* No extensions according to base block, no HF-EEODB. */
if ( ! edid_extension_block_count ( edid ) )
return 0 ;
/* HF-EEODB is always in the first EDID extension block only */
cta = edid_extension_block_data ( edid , 0 ) ;
if ( edid_block_tag ( cta ) ! = CEA_EXT | | cea_revision ( cta ) < 3 )
return 0 ;
/* Need to have the data block collection, and at least 3 bytes. */
if ( cea_db_collection_size ( cta ) < 3 )
return 0 ;
/*
* Sinks that include the HF - EEODB in their E - EDID shall include one and
* only one instance of the HF - EEODB in the E - EDID , occupying bytes 4
* through 6 of Block 1 of the E - EDID .
*/
if ( ! cea_db_is_hdmi_forum_eeodb ( & cta [ 4 ] ) )
return 0 ;
return cta [ 4 + 2 ] ;
}
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
static void drm_parse_y420cmdb_bitmap ( struct drm_connector * connector ,
const u8 * db )
{
struct drm_display_info * info = & connector - > display_info ;
struct drm_hdmi_info * hdmi = & info - > hdmi ;
u8 map_len = cea_db_payload_len ( db ) - 1 ;
u8 count ;
u64 map = 0 ;
if ( map_len = = 0 ) {
/* All CEA modes support ycbcr420 sampling also.*/
hdmi - > y420_cmdb_map = U64_MAX ;
2022-01-20 16:16:13 +01:00
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR420 ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
return ;
}
/*
* This map indicates which of the existing CEA block modes
* from VDB can support YCBCR420 output too . So if bit = 0 is
* set , first mode from VDB can support YCBCR420 output too .
* We will parse and keep this map , before parsing VDB itself
* to avoid going through the same block again and again .
*
* Spec is not clear about max possible size of this block .
* Clamping max bitmap block size at 8 bytes . Every byte can
* address 8 CEA modes , in this way this map can address
* 8 * 8 = first 64 SVDs .
*/
if ( WARN_ON_ONCE ( map_len > 8 ) )
map_len = 8 ;
for ( count = 0 ; count < map_len ; count + + )
map | = ( u64 ) db [ 2 + count ] < < ( 8 * count ) ;
if ( map )
2022-01-20 16:16:13 +01:00
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR420 ;
drm/edid: parse YCBCR420 videomodes from EDID
HDMI 2.0 spec adds support for YCBCR420 sub-sampled output.
CEA-861-F adds two new blocks in EDID's CEA extension blocks,
to provide information about sink's YCBCR420 output capabilities.
These blocks are:
- YCBCR420vdb(YCBCR 420 video data block):
This block contains VICs of video modes, which can be sopported only
in YCBCR420 output mode (Not in RGB/YCBCR444/422. Its like a normal
SVD block, valid for YCBCR420 modes only.
- YCBCR420cmdb(YCBCR 420 capability map data block):
This block gives information about video modes which can support
YCBCR420 output mode also (along with RGB,YCBCR444/422 etc) This
block contains a bitmap index of normal svd videomodes, which can
support YCBCR420 output too.
So if bit 0 from first vcb byte is set, first video mode in the svd
list can support YCBCR420 output too. Bit 1 means second video mode
from svd list can support YCBCR420 output too, and so on.
This patch adds two bitmaps in display's hdmi_info structure, one each
for VCB and VDB modes. If the source is HDMI 2.0 capable, this patch
adds:
- VDB modes (YCBCR 420 only modes) in connector's mode list, also makes
an entry in the vdb_bitmap per vic.
- VCB modes (YCBCR 420 also modes) only entry in the vcb_bitmap.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
V2: Addressed
Review comments from Emil:
- Use 1ULL<<i instead of 1<<i to make sure the output is 64bit.
- Use the suggested method for updating dbmap.
- Add documentation for YCBCR420_vcb_map to fix kbuild warning.
Review comments from Ville:
- Do not expose the YCBCR420 flags in uabi layer, keep it internal.
- Save a map of YCBCR420 modes for future reference.
- Check db length before trying to parse extended tag.
- Add a warning if there are > 64 modes in capability map block.
- Use y420cmdb in function names and macros while dealing with vcb
to be aligned with spec.
- Move the display information parsing block ahead of mode parsing
blocks.
V3: Addressed design/review comments from Ville
- Do not add flags in video modes, else we have to expose them to user
- There should not be a UABI change, and kernel should detect the
choice of the output based on type of mode, and the bitmaps.
- Use standard bitops from kernel bitmap header, instead of calculating
bit positions manually.
V4: Addressed review comments from Ville:
- s/ycbcr_420_vdb/y420vdb
- s/ycbcr_420_vcb/y420cmdb
- Be less verbose on description of do_y420vdb_modes
- Move newmode variable in the loop scope.
- Use svd_to_vic() to get a VIC, instead of 0x7f
- Remove bitmap description for CMDB modes & VDB modes
- Dont add connector->ycbcr_420_allowed check for cmdb modes
- Remove 'len' variable, in is_y420cmdb function, which is used
only once
- Add length check in is_y420vdb function
- Remove unnecessary if (!db) check in function parse_y420cmdb_bitmap
- Do not add print about YCBCR 420 modes
- Fix indentation in few places
- Move ycbcr420_dc_modes in next patch, where its used
- Add a separate patch for movement of drm_add_display_info()
V5: Addressed review comments from Ville:
- Add the patch which cleans up the current EXTENDED_TAG usage
- Make y420_cmdb_map u64
- Do not block ycbcr420 modes while parsing the EDID, rather
add a separate helper function to prune ycbcr420-only modes from
connector's probed modes.
V6: Rebase
V7: Move this patch after the 420_only validation patch (Ville)
V8: Addressed review comments from Ville
- use cea_vic_valid check before adding cmdb/vdb modes
- add check for i < 64 while adding cmdb modes
- use 1ULL while checking bitmap
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1500028426-14883-1-git-send-email-shashank.sharma@intel.com
[vsyrjala: Fix checkpatch complaints and indentation]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-14 16:03:46 +05:30
hdmi - > y420_cmdb_map = map ;
}
2022-05-11 12:26:50 +03:00
static int add_cea_modes ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
{
2022-05-03 12:23:53 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
int modes = 0 ;
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:53 +03:00
cea_db_iter_for_each ( db , & iter ) {
const u8 * hdmi = NULL , * video = NULL ;
u8 hdmi_len = 0 , video_len = 0 ;
if ( cea_db_tag ( db ) = = CTA_DB_VIDEO ) {
video = cea_db_data ( db ) ;
video_len = cea_db_payload_len ( db ) ;
modes + = do_cea_modes ( connector , video , video_len ) ;
} else if ( cea_db_is_hdmi_vsdb ( db ) ) {
/* FIXME: Switch to use cea_db_data() */
hdmi = ( const u8 * ) db ;
hdmi_len = cea_db_payload_len ( db ) ;
} else if ( cea_db_is_y420vdb ( db ) ) {
const u8 * vdb420 = cea_db_data ( db ) + 1 ;
/* Add 4:2:0(only) modes present in EDID */
modes + = do_y420vdb_modes ( connector , vdb420 ,
cea_db_payload_len ( db ) - 1 ) ;
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
}
2022-05-03 12:23:53 +03:00
/*
* We parse the HDMI VSDB after having added the cea modes as we
* will be patching their flags when the sink supports stereo
* 3 D .
*/
if ( hdmi )
modes + = do_hdmi_vsdb_modes ( connector , hdmi , hdmi_len ,
video , video_len ) ;
}
cea_db_iter_end ( & iter ) ;
2013-09-25 16:45:23 +01:00
drm/edid: support CEA video modes.
TFT/plasma televisions and projectors have become commonplace, and so
has the use of PCs to drive them. Add the video modes specified by an
EDID's CEA extension to the mode database for a connector.
Before:
[ 1.158869] [drm:drm_mode_debug_printmodeline], Modeline
19:"1920x1080i" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.158875] [drm:drm_mode_debug_printmodeline], Modeline
18:"1920x1080i" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.158882] [drm:drm_mode_debug_printmodeline], Modeline
20:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
After:
[ 1.144175] [drm:drm_mode_debug_printmodeline], Modeline
22:"1920x1080" 0 74250 1920 2448 2492 2640 1080 1084 1094 1125 0x40 0x15
[ 1.144179] [drm:drm_mode_debug_printmodeline], Modeline
21:"1920x1080" 0 74250 1920 2008 2052 2200 1080 1084 1094 1125 0x48 0x15
[ 1.144187] [drm:drm_mode_debug_printmodeline], Modeline
30:"1920x1080" 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5
[ 1.144190] [drm:drm_mode_debug_printmodeline], Modeline
29:"1920x1080" 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x40 0x5
[ 1.144192] [drm:drm_mode_debug_printmodeline], Modeline
25:"1920x1080" 24 74250 1920 2558 2602 2750 1080 1084 1089 1125 0x40 0x5
[ 1.144195] [drm:drm_mode_debug_printmodeline], Modeline
24:"1280x720" 50 74250 1280 1720 1760 1980 720 725 730 750 0x40 0x5
[ 1.144198] [drm:drm_mode_debug_printmodeline], Modeline
23:"1280x720" 60 74250 1280 1390 1430 1650 720 725 730 750 0x40 0x5
[ 1.144201] [drm:drm_mode_debug_printmodeline], Modeline 27:"720x576"
50 27000 720 732 796 864 576 581 586 625 0x40 0xa
[ 1.144203] [drm:drm_mode_debug_printmodeline], Modeline 26:"720x480"
60 27000 720 736 798 858 480 489 495 525 0x40 0xa
[ 1.144206] [drm:drm_mode_debug_printmodeline], Modeline 28:"640x480"
60 25175 640 656 752 800 480 490 492 525 0x40 0xa
Signed-off-by: Christian Schmidt <schmidt@digadd.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-12-19 14:53:16 +00:00
return modes ;
}
2015-10-08 11:43:32 +03:00
static void fixup_detailed_cea_mode_clock ( struct drm_display_mode * mode )
{
const struct drm_display_mode * cea_mode ;
int clock1 , clock2 , clock ;
2016-01-08 13:21:51 +02:00
u8 vic ;
2015-10-08 11:43:32 +03:00
const char * type ;
2015-11-16 21:05:12 +02:00
/*
* allow 5 kHz clock difference either way to account for
* the 10 kHz clock resolution limit of detailed timings .
*/
2016-01-08 13:21:51 +02:00
vic = drm_match_cea_mode_clock_tolerance ( mode , 5 ) ;
if ( drm_valid_cea_vic ( vic ) ) {
2015-10-08 11:43:32 +03:00
type = " CEA " ;
2019-12-13 19:43:45 +02:00
cea_mode = cea_mode_for_vic ( vic ) ;
2015-10-08 11:43:32 +03:00
clock1 = cea_mode - > clock ;
clock2 = cea_mode_alternate_clock ( cea_mode ) ;
} else {
2016-01-08 13:21:51 +02:00
vic = drm_match_hdmi_mode_clock_tolerance ( mode , 5 ) ;
if ( drm_valid_hdmi_vic ( vic ) ) {
2015-10-08 11:43:32 +03:00
type = " HDMI " ;
2016-01-08 13:21:51 +02:00
cea_mode = & edid_4k_modes [ vic ] ;
2015-10-08 11:43:32 +03:00
clock1 = cea_mode - > clock ;
clock2 = hdmi_mode_alternate_clock ( cea_mode ) ;
} else {
return ;
}
}
/* pick whichever is closest */
if ( abs ( mode - > clock - clock1 ) < abs ( mode - > clock - clock2 ) )
clock = clock1 ;
else
clock = clock2 ;
if ( mode - > clock = = clock )
return ;
DRM_DEBUG ( " detailed mode matches %s VIC %d, adjusting clock %d -> %d \n " ,
2016-01-08 13:21:51 +02:00
type , vic , mode - > clock , clock ) ;
2015-10-08 11:43:32 +03:00
mode - > clock = clock ;
}
2022-07-19 12:56:58 +03:00
static void drm_calculate_luminance_range ( struct drm_connector * connector )
{
struct hdr_static_metadata * hdr_metadata = & connector - > hdr_sink_metadata . hdmi_type1 ;
struct drm_luminance_range_info * luminance_range =
& connector - > display_info . luminance_range ;
static const u8 pre_computed_values [ ] = {
50 , 51 , 52 , 53 , 55 , 56 , 57 , 58 , 59 , 61 , 62 , 63 , 65 , 66 , 68 , 69 ,
71 , 72 , 74 , 75 , 77 , 79 , 81 , 82 , 84 , 86 , 88 , 90 , 92 , 94 , 96 , 98
} ;
u32 max_avg , min_cll , max , min , q , r ;
if ( ! ( hdr_metadata - > metadata_type & BIT ( HDMI_STATIC_METADATA_TYPE1 ) ) )
return ;
max_avg = hdr_metadata - > max_fall ;
min_cll = hdr_metadata - > min_cll ;
/*
* From the specification ( CTA - 861 - G ) , for calculating the maximum
* luminance we need to use :
* Luminance = 50 * 2 * * ( CV / 32 )
* Where CV is a one - byte value .
* For calculating this expression we may need float point precision ;
* to avoid this complexity level , we take advantage that CV is divided
* by a constant . From the Euclids division algorithm , we know that CV
* can be written as : CV = 32 * q + r . Next , we replace CV in the
* Luminance expression and get 50 * ( 2 * * q ) * ( 2 * * ( r / 32 ) ) , hence we just
* need to pre - compute the value of r / 32. For pre - computing the values
* We just used the following Ruby line :
* ( 0. . .32 ) . each { | cv | puts ( 50 * 2 * * ( cv / 32.0 ) ) . round }
* The results of the above expressions can be verified at
* pre_computed_values .
*/
q = max_avg > > 5 ;
r = max_avg % 32 ;
max = ( 1 < < q ) * pre_computed_values [ r ] ;
/* min luminance: maxLum * (CV/255)^2 / 100 */
q = DIV_ROUND_CLOSEST ( min_cll , 255 ) ;
min = max * DIV_ROUND_CLOSEST ( ( q * q ) , 100 ) ;
luminance_range - > min_luminance = min ;
luminance_range - > max_luminance = max ;
}
2019-05-16 19:40:08 +05:30
static uint8_t eotf_supported ( const u8 * edid_ext )
{
return edid_ext [ 2 ] &
( BIT ( HDMI_EOTF_TRADITIONAL_GAMMA_SDR ) |
BIT ( HDMI_EOTF_TRADITIONAL_GAMMA_HDR ) |
2019-05-16 19:40:12 +05:30
BIT ( HDMI_EOTF_SMPTE_ST2084 ) |
BIT ( HDMI_EOTF_BT_2100_HLG ) ) ;
2019-05-16 19:40:08 +05:30
}
static uint8_t hdr_metadata_type ( const u8 * edid_ext )
{
return edid_ext [ 3 ] &
BIT ( HDMI_STATIC_METADATA_TYPE1 ) ;
}
static void
drm_parse_hdr_metadata_block ( struct drm_connector * connector , const u8 * db )
{
u16 len ;
len = cea_db_payload_len ( db ) ;
connector - > hdr_sink_metadata . hdmi_type1 . eotf =
eotf_supported ( db ) ;
connector - > hdr_sink_metadata . hdmi_type1 . metadata_type =
hdr_metadata_type ( db ) ;
if ( len > = 4 )
connector - > hdr_sink_metadata . hdmi_type1 . max_cll = db [ 4 ] ;
if ( len > = 5 )
connector - > hdr_sink_metadata . hdmi_type1 . max_fall = db [ 5 ] ;
2022-07-19 12:56:58 +03:00
if ( len > = 6 ) {
2019-05-16 19:40:08 +05:30
connector - > hdr_sink_metadata . hdmi_type1 . min_cll = db [ 6 ] ;
2022-07-19 12:56:58 +03:00
/* Calculate only when all values are available */
drm_calculate_luminance_range ( connector ) ;
}
2019-05-16 19:40:08 +05:30
}
2011-09-05 14:23:20 +08:00
static void
2016-09-28 16:51:41 +03:00
drm_parse_hdmi_vsdb_audio ( struct drm_connector * connector , const u8 * db )
2011-09-05 14:23:20 +08:00
{
2012-08-16 14:55:05 +00:00
u8 len = cea_db_payload_len ( db ) ;
2011-09-05 14:23:20 +08:00
2017-11-01 16:20:57 +02:00
if ( len > = 6 & & ( db [ 6 ] & ( 1 < < 7 ) ) )
connector - > eld [ DRM_ELD_SAD_COUNT_CONN_TYPE ] | = DRM_ELD_SUPPORTS_AI ;
2012-08-16 14:55:05 +00:00
if ( len > = 8 ) {
connector - > latency_present [ 0 ] = db [ 8 ] > > 7 ;
connector - > latency_present [ 1 ] = ( db [ 8 ] > > 6 ) & 1 ;
}
if ( len > = 9 )
connector - > video_latency [ 0 ] = db [ 9 ] ;
if ( len > = 10 )
connector - > audio_latency [ 0 ] = db [ 10 ] ;
if ( len > = 11 )
connector - > video_latency [ 1 ] = db [ 11 ] ;
if ( len > = 12 )
connector - > audio_latency [ 1 ] = db [ 12 ] ;
2011-09-05 14:23:20 +08:00
2016-09-28 16:51:41 +03:00
DRM_DEBUG_KMS ( " HDMI: latency present %d %d, "
" video latency %d %d, "
" audio latency %d %d \n " ,
connector - > latency_present [ 0 ] ,
connector - > latency_present [ 1 ] ,
connector - > video_latency [ 0 ] ,
connector - > video_latency [ 1 ] ,
connector - > audio_latency [ 0 ] ,
connector - > audio_latency [ 1 ] ) ;
2011-09-05 14:23:20 +08:00
}
static void
2022-03-28 17:34:29 +03:00
monitor_name ( const struct detailed_timing * timing , void * data )
2011-09-05 14:23:20 +08:00
{
2022-03-28 17:34:29 +03:00
const char * * res = data ;
if ( ! is_display_descriptor ( timing , EDID_DETAIL_MONITOR_NAME ) )
2020-01-24 22:02:25 +02:00
return ;
2022-03-28 17:34:29 +03:00
* res = timing - > data . other_data . data . str . str ;
2012-08-16 14:55:06 +00:00
}
2022-05-09 15:03:14 +03:00
static int get_monitor_name ( const struct drm_edid * drm_edid , char name [ 13 ] )
2016-04-14 10:18:35 -07:00
{
2022-03-28 17:34:29 +03:00
const char * edid_name = NULL ;
2016-04-14 10:18:35 -07:00
int mnl ;
2022-05-09 15:03:14 +03:00
if ( ! drm_edid | | ! name )
2016-04-14 10:18:35 -07:00
return 0 ;
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , monitor_name , & edid_name ) ;
2016-04-14 10:18:35 -07:00
for ( mnl = 0 ; edid_name & & mnl < 13 ; mnl + + ) {
if ( edid_name [ mnl ] = = 0x0a )
break ;
name [ mnl ] = edid_name [ mnl ] ;
}
return mnl ;
}
/**
* drm_edid_get_monitor_name - fetch the monitor name from the edid
* @ edid : monitor EDID information
* @ name : pointer to a character array to hold the name of the monitor
* @ bufsize : The size of the name buffer ( should be at least 14 chars . )
*
*/
2022-03-28 17:34:32 +03:00
void drm_edid_get_monitor_name ( const struct edid * edid , char * name , int bufsize )
2016-04-14 10:18:35 -07:00
{
2022-05-09 15:03:14 +03:00
int name_length = 0 ;
2020-01-24 22:02:27 +02:00
2016-04-14 10:18:35 -07:00
if ( bufsize < = 0 )
return ;
2022-05-09 15:03:14 +03:00
if ( edid ) {
char buf [ 13 ] ;
struct drm_edid drm_edid = {
. edid = edid ,
. size = edid_size ( edid ) ,
} ;
name_length = min ( get_monitor_name ( & drm_edid , buf ) , bufsize - 1 ) ;
memcpy ( name , buf , name_length ) ;
}
2016-04-14 10:18:35 -07:00
name [ name_length ] = ' \0 ' ;
}
EXPORT_SYMBOL ( drm_edid_get_monitor_name ) ;
2017-11-01 16:21:00 +02:00
static void clear_eld ( struct drm_connector * connector )
{
memset ( connector - > eld , 0 , sizeof ( connector - > eld ) ) ;
connector - > latency_present [ 0 ] = false ;
connector - > latency_present [ 1 ] = false ;
connector - > video_latency [ 0 ] = 0 ;
connector - > audio_latency [ 0 ] = 0 ;
connector - > video_latency [ 1 ] = 0 ;
connector - > audio_latency [ 1 ] = 0 ;
}
2017-11-01 16:21:03 +02:00
/*
2011-09-05 14:23:20 +08:00
* drm_edid_to_eld - build ELD from EDID
* @ connector : connector corresponding to the HDMI / DP sink
2022-05-11 12:23:49 +03:00
* @ drm_edid : EDID to parse
2011-09-05 14:23:20 +08:00
*
2014-04-29 11:44:34 +02:00
* Fill the ELD ( EDID - Like Data ) buffer for passing to the audio driver . The
2017-11-01 16:20:58 +02:00
* HDCP and Port_ID ELD fields are left for the graphics driver to fill in .
2011-09-05 14:23:20 +08:00
*/
2022-03-28 17:34:32 +03:00
static void drm_edid_to_eld ( struct drm_connector * connector ,
2022-05-11 12:23:49 +03:00
const struct drm_edid * drm_edid )
2011-09-05 14:23:20 +08:00
{
2022-05-03 12:24:04 +03:00
const struct drm_display_info * info = & connector - > display_info ;
2022-05-03 12:23:59 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
2011-09-05 14:23:20 +08:00
uint8_t * eld = connector - > eld ;
2016-03-09 22:07:46 +02:00
int total_sad_count = 0 ;
2011-09-05 14:23:20 +08:00
int mnl ;
2017-11-01 16:21:00 +02:00
clear_eld ( connector ) ;
2016-09-28 16:51:34 +03:00
2022-05-11 12:23:49 +03:00
if ( ! drm_edid )
2017-02-17 17:20:52 +02:00
return ;
2022-05-09 15:03:14 +03:00
mnl = get_monitor_name ( drm_edid , & eld [ DRM_ELD_MONITOR_NAME_STRING ] ) ;
2017-11-01 16:20:57 +02:00
DRM_DEBUG_KMS ( " ELD monitor %s \n " , & eld [ DRM_ELD_MONITOR_NAME_STRING ] ) ;
2016-04-14 10:18:35 -07:00
2022-05-03 12:24:04 +03:00
eld [ DRM_ELD_CEA_EDID_VER_MNL ] = info - > cea_rev < < DRM_ELD_CEA_EDID_VER_SHIFT ;
2017-11-01 16:20:57 +02:00
eld [ DRM_ELD_CEA_EDID_VER_MNL ] | = mnl ;
2011-09-05 14:23:20 +08:00
2017-11-01 16:20:57 +02:00
eld [ DRM_ELD_VER ] = DRM_ELD_VER_CEA861D ;
2011-09-05 14:23:20 +08:00
2022-05-11 12:23:49 +03:00
eld [ DRM_ELD_MANUFACTURER_NAME0 ] = drm_edid - > edid - > mfg_id [ 0 ] ;
eld [ DRM_ELD_MANUFACTURER_NAME1 ] = drm_edid - > edid - > mfg_id [ 1 ] ;
eld [ DRM_ELD_PRODUCT_CODE0 ] = drm_edid - > edid - > prod_code [ 0 ] ;
eld [ DRM_ELD_PRODUCT_CODE1 ] = drm_edid - > edid - > prod_code [ 1 ] ;
2011-09-05 14:23:20 +08:00
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:59 +03:00
cea_db_iter_for_each ( db , & iter ) {
const u8 * data = cea_db_data ( db ) ;
int len = cea_db_payload_len ( db ) ;
2020-03-06 09:32:13 -08:00
int sad_count ;
2012-08-16 14:55:04 +00:00
2022-05-03 12:23:59 +03:00
switch ( cea_db_tag ( db ) ) {
case CTA_DB_AUDIO :
/* Audio Data Block, contains SADs */
sad_count = min ( len / 3 , 15 - total_sad_count ) ;
if ( sad_count > = 1 )
memcpy ( & eld [ DRM_ELD_CEA_SAD ( mnl , total_sad_count ) ] ,
data , sad_count * 3 ) ;
total_sad_count + = sad_count ;
break ;
case CTA_DB_SPEAKER :
/* Speaker Allocation Data Block */
if ( len > = 1 )
eld [ DRM_ELD_SPEAKER ] = data [ 0 ] ;
break ;
case CTA_DB_VENDOR :
/* HDMI Vendor-Specific Data Block */
if ( cea_db_is_hdmi_vsdb ( db ) )
drm_parse_hdmi_vsdb_audio ( connector , ( const u8 * ) db ) ;
break ;
default :
break ;
2011-09-05 14:23:20 +08:00
}
2012-08-16 14:55:04 +00:00
}
2022-05-03 12:23:59 +03:00
cea_db_iter_end ( & iter ) ;
2017-11-01 16:20:57 +02:00
eld [ DRM_ELD_SAD_COUNT_CONN_TYPE ] | = total_sad_count < < DRM_ELD_SAD_COUNT_SHIFT ;
2011-09-05 14:23:20 +08:00
2017-11-01 16:20:58 +02:00
if ( connector - > connector_type = = DRM_MODE_CONNECTOR_DisplayPort | |
connector - > connector_type = = DRM_MODE_CONNECTOR_eDP )
eld [ DRM_ELD_SAD_COUNT_CONN_TYPE ] | = DRM_ELD_CONN_TYPE_DP ;
else
eld [ DRM_ELD_SAD_COUNT_CONN_TYPE ] | = DRM_ELD_CONN_TYPE_HDMI ;
2011-09-05 14:23:20 +08:00
2014-10-28 16:20:48 +02:00
eld [ DRM_ELD_BASELINE_ELD_LEN ] =
DIV_ROUND_UP ( drm_eld_calc_baseline_block_size ( eld ) , 4 ) ;
DRM_DEBUG_KMS ( " ELD size %d, SAD count %d \n " ,
2016-03-09 22:07:46 +02:00
drm_eld_size ( eld ) , total_sad_count ) ;
2011-09-05 14:23:20 +08:00
}
2022-05-09 15:03:16 +03:00
static int _drm_edid_to_sad ( const struct drm_edid * drm_edid ,
struct cea_sad * * sads )
2013-04-19 19:01:25 +02:00
{
2022-05-03 12:23:55 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
2013-04-19 19:01:25 +02:00
int count = 0 ;
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:55 +03:00
cea_db_iter_for_each ( db , & iter ) {
2022-05-03 12:23:49 +03:00
if ( cea_db_tag ( db ) = = CTA_DB_AUDIO ) {
2013-04-19 19:01:25 +02:00
int j ;
2020-07-02 18:53:32 +05:30
2022-05-03 12:23:55 +03:00
count = cea_db_payload_len ( db ) / 3 ; /* SAD is 3B */
2013-04-19 19:01:25 +02:00
* sads = kcalloc ( count , sizeof ( * * sads ) , GFP_KERNEL ) ;
if ( ! * sads )
return - ENOMEM ;
for ( j = 0 ; j < count ; j + + ) {
2022-05-03 12:23:55 +03:00
const u8 * sad = & db - > data [ j * 3 ] ;
2013-04-19 19:01:25 +02:00
( * sads ) [ j ] . format = ( sad [ 0 ] & 0x78 ) > > 3 ;
( * sads ) [ j ] . channels = sad [ 0 ] & 0x7 ;
( * sads ) [ j ] . freq = sad [ 1 ] & 0x7F ;
( * sads ) [ j ] . byte2 = sad [ 2 ] ;
}
break ;
}
}
2022-05-03 12:23:55 +03:00
cea_db_iter_end ( & iter ) ;
DRM_DEBUG_KMS ( " Found %d Short Audio Descriptors \n " , count ) ;
2013-04-19 19:01:25 +02:00
return count ;
}
2022-05-09 15:03:16 +03:00
/**
* drm_edid_to_sad - extracts SADs from EDID
* @ edid : EDID to parse
* @ sads : pointer that will be set to the extracted SADs
*
* Looks for CEA EDID block and extracts SADs ( Short Audio Descriptors ) from it .
*
* Note : The returned pointer needs to be freed using kfree ( ) .
*
* Return : The number of found SADs or negative number on error .
*/
int drm_edid_to_sad ( const struct edid * edid , struct cea_sad * * sads )
{
struct drm_edid drm_edid ;
return _drm_edid_to_sad ( drm_edid_legacy_init ( & drm_edid , edid ) , sads ) ;
}
2013-04-19 19:01:25 +02:00
EXPORT_SYMBOL ( drm_edid_to_sad ) ;
2022-05-09 15:03:17 +03:00
static int _drm_edid_to_speaker_allocation ( const struct drm_edid * drm_edid ,
u8 * * sadb )
2013-07-25 15:55:32 -04:00
{
2022-05-03 12:23:54 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
2013-07-25 15:55:32 -04:00
int count = 0 ;
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:54 +03:00
cea_db_iter_for_each ( db , & iter ) {
if ( cea_db_tag ( db ) = = CTA_DB_SPEAKER & &
cea_db_payload_len ( db ) = = 3 ) {
* sadb = kmemdup ( db - > data , cea_db_payload_len ( db ) ,
GFP_KERNEL ) ;
if ( ! * sadb )
return - ENOMEM ;
count = cea_db_payload_len ( db ) ;
break ;
2013-07-25 15:55:32 -04:00
}
}
2022-05-03 12:23:54 +03:00
cea_db_iter_end ( & iter ) ;
DRM_DEBUG_KMS ( " Found %d Speaker Allocation Data Blocks \n " , count ) ;
2013-07-25 15:55:32 -04:00
return count ;
}
2022-05-09 15:03:17 +03:00
/**
* drm_edid_to_speaker_allocation - extracts Speaker Allocation Data Blocks from EDID
* @ edid : EDID to parse
* @ sadb : pointer to the speaker block
*
* Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it .
*
* Note : The returned pointer needs to be freed using kfree ( ) .
*
* Return : The number of found Speaker Allocation Blocks or negative number on
* error .
*/
int drm_edid_to_speaker_allocation ( const struct edid * edid , u8 * * sadb )
{
struct drm_edid drm_edid ;
return _drm_edid_to_speaker_allocation ( drm_edid_legacy_init ( & drm_edid , edid ) ,
sadb ) ;
}
2013-07-25 15:55:32 -04:00
EXPORT_SYMBOL ( drm_edid_to_speaker_allocation ) ;
2011-09-05 14:23:20 +08:00
/**
2014-04-29 11:44:34 +02:00
* drm_av_sync_delay - compute the HDMI / DP sink audio - video sync delay
2011-09-05 14:23:20 +08:00
* @ connector : connector associated with the HDMI / DP sink
* @ mode : the display mode
2014-04-29 11:44:34 +02:00
*
* Return : The HDMI / DP sink ' s audio - video sync delay in milliseconds or 0 if
* the sink doesn ' t support audio or video .
2011-09-05 14:23:20 +08:00
*/
int drm_av_sync_delay ( struct drm_connector * connector ,
2015-09-07 18:22:58 +03:00
const struct drm_display_mode * mode )
2011-09-05 14:23:20 +08:00
{
int i = ! ! ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) ;
int a , v ;
if ( ! connector - > latency_present [ 0 ] )
return 0 ;
if ( ! connector - > latency_present [ 1 ] )
i = 0 ;
a = connector - > audio_latency [ i ] ;
v = connector - > video_latency [ i ] ;
/*
* HDMI / DP sink doesn ' t support audio or video ?
*/
if ( a = = 255 | | v = = 255 )
return 0 ;
/*
* Convert raw EDID values to millisecond .
* Treat unknown latency as 0 ms .
*/
if ( a )
a = min ( 2 * ( a - 1 ) , 500 ) ;
if ( v )
v = min ( 2 * ( v - 1 ) , 500 ) ;
return max ( v - a , 0 ) ;
}
EXPORT_SYMBOL ( drm_av_sync_delay ) ;
2022-05-09 15:03:18 +03:00
static bool _drm_detect_hdmi_monitor ( const struct drm_edid * drm_edid )
2010-09-19 14:27:28 +08:00
{
2022-05-03 12:23:56 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
bool hdmi = false ;
2009-03-26 19:26:23 +08:00
/*
* Because HDMI identifier is in Vendor Specific Block ,
* search it from all data blocks of CEA extension .
*/
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:56 +03:00
cea_db_iter_for_each ( db , & iter ) {
if ( cea_db_is_hdmi_vsdb ( db ) ) {
hdmi = true ;
break ;
}
2009-03-26 19:26:23 +08:00
}
2022-05-03 12:23:56 +03:00
cea_db_iter_end ( & iter ) ;
2009-03-26 19:26:23 +08:00
2022-05-03 12:23:56 +03:00
return hdmi ;
2009-03-26 19:26:23 +08:00
}
2022-05-09 15:03:18 +03:00
/**
* drm_detect_hdmi_monitor - detect whether monitor is HDMI
* @ edid : monitor EDID information
*
* Parse the CEA extension according to CEA - 861 - B .
*
* Drivers that have added the modes parsed from EDID to drm_display_info
* should use & drm_display_info . is_hdmi instead of calling this function .
*
* Return : True if the monitor is HDMI , false if not or unknown .
*/
bool drm_detect_hdmi_monitor ( const struct edid * edid )
{
struct drm_edid drm_edid ;
return _drm_detect_hdmi_monitor ( drm_edid_legacy_init ( & drm_edid , edid ) ) ;
}
2009-03-26 19:26:23 +08:00
EXPORT_SYMBOL ( drm_detect_hdmi_monitor ) ;
2022-05-09 15:03:19 +03:00
static bool _drm_detect_monitor_audio ( const struct drm_edid * drm_edid )
2010-09-19 14:27:28 +08:00
{
2022-05-03 12:24:02 +03:00
struct drm_edid_iter edid_iter ;
2022-05-03 12:23:57 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
2021-03-29 16:37:15 +03:00
const u8 * edid_ext ;
2010-09-19 14:27:28 +08:00
bool has_audio = false ;
2022-05-09 15:03:21 +03:00
drm_edid_iter_begin ( drm_edid , & edid_iter ) ;
2022-05-03 12:24:02 +03:00
drm_edid_iter_for_each ( edid_ext , & edid_iter ) {
if ( edid_ext [ 0 ] = = CEA_EXT ) {
has_audio = edid_ext [ 3 ] & EDID_BASIC_AUDIO ;
if ( has_audio )
break ;
}
}
drm_edid_iter_end ( & edid_iter ) ;
2010-09-19 14:27:28 +08:00
if ( has_audio ) {
DRM_DEBUG_KMS ( " Monitor has basic audio support \n " ) ;
goto end ;
}
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:57 +03:00
cea_db_iter_for_each ( db , & iter ) {
if ( cea_db_tag ( db ) = = CTA_DB_AUDIO ) {
const u8 * data = cea_db_data ( db ) ;
int i ;
2010-09-19 14:27:28 +08:00
2022-05-03 12:23:57 +03:00
for ( i = 0 ; i < cea_db_payload_len ( db ) ; i + = 3 )
2010-09-19 14:27:28 +08:00
DRM_DEBUG_KMS ( " CEA audio format %d \n " ,
2022-05-03 12:23:57 +03:00
( data [ i ] > > 3 ) & 0xf ) ;
has_audio = true ;
break ;
2010-09-19 14:27:28 +08:00
}
}
2022-05-03 12:23:57 +03:00
cea_db_iter_end ( & iter ) ;
2010-09-19 14:27:28 +08:00
end :
return has_audio ;
}
2022-05-09 15:03:19 +03:00
/**
* drm_detect_monitor_audio - check monitor audio capability
* @ edid : EDID block to scan
*
* Monitor should have CEA extension block .
* If monitor has ' basic audio ' , but no CEA audio blocks , it ' s ' basic
* audio ' only . If there is any audio extension block and supported
* audio format , assume at least ' basic audio ' support , even if ' basic
* audio ' is not defined in EDID .
*
* Return : True if the monitor supports audio , false otherwise .
*/
bool drm_detect_monitor_audio ( const struct edid * edid )
{
struct drm_edid drm_edid ;
return _drm_detect_monitor_audio ( drm_edid_legacy_init ( & drm_edid , edid ) ) ;
}
2010-09-19 14:27:28 +08:00
EXPORT_SYMBOL ( drm_detect_monitor_audio ) ;
2013-01-17 16:31:30 +02:00
2017-01-11 16:18:35 +02:00
/**
* drm_default_rgb_quant_range - default RGB quantization range
* @ mode : display mode
*
* Determine the default RGB quantization range for the mode ,
* as specified in CEA - 861.
*
* Return : The default RGB quantization range for the mode
*/
enum hdmi_quantization_range
drm_default_rgb_quant_range ( const struct drm_display_mode * mode )
{
/* All CEA modes other than VIC 1 use limited quantization range. */
return drm_match_cea_mode ( mode ) > 1 ?
HDMI_QUANTIZATION_RANGE_LIMITED :
HDMI_QUANTIZATION_RANGE_FULL ;
}
EXPORT_SYMBOL ( drm_default_rgb_quant_range ) ;
2019-01-08 19:28:28 +02:00
static void drm_parse_vcdb ( struct drm_connector * connector , const u8 * db )
{
struct drm_display_info * info = & connector - > display_info ;
DRM_DEBUG_KMS ( " CEA VCDB 0x%02x \n " , db [ 2 ] ) ;
if ( db [ 2 ] & EDID_CEA_VCDB_QS )
info - > rgb_quant_range_selectable = true ;
}
2020-12-18 16:07:10 +05:30
static
void drm_get_max_frl_rate ( int max_frl_rate , u8 * max_lanes , u8 * max_rate_per_lane )
{
switch ( max_frl_rate ) {
case 1 :
* max_lanes = 3 ;
* max_rate_per_lane = 3 ;
break ;
case 2 :
* max_lanes = 3 ;
* max_rate_per_lane = 6 ;
break ;
case 3 :
* max_lanes = 4 ;
* max_rate_per_lane = 6 ;
break ;
case 4 :
* max_lanes = 4 ;
* max_rate_per_lane = 8 ;
break ;
case 5 :
* max_lanes = 4 ;
* max_rate_per_lane = 10 ;
break ;
case 6 :
* max_lanes = 4 ;
* max_rate_per_lane = 12 ;
break ;
case 0 :
default :
* max_lanes = 0 ;
* max_rate_per_lane = 0 ;
}
}
2017-07-13 21:03:13 +05:30
static void drm_parse_ycbcr420_deep_color_info ( struct drm_connector * connector ,
const u8 * db )
{
u8 dc_mask ;
struct drm_hdmi_info * hdmi = & connector - > display_info . hdmi ;
dc_mask = db [ 7 ] & DRM_EDID_YCBCR420_DC_MASK ;
2018-10-05 14:52:15 -07:00
hdmi - > y420_dc_modes = dc_mask ;
2017-07-13 21:03:13 +05:30
}
2022-05-03 12:23:48 +03:00
/* Sink Capability Data Structure */
static void drm_parse_hdmi_forum_scds ( struct drm_connector * connector ,
const u8 * hf_scds )
2017-03-13 16:54:01 +05:30
{
2017-03-13 16:54:02 +05:30
struct drm_display_info * display = & connector - > display_info ;
struct drm_hdmi_info * hdmi = & display - > hdmi ;
2017-03-13 16:54:01 +05:30
2017-11-13 19:04:19 +02:00
display - > has_hdmi_infoframe = true ;
2022-05-03 12:23:48 +03:00
if ( hf_scds [ 6 ] & 0x80 ) {
2017-03-13 16:54:01 +05:30
hdmi - > scdc . supported = true ;
2022-05-03 12:23:48 +03:00
if ( hf_scds [ 6 ] & 0x40 )
2017-03-13 16:54:01 +05:30
hdmi - > scdc . read_request = true ;
}
2017-03-13 16:54:02 +05:30
/*
* All HDMI 2.0 monitors must support scrambling at rates > 340 MHz .
* And as per the spec , three factors confirm this :
* * Availability of a HF - VSDB block in EDID ( check )
* * Non zero Max_TMDS_Char_Rate filed in HF - VSDB ( let ' s check )
* * SCDC support available ( let ' s check )
* Lets check it out .
*/
2022-05-03 12:23:48 +03:00
if ( hf_scds [ 5 ] ) {
2017-03-13 16:54:02 +05:30
/* max clock is 5000 KHz times block value */
2022-05-03 12:23:48 +03:00
u32 max_tmds_clock = hf_scds [ 5 ] * 5000 ;
2017-03-13 16:54:02 +05:30
struct drm_scdc * scdc = & hdmi - > scdc ;
if ( max_tmds_clock > 340000 ) {
display - > max_tmds_clock = max_tmds_clock ;
DRM_DEBUG_KMS ( " HF-VSDB: max TMDS clock %d kHz \n " ,
display - > max_tmds_clock ) ;
}
if ( scdc - > supported ) {
scdc - > scrambling . supported = true ;
2019-12-06 14:53:35 +01:00
/* Few sinks support scrambling for clocks < 340M */
2022-05-03 12:23:48 +03:00
if ( ( hf_scds [ 6 ] & 0x8 ) )
2017-03-13 16:54:02 +05:30
scdc - > scrambling . low_rates = true ;
}
}
2017-07-13 21:03:13 +05:30
2022-05-03 12:23:48 +03:00
if ( hf_scds [ 7 ] ) {
2020-12-18 16:07:10 +05:30
u8 max_frl_rate ;
2020-12-18 16:07:11 +05:30
u8 dsc_max_frl_rate ;
u8 dsc_max_slices ;
struct drm_hdmi_dsc_cap * hdmi_dsc = & hdmi - > dsc_cap ;
2020-12-18 16:07:10 +05:30
DRM_DEBUG_KMS ( " hdmi_21 sink detected. parsing edid \n " ) ;
2022-05-03 12:23:48 +03:00
max_frl_rate = ( hf_scds [ 7 ] & DRM_EDID_MAX_FRL_RATE_MASK ) > > 4 ;
2020-12-18 16:07:10 +05:30
drm_get_max_frl_rate ( max_frl_rate , & hdmi - > max_lanes ,
& hdmi - > max_frl_rate_per_lane ) ;
2022-05-03 12:23:48 +03:00
hdmi_dsc - > v_1p2 = hf_scds [ 11 ] & DRM_EDID_DSC_1P2 ;
2020-12-18 16:07:11 +05:30
if ( hdmi_dsc - > v_1p2 ) {
2022-05-03 12:23:48 +03:00
hdmi_dsc - > native_420 = hf_scds [ 11 ] & DRM_EDID_DSC_NATIVE_420 ;
hdmi_dsc - > all_bpp = hf_scds [ 11 ] & DRM_EDID_DSC_ALL_BPP ;
2020-12-18 16:07:11 +05:30
2022-05-03 12:23:48 +03:00
if ( hf_scds [ 11 ] & DRM_EDID_DSC_16BPC )
2020-12-18 16:07:11 +05:30
hdmi_dsc - > bpc_supported = 16 ;
2022-05-03 12:23:48 +03:00
else if ( hf_scds [ 11 ] & DRM_EDID_DSC_12BPC )
2020-12-18 16:07:11 +05:30
hdmi_dsc - > bpc_supported = 12 ;
2022-05-03 12:23:48 +03:00
else if ( hf_scds [ 11 ] & DRM_EDID_DSC_10BPC )
2020-12-18 16:07:11 +05:30
hdmi_dsc - > bpc_supported = 10 ;
else
hdmi_dsc - > bpc_supported = 0 ;
2022-05-03 12:23:48 +03:00
dsc_max_frl_rate = ( hf_scds [ 12 ] & DRM_EDID_DSC_MAX_FRL_RATE_MASK ) > > 4 ;
2020-12-18 16:07:11 +05:30
drm_get_max_frl_rate ( dsc_max_frl_rate , & hdmi_dsc - > max_lanes ,
& hdmi_dsc - > max_frl_rate_per_lane ) ;
2022-05-03 12:23:48 +03:00
hdmi_dsc - > total_chunk_kbytes = hf_scds [ 13 ] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES ;
2020-12-18 16:07:11 +05:30
2022-05-03 12:23:48 +03:00
dsc_max_slices = hf_scds [ 12 ] & DRM_EDID_DSC_MAX_SLICES ;
2020-12-18 16:07:11 +05:30
switch ( dsc_max_slices ) {
case 1 :
hdmi_dsc - > max_slices = 1 ;
hdmi_dsc - > clk_per_slice = 340 ;
break ;
case 2 :
hdmi_dsc - > max_slices = 2 ;
hdmi_dsc - > clk_per_slice = 340 ;
break ;
case 3 :
hdmi_dsc - > max_slices = 4 ;
hdmi_dsc - > clk_per_slice = 340 ;
break ;
case 4 :
hdmi_dsc - > max_slices = 8 ;
hdmi_dsc - > clk_per_slice = 340 ;
break ;
case 5 :
hdmi_dsc - > max_slices = 8 ;
hdmi_dsc - > clk_per_slice = 400 ;
break ;
case 6 :
hdmi_dsc - > max_slices = 12 ;
hdmi_dsc - > clk_per_slice = 400 ;
break ;
case 7 :
hdmi_dsc - > max_slices = 16 ;
hdmi_dsc - > clk_per_slice = 400 ;
break ;
case 0 :
default :
hdmi_dsc - > max_slices = 0 ;
hdmi_dsc - > clk_per_slice = 0 ;
}
}
2020-12-18 16:07:10 +05:30
}
2022-05-03 12:23:48 +03:00
drm_parse_ycbcr420_deep_color_info ( connector , hf_scds ) ;
2017-03-13 16:54:01 +05:30
}
2016-09-28 16:51:39 +03:00
static void drm_parse_hdmi_deep_color_info ( struct drm_connector * connector ,
const u8 * hdmi )
2014-03-27 19:59:39 +01:00
{
2016-09-28 16:51:38 +03:00
struct drm_display_info * info = & connector - > display_info ;
2014-03-27 19:59:39 +01:00
unsigned int dc_bpc = 0 ;
2016-09-28 16:51:39 +03:00
/* HDMI supports at least 8 bpc */
info - > bpc = 8 ;
2014-03-27 19:59:39 +01:00
2016-09-28 16:51:39 +03:00
if ( cea_db_payload_len ( hdmi ) < 6 )
return ;
if ( hdmi [ 6 ] & DRM_EDID_HDMI_DC_30 ) {
dc_bpc = 10 ;
2022-01-20 16:16:12 +01:00
info - > edid_hdmi_rgb444_dc_modes | = DRM_EDID_HDMI_DC_30 ;
2016-09-28 16:51:39 +03:00
DRM_DEBUG ( " %s: HDMI sink does deep color 30. \n " ,
connector - > name ) ;
}
if ( hdmi [ 6 ] & DRM_EDID_HDMI_DC_36 ) {
dc_bpc = 12 ;
2022-01-20 16:16:12 +01:00
info - > edid_hdmi_rgb444_dc_modes | = DRM_EDID_HDMI_DC_36 ;
2016-09-28 16:51:39 +03:00
DRM_DEBUG ( " %s: HDMI sink does deep color 36. \n " ,
connector - > name ) ;
}
if ( hdmi [ 6 ] & DRM_EDID_HDMI_DC_48 ) {
dc_bpc = 16 ;
2022-01-20 16:16:12 +01:00
info - > edid_hdmi_rgb444_dc_modes | = DRM_EDID_HDMI_DC_48 ;
2016-09-28 16:51:39 +03:00
DRM_DEBUG ( " %s: HDMI sink does deep color 48. \n " ,
connector - > name ) ;
}
if ( dc_bpc = = 0 ) {
DRM_DEBUG ( " %s: No deep color support on this HDMI sink. \n " ,
connector - > name ) ;
return ;
}
DRM_DEBUG ( " %s: Assigning HDMI sink color depth as %d bpc. \n " ,
connector - > name , dc_bpc ) ;
info - > bpc = dc_bpc ;
2014-03-27 19:59:39 +01:00
2016-09-28 16:51:39 +03:00
/* YCRCB444 is optional according to spec. */
if ( hdmi [ 6 ] & DRM_EDID_HDMI_DC_Y444 ) {
2022-01-20 16:16:12 +01:00
info - > edid_hdmi_ycbcr444_dc_modes = info - > edid_hdmi_rgb444_dc_modes ;
2016-09-28 16:51:39 +03:00
DRM_DEBUG ( " %s: HDMI sink does YCRCB444 in deep color. \n " ,
connector - > name ) ;
}
2014-03-27 19:59:39 +01:00
2016-09-28 16:51:39 +03:00
/*
* Spec says that if any deep color mode is supported at all ,
* then deep color 36 bit must be supported .
*/
if ( ! ( hdmi [ 6 ] & DRM_EDID_HDMI_DC_36 ) ) {
DRM_DEBUG ( " %s: HDMI sink should do DC_36, but does not! \n " ,
connector - > name ) ;
}
}
2014-03-27 19:59:39 +01:00
2016-09-28 16:51:41 +03:00
static void
drm_parse_hdmi_vsdb_video ( struct drm_connector * connector , const u8 * db )
{
struct drm_display_info * info = & connector - > display_info ;
u8 len = cea_db_payload_len ( db ) ;
2020-02-26 13:24:23 +02:00
info - > is_hdmi = true ;
2016-09-28 16:51:41 +03:00
if ( len > = 6 )
info - > dvi_dual = db [ 6 ] & 1 ;
if ( len > = 7 )
info - > max_tmds_clock = db [ 7 ] * 5000 ;
DRM_DEBUG_KMS ( " HDMI: DVI dual %d, "
" max TMDS clock %d kHz \n " ,
info - > dvi_dual ,
info - > max_tmds_clock ) ;
drm_parse_hdmi_deep_color_info ( connector , db ) ;
}
2022-01-23 11:16:52 +01:00
/*
* See EDID extension for head - mounted and specialized monitors , specified at :
* https : //docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
*/
static void drm_parse_microsoft_vsdb ( struct drm_connector * connector ,
const u8 * db )
{
struct drm_display_info * info = & connector - > display_info ;
u8 version = db [ 4 ] ;
bool desktop_usage = db [ 5 ] & BIT ( 6 ) ;
/* Version 1 and 2 for HMDs, version 3 flags desktop usage explicitly */
if ( version = = 1 | | version = = 2 | | ( version = = 3 & & ! desktop_usage ) )
info - > non_desktop = true ;
drm_dbg_kms ( connector - > dev , " HMD or specialized display VSDB version %u: 0x%02x \n " ,
version , db [ 5 ] ) ;
}
2016-09-28 16:51:39 +03:00
static void drm_parse_cea_ext ( struct drm_connector * connector ,
2022-05-11 12:21:04 +03:00
const struct drm_edid * drm_edid )
2016-09-28 16:51:39 +03:00
{
struct drm_display_info * info = & connector - > display_info ;
2022-05-05 13:52:42 +03:00
struct drm_edid_iter edid_iter ;
2022-05-03 12:23:58 +03:00
const struct cea_db * db ;
struct cea_db_iter iter ;
2016-09-28 16:51:39 +03:00
const u8 * edid_ext ;
2014-03-27 19:59:39 +01:00
2022-05-09 15:03:21 +03:00
drm_edid_iter_begin ( drm_edid , & edid_iter ) ;
2022-05-05 13:52:42 +03:00
drm_edid_iter_for_each ( edid_ext , & edid_iter ) {
if ( edid_ext [ 0 ] ! = CEA_EXT )
continue ;
2014-03-27 19:59:39 +01:00
2022-05-05 13:52:42 +03:00
if ( ! info - > cea_rev )
info - > cea_rev = edid_ext [ 1 ] ;
2014-03-27 19:59:39 +01:00
2022-05-05 13:52:42 +03:00
if ( info - > cea_rev ! = edid_ext [ 1 ] )
DRM_DEBUG_KMS ( " CEA extension version mismatch %u != %u \n " ,
info - > cea_rev , edid_ext [ 1 ] ) ;
2022-03-23 12:04:38 +02:00
2022-05-05 13:52:42 +03:00
/* The existence of a CTA extension should imply RGB support */
info - > color_formats = DRM_COLOR_FORMAT_RGB444 ;
2022-03-23 12:04:38 +02:00
if ( edid_ext [ 3 ] & EDID_CEA_YCRCB444 )
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR444 ;
if ( edid_ext [ 3 ] & EDID_CEA_YCRCB422 )
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR422 ;
}
2022-05-05 13:52:42 +03:00
drm_edid_iter_end ( & edid_iter ) ;
2016-09-28 16:51:39 +03:00
2022-05-09 15:03:20 +03:00
cea_db_iter_edid_begin ( drm_edid , & iter ) ;
2022-05-03 12:23:58 +03:00
cea_db_iter_for_each ( db , & iter ) {
/* FIXME: convert parsers to use struct cea_db */
const u8 * data = ( const u8 * ) db ;
2016-09-28 16:51:39 +03:00
2016-09-28 16:51:41 +03:00
if ( cea_db_is_hdmi_vsdb ( db ) )
2022-05-03 12:23:58 +03:00
drm_parse_hdmi_vsdb_video ( connector , data ) ;
2022-05-09 15:03:00 +03:00
else if ( cea_db_is_hdmi_forum_vsdb ( db ) | |
cea_db_is_hdmi_forum_scdb ( db ) )
2022-05-03 12:23:58 +03:00
drm_parse_hdmi_forum_scds ( connector , data ) ;
2022-05-09 15:03:00 +03:00
else if ( cea_db_is_microsoft_vsdb ( db ) )
2022-05-03 12:23:58 +03:00
drm_parse_microsoft_vsdb ( connector , data ) ;
2022-05-09 15:03:00 +03:00
else if ( cea_db_is_y420cmdb ( db ) )
2022-05-03 12:23:58 +03:00
drm_parse_y420cmdb_bitmap ( connector , data ) ;
2022-05-09 15:03:00 +03:00
else if ( cea_db_is_vcdb ( db ) )
2022-05-03 12:23:58 +03:00
drm_parse_vcdb ( connector , data ) ;
2022-05-09 15:03:00 +03:00
else if ( cea_db_is_hdmi_hdr_metadata_block ( db ) )
2022-05-03 12:23:58 +03:00
drm_parse_hdr_metadata_block ( connector , data ) ;
2016-09-28 16:51:39 +03:00
}
2022-05-03 12:23:58 +03:00
cea_db_iter_end ( & iter ) ;
2014-03-27 19:59:39 +01:00
}
2020-03-10 16:16:51 -07:00
static
2022-03-28 17:34:29 +03:00
void get_monitor_range ( const struct detailed_timing * timing ,
2020-03-10 16:16:51 -07:00
void * info_monitor_range )
{
struct drm_monitor_range_info * monitor_range = info_monitor_range ;
const struct detailed_non_pixel * data = & timing - > data . other_data ;
const struct detailed_data_monitor_range * range = & data - > data . range ;
2022-03-28 17:34:24 +03:00
if ( ! is_display_descriptor ( timing , EDID_DETAIL_MONITOR_RANGE ) )
2020-03-10 16:16:51 -07:00
return ;
/*
* Check for flag range limits only . If flag = = 1 then
* no additional timing information provided .
* Default GTF , GTF Secondary curve and CVT are not
* supported
*/
if ( range - > flags ! = DRM_EDID_RANGE_LIMITS_ONLY_FLAG )
return ;
monitor_range - > min_vfreq = range - > min_vfreq ;
monitor_range - > max_vfreq = range - > max_vfreq ;
}
2022-05-11 12:21:04 +03:00
static void drm_get_monitor_range ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2020-03-10 16:16:51 -07:00
{
struct drm_display_info * info = & connector - > display_info ;
2022-05-09 15:03:24 +03:00
if ( ! version_greater ( drm_edid , 1 , 1 ) )
2020-03-10 16:16:51 -07:00
return ;
2022-05-09 15:03:15 +03:00
drm_for_each_detailed_block ( drm_edid , get_monitor_range ,
2020-03-10 16:16:51 -07:00
& info - > monitor_range ) ;
DRM_DEBUG_KMS ( " Supported Monitor Refresh rate range is %d Hz - %d Hz \n " ,
info - > monitor_range . min_vfreq ,
info - > monitor_range . max_vfreq ) ;
}
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
static void drm_parse_vesa_mso_data ( struct drm_connector * connector ,
const struct displayid_block * block )
{
struct displayid_vesa_vendor_specific_block * vesa =
( struct displayid_vesa_vendor_specific_block * ) block ;
struct drm_display_info * info = & connector - > display_info ;
if ( block - > num_bytes < 3 ) {
drm_dbg_kms ( connector - > dev , " Unexpected vendor block size %u \n " ,
block - > num_bytes ) ;
return ;
}
if ( oui ( vesa - > oui [ 0 ] , vesa - > oui [ 1 ] , vesa - > oui [ 2 ] ) ! = VESA_IEEE_OUI )
return ;
if ( sizeof ( * vesa ) ! = sizeof ( * block ) + block - > num_bytes ) {
drm_dbg_kms ( connector - > dev , " Unexpected VESA vendor block size \n " ) ;
return ;
}
switch ( FIELD_GET ( DISPLAYID_VESA_MSO_MODE , vesa - > mso ) ) {
default :
drm_dbg_kms ( connector - > dev , " Reserved MSO mode value \n " ) ;
fallthrough ;
case 0 :
info - > mso_stream_count = 0 ;
break ;
case 1 :
info - > mso_stream_count = 2 ; /* 2 or 4 links */
break ;
case 2 :
info - > mso_stream_count = 4 ; /* 4 links */
break ;
}
if ( ! info - > mso_stream_count ) {
info - > mso_pixel_overlap = 0 ;
return ;
}
info - > mso_pixel_overlap = FIELD_GET ( DISPLAYID_VESA_MSO_OVERLAP , vesa - > mso ) ;
if ( info - > mso_pixel_overlap > 8 ) {
drm_dbg_kms ( connector - > dev , " Reserved MSO pixel overlap value %u \n " ,
info - > mso_pixel_overlap ) ;
info - > mso_pixel_overlap = 8 ;
}
drm_dbg_kms ( connector - > dev , " MSO stream count %u, pixel overlap %u \n " ,
info - > mso_stream_count , info - > mso_pixel_overlap ) ;
}
2022-05-11 12:21:04 +03:00
static void drm_update_mso ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
{
const struct displayid_block * block ;
struct displayid_iter iter ;
2022-05-09 15:03:23 +03:00
displayid_iter_edid_begin ( drm_edid , & iter ) ;
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
displayid_iter_for_each ( block , & iter ) {
if ( block - > tag = = DATA_BLOCK_2_VENDOR_SPECIFIC )
drm_parse_vesa_mso_data ( connector , block ) ;
}
displayid_iter_end ( & iter ) ;
}
2017-12-13 00:44:26 -08:00
/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
* all of the values which would have been set from EDID
*/
2022-06-29 12:27:46 +03:00
static void drm_reset_display_info ( struct drm_connector * connector )
2017-12-13 00:44:26 -08:00
{
struct drm_display_info * info = & connector - > display_info ;
info - > width_mm = 0 ;
info - > height_mm = 0 ;
info - > bpc = 0 ;
info - > color_formats = 0 ;
info - > cea_rev = 0 ;
info - > max_tmds_clock = 0 ;
info - > dvi_dual = false ;
2020-02-26 13:24:23 +02:00
info - > is_hdmi = false ;
2017-12-13 00:44:26 -08:00
info - > has_hdmi_infoframe = false ;
2019-01-08 19:28:28 +02:00
info - > rgb_quant_range_selectable = false ;
2018-04-24 16:02:50 +03:00
memset ( & info - > hdmi , 0 , sizeof ( info - > hdmi ) ) ;
2017-12-13 00:44:26 -08:00
2022-01-25 10:32:51 +01:00
info - > edid_hdmi_rgb444_dc_modes = 0 ;
info - > edid_hdmi_ycbcr444_dc_modes = 0 ;
2017-12-13 00:44:26 -08:00
info - > non_desktop = 0 ;
2020-03-10 16:16:51 -07:00
memset ( & info - > monitor_range , 0 , sizeof ( info - > monitor_range ) ) ;
2022-07-19 12:56:58 +03:00
memset ( & info - > luminance_range , 0 , sizeof ( info - > luminance_range ) ) ;
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
info - > mso_stream_count = 0 ;
info - > mso_pixel_overlap = 0 ;
2017-12-13 00:44:26 -08:00
}
2022-05-11 12:21:04 +03:00
static u32 update_display_info ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2011-04-15 12:49:23 -07:00
{
2016-09-28 16:51:38 +03:00
struct drm_display_info * info = & connector - > display_info ;
2022-05-11 12:21:04 +03:00
const struct edid * edid = drm_edid - > edid ;
2011-08-03 09:22:54 -07:00
2022-05-11 12:21:04 +03:00
u32 quirks = edid_get_quirks ( drm_edid ) ;
2017-12-13 00:44:26 -08:00
2018-04-24 16:02:50 +03:00
drm_reset_display_info ( connector ) ;
2011-04-15 12:49:23 -07:00
info - > width_mm = edid - > width_cm * 10 ;
info - > height_mm = edid - > height_cm * 10 ;
2022-05-11 12:21:04 +03:00
drm_get_monitor_range ( connector , drm_edid ) ;
2020-03-10 16:16:51 -07:00
2012-04-16 15:16:19 +02:00
if ( edid - > revision < 3 )
2021-12-28 12:10:51 +02:00
goto out ;
2011-04-15 12:49:23 -07:00
if ( ! ( edid - > input & DRM_EDID_INPUT_DIGITAL ) )
2021-12-28 12:10:51 +02:00
goto out ;
2011-04-15 12:49:23 -07:00
drm/edid: Always set RGB444
In order to fill the drm_display_info structure each time an EDID is
read, the code currently will call drm_add_display_info with the parsed
EDID.
drm_add_display_info will then call drm_reset_display_info to reset all
the fields to 0, and then set them to the proper value depending on the
EDID.
In the color_formats case, we will thus report that we don't support any
color format, and then fill it back with RGB444 plus the additional
formats described in the EDID Feature Support byte.
However, since that byte only contains format-related bits since the 1.4
specification, this doesn't happen if the EDID is following an earlier
specification. In turn, it means that for one of these EDID, we end up
with color_formats set to 0.
The EDID 1.3 specification never really specifies what it means by RGB
exactly, but since both HDMI and DVI will use RGB444, it's fairly safe
to assume it's supposed to be RGB444.
Let's move the addition of RGB444 to color_formats earlier in
drm_add_display_info() so that it's always set for a digital display.
Fixes: da05a5a71ad8 ("drm: parse color format support for digital displays")
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reported-by: Matthias Reichl <hias@horus.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220203115416.1137308-1-maxime@cerno.tech
2022-02-03 12:54:16 +01:00
info - > color_formats | = DRM_COLOR_FORMAT_RGB444 ;
2022-05-11 12:21:04 +03:00
drm_parse_cea_ext ( connector , drm_edid ) ;
2014-03-27 19:59:39 +01:00
2016-07-06 12:05:48 +02:00
/*
* Digital sink with " DFP 1.x compliant TMDS " according to EDID 1.3 ?
*
* For such displays , the DFP spec 1.0 , section 3.10 " EDID support "
* tells us to assume 8 bpc color depth if the EDID doesn ' t have
* extensions which tell otherwise .
*/
2019-05-29 14:02:04 +03:00
if ( info - > bpc = = 0 & & edid - > revision = = 3 & &
edid - > input & DRM_EDID_DIGITAL_DFP_1_X ) {
2016-07-06 12:05:48 +02:00
info - > bpc = 8 ;
DRM_DEBUG ( " %s: Assigning DFP sink color depth as %d bpc. \n " ,
connector - > name , info - > bpc ) ;
}
2012-04-16 15:16:19 +02:00
/* Only defined for 1.4 with digital displays */
if ( edid - > revision < 4 )
2021-12-28 12:10:51 +02:00
goto out ;
2012-04-16 15:16:19 +02:00
2011-04-15 12:49:23 -07:00
switch ( edid - > input & DRM_EDID_DIGITAL_DEPTH_MASK ) {
case DRM_EDID_DIGITAL_DEPTH_6 :
info - > bpc = 6 ;
break ;
case DRM_EDID_DIGITAL_DEPTH_8 :
info - > bpc = 8 ;
break ;
case DRM_EDID_DIGITAL_DEPTH_10 :
info - > bpc = 10 ;
break ;
case DRM_EDID_DIGITAL_DEPTH_12 :
info - > bpc = 12 ;
break ;
case DRM_EDID_DIGITAL_DEPTH_14 :
info - > bpc = 14 ;
break ;
case DRM_EDID_DIGITAL_DEPTH_16 :
info - > bpc = 16 ;
break ;
case DRM_EDID_DIGITAL_DEPTH_UNDEF :
default :
info - > bpc = 0 ;
break ;
}
2011-04-15 13:48:57 -07:00
2014-03-27 19:59:39 +01:00
DRM_DEBUG ( " %s: Assigning EDID-1.4 digital sink color depth as %d bpc. \n " ,
2014-06-03 14:56:20 +03:00
connector - > name , info - > bpc ) ;
2014-03-27 19:59:39 +01:00
2012-04-16 15:16:18 +02:00
if ( edid - > features & DRM_EDID_FEATURE_RGB_YCRCB444 )
2022-01-20 16:16:13 +01:00
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR444 ;
2012-04-16 15:16:18 +02:00
if ( edid - > features & DRM_EDID_FEATURE_RGB_YCRCB422 )
2022-01-20 16:16:13 +01:00
info - > color_formats | = DRM_COLOR_FORMAT_YCBCR422 ;
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
2022-05-11 12:21:04 +03:00
drm_update_mso ( connector , drm_edid ) ;
drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
The VESA Organization Vendor-Specific Data Block, defined in VESA
DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
stream count and segment pixel overlap.
DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
describing how DisplayID sections may be embedded in EDID extension
blocks. DisplayID v2.0 does not have such a section, perhaps implying
that DisplayID v2.0 data should not be included in EDID extensions, but
rather in a "pure" DisplayID structure at its own DDC address pair
A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
However, in practice, displays out in the field have embedded DisplayID
v2.0 data blocks in EDID extensions, including, in particular, some eDP
MSO displays, where a pure DisplayID structure is not available at all.
Parse the MSO data from the DisplayID data block. Do it as part of
drm_add_display_info(), extending it to parse also DisplayID data to
avoid requiring extra calls to update the information.
v2: Check for VESA OUI (Ville)
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/73ca2887e7b37880690f5c9ba4594c9cd1170669.1630419362.git.jani.nikula@intel.com
2021-08-31 17:17:33 +03:00
2021-12-28 12:10:51 +02:00
out :
if ( quirks & EDID_QUIRK_NON_DESKTOP ) {
drm_dbg_kms ( connector - > dev , " Non-desktop display%s \n " ,
info - > non_desktop ? " (redundant quirk) " : " " ) ;
info - > non_desktop = true ;
}
2017-12-13 00:44:26 -08:00
return quirks ;
2011-04-15 12:49:23 -07:00
}
2016-05-02 08:35:05 +10:00
static struct drm_display_mode * drm_mode_displayid_detailed ( struct drm_device * dev ,
2022-01-23 22:19:55 +03:00
struct displayid_detailed_timings_1 * timings ,
bool type_7 )
2016-05-02 08:35:05 +10:00
{
struct drm_display_mode * mode ;
unsigned pixel_clock = ( timings - > pixel_clock [ 0 ] |
( timings - > pixel_clock [ 1 ] < < 8 ) |
2020-04-23 18:17:43 +03:00
( timings - > pixel_clock [ 2 ] < < 16 ) ) + 1 ;
2016-05-02 08:35:05 +10:00
unsigned hactive = ( timings - > hactive [ 0 ] | timings - > hactive [ 1 ] < < 8 ) + 1 ;
unsigned hblank = ( timings - > hblank [ 0 ] | timings - > hblank [ 1 ] < < 8 ) + 1 ;
unsigned hsync = ( timings - > hsync [ 0 ] | ( timings - > hsync [ 1 ] & 0x7f ) < < 8 ) + 1 ;
unsigned hsync_width = ( timings - > hsw [ 0 ] | timings - > hsw [ 1 ] < < 8 ) + 1 ;
unsigned vactive = ( timings - > vactive [ 0 ] | timings - > vactive [ 1 ] < < 8 ) + 1 ;
unsigned vblank = ( timings - > vblank [ 0 ] | timings - > vblank [ 1 ] < < 8 ) + 1 ;
unsigned vsync = ( timings - > vsync [ 0 ] | ( timings - > vsync [ 1 ] & 0x7f ) < < 8 ) + 1 ;
unsigned vsync_width = ( timings - > vsw [ 0 ] | timings - > vsw [ 1 ] < < 8 ) + 1 ;
bool hsync_positive = ( timings - > hsync [ 1 ] > > 7 ) & 0x1 ;
bool vsync_positive = ( timings - > vsync [ 1 ] > > 7 ) & 0x1 ;
2020-07-02 18:53:32 +05:30
2016-05-02 08:35:05 +10:00
mode = drm_mode_create ( dev ) ;
if ( ! mode )
return NULL ;
2022-01-23 22:19:55 +03:00
/* resolution is kHz for type VII, and 10 kHz for type I */
mode - > clock = type_7 ? pixel_clock : pixel_clock * 10 ;
2016-05-02 08:35:05 +10:00
mode - > hdisplay = hactive ;
mode - > hsync_start = mode - > hdisplay + hsync ;
mode - > hsync_end = mode - > hsync_start + hsync_width ;
mode - > htotal = mode - > hdisplay + hblank ;
mode - > vdisplay = vactive ;
mode - > vsync_start = mode - > vdisplay + vsync ;
mode - > vsync_end = mode - > vsync_start + vsync_width ;
mode - > vtotal = mode - > vdisplay + vblank ;
mode - > flags = 0 ;
mode - > flags | = hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC ;
mode - > flags | = vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC ;
mode - > type = DRM_MODE_TYPE_DRIVER ;
if ( timings - > flags & 0x80 )
mode - > type | = DRM_MODE_TYPE_PREFERRED ;
drm_mode_set_name ( mode ) ;
return mode ;
}
static int add_displayid_detailed_1_modes ( struct drm_connector * connector ,
2021-03-29 16:37:15 +03:00
const struct displayid_block * block )
2016-05-02 08:35:05 +10:00
{
struct displayid_detailed_timing_block * det = ( struct displayid_detailed_timing_block * ) block ;
int i ;
int num_timings ;
struct drm_display_mode * newmode ;
int num_modes = 0 ;
2022-01-23 22:19:55 +03:00
bool type_7 = block - > tag = = DATA_BLOCK_2_TYPE_7_DETAILED_TIMING ;
2016-05-02 08:35:05 +10:00
/* blocks must be multiple of 20 bytes length */
if ( block - > num_bytes % 20 )
return 0 ;
num_timings = block - > num_bytes / 20 ;
for ( i = 0 ; i < num_timings ; i + + ) {
struct displayid_detailed_timings_1 * timings = & det - > timings [ i ] ;
2022-01-23 22:19:55 +03:00
newmode = drm_mode_displayid_detailed ( connector - > dev , timings , type_7 ) ;
2016-05-02 08:35:05 +10:00
if ( ! newmode )
continue ;
drm_mode_probed_add ( connector , newmode ) ;
num_modes + + ;
}
return num_modes ;
}
static int add_displayid_detailed_modes ( struct drm_connector * connector ,
2022-05-11 12:26:50 +03:00
const struct drm_edid * drm_edid )
2016-05-02 08:35:05 +10:00
{
2021-03-29 16:37:15 +03:00
const struct displayid_block * block ;
2021-03-29 16:37:18 +03:00
struct displayid_iter iter ;
2016-05-02 08:35:05 +10:00
int num_modes = 0 ;
2022-05-09 15:03:23 +03:00
displayid_iter_edid_begin ( drm_edid , & iter ) ;
2021-03-29 16:37:18 +03:00
displayid_iter_for_each ( block , & iter ) {
2022-01-23 22:19:55 +03:00
if ( block - > tag = = DATA_BLOCK_TYPE_1_DETAILED_TIMING | |
block - > tag = = DATA_BLOCK_2_TYPE_7_DETAILED_TIMING )
2021-03-29 16:37:18 +03:00
num_modes + = add_displayid_detailed_1_modes ( connector , block ) ;
2016-05-02 08:35:05 +10:00
}
2021-03-29 16:37:18 +03:00
displayid_iter_end ( & iter ) ;
2020-05-27 16:03:09 +03:00
2016-05-02 08:35:05 +10:00
return num_modes ;
}
2022-06-29 12:27:50 +03:00
static int _drm_edid_connector_update ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2008-11-07 14:05:41 -08:00
{
int num_modes = 0 ;
u32 quirks ;
2022-05-09 15:03:03 +03:00
if ( ! drm_edid ) {
2022-05-03 12:23:46 +03:00
drm_reset_display_info ( connector ) ;
2017-11-01 16:21:01 +02:00
clear_eld ( connector ) ;
2008-11-07 14:05:41 -08:00
return 0 ;
}
2017-07-13 21:03:09 +05:30
/*
* CEA - 861 - F adds ycbcr capability map block , for HDMI 2.0 sinks .
* To avoid multiple parsing of same block , lets parse that map
* from sink info , before parsing CEA modes .
*/
2022-05-11 12:21:04 +03:00
quirks = update_display_info ( connector , drm_edid ) ;
2017-07-13 21:03:09 +05:30
2022-05-11 12:21:04 +03:00
/* Depends on info->cea_rev set by update_display_info() above */
2022-05-11 12:23:49 +03:00
drm_edid_to_eld ( connector , drm_edid ) ;
2022-05-03 12:24:04 +03:00
2010-03-29 21:43:21 +00:00
/*
* EDID spec says modes should be preferred in this order :
* - preferred detailed mode
* - other detailed modes from base block
* - detailed modes from extension blocks
* - CVT 3 - byte code modes
* - standard timing codes
* - established timing codes
* - modes inferred from GTF or CVT range information
*
2010-08-03 14:38:19 -04:00
* We get this pretty much right .
2010-03-29 21:43:21 +00:00
*
* XXX order for additional mode types in extension blocks ?
*/
2022-05-11 12:26:50 +03:00
num_modes + = add_detailed_modes ( connector , drm_edid , quirks ) ;
num_modes + = add_cvt_modes ( connector , drm_edid ) ;
num_modes + = add_standard_modes ( connector , drm_edid ) ;
num_modes + = add_established_modes ( connector , drm_edid ) ;
num_modes + = add_cea_modes ( connector , drm_edid ) ;
num_modes + = add_alternate_cea_modes ( connector , drm_edid ) ;
num_modes + = add_displayid_detailed_modes ( connector , drm_edid ) ;
if ( drm_edid - > edid - > features & DRM_EDID_FEATURE_DEFAULT_GTF )
num_modes + = add_inferred_modes ( connector , drm_edid ) ;
2008-11-07 14:05:41 -08:00
if ( quirks & ( EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75 ) )
edid_fixup_preferred ( connector , quirks ) ;
2016-07-06 12:05:44 +02:00
if ( quirks & EDID_QUIRK_FORCE_6BPC )
connector - > display_info . bpc = 6 ;
2013-12-07 13:22:42 +01:00
if ( quirks & EDID_QUIRK_FORCE_8BPC )
connector - > display_info . bpc = 8 ;
2017-04-21 17:05:08 +02:00
if ( quirks & EDID_QUIRK_FORCE_10BPC )
connector - > display_info . bpc = 10 ;
2014-05-23 21:40:55 +02:00
if ( quirks & EDID_QUIRK_FORCE_12BPC )
connector - > display_info . bpc = 12 ;
2008-11-07 14:05:41 -08:00
return num_modes ;
}
2022-03-28 17:34:33 +03:00
2022-06-29 12:27:47 +03:00
static void _drm_update_tile_info ( struct drm_connector * connector ,
const struct drm_edid * drm_edid ) ;
2022-06-29 12:27:46 +03:00
2022-06-29 12:27:50 +03:00
static int _drm_edid_connector_property_update ( struct drm_connector * connector ,
2022-06-29 12:27:47 +03:00
const struct drm_edid * drm_edid )
2022-06-29 12:27:46 +03:00
{
struct drm_device * dev = connector - > dev ;
int ret ;
if ( connector - > edid_blob_ptr ) {
2022-06-29 12:27:47 +03:00
const struct edid * old_edid = connector - > edid_blob_ptr - > data ;
2022-06-29 12:27:46 +03:00
if ( old_edid ) {
2022-06-29 12:27:47 +03:00
if ( ! drm_edid_are_equal ( drm_edid ? drm_edid - > edid : NULL , old_edid ) ) {
2022-06-29 12:27:48 +03:00
connector - > epoch_counter + + ;
drm_dbg_kms ( dev , " [CONNECTOR:%d:%s] EDID changed, epoch counter %llu \n " ,
connector - > base . id , connector - > name ,
connector - > epoch_counter ) ;
2022-06-29 12:27:46 +03:00
}
}
}
ret = drm_property_replace_global_blob ( dev ,
& connector - > edid_blob_ptr ,
2022-06-29 12:27:47 +03:00
drm_edid ? drm_edid - > size : 0 ,
drm_edid ? drm_edid - > edid : NULL ,
2022-06-29 12:27:46 +03:00
& connector - > base ,
dev - > mode_config . edid_property ) ;
2022-06-29 12:27:48 +03:00
if ( ret ) {
drm_dbg_kms ( dev , " [CONNECTOR:%d:%s] EDID property update failed (%d) \n " ,
connector - > base . id , connector - > name , ret ) ;
goto out ;
}
ret = drm_object_property_set_value ( & connector - > base ,
dev - > mode_config . non_desktop_property ,
connector - > display_info . non_desktop ) ;
if ( ret ) {
drm_dbg_kms ( dev , " [CONNECTOR:%d:%s] Non-desktop property update failed (%d) \n " ,
connector - > base . id , connector - > name , ret ) ;
goto out ;
}
ret = drm_connector_set_tile_property ( connector ) ;
if ( ret ) {
drm_dbg_kms ( dev , " [CONNECTOR:%d:%s] Tile property update failed (%d) \n " ,
connector - > base . id , connector - > name , ret ) ;
goto out ;
}
out :
return ret ;
2022-06-29 12:27:46 +03:00
}
2022-06-29 12:27:47 +03:00
2022-06-29 12:27:50 +03:00
/**
* drm_edid_connector_update - Update connector information from EDID
* @ connector : Connector
* @ drm_edid : EDID
*
* Update the connector mode list , display info , ELD , HDR metadata , relevant
* properties , etc . from the passed in EDID .
*
* If EDID is NULL , reset the information .
*
* Return : The number of modes added or 0 if we couldn ' t find any .
*/
int drm_edid_connector_update ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
{
int count ;
/*
* FIXME : Reconcile the differences in override_edid handling between
* this and drm_connector_update_edid_property ( ) .
*
* If override_edid is set , and the EDID passed in here originates from
* drm_edid_read ( ) and friends , it will be the override EDID , and there
* are no issues . drm_connector_update_edid_property ( ) ignoring requests
* to set the EDID dates back to a time when override EDID was not
* handled at the low level EDID read .
*
* The only way the EDID passed in here can be different from the
* override EDID is when a driver passes in an EDID that does * not *
* originate from drm_edid_read ( ) and friends , or passes in a stale
* cached version . This , in turn , is a question of when an override EDID
* set via debugfs should take effect .
*/
count = _drm_edid_connector_update ( connector , drm_edid ) ;
_drm_update_tile_info ( connector , drm_edid ) ;
/* Note: Ignore errors for now. */
_drm_edid_connector_property_update ( connector , drm_edid ) ;
return count ;
}
EXPORT_SYMBOL ( drm_edid_connector_update ) ;
static int _drm_connector_update_edid_property ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
{
/* ignore requests to set edid when overridden */
if ( connector - > override_edid )
return 0 ;
/*
* Set the display info , using edid if available , otherwise resetting
* the values to defaults . This duplicates the work done in
* drm_add_edid_modes , but that function is not consistently called
* before this one in all drivers and the computation is cheap enough
* that it seems better to duplicate it rather than attempt to ensure
* some arbitrary ordering of calls .
*/
if ( drm_edid )
update_display_info ( connector , drm_edid ) ;
else
drm_reset_display_info ( connector ) ;
_drm_update_tile_info ( connector , drm_edid ) ;
return _drm_edid_connector_property_update ( connector , drm_edid ) ;
}
2022-06-29 12:27:47 +03:00
/**
* drm_connector_update_edid_property - update the edid property of a connector
* @ connector : drm connector
* @ edid : new value of the edid property
*
* This function creates a new blob modeset object and assigns its id to the
* connector ' s edid property .
* Since we also parse tile information from EDID ' s displayID block , we also
* set the connector ' s tile property here . See drm_connector_set_tile_property ( )
* for more details .
*
2022-06-29 12:27:50 +03:00
* This function is deprecated . Use drm_edid_connector_update ( ) instead .
*
2022-06-29 12:27:47 +03:00
* Returns :
* Zero on success , negative errno on failure .
*/
int drm_connector_update_edid_property ( struct drm_connector * connector ,
const struct edid * edid )
{
struct drm_edid drm_edid ;
return _drm_connector_update_edid_property ( connector ,
drm_edid_legacy_init ( & drm_edid , edid ) ) ;
}
2022-06-29 12:27:46 +03:00
EXPORT_SYMBOL ( drm_connector_update_edid_property ) ;
2022-03-28 17:34:33 +03:00
/**
* drm_add_edid_modes - add modes from EDID data , if available
* @ connector : connector we ' re probing
* @ edid : EDID data
*
* Add the specified modes to the connector ' s mode list . Also fills out the
* & drm_display_info structure and ELD in @ connector with any information which
* can be derived from the edid .
*
2022-06-29 12:27:50 +03:00
* This function is deprecated . Use drm_edid_connector_update ( ) instead .
*
2022-03-28 17:34:33 +03:00
* Return : The number of modes added or 0 if we couldn ' t find any .
*/
int drm_add_edid_modes ( struct drm_connector * connector , struct edid * edid )
{
2022-05-09 15:03:03 +03:00
struct drm_edid drm_edid ;
2022-03-28 17:34:33 +03:00
if ( edid & & ! drm_edid_is_valid ( edid ) ) {
drm_warn ( connector - > dev , " %s: EDID invalid. \n " ,
connector - > name ) ;
edid = NULL ;
}
2022-06-29 12:27:50 +03:00
return _drm_edid_connector_update ( connector ,
drm_edid_legacy_init ( & drm_edid , edid ) ) ;
2022-03-28 17:34:33 +03:00
}
2008-11-07 14:05:41 -08:00
EXPORT_SYMBOL ( drm_add_edid_modes ) ;
2009-09-03 09:33:48 +08:00
/**
* drm_add_modes_noedid - add modes for the connectors without EDID
* @ connector : connector we ' re probing
* @ hdisplay : the horizontal display limit
* @ vdisplay : the vertical display limit
*
* Add the specified modes to the connector ' s mode list . Only when the
* hdisplay / vdisplay is not beyond the given limit , it will be added .
*
2014-04-29 11:44:34 +02:00
* Return : The number of modes added or 0 if we couldn ' t find any .
2009-09-03 09:33:48 +08:00
*/
int drm_add_modes_noedid ( struct drm_connector * connector ,
int hdisplay , int vdisplay )
{
int i , count , num_modes = 0 ;
2011-01-26 09:49:47 +00:00
struct drm_display_mode * mode ;
2009-09-03 09:33:48 +08:00
struct drm_device * dev = connector - > dev ;
2015-08-10 11:55:37 +02:00
count = ARRAY_SIZE ( drm_dmt_modes ) ;
2009-09-03 09:33:48 +08:00
if ( hdisplay < 0 )
hdisplay = 0 ;
if ( vdisplay < 0 )
vdisplay = 0 ;
for ( i = 0 ; i < count ; i + + ) {
2011-01-26 09:49:47 +00:00
const struct drm_display_mode * ptr = & drm_dmt_modes [ i ] ;
2020-07-02 18:53:32 +05:30
2009-09-03 09:33:48 +08:00
if ( hdisplay & & vdisplay ) {
/*
* Only when two are valid , they will be used to check
* whether the mode should be added to the mode list of
* the connector .
*/
if ( ptr - > hdisplay > hdisplay | |
ptr - > vdisplay > vdisplay )
continue ;
}
2009-11-23 14:23:04 -05:00
if ( drm_mode_vrefresh ( ptr ) > 61 )
continue ;
2009-09-03 09:33:48 +08:00
mode = drm_mode_duplicate ( dev , ptr ) ;
if ( mode ) {
drm_mode_probed_add ( connector , mode ) ;
num_modes + + ;
}
}
return num_modes ;
}
EXPORT_SYMBOL ( drm_add_modes_noedid ) ;
2012-11-21 15:31:35 +01:00
2014-04-29 11:44:34 +02:00
/**
* drm_set_preferred_mode - Sets the preferred mode of a connector
* @ connector : connector whose mode list should be processed
* @ hpref : horizontal resolution of preferred mode
* @ vpref : vertical resolution of preferred mode
*
* Marks a mode as preferred if it matches the resolution specified by @ hpref
* and @ vpref .
*/
2013-10-11 10:01:08 +02:00
void drm_set_preferred_mode ( struct drm_connector * connector ,
int hpref , int vpref )
{
struct drm_display_mode * mode ;
list_for_each_entry ( mode , & connector - > probed_modes , head ) {
2014-04-29 11:44:34 +02:00
if ( mode - > hdisplay = = hpref & &
2014-01-23 16:27:56 +01:00
mode - > vdisplay = = vpref )
2013-10-11 10:01:08 +02:00
mode - > type | = DRM_MODE_TYPE_PREFERRED ;
}
}
EXPORT_SYMBOL ( drm_set_preferred_mode ) ;
2020-05-26 04:14:47 +03:00
static bool is_hdmi2_sink ( const struct drm_connector * connector )
2019-01-08 19:28:25 +02:00
{
/*
* FIXME : sil - sii8620 doesn ' t have a connector around when
* we need one , so we have to be prepared for a NULL connector .
*/
if ( ! connector )
return true ;
return connector - > display_info . hdmi . scdc . supported | |
2022-01-20 16:16:13 +01:00
connector - > display_info . color_formats & DRM_COLOR_FORMAT_YCBCR420 ;
2019-01-08 19:28:25 +02:00
}
2020-05-26 04:14:47 +03:00
static u8 drm_mode_hdmi_vic ( const struct drm_connector * connector ,
2019-10-04 17:19:13 +03:00
const struct drm_display_mode * mode )
{
bool has_hdmi_infoframe = connector ?
connector - > display_info . has_hdmi_infoframe : false ;
if ( ! has_hdmi_infoframe )
return 0 ;
/* No HDMI VIC when signalling 3D video format */
if ( mode - > flags & DRM_MODE_FLAG_3D_MASK )
return 0 ;
return drm_match_hdmi_mode ( mode ) ;
}
2020-05-26 04:14:47 +03:00
static u8 drm_mode_cea_vic ( const struct drm_connector * connector ,
2019-10-04 17:19:12 +03:00
const struct drm_display_mode * mode )
{
u8 vic ;
/*
* HDMI spec says if a mode is found in HDMI 1.4 b 4 K modes
* we should send its VIC in vendor infoframes , else send the
* VIC in AVI infoframes . Lets check if this mode is present in
* HDMI 1.4 b 4 K modes
*/
2019-10-04 17:19:13 +03:00
if ( drm_mode_hdmi_vic ( connector , mode ) )
2019-10-04 17:19:12 +03:00
return 0 ;
vic = drm_match_cea_mode ( mode ) ;
/*
* HDMI 1.4 VIC range : 1 < = VIC < = 64 ( CEA - 861 - D ) but
* HDMI 2.0 VIC range : 1 < = VIC < = 107 ( CEA - 861 - F ) . So we
* have to make sure we dont break HDMI 1.4 sinks .
*/
if ( ! is_hdmi2_sink ( connector ) & & vic > 64 )
return 0 ;
return vic ;
}
2012-11-21 15:31:35 +01:00
/**
* drm_hdmi_avi_infoframe_from_display_mode ( ) - fill an HDMI AVI infoframe with
* data from a DRM display mode
* @ frame : HDMI AVI infoframe
2019-01-08 19:28:25 +02:00
* @ connector : the connector
2012-11-21 15:31:35 +01:00
* @ mode : DRM display mode
*
2014-04-29 11:44:34 +02:00
* Return : 0 on success or a negative error code on failure .
2012-11-21 15:31:35 +01:00
*/
int
drm_hdmi_avi_infoframe_from_display_mode ( struct hdmi_avi_infoframe * frame ,
2020-05-26 04:14:47 +03:00
const struct drm_connector * connector ,
2019-01-08 19:28:25 +02:00
const struct drm_display_mode * mode )
2012-11-21 15:31:35 +01:00
{
2018-05-08 16:39:39 +05:30
enum hdmi_picture_aspect picture_aspect ;
2019-11-18 18:18:31 +08:00
u8 vic , hdmi_vic ;
2012-11-21 15:31:35 +01:00
if ( ! frame | | ! mode )
return - EINVAL ;
2020-02-26 13:24:21 +02:00
hdmi_avi_infoframe_init ( frame ) ;
2012-11-21 15:31:35 +01:00
2013-08-06 20:32:22 +01:00
if ( mode - > flags & DRM_MODE_FLAG_DBLCLK )
frame - > pixel_repeat = 1 ;
2019-11-18 18:18:31 +08:00
vic = drm_mode_cea_vic ( connector , mode ) ;
hdmi_vic = drm_mode_hdmi_vic ( connector , mode ) ;
drm: handle HDMI 2.0 VICs in AVI info-frames
HDMI 1.4b support the CEA video modes as per range of CEA-861-D (VIC 1-64).
For any other mode, the VIC filed in AVI infoframes should be 0.
HDMI 2.0 sinks, support video modes range as per CEA-861-F spec, which is
extended to (VIC 1-107).
This patch adds a bool input variable, which indicates if the connected
sink is a HDMI 2.0 sink or not. This will make sure that we don't pass a
HDMI 2.0 VIC to a HDMI 1.4 sink.
This patch touches all drm drivers, who are callers of this function
drm_hdmi_avi_infoframe_from_display_mode but to make sure there is
no change in current behavior, is_hdmi2 is kept as false.
In case of I915 driver, this patch:
- checks if the connected display is HDMI 2.0.
- HDMI infoframes carry one of this two type of information:
- VIC for 4K modes for HDMI 1.4 sinks
- S3D information for S3D modes
As CEA-861-F has already defined VICs for 4K videomodes, this
patch doesn't allow sending HDMI infoframes for HDMI 2.0 sinks,
until the mode is 3D.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <jose.abreu@synopsys.com>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
PS: This patch touches a few lines in few files, which were
already above 80 char, so checkpatch gives 80 char warning again.
- gpu/drm/omapdrm/omap_encoder.c
- gpu/drm/i915/intel_sdvo.c
V2: Rebase, Added r-b from Andrzej
V3: Addressed review comment from Ville:
- Do not send VICs in both AVI-IF and HDMI-IF
send only one of it.
V4: Rebase
V5: Added r-b from Neil.
Addressed review comments from Ville
- Do not block HDMI vendor IF, instead check for VIC while
handling AVI infoframes
V6: Rebase
V7: Rebase
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1499960000-9232-2-git-send-email-shashank.sharma@intel.com
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-13 21:03:07 +05:30
2012-11-21 15:31:35 +01:00
frame - > picture_aspect = HDMI_PICTURE_ASPECT_NONE ;
2014-04-01 16:26:59 +05:30
2018-05-15 16:59:27 +03:00
/*
* As some drivers don ' t support atomic , we can ' t use connector state .
* So just initialize the frame with default values , just the same way
* as it ' s done with other properties here .
*/
frame - > content_type = HDMI_CONTENT_TYPE_GRAPHICS ;
frame - > itc = 0 ;
2014-06-05 14:45:29 +05:30
/*
* Populate picture aspect ratio from either
2019-11-18 18:18:31 +08:00
* user input ( if specified ) or from the CEA / HDMI mode lists .
2014-06-05 14:45:29 +05:30
*/
2018-05-08 16:39:39 +05:30
picture_aspect = mode - > picture_aspect_ratio ;
2019-11-18 18:18:31 +08:00
if ( picture_aspect = = HDMI_PICTURE_ASPECT_NONE ) {
if ( vic )
picture_aspect = drm_get_cea_aspect_ratio ( vic ) ;
else if ( hdmi_vic )
picture_aspect = drm_get_hdmi_aspect_ratio ( hdmi_vic ) ;
}
2014-04-01 16:26:59 +05:30
2018-05-08 16:39:39 +05:30
/*
* The infoframe can ' t convey anything but none , 4 : 3
* and 16 : 9 , so if the user has asked for anything else
* we can only satisfy it by specifying the right VIC .
*/
if ( picture_aspect > HDMI_PICTURE_ASPECT_16_9 ) {
2019-11-18 18:18:31 +08:00
if ( vic ) {
if ( picture_aspect ! = drm_get_cea_aspect_ratio ( vic ) )
return - EINVAL ;
} else if ( hdmi_vic ) {
if ( picture_aspect ! = drm_get_hdmi_aspect_ratio ( hdmi_vic ) )
return - EINVAL ;
} else {
2018-05-08 16:39:39 +05:30
return - EINVAL ;
2019-11-18 18:18:31 +08:00
}
2018-05-08 16:39:39 +05:30
picture_aspect = HDMI_PICTURE_ASPECT_NONE ;
}
2019-11-18 18:18:31 +08:00
frame - > video_code = vic ;
2018-05-08 16:39:39 +05:30
frame - > picture_aspect = picture_aspect ;
2012-11-21 15:31:35 +01:00
frame - > active_aspect = HDMI_ACTIVE_ASPECT_PICTURE ;
2014-02-27 09:19:30 -06:00
frame - > scan_mode = HDMI_SCAN_MODE_UNDERSCAN ;
2012-11-21 15:31:35 +01:00
return 0 ;
}
EXPORT_SYMBOL ( drm_hdmi_avi_infoframe_from_display_mode ) ;
2013-08-19 16:59:03 +01:00
2017-01-11 14:57:23 +02:00
/**
* drm_hdmi_avi_infoframe_quant_range ( ) - fill the HDMI AVI infoframe
* quantization range information
* @ frame : HDMI AVI infoframe
2019-01-08 19:28:25 +02:00
* @ connector : the connector
2017-01-11 14:57:24 +02:00
* @ mode : DRM display mode
2017-01-11 14:57:23 +02:00
* @ rgb_quant_range : RGB quantization range ( Q )
*/
void
drm_hdmi_avi_infoframe_quant_range ( struct hdmi_avi_infoframe * frame ,
2020-05-26 04:14:47 +03:00
const struct drm_connector * connector ,
2017-01-11 14:57:24 +02:00
const struct drm_display_mode * mode ,
2019-01-08 19:28:28 +02:00
enum hdmi_quantization_range rgb_quant_range )
2017-01-11 14:57:23 +02:00
{
2019-01-08 19:28:28 +02:00
const struct drm_display_info * info = & connector - > display_info ;
2017-01-11 14:57:23 +02:00
/*
* CEA - 861 :
* " A Source shall not send a non-zero Q value that does not correspond
* to the default RGB Quantization Range for the transmitted Picture
* unless the Sink indicates support for the Q bit in a Video
* Capabilities Data Block . "
2017-01-11 14:57:24 +02:00
*
* HDMI 2.0 recommends sending non - zero Q when it does match the
* default RGB quantization range for the mode , even when QS = 0.
2017-01-11 14:57:23 +02:00
*/
2019-01-08 19:28:28 +02:00
if ( info - > rgb_quant_range_selectable | |
2017-01-11 14:57:24 +02:00
rgb_quant_range = = drm_default_rgb_quant_range ( mode ) )
2017-01-11 14:57:23 +02:00
frame - > quantization_range = rgb_quant_range ;
else
frame - > quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT ;
2017-01-11 14:57:25 +02:00
/*
* CEA - 861 - F :
* " When transmitting any RGB colorimetry, the Source should set the
* YQ - field to match the RGB Quantization Range being transmitted
* ( e . g . , when Limited Range RGB , set YQ = 0 or when Full Range RGB ,
* set YQ = 1 ) and the Sink shall ignore the YQ - field . "
2017-11-08 17:25:04 +02:00
*
* Unfortunate certain sinks ( eg . VIZ Model 67 / E261VA ) get confused
* by non - zero YQ when receiving RGB . There doesn ' t seem to be any
* good way to tell which version of CEA - 861 the sink supports , so
* we limit non - zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based
* on on CEA - 861 - F .
2017-01-11 14:57:25 +02:00
*/
2019-01-08 19:28:25 +02:00
if ( ! is_hdmi2_sink ( connector ) | |
2017-11-08 17:25:04 +02:00
rgb_quant_range = = HDMI_QUANTIZATION_RANGE_LIMITED )
2017-01-11 14:57:25 +02:00
frame - > ycc_quantization_range =
HDMI_YCC_QUANTIZATION_RANGE_LIMITED ;
else
frame - > ycc_quantization_range =
HDMI_YCC_QUANTIZATION_RANGE_FULL ;
2017-01-11 14:57:23 +02:00
}
EXPORT_SYMBOL ( drm_hdmi_avi_infoframe_quant_range ) ;
2013-09-25 16:45:26 +01:00
static enum hdmi_3d_structure
s3d_structure_from_display_mode ( const struct drm_display_mode * mode )
{
u32 layout = mode - > flags & DRM_MODE_FLAG_3D_MASK ;
switch ( layout ) {
case DRM_MODE_FLAG_3D_FRAME_PACKING :
return HDMI_3D_STRUCTURE_FRAME_PACKING ;
case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE :
return HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE ;
case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE :
return HDMI_3D_STRUCTURE_LINE_ALTERNATIVE ;
case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL :
return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL ;
case DRM_MODE_FLAG_3D_L_DEPTH :
return HDMI_3D_STRUCTURE_L_DEPTH ;
case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH :
return HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH ;
case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM :
return HDMI_3D_STRUCTURE_TOP_AND_BOTTOM ;
case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF :
return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF ;
default :
return HDMI_3D_STRUCTURE_INVALID ;
}
}
2013-08-19 16:59:03 +01:00
/**
* drm_hdmi_vendor_infoframe_from_display_mode ( ) - fill an HDMI infoframe with
* data from a DRM display mode
* @ frame : HDMI vendor infoframe
2017-11-13 19:04:19 +02:00
* @ connector : the connector
2013-08-19 16:59:03 +01:00
* @ mode : DRM display mode
*
* Note that there ' s is a need to send HDMI vendor infoframes only when using a
* 4 k or stereoscopic 3 D mode . So when giving any other mode as input this
* function will return - EINVAL , error that can be safely ignored .
*
2014-04-29 11:44:34 +02:00
* Return : 0 on success or a negative error code on failure .
2013-08-19 16:59:03 +01:00
*/
int
drm_hdmi_vendor_infoframe_from_display_mode ( struct hdmi_vendor_infoframe * frame ,
2020-05-26 04:14:47 +03:00
const struct drm_connector * connector ,
2013-08-19 16:59:03 +01:00
const struct drm_display_mode * mode )
{
2017-11-13 19:04:19 +02:00
/*
* FIXME : sil - sii8620 doesn ' t have a connector around when
* we need one , so we have to be prepared for a NULL connector .
*/
bool has_hdmi_infoframe = connector ?
connector - > display_info . has_hdmi_infoframe : false ;
2013-08-19 16:59:03 +01:00
int err ;
if ( ! frame | | ! mode )
return - EINVAL ;
2017-11-13 19:04:19 +02:00
if ( ! has_hdmi_infoframe )
return - EINVAL ;
2019-10-04 17:19:13 +03:00
err = hdmi_vendor_infoframe_init ( frame ) ;
if ( err < 0 )
return err ;
2013-09-25 16:45:26 +01:00
2017-11-13 19:04:19 +02:00
/*
* Even if it ' s not absolutely necessary to send the infoframe
* ( ie . vic = = 0 and s3d_struct = = 0 ) we will still send it if we
* know that the sink can handle it . This is based on a
* suggestion in HDMI 2.0 Appendix F . Apparently some sinks
2021-07-30 21:27:29 +08:00
* have trouble realizing that they should switch from 3 D to 2 D
2017-11-13 19:04:19 +02:00
* mode if the source simply stops sending the infoframe when
* it wants to switch from 3 D to 2 D .
*/
2019-10-04 17:19:13 +03:00
frame - > vic = drm_mode_hdmi_vic ( connector , mode ) ;
2017-11-13 19:04:19 +02:00
frame - > s3d_struct = s3d_structure_from_display_mode ( mode ) ;
2013-08-19 16:59:03 +01:00
return 0 ;
}
EXPORT_SYMBOL ( drm_hdmi_vendor_infoframe_from_display_mode ) ;
2014-10-20 16:29:33 +10:00
2020-05-27 16:03:09 +03:00
static void drm_parse_tiled_block ( struct drm_connector * connector ,
const struct displayid_block * block )
2016-05-03 15:31:12 +10:00
{
2020-03-13 18:20:54 +02:00
const struct displayid_tiled_block * tile = ( struct displayid_tiled_block * ) block ;
2016-05-03 15:31:12 +10:00
u16 w , h ;
u8 tile_v_loc , tile_h_loc ;
u8 num_v_tile , num_h_tile ;
struct drm_tile_group * tg ;
w = tile - > tile_size [ 0 ] | tile - > tile_size [ 1 ] < < 8 ;
h = tile - > tile_size [ 2 ] | tile - > tile_size [ 3 ] < < 8 ;
num_v_tile = ( tile - > topo [ 0 ] & 0xf ) | ( tile - > topo [ 2 ] & 0x30 ) ;
num_h_tile = ( tile - > topo [ 0 ] > > 4 ) | ( ( tile - > topo [ 2 ] > > 2 ) & 0x30 ) ;
tile_v_loc = ( tile - > topo [ 1 ] & 0xf ) | ( ( tile - > topo [ 2 ] & 0x3 ) < < 4 ) ;
tile_h_loc = ( tile - > topo [ 1 ] > > 4 ) | ( ( ( tile - > topo [ 2 ] > > 2 ) & 0x3 ) < < 4 ) ;
connector - > has_tile = true ;
if ( tile - > tile_cap & 0x80 )
connector - > tile_is_single_monitor = true ;
connector - > num_h_tile = num_h_tile + 1 ;
connector - > num_v_tile = num_v_tile + 1 ;
connector - > tile_h_loc = tile_h_loc ;
connector - > tile_v_loc = tile_v_loc ;
connector - > tile_h_size = w + 1 ;
connector - > tile_v_size = h + 1 ;
DRM_DEBUG_KMS ( " tile cap 0x%x \n " , tile - > tile_cap ) ;
DRM_DEBUG_KMS ( " tile_size %d x %d \n " , w + 1 , h + 1 ) ;
DRM_DEBUG_KMS ( " topo num tiles %dx%d, location %dx%d \n " ,
num_h_tile + 1 , num_v_tile + 1 , tile_h_loc , tile_v_loc ) ;
DRM_DEBUG_KMS ( " vend %c%c%c \n " , tile - > topology_id [ 0 ] , tile - > topology_id [ 1 ] , tile - > topology_id [ 2 ] ) ;
tg = drm_mode_get_tile_group ( connector - > dev , tile - > topology_id ) ;
2020-05-27 16:03:10 +03:00
if ( ! tg )
2016-05-03 15:31:12 +10:00
tg = drm_mode_create_tile_group ( connector - > dev , tile - > topology_id ) ;
if ( ! tg )
2020-05-27 16:03:09 +03:00
return ;
2016-05-03 15:31:12 +10:00
if ( connector - > tile_group ! = tg ) {
/* if we haven't got a pointer,
take the reference , drop ref to old tile group */
2020-05-27 16:03:10 +03:00
if ( connector - > tile_group )
2016-05-03 15:31:12 +10:00
drm_mode_put_tile_group ( connector - > dev , connector - > tile_group ) ;
connector - > tile_group = tg ;
2020-05-27 16:03:10 +03:00
} else {
2016-05-03 15:31:12 +10:00
/* if same tile group, then release the ref we just took. */
drm_mode_put_tile_group ( connector - > dev , tg ) ;
2020-05-27 16:03:10 +03:00
}
2016-05-03 15:31:12 +10:00
}
2022-05-09 15:03:22 +03:00
static void _drm_update_tile_info ( struct drm_connector * connector ,
const struct drm_edid * drm_edid )
2014-10-20 16:29:33 +10:00
{
2021-03-29 16:37:20 +03:00
const struct displayid_block * block ;
struct displayid_iter iter ;
2020-03-13 18:20:48 +02:00
2014-10-20 16:29:33 +10:00
connector - > has_tile = false ;
2020-05-27 16:03:09 +03:00
2022-05-09 15:03:23 +03:00
displayid_iter_edid_begin ( drm_edid , & iter ) ;
2021-03-29 16:37:20 +03:00
displayid_iter_for_each ( block , & iter ) {
if ( block - > tag = = DATA_BLOCK_TILED_DISPLAY )
drm_parse_tiled_block ( connector , block ) ;
2014-10-20 16:29:33 +10:00
}
2021-03-29 16:37:20 +03:00
displayid_iter_end ( & iter ) ;
2014-10-20 16:29:33 +10:00
2020-05-27 16:03:09 +03:00
if ( ! connector - > has_tile & & connector - > tile_group ) {
2014-10-20 16:29:33 +10:00
drm_mode_put_tile_group ( connector - > dev , connector - > tile_group ) ;
connector - > tile_group = NULL ;
}
}