1235783Skib/* 2235783Skib * Copyright (c) 2006 Luc Verhaegen (quirks list) 3235783Skib * Copyright (c) 2007-2008 Intel Corporation 4235783Skib * Jesse Barnes <jesse.barnes@intel.com> 5235783Skib * Copyright 2010 Red Hat, Inc. 6235783Skib * 7235783Skib * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from 8235783Skib * FB layer. 9235783Skib * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com> 10235783Skib * 11235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 12235783Skib * copy of this software and associated documentation files (the "Software"), 13235783Skib * to deal in the Software without restriction, including without limitation 14235783Skib * the rights to use, copy, modify, merge, publish, distribute, sub license, 15235783Skib * and/or sell copies of the Software, and to permit persons to whom the 16235783Skib * Software is furnished to do so, subject to the following conditions: 17235783Skib * 18235783Skib * The above copyright notice and this permission notice (including the 19235783Skib * next paragraph) shall be included in all copies or substantial portions 20235783Skib * of the Software. 21235783Skib * 22235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 25235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27235783Skib * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28235783Skib * DEALINGS IN THE SOFTWARE. 29235783Skib */ 30235783Skib 31235783Skib#include <sys/cdefs.h> 32235783Skib__FBSDID("$FreeBSD: releng/11.0/sys/dev/drm2/drm_edid.c 298334 2016-04-20 03:45:45Z cem $"); 33235783Skib 34235783Skib#include <dev/drm2/drmP.h> 35235783Skib#include <dev/drm2/drm_edid.h> 36280183Sdumbbell#include "drm_edid_modes.h" 37268564Srpaulo#include <dev/iicbus/iic.h> 38235783Skib#include <dev/iicbus/iiconf.h> 39235783Skib#include "iicbus_if.h" 40235783Skib 41235783Skib#define version_greater(edid, maj, min) \ 42235783Skib (((edid)->version > (maj)) || \ 43235783Skib ((edid)->version == (maj) && (edid)->revision > (min))) 44235783Skib 45235783Skib#define EDID_EST_TIMINGS 16 46235783Skib#define EDID_STD_TIMINGS 8 47235783Skib#define EDID_DETAILED_TIMINGS 4 48235783Skib 49235783Skib/* 50235783Skib * EDID blocks out in the wild have a variety of bugs, try to collect 51235783Skib * them here (note that userspace may work around broken monitors first, 52235783Skib * but fixes should make their way here so that the kernel "just works" 53235783Skib * on as many displays as possible). 54235783Skib */ 55235783Skib 56235783Skib/* First detailed mode wrong, use largest 60Hz mode */ 57235783Skib#define EDID_QUIRK_PREFER_LARGE_60 (1 << 0) 58235783Skib/* Reported 135MHz pixel clock is too high, needs adjustment */ 59235783Skib#define EDID_QUIRK_135_CLOCK_TOO_HIGH (1 << 1) 60235783Skib/* Prefer the largest mode at 75 Hz */ 61235783Skib#define EDID_QUIRK_PREFER_LARGE_75 (1 << 2) 62235783Skib/* Detail timing is in cm not mm */ 63235783Skib#define EDID_QUIRK_DETAILED_IN_CM (1 << 3) 64235783Skib/* Detailed timing descriptors have bogus size values, so just take the 65235783Skib * maximum size and use that. 66235783Skib */ 67235783Skib#define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE (1 << 4) 68235783Skib/* Monitor forgot to set the first detailed is preferred bit. */ 69235783Skib#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) 70235783Skib/* use +hsync +vsync for detailed mode */ 71235783Skib#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) 72280183Sdumbbell/* Force reduced-blanking timings for detailed modes */ 73280183Sdumbbell#define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7) 74235783Skib 75235783Skibstruct detailed_mode_closure { 76235783Skib struct drm_connector *connector; 77235783Skib struct edid *edid; 78235783Skib bool preferred; 79235783Skib u32 quirks; 80235783Skib int modes; 81235783Skib}; 82235783Skib 83235783Skib#define LEVEL_DMT 0 84235783Skib#define LEVEL_GTF 1 85235783Skib#define LEVEL_GTF2 2 86235783Skib#define LEVEL_CVT 3 87235783Skib 88235783Skibstatic struct edid_quirk { 89277487Skib char vendor[4]; 90235783Skib int product_id; 91235783Skib u32 quirks; 92235783Skib} edid_quirk_list[] = { 93235783Skib /* Acer AL1706 */ 94235783Skib { "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 }, 95235783Skib /* Acer F51 */ 96235783Skib { "API", 0x7602, EDID_QUIRK_PREFER_LARGE_60 }, 97235783Skib /* Unknown Acer */ 98235783Skib { "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, 99235783Skib 100235783Skib /* Belinea 10 15 55 */ 101235783Skib { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, 102235783Skib { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, 103235783Skib 104235783Skib /* Envision Peripherals, Inc. EN-7100e */ 105235783Skib { "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH }, 106235783Skib /* Envision EN2028 */ 107235783Skib { "EPI", 8232, EDID_QUIRK_PREFER_LARGE_60 }, 108235783Skib 109235783Skib /* Funai Electronics PM36B */ 110235783Skib { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 | 111235783Skib EDID_QUIRK_DETAILED_IN_CM }, 112235783Skib 113235783Skib /* LG Philips LCD LP154W01-A5 */ 114235783Skib { "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, 115235783Skib { "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, 116235783Skib 117235783Skib /* Philips 107p5 CRT */ 118235783Skib { "PHL", 57364, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, 119235783Skib 120235783Skib /* Proview AY765C */ 121235783Skib { "PTS", 765, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, 122235783Skib 123235783Skib /* Samsung SyncMaster 205BW. Note: irony */ 124235783Skib { "SAM", 541, EDID_QUIRK_DETAILED_SYNC_PP }, 125235783Skib /* Samsung SyncMaster 22[5-6]BW */ 126235783Skib { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, 127235783Skib { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, 128280183Sdumbbell 129280183Sdumbbell /* ViewSonic VA2026w */ 130280183Sdumbbell { "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING }, 131235783Skib}; 132235783Skib 133235783Skib/*** DDC fetch and block validation ***/ 134235783Skib 135235783Skibstatic const u8 edid_header[] = { 136235783Skib 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 137235783Skib}; 138235783Skib 139235783Skib /* 140235783Skib * Sanity check the header of the base EDID block. Return 8 if the header 141235783Skib * is perfect, down to 0 if it's totally wrong. 142235783Skib */ 143235783Skibint drm_edid_header_is_valid(const u8 *raw_edid) 144235783Skib{ 145235783Skib int i, score = 0; 146235783Skib 147235783Skib for (i = 0; i < sizeof(edid_header); i++) 148235783Skib if (raw_edid[i] == edid_header[i]) 149235783Skib score++; 150235783Skib 151235783Skib return score; 152235783Skib} 153280183SdumbbellEXPORT_SYMBOL(drm_edid_header_is_valid); 154235783Skib 155280183Sdumbbellstatic int edid_fixup __read_mostly = 6; 156280183Sdumbbellmodule_param_named(edid_fixup, edid_fixup, int, 0400); 157280183SdumbbellMODULE_PARM_DESC(edid_fixup, 158280183Sdumbbell "Minimum number of valid EDID header bytes (0-8, default 6)"); 159280183Sdumbbell 160235783Skib/* 161235783Skib * Sanity check the EDID block (base or extension). Return 0 if the block 162235783Skib * doesn't check out, or 1 if it's valid. 163235783Skib */ 164280183Sdumbbellbool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) 165235783Skib{ 166235783Skib int i; 167235783Skib u8 csum = 0; 168235783Skib struct edid *edid = (struct edid *)raw_edid; 169235783Skib 170280183Sdumbbell if (edid_fixup > 8 || edid_fixup < 0) 171280183Sdumbbell edid_fixup = 6; 172280183Sdumbbell 173277487Skib if (block == 0) { 174235783Skib int score = drm_edid_header_is_valid(raw_edid); 175235783Skib if (score == 8) ; 176280183Sdumbbell else if (score >= edid_fixup) { 177235783Skib DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); 178235783Skib memcpy(raw_edid, edid_header, sizeof(edid_header)); 179235783Skib } else { 180235783Skib goto bad; 181235783Skib } 182235783Skib } 183235783Skib 184235783Skib for (i = 0; i < EDID_LENGTH; i++) 185235783Skib csum += raw_edid[i]; 186235783Skib if (csum) { 187280183Sdumbbell if (print_bad_edid) { 188280183Sdumbbell DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); 189280183Sdumbbell } 190235783Skib 191235783Skib /* allow CEA to slide through, switches mangle this */ 192235783Skib if (raw_edid[0] != 0x02) 193235783Skib goto bad; 194235783Skib } 195235783Skib 196235783Skib /* per-block-type checks */ 197235783Skib switch (raw_edid[0]) { 198235783Skib case 0: /* base */ 199235783Skib if (edid->version != 1) { 200235783Skib DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); 201235783Skib goto bad; 202235783Skib } 203235783Skib 204235783Skib if (edid->revision > 4) 205235783Skib DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n"); 206235783Skib break; 207235783Skib 208235783Skib default: 209235783Skib break; 210235783Skib } 211235783Skib 212235783Skib return 1; 213235783Skib 214235783Skibbad: 215280183Sdumbbell if (raw_edid && print_bad_edid) { 216235783Skib DRM_DEBUG_KMS("Raw EDID:\n"); 217280183Sdumbbell for (i = 0; i < EDID_LENGTH; ) { 218280183Sdumbbell printf("%02x", raw_edid[i]); 219280183Sdumbbell i++; 220280183Sdumbbell if (i % 16 == 0 || i == EDID_LENGTH) 221280183Sdumbbell printf("\n"); 222280183Sdumbbell else if (i % 8 == 0) 223280183Sdumbbell printf(" "); 224280183Sdumbbell else 225280183Sdumbbell printf(" "); 226235783Skib } 227235783Skib } 228235783Skib return 0; 229235783Skib} 230280183SdumbbellEXPORT_SYMBOL(drm_edid_block_valid); 231235783Skib 232235783Skib/** 233235783Skib * drm_edid_is_valid - sanity check EDID data 234235783Skib * @edid: EDID data 235235783Skib * 236235783Skib * Sanity-check an entire EDID record (including extensions) 237235783Skib */ 238235783Skibbool drm_edid_is_valid(struct edid *edid) 239235783Skib{ 240235783Skib int i; 241235783Skib u8 *raw = (u8 *)edid; 242235783Skib 243235783Skib if (!edid) 244235783Skib return false; 245235783Skib 246235783Skib for (i = 0; i <= edid->extensions; i++) 247280183Sdumbbell if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true)) 248235783Skib return false; 249235783Skib 250235783Skib return true; 251235783Skib} 252280183SdumbbellEXPORT_SYMBOL(drm_edid_is_valid); 253235783Skib 254235783Skib#define DDC_SEGMENT_ADDR 0x30 255235783Skib/** 256235783Skib * Get EDID information via I2C. 257235783Skib * 258235783Skib * \param adapter : i2c device adaptor 259235783Skib * \param buf : EDID data buffer to be filled 260235783Skib * \param len : EDID data buffer length 261235783Skib * \return 0 on success or -1 on failure. 262235783Skib * 263235783Skib * Try to fetch EDID information by calling i2c driver function. 264235783Skib */ 265235783Skibstatic int 266235783Skibdrm_do_probe_ddc_edid(device_t adapter, unsigned char *buf, 267235783Skib int block, int len) 268235783Skib{ 269235783Skib unsigned char start = block * EDID_LENGTH; 270254833Sdumbbell unsigned char segment = block >> 1; 271254833Sdumbbell unsigned char xfers = segment ? 3 : 2; 272235783Skib int ret, retries = 5; 273235783Skib 274235783Skib /* The core i2c driver will automatically retry the transfer if the 275235783Skib * adapter reports EAGAIN. However, we find that bit-banging transfers 276235783Skib * are susceptible to errors under a heavily loaded machine and 277235783Skib * generate spurious NAKs and timeouts. Retrying the transfer 278235783Skib * of the individual block a few times seems to overcome this. 279235783Skib */ 280235783Skib do { 281235783Skib struct iic_msg msgs[] = { 282235783Skib { 283280183Sdumbbell .slave = DDC_SEGMENT_ADDR << 1, 284280183Sdumbbell .flags = 0, 285280183Sdumbbell .len = 1, 286280183Sdumbbell .buf = &segment, 287254833Sdumbbell }, { 288249041Sdumbbell .slave = DDC_ADDR << 1, 289280183Sdumbbell .flags = 0, 290235783Skib .len = 1, 291235783Skib .buf = &start, 292235783Skib }, { 293249041Sdumbbell .slave = DDC_ADDR << 1, 294235783Skib .flags = IIC_M_RD, 295235783Skib .len = len, 296235783Skib .buf = buf, 297235783Skib } 298235783Skib }; 299254833Sdumbbell 300254833Sdumbbell /* 301254833Sdumbbell * Avoid sending the segment addr to not upset non-compliant ddc 302254833Sdumbbell * monitors. 303254833Sdumbbell */ 304254833Sdumbbell ret = iicbus_transfer(adapter, &msgs[3 - xfers], xfers); 305254833Sdumbbell 306235783Skib if (ret != 0) 307235783Skib DRM_DEBUG_KMS("iicbus_transfer countdown %d error %d\n", 308235783Skib retries, ret); 309235783Skib } while (ret != 0 && --retries); 310235783Skib 311280183Sdumbbell return ret == 0 ? 0 : -1; 312235783Skib} 313235783Skib 314235783Skibstatic bool drm_edid_is_zero(u8 *in_edid, int length) 315235783Skib{ 316235783Skib int i; 317235783Skib u32 *raw_edid = (u32 *)in_edid; 318235783Skib 319235783Skib for (i = 0; i < length / 4; i++) 320235783Skib if (*(raw_edid + i) != 0) 321235783Skib return false; 322280183Sdumbbell 323235783Skib return true; 324235783Skib} 325235783Skib 326235783Skibstatic u8 * 327235783Skibdrm_do_get_edid(struct drm_connector *connector, device_t adapter) 328235783Skib{ 329235783Skib int i, j = 0, valid_extensions = 0; 330235783Skib u8 *block, *new; 331280183Sdumbbell bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_DEBUGBITS_KMS); 332235783Skib 333280183Sdumbbell if ((block = malloc(EDID_LENGTH, DRM_MEM_KMS, M_NOWAIT)) == NULL) 334280183Sdumbbell return NULL; 335235783Skib 336235783Skib /* base block fetch */ 337235783Skib for (i = 0; i < 4; i++) { 338235783Skib if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) 339235783Skib goto out; 340280183Sdumbbell if (drm_edid_block_valid(block, 0, print_bad_edid)) 341235783Skib break; 342235783Skib if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { 343235783Skib connector->null_edid_counter++; 344235783Skib goto carp; 345235783Skib } 346235783Skib } 347235783Skib if (i == 4) 348235783Skib goto carp; 349235783Skib 350235783Skib /* if there's no extensions, we're done */ 351235783Skib if (block[0x7e] == 0) 352235783Skib return block; 353235783Skib 354235783Skib new = reallocf(block, (block[0x7e] + 1) * EDID_LENGTH, DRM_MEM_KMS, 355280183Sdumbbell M_NOWAIT); 356298334Scem if (!new) { 357298334Scem block = NULL; 358280183Sdumbbell goto out; 359298334Scem } 360235783Skib block = new; 361235783Skib 362235783Skib for (j = 1; j <= block[0x7e]; j++) { 363235783Skib for (i = 0; i < 4; i++) { 364235783Skib if (drm_do_probe_ddc_edid(adapter, 365235783Skib block + (valid_extensions + 1) * EDID_LENGTH, 366235783Skib j, EDID_LENGTH)) 367235783Skib goto out; 368280183Sdumbbell if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) { 369235783Skib valid_extensions++; 370235783Skib break; 371235783Skib } 372235783Skib } 373280183Sdumbbell 374280183Sdumbbell if (i == 4 && print_bad_edid) { 375280183Sdumbbell dev_warn(connector->dev->dev, 376280183Sdumbbell "%s: Ignoring invalid EDID block %d.\n", 377280183Sdumbbell drm_get_connector_name(connector), j); 378280183Sdumbbell 379280183Sdumbbell connector->bad_edid_counter++; 380280183Sdumbbell } 381235783Skib } 382235783Skib 383235783Skib if (valid_extensions != block[0x7e]) { 384235783Skib block[EDID_LENGTH-1] += block[0x7e] - valid_extensions; 385235783Skib block[0x7e] = valid_extensions; 386235783Skib new = reallocf(block, (valid_extensions + 1) * EDID_LENGTH, 387280183Sdumbbell DRM_MEM_KMS, M_NOWAIT); 388280183Sdumbbell if (!new) 389280183Sdumbbell goto out; 390235783Skib block = new; 391235783Skib } 392235783Skib 393235783Skib return block; 394235783Skib 395235783Skibcarp: 396280183Sdumbbell if (print_bad_edid) { 397280183Sdumbbell dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n", 398280183Sdumbbell drm_get_connector_name(connector), j); 399280183Sdumbbell } 400280183Sdumbbell connector->bad_edid_counter++; 401235783Skib 402235783Skibout: 403235783Skib free(block, DRM_MEM_KMS); 404235783Skib return NULL; 405235783Skib} 406235783Skib 407235783Skib/** 408235783Skib * Probe DDC presence. 409235783Skib * 410235783Skib * \param adapter : i2c device adaptor 411235783Skib * \return 1 on success 412235783Skib */ 413280183Sdumbbellbool 414235783Skibdrm_probe_ddc(device_t adapter) 415235783Skib{ 416235783Skib unsigned char out; 417235783Skib 418235783Skib return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0); 419235783Skib} 420280183SdumbbellEXPORT_SYMBOL(drm_probe_ddc); 421235783Skib 422235783Skib/** 423235783Skib * drm_get_edid - get EDID data, if available 424235783Skib * @connector: connector we're probing 425235783Skib * @adapter: i2c adapter to use for DDC 426235783Skib * 427235783Skib * Poke the given i2c channel to grab EDID data if possible. If found, 428235783Skib * attach it to the connector. 429235783Skib * 430235783Skib * Return edid data or NULL if we couldn't find any. 431235783Skib */ 432235783Skibstruct edid *drm_get_edid(struct drm_connector *connector, 433235783Skib device_t adapter) 434235783Skib{ 435235783Skib struct edid *edid = NULL; 436235783Skib 437235783Skib if (drm_probe_ddc(adapter)) 438235783Skib edid = (struct edid *)drm_do_get_edid(connector, adapter); 439235783Skib 440235783Skib return edid; 441235783Skib} 442280183SdumbbellEXPORT_SYMBOL(drm_get_edid); 443235783Skib 444235783Skib/*** EDID parsing ***/ 445235783Skib 446235783Skib/** 447235783Skib * edid_vendor - match a string against EDID's obfuscated vendor field 448235783Skib * @edid: EDID to match 449235783Skib * @vendor: vendor string 450235783Skib * 451235783Skib * Returns true if @vendor is in @edid, false otherwise 452235783Skib */ 453235783Skibstatic bool edid_vendor(struct edid *edid, char *vendor) 454235783Skib{ 455235783Skib char edid_vendor[3]; 456235783Skib 457235783Skib edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@'; 458235783Skib edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) | 459235783Skib ((edid->mfg_id[1] & 0xe0) >> 5)) + '@'; 460235783Skib edid_vendor[2] = (edid->mfg_id[1] & 0x1f) + '@'; 461235783Skib 462235783Skib return !strncmp(edid_vendor, vendor, 3); 463235783Skib} 464235783Skib 465235783Skib/** 466235783Skib * edid_get_quirks - return quirk flags for a given EDID 467235783Skib * @edid: EDID to process 468235783Skib * 469235783Skib * This tells subsequent routines what fixes they need to apply. 470235783Skib */ 471235783Skibstatic u32 edid_get_quirks(struct edid *edid) 472235783Skib{ 473235783Skib struct edid_quirk *quirk; 474235783Skib int i; 475235783Skib 476280183Sdumbbell for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) { 477235783Skib quirk = &edid_quirk_list[i]; 478235783Skib 479235783Skib if (edid_vendor(edid, quirk->vendor) && 480235783Skib (EDID_PRODUCT_ID(edid) == quirk->product_id)) 481235783Skib return quirk->quirks; 482235783Skib } 483235783Skib 484235783Skib return 0; 485235783Skib} 486235783Skib 487235783Skib#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) 488235783Skib#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh)) 489235783Skib 490235783Skib/** 491235783Skib * edid_fixup_preferred - set preferred modes based on quirk list 492235783Skib * @connector: has mode list to fix up 493235783Skib * @quirks: quirks list 494235783Skib * 495235783Skib * Walk the mode list for @connector, clearing the preferred status 496235783Skib * on existing modes and setting it anew for the right mode ala @quirks. 497235783Skib */ 498235783Skibstatic void edid_fixup_preferred(struct drm_connector *connector, 499235783Skib u32 quirks) 500235783Skib{ 501235783Skib struct drm_display_mode *t, *cur_mode, *preferred_mode; 502235783Skib int target_refresh = 0; 503235783Skib 504235783Skib if (list_empty(&connector->probed_modes)) 505235783Skib return; 506235783Skib 507235783Skib if (quirks & EDID_QUIRK_PREFER_LARGE_60) 508235783Skib target_refresh = 60; 509235783Skib if (quirks & EDID_QUIRK_PREFER_LARGE_75) 510235783Skib target_refresh = 75; 511235783Skib 512235783Skib preferred_mode = list_first_entry(&connector->probed_modes, 513235783Skib struct drm_display_mode, head); 514235783Skib 515235783Skib list_for_each_entry_safe(cur_mode, t, &connector->probed_modes, head) { 516235783Skib cur_mode->type &= ~DRM_MODE_TYPE_PREFERRED; 517235783Skib 518235783Skib if (cur_mode == preferred_mode) 519235783Skib continue; 520235783Skib 521235783Skib /* Largest mode is preferred */ 522235783Skib if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode)) 523235783Skib preferred_mode = cur_mode; 524235783Skib 525235783Skib /* At a given size, try to get closest to target refresh */ 526235783Skib if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) && 527235783Skib MODE_REFRESH_DIFF(cur_mode, target_refresh) < 528235783Skib MODE_REFRESH_DIFF(preferred_mode, target_refresh)) { 529235783Skib preferred_mode = cur_mode; 530235783Skib } 531235783Skib } 532235783Skib 533235783Skib preferred_mode->type |= DRM_MODE_TYPE_PREFERRED; 534235783Skib} 535235783Skib 536277487Skibstatic bool 537277487Skibmode_is_rb(const struct drm_display_mode *mode) 538277487Skib{ 539277487Skib return (mode->htotal - mode->hdisplay == 160) && 540277487Skib (mode->hsync_end - mode->hdisplay == 80) && 541277487Skib (mode->hsync_end - mode->hsync_start == 32) && 542277487Skib (mode->vsync_start - mode->vdisplay == 3); 543277487Skib} 544277487Skib 545277487Skib/* 546277487Skib * drm_mode_find_dmt - Create a copy of a mode if present in DMT 547277487Skib * @dev: Device to duplicate against 548277487Skib * @hsize: Mode width 549277487Skib * @vsize: Mode height 550277487Skib * @fresh: Mode refresh rate 551277487Skib * @rb: Mode reduced-blanking-ness 552277487Skib * 553277487Skib * Walk the DMT mode list looking for a match for the given parameters. 554277487Skib * Return a newly allocated copy of the mode, or NULL if not found. 555277487Skib */ 556235783Skibstruct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, 557277487Skib int hsize, int vsize, int fresh, 558277487Skib bool rb) 559235783Skib{ 560235783Skib int i; 561235783Skib 562235783Skib for (i = 0; i < drm_num_dmt_modes; i++) { 563280183Sdumbbell const struct drm_display_mode *ptr = &drm_dmt_modes[i]; 564277487Skib if (hsize != ptr->hdisplay) 565277487Skib continue; 566277487Skib if (vsize != ptr->vdisplay) 567277487Skib continue; 568277487Skib if (fresh != drm_mode_vrefresh(ptr)) 569277487Skib continue; 570277487Skib if (rb != mode_is_rb(ptr)) 571277487Skib continue; 572277487Skib 573277487Skib return drm_mode_duplicate(dev, ptr); 574235783Skib } 575277487Skib 576277487Skib return NULL; 577235783Skib} 578280183SdumbbellEXPORT_SYMBOL(drm_mode_find_dmt); 579235783Skib 580235783Skibtypedef void detailed_cb(struct detailed_timing *timing, void *closure); 581235783Skib 582235783Skibstatic void 583235783Skibcea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure) 584235783Skib{ 585235783Skib int i, n = 0; 586280183Sdumbbell u8 d = ext[0x02]; 587235783Skib u8 *det_base = ext + d; 588235783Skib 589280183Sdumbbell n = (127 - d) / 18; 590235783Skib for (i = 0; i < n; i++) 591235783Skib cb((struct detailed_timing *)(det_base + 18 * i), closure); 592235783Skib} 593235783Skib 594235783Skibstatic void 595235783Skibvtb_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure) 596235783Skib{ 597235783Skib unsigned int i, n = min((int)ext[0x02], 6); 598235783Skib u8 *det_base = ext + 5; 599235783Skib 600235783Skib if (ext[0x01] != 1) 601235783Skib return; /* unknown version */ 602235783Skib 603235783Skib for (i = 0; i < n; i++) 604235783Skib cb((struct detailed_timing *)(det_base + 18 * i), closure); 605235783Skib} 606235783Skib 607235783Skibstatic void 608235783Skibdrm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure) 609235783Skib{ 610235783Skib int i; 611235783Skib struct edid *edid = (struct edid *)raw_edid; 612235783Skib 613235783Skib if (edid == NULL) 614235783Skib return; 615235783Skib 616235783Skib for (i = 0; i < EDID_DETAILED_TIMINGS; i++) 617235783Skib cb(&(edid->detailed_timings[i]), closure); 618235783Skib 619235783Skib for (i = 1; i <= raw_edid[0x7e]; i++) { 620235783Skib u8 *ext = raw_edid + (i * EDID_LENGTH); 621235783Skib switch (*ext) { 622235783Skib case CEA_EXT: 623235783Skib cea_for_each_detailed_block(ext, cb, closure); 624235783Skib break; 625235783Skib case VTB_EXT: 626235783Skib vtb_for_each_detailed_block(ext, cb, closure); 627235783Skib break; 628235783Skib default: 629235783Skib break; 630235783Skib } 631235783Skib } 632235783Skib} 633235783Skib 634235783Skibstatic void 635235783Skibis_rb(struct detailed_timing *t, void *data) 636235783Skib{ 637235783Skib u8 *r = (u8 *)t; 638235783Skib if (r[3] == EDID_DETAIL_MONITOR_RANGE) 639235783Skib if (r[15] & 0x10) 640235783Skib *(bool *)data = true; 641235783Skib} 642235783Skib 643235783Skib/* EDID 1.4 defines this explicitly. For EDID 1.3, we guess, badly. */ 644235783Skibstatic bool 645235783Skibdrm_monitor_supports_rb(struct edid *edid) 646235783Skib{ 647235783Skib if (edid->revision >= 4) { 648280183Sdumbbell bool ret = false; 649235783Skib drm_for_each_detailed_block((u8 *)edid, is_rb, &ret); 650235783Skib return ret; 651235783Skib } 652235783Skib 653235783Skib return ((edid->input & DRM_EDID_INPUT_DIGITAL) != 0); 654235783Skib} 655235783Skib 656235783Skibstatic void 657235783Skibfind_gtf2(struct detailed_timing *t, void *data) 658235783Skib{ 659235783Skib u8 *r = (u8 *)t; 660235783Skib if (r[3] == EDID_DETAIL_MONITOR_RANGE && r[10] == 0x02) 661235783Skib *(u8 **)data = r; 662235783Skib} 663235783Skib 664235783Skib/* Secondary GTF curve kicks in above some break frequency */ 665235783Skibstatic int 666235783Skibdrm_gtf2_hbreak(struct edid *edid) 667235783Skib{ 668235783Skib u8 *r = NULL; 669235783Skib drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); 670235783Skib return r ? (r[12] * 2) : 0; 671235783Skib} 672235783Skib 673235783Skibstatic int 674235783Skibdrm_gtf2_2c(struct edid *edid) 675235783Skib{ 676235783Skib u8 *r = NULL; 677235783Skib drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); 678235783Skib return r ? r[13] : 0; 679235783Skib} 680235783Skib 681235783Skibstatic int 682235783Skibdrm_gtf2_m(struct edid *edid) 683235783Skib{ 684235783Skib u8 *r = NULL; 685235783Skib drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); 686235783Skib return r ? (r[15] << 8) + r[14] : 0; 687235783Skib} 688235783Skib 689235783Skibstatic int 690235783Skibdrm_gtf2_k(struct edid *edid) 691235783Skib{ 692235783Skib u8 *r = NULL; 693235783Skib drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); 694235783Skib return r ? r[16] : 0; 695235783Skib} 696235783Skib 697235783Skibstatic int 698235783Skibdrm_gtf2_2j(struct edid *edid) 699235783Skib{ 700235783Skib u8 *r = NULL; 701235783Skib drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); 702235783Skib return r ? r[17] : 0; 703235783Skib} 704235783Skib 705235783Skib/** 706235783Skib * standard_timing_level - get std. timing level(CVT/GTF/DMT) 707235783Skib * @edid: EDID block to scan 708235783Skib */ 709235783Skibstatic int standard_timing_level(struct edid *edid) 710235783Skib{ 711235783Skib if (edid->revision >= 2) { 712235783Skib if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)) 713235783Skib return LEVEL_CVT; 714235783Skib if (drm_gtf2_hbreak(edid)) 715235783Skib return LEVEL_GTF2; 716235783Skib return LEVEL_GTF; 717235783Skib } 718235783Skib return LEVEL_DMT; 719235783Skib} 720235783Skib 721235783Skib/* 722235783Skib * 0 is reserved. The spec says 0x01 fill for unused timings. Some old 723235783Skib * monitors fill with ascii space (0x20) instead. 724235783Skib */ 725235783Skibstatic int 726235783Skibbad_std_timing(u8 a, u8 b) 727235783Skib{ 728235783Skib return (a == 0x00 && b == 0x00) || 729235783Skib (a == 0x01 && b == 0x01) || 730235783Skib (a == 0x20 && b == 0x20); 731235783Skib} 732235783Skib 733235783Skib/** 734235783Skib * drm_mode_std - convert standard mode info (width, height, refresh) into mode 735235783Skib * @t: standard timing params 736235783Skib * @timing_level: standard timing level 737235783Skib * 738235783Skib * Take the standard timing params (in this case width, aspect, and refresh) 739235783Skib * and convert them into a real mode using CVT/GTF/DMT. 740235783Skib */ 741235783Skibstatic struct drm_display_mode * 742235783Skibdrm_mode_std(struct drm_connector *connector, struct edid *edid, 743235783Skib struct std_timing *t, int revision) 744235783Skib{ 745235783Skib struct drm_device *dev = connector->dev; 746235783Skib struct drm_display_mode *m, *mode = NULL; 747235783Skib int hsize, vsize; 748235783Skib int vrefresh_rate; 749235783Skib unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) 750235783Skib >> EDID_TIMING_ASPECT_SHIFT; 751235783Skib unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) 752235783Skib >> EDID_TIMING_VFREQ_SHIFT; 753235783Skib int timing_level = standard_timing_level(edid); 754235783Skib 755235783Skib if (bad_std_timing(t->hsize, t->vfreq_aspect)) 756235783Skib return NULL; 757235783Skib 758235783Skib /* According to the EDID spec, the hdisplay = hsize * 8 + 248 */ 759235783Skib hsize = t->hsize * 8 + 248; 760235783Skib /* vrefresh_rate = vfreq + 60 */ 761235783Skib vrefresh_rate = vfreq + 60; 762235783Skib /* the vdisplay is calculated based on the aspect ratio */ 763235783Skib if (aspect_ratio == 0) { 764235783Skib if (revision < 3) 765235783Skib vsize = hsize; 766235783Skib else 767235783Skib vsize = (hsize * 10) / 16; 768235783Skib } else if (aspect_ratio == 1) 769235783Skib vsize = (hsize * 3) / 4; 770235783Skib else if (aspect_ratio == 2) 771235783Skib vsize = (hsize * 4) / 5; 772235783Skib else 773235783Skib vsize = (hsize * 9) / 16; 774235783Skib 775235783Skib /* HDTV hack, part 1 */ 776235783Skib if (vrefresh_rate == 60 && 777235783Skib ((hsize == 1360 && vsize == 765) || 778235783Skib (hsize == 1368 && vsize == 769))) { 779235783Skib hsize = 1366; 780235783Skib vsize = 768; 781235783Skib } 782235783Skib 783235783Skib /* 784235783Skib * If this connector already has a mode for this size and refresh 785235783Skib * rate (because it came from detailed or CVT info), use that 786235783Skib * instead. This way we don't have to guess at interlace or 787235783Skib * reduced blanking. 788235783Skib */ 789235783Skib list_for_each_entry(m, &connector->probed_modes, head) 790235783Skib if (m->hdisplay == hsize && m->vdisplay == vsize && 791235783Skib drm_mode_vrefresh(m) == vrefresh_rate) 792235783Skib return NULL; 793235783Skib 794235783Skib /* HDTV hack, part 2 */ 795235783Skib if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) { 796235783Skib mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0, 797235783Skib false); 798235783Skib mode->hdisplay = 1366; 799235783Skib mode->hsync_start = mode->hsync_start - 1; 800235783Skib mode->hsync_end = mode->hsync_end - 1; 801235783Skib return mode; 802235783Skib } 803235783Skib 804235783Skib /* check whether it can be found in default mode table */ 805277487Skib if (drm_monitor_supports_rb(edid)) { 806277487Skib mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, 807277487Skib true); 808277487Skib if (mode) 809277487Skib return mode; 810277487Skib } 811277487Skib mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, false); 812235783Skib if (mode) 813235783Skib return mode; 814235783Skib 815277487Skib /* okay, generate it */ 816235783Skib switch (timing_level) { 817235783Skib case LEVEL_DMT: 818235783Skib break; 819235783Skib case LEVEL_GTF: 820235783Skib mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); 821235783Skib break; 822235783Skib case LEVEL_GTF2: 823235783Skib /* 824235783Skib * This is potentially wrong if there's ever a monitor with 825235783Skib * more than one ranges section, each claiming a different 826235783Skib * secondary GTF curve. Please don't do that. 827235783Skib */ 828235783Skib mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); 829277487Skib if (!mode) 830277487Skib return NULL; 831235783Skib if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) { 832280183Sdumbbell drm_mode_destroy(dev, mode); 833235783Skib mode = drm_gtf_mode_complex(dev, hsize, vsize, 834235783Skib vrefresh_rate, 0, 0, 835235783Skib drm_gtf2_m(edid), 836235783Skib drm_gtf2_2c(edid), 837235783Skib drm_gtf2_k(edid), 838235783Skib drm_gtf2_2j(edid)); 839235783Skib } 840235783Skib break; 841235783Skib case LEVEL_CVT: 842235783Skib mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, 843235783Skib false); 844235783Skib break; 845235783Skib } 846235783Skib return mode; 847235783Skib} 848235783Skib 849235783Skib/* 850235783Skib * EDID is delightfully ambiguous about how interlaced modes are to be 851235783Skib * encoded. Our internal representation is of frame height, but some 852235783Skib * HDTV detailed timings are encoded as field height. 853235783Skib * 854235783Skib * The format list here is from CEA, in frame size. Technically we 855235783Skib * should be checking refresh rate too. Whatever. 856235783Skib */ 857235783Skibstatic void 858235783Skibdrm_mode_do_interlace_quirk(struct drm_display_mode *mode, 859235783Skib struct detailed_pixel_timing *pt) 860235783Skib{ 861235783Skib int i; 862235783Skib static const struct { 863235783Skib int w, h; 864235783Skib } cea_interlaced[] = { 865235783Skib { 1920, 1080 }, 866235783Skib { 720, 480 }, 867235783Skib { 1440, 480 }, 868235783Skib { 2880, 480 }, 869235783Skib { 720, 576 }, 870235783Skib { 1440, 576 }, 871235783Skib { 2880, 576 }, 872235783Skib }; 873235783Skib 874235783Skib if (!(pt->misc & DRM_EDID_PT_INTERLACED)) 875235783Skib return; 876235783Skib 877280183Sdumbbell for (i = 0; i < ARRAY_SIZE(cea_interlaced); i++) { 878235783Skib if ((mode->hdisplay == cea_interlaced[i].w) && 879235783Skib (mode->vdisplay == cea_interlaced[i].h / 2)) { 880235783Skib mode->vdisplay *= 2; 881235783Skib mode->vsync_start *= 2; 882235783Skib mode->vsync_end *= 2; 883235783Skib mode->vtotal *= 2; 884235783Skib mode->vtotal |= 1; 885235783Skib } 886235783Skib } 887235783Skib 888235783Skib mode->flags |= DRM_MODE_FLAG_INTERLACE; 889235783Skib} 890235783Skib 891235783Skib/** 892235783Skib * drm_mode_detailed - create a new mode from an EDID detailed timing section 893235783Skib * @dev: DRM device (needed to create new mode) 894235783Skib * @edid: EDID block 895235783Skib * @timing: EDID detailed timing info 896235783Skib * @quirks: quirks to apply 897235783Skib * 898235783Skib * An EDID detailed timing block contains enough info for us to create and 899235783Skib * return a new struct drm_display_mode. 900235783Skib */ 901235783Skibstatic struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, 902235783Skib struct edid *edid, 903235783Skib struct detailed_timing *timing, 904235783Skib u32 quirks) 905235783Skib{ 906235783Skib struct drm_display_mode *mode; 907235783Skib struct detailed_pixel_timing *pt = &timing->data.pixel_data; 908235783Skib unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo; 909235783Skib unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo; 910235783Skib unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo; 911235783Skib unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; 912235783Skib unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo; 913235783Skib unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo; 914280183Sdumbbell unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 2 | pt->vsync_offset_pulse_width_lo >> 4; 915235783Skib unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf); 916235783Skib 917235783Skib /* ignore tiny modes */ 918235783Skib if (hactive < 64 || vactive < 64) 919235783Skib return NULL; 920235783Skib 921235783Skib if (pt->misc & DRM_EDID_PT_STEREO) { 922235783Skib printf("stereo mode not supported\n"); 923235783Skib return NULL; 924235783Skib } 925235783Skib if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { 926235783Skib printf("composite sync not supported\n"); 927235783Skib } 928235783Skib 929235783Skib /* it is incorrect if hsync/vsync width is zero */ 930235783Skib if (!hsync_pulse_width || !vsync_pulse_width) { 931235783Skib DRM_DEBUG_KMS("Incorrect Detailed timing. " 932235783Skib "Wrong Hsync/Vsync pulse width\n"); 933235783Skib return NULL; 934235783Skib } 935280183Sdumbbell 936280183Sdumbbell if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) { 937280183Sdumbbell mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false); 938280183Sdumbbell if (!mode) 939280183Sdumbbell return NULL; 940280183Sdumbbell 941280183Sdumbbell goto set_size; 942280183Sdumbbell } 943280183Sdumbbell 944235783Skib mode = drm_mode_create(dev); 945235783Skib if (!mode) 946235783Skib return NULL; 947235783Skib 948235783Skib if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) 949280183Sdumbbell timing->pixel_clock = cpu_to_le16(1088); 950235783Skib 951280183Sdumbbell mode->clock = le16_to_cpu(timing->pixel_clock) * 10; 952235783Skib 953235783Skib mode->hdisplay = hactive; 954235783Skib mode->hsync_start = mode->hdisplay + hsync_offset; 955235783Skib mode->hsync_end = mode->hsync_start + hsync_pulse_width; 956235783Skib mode->htotal = mode->hdisplay + hblank; 957235783Skib 958235783Skib mode->vdisplay = vactive; 959235783Skib mode->vsync_start = mode->vdisplay + vsync_offset; 960235783Skib mode->vsync_end = mode->vsync_start + vsync_pulse_width; 961235783Skib mode->vtotal = mode->vdisplay + vblank; 962235783Skib 963235783Skib /* Some EDIDs have bogus h/vtotal values */ 964235783Skib if (mode->hsync_end > mode->htotal) 965235783Skib mode->htotal = mode->hsync_end + 1; 966235783Skib if (mode->vsync_end > mode->vtotal) 967235783Skib mode->vtotal = mode->vsync_end + 1; 968235783Skib 969235783Skib drm_mode_do_interlace_quirk(mode, pt); 970235783Skib 971235783Skib if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { 972235783Skib pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; 973235783Skib } 974235783Skib 975235783Skib mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ? 976235783Skib DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; 977235783Skib mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? 978235783Skib DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; 979235783Skib 980280183Sdumbbellset_size: 981235783Skib mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; 982235783Skib mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; 983235783Skib 984235783Skib if (quirks & EDID_QUIRK_DETAILED_IN_CM) { 985235783Skib mode->width_mm *= 10; 986235783Skib mode->height_mm *= 10; 987235783Skib } 988235783Skib 989235783Skib if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { 990235783Skib mode->width_mm = edid->width_cm * 10; 991235783Skib mode->height_mm = edid->height_cm * 10; 992235783Skib } 993235783Skib 994280183Sdumbbell mode->type = DRM_MODE_TYPE_DRIVER; 995280183Sdumbbell mode->vrefresh = drm_mode_vrefresh(mode); 996280183Sdumbbell drm_mode_set_name(mode); 997280183Sdumbbell 998235783Skib return mode; 999235783Skib} 1000235783Skib 1001235783Skibstatic bool 1002280183Sdumbbellmode_in_hsync_range(const struct drm_display_mode *mode, 1003235783Skib struct edid *edid, u8 *t) 1004235783Skib{ 1005235783Skib int hsync, hmin, hmax; 1006235783Skib 1007235783Skib hmin = t[7]; 1008235783Skib if (edid->revision >= 4) 1009235783Skib hmin += ((t[4] & 0x04) ? 255 : 0); 1010235783Skib hmax = t[8]; 1011235783Skib if (edid->revision >= 4) 1012235783Skib hmax += ((t[4] & 0x08) ? 255 : 0); 1013235783Skib hsync = drm_mode_hsync(mode); 1014235783Skib 1015235783Skib return (hsync <= hmax && hsync >= hmin); 1016235783Skib} 1017235783Skib 1018235783Skibstatic bool 1019280183Sdumbbellmode_in_vsync_range(const struct drm_display_mode *mode, 1020235783Skib struct edid *edid, u8 *t) 1021235783Skib{ 1022235783Skib int vsync, vmin, vmax; 1023235783Skib 1024235783Skib vmin = t[5]; 1025235783Skib if (edid->revision >= 4) 1026235783Skib vmin += ((t[4] & 0x01) ? 255 : 0); 1027235783Skib vmax = t[6]; 1028235783Skib if (edid->revision >= 4) 1029235783Skib vmax += ((t[4] & 0x02) ? 255 : 0); 1030235783Skib vsync = drm_mode_vrefresh(mode); 1031235783Skib 1032235783Skib return (vsync <= vmax && vsync >= vmin); 1033235783Skib} 1034235783Skib 1035235783Skibstatic u32 1036235783Skibrange_pixel_clock(struct edid *edid, u8 *t) 1037235783Skib{ 1038235783Skib /* unspecified */ 1039235783Skib if (t[9] == 0 || t[9] == 255) 1040235783Skib return 0; 1041235783Skib 1042235783Skib /* 1.4 with CVT support gives us real precision, yay */ 1043235783Skib if (edid->revision >= 4 && t[10] == 0x04) 1044235783Skib return (t[9] * 10000) - ((t[12] >> 2) * 250); 1045235783Skib 1046235783Skib /* 1.3 is pathetic, so fuzz up a bit */ 1047235783Skib return t[9] * 10000 + 5001; 1048235783Skib} 1049235783Skib 1050235783Skibstatic bool 1051280183Sdumbbellmode_in_range(const struct drm_display_mode *mode, struct edid *edid, 1052235783Skib struct detailed_timing *timing) 1053235783Skib{ 1054235783Skib u32 max_clock; 1055235783Skib u8 *t = (u8 *)timing; 1056235783Skib 1057235783Skib if (!mode_in_hsync_range(mode, edid, t)) 1058235783Skib return false; 1059235783Skib 1060235783Skib if (!mode_in_vsync_range(mode, edid, t)) 1061235783Skib return false; 1062235783Skib 1063235783Skib if ((max_clock = range_pixel_clock(edid, t))) 1064235783Skib if (mode->clock > max_clock) 1065235783Skib return false; 1066235783Skib 1067235783Skib /* 1.4 max horizontal check */ 1068235783Skib if (edid->revision >= 4 && t[10] == 0x04) 1069235783Skib if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3)))) 1070235783Skib return false; 1071235783Skib 1072235783Skib if (mode_is_rb(mode) && !drm_monitor_supports_rb(edid)) 1073235783Skib return false; 1074235783Skib 1075235783Skib return true; 1076235783Skib} 1077235783Skib 1078280183Sdumbbellstatic bool valid_inferred_mode(const struct drm_connector *connector, 1079280183Sdumbbell const struct drm_display_mode *mode) 1080280183Sdumbbell{ 1081280183Sdumbbell struct drm_display_mode *m; 1082280183Sdumbbell bool ok = false; 1083280183Sdumbbell 1084280183Sdumbbell list_for_each_entry(m, &connector->probed_modes, head) { 1085280183Sdumbbell if (mode->hdisplay == m->hdisplay && 1086280183Sdumbbell mode->vdisplay == m->vdisplay && 1087280183Sdumbbell drm_mode_vrefresh(mode) == drm_mode_vrefresh(m)) 1088280183Sdumbbell return false; /* duplicated */ 1089280183Sdumbbell if (mode->hdisplay <= m->hdisplay && 1090280183Sdumbbell mode->vdisplay <= m->vdisplay) 1091280183Sdumbbell ok = true; 1092280183Sdumbbell } 1093280183Sdumbbell return ok; 1094280183Sdumbbell} 1095280183Sdumbbell 1096235783Skibstatic int 1097277487Skibdrm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid, 1098235783Skib struct detailed_timing *timing) 1099235783Skib{ 1100235783Skib int i, modes = 0; 1101235783Skib struct drm_display_mode *newmode; 1102235783Skib struct drm_device *dev = connector->dev; 1103235783Skib 1104235783Skib for (i = 0; i < drm_num_dmt_modes; i++) { 1105280183Sdumbbell if (mode_in_range(drm_dmt_modes + i, edid, timing) && 1106280183Sdumbbell valid_inferred_mode(connector, drm_dmt_modes + i)) { 1107235783Skib newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); 1108235783Skib if (newmode) { 1109235783Skib drm_mode_probed_add(connector, newmode); 1110235783Skib modes++; 1111235783Skib } 1112235783Skib } 1113235783Skib } 1114235783Skib 1115235783Skib return modes; 1116235783Skib} 1117235783Skib 1118277487Skib/* fix up 1366x768 mode from 1368x768; 1119277487Skib * GFT/CVT can't express 1366 width which isn't dividable by 8 1120277487Skib */ 1121277487Skibstatic void fixup_mode_1366x768(struct drm_display_mode *mode) 1122277487Skib{ 1123277487Skib if (mode->hdisplay == 1368 && mode->vdisplay == 768) { 1124277487Skib mode->hdisplay = 1366; 1125277487Skib mode->hsync_start--; 1126277487Skib mode->hsync_end--; 1127277487Skib drm_mode_set_name(mode); 1128277487Skib } 1129277487Skib} 1130277487Skib 1131277487Skibstatic int 1132277487Skibdrm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, 1133277487Skib struct detailed_timing *timing) 1134277487Skib{ 1135277487Skib int i, modes = 0; 1136277487Skib struct drm_display_mode *newmode; 1137277487Skib struct drm_device *dev = connector->dev; 1138277487Skib 1139277487Skib for (i = 0; i < num_extra_modes; i++) { 1140277487Skib const struct minimode *m = &extra_modes[i]; 1141277487Skib newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0); 1142277487Skib if (!newmode) 1143277487Skib return modes; 1144277487Skib 1145277487Skib fixup_mode_1366x768(newmode); 1146280183Sdumbbell if (!mode_in_range(newmode, edid, timing) || 1147280183Sdumbbell !valid_inferred_mode(connector, newmode)) { 1148277487Skib drm_mode_destroy(dev, newmode); 1149277487Skib continue; 1150277487Skib } 1151277487Skib 1152277487Skib drm_mode_probed_add(connector, newmode); 1153277487Skib modes++; 1154277487Skib } 1155277487Skib 1156277487Skib return modes; 1157277487Skib} 1158277487Skib 1159277487Skibstatic int 1160277487Skibdrm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid, 1161277487Skib struct detailed_timing *timing) 1162277487Skib{ 1163277487Skib int i, modes = 0; 1164277487Skib struct drm_display_mode *newmode; 1165277487Skib struct drm_device *dev = connector->dev; 1166277487Skib bool rb = drm_monitor_supports_rb(edid); 1167277487Skib 1168277487Skib for (i = 0; i < num_extra_modes; i++) { 1169277487Skib const struct minimode *m = &extra_modes[i]; 1170277487Skib newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0); 1171277487Skib if (!newmode) 1172277487Skib return modes; 1173277487Skib 1174277487Skib fixup_mode_1366x768(newmode); 1175280183Sdumbbell if (!mode_in_range(newmode, edid, timing) || 1176280183Sdumbbell !valid_inferred_mode(connector, newmode)) { 1177277487Skib drm_mode_destroy(dev, newmode); 1178277487Skib continue; 1179277487Skib } 1180277487Skib 1181277487Skib drm_mode_probed_add(connector, newmode); 1182277487Skib modes++; 1183277487Skib } 1184277487Skib 1185277487Skib return modes; 1186277487Skib} 1187277487Skib 1188235783Skibstatic void 1189235783Skibdo_inferred_modes(struct detailed_timing *timing, void *c) 1190235783Skib{ 1191235783Skib struct detailed_mode_closure *closure = c; 1192235783Skib struct detailed_non_pixel *data = &timing->data.other_data; 1193277487Skib struct detailed_data_monitor_range *range = &data->data.range; 1194235783Skib 1195277487Skib if (data->type != EDID_DETAIL_MONITOR_RANGE) 1196277487Skib return; 1197277487Skib 1198277487Skib closure->modes += drm_dmt_modes_for_range(closure->connector, 1199277487Skib closure->edid, 1200277487Skib timing); 1201277487Skib 1202277487Skib if (!version_greater(closure->edid, 1, 1)) 1203277487Skib return; /* GTF not defined yet */ 1204277487Skib 1205277487Skib switch (range->flags) { 1206277487Skib case 0x02: /* secondary gtf, XXX could do more */ 1207277487Skib case 0x00: /* default gtf */ 1208235783Skib closure->modes += drm_gtf_modes_for_range(closure->connector, 1209235783Skib closure->edid, 1210235783Skib timing); 1211277487Skib break; 1212277487Skib case 0x04: /* cvt, only in 1.4+ */ 1213277487Skib if (!version_greater(closure->edid, 1, 3)) 1214277487Skib break; 1215277487Skib 1216277487Skib closure->modes += drm_cvt_modes_for_range(closure->connector, 1217277487Skib closure->edid, 1218277487Skib timing); 1219277487Skib break; 1220277487Skib case 0x01: /* just the ranges, no formula */ 1221277487Skib default: 1222277487Skib break; 1223277487Skib } 1224235783Skib} 1225235783Skib 1226235783Skibstatic int 1227235783Skibadd_inferred_modes(struct drm_connector *connector, struct edid *edid) 1228235783Skib{ 1229235783Skib struct detailed_mode_closure closure = { 1230235783Skib connector, edid, 0, 0, 0 1231235783Skib }; 1232235783Skib 1233235783Skib if (version_greater(edid, 1, 0)) 1234235783Skib drm_for_each_detailed_block((u8 *)edid, do_inferred_modes, 1235235783Skib &closure); 1236235783Skib 1237235783Skib return closure.modes; 1238235783Skib} 1239235783Skib 1240235783Skibstatic int 1241235783Skibdrm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) 1242235783Skib{ 1243235783Skib int i, j, m, modes = 0; 1244235783Skib struct drm_display_mode *mode; 1245235783Skib u8 *est = ((u8 *)timing) + 5; 1246235783Skib 1247235783Skib for (i = 0; i < 6; i++) { 1248235783Skib for (j = 7; j > 0; j--) { 1249235783Skib m = (i * 8) + (7 - j); 1250280183Sdumbbell if (m >= ARRAY_SIZE(est3_modes)) 1251235783Skib break; 1252235783Skib if (est[i] & (1 << j)) { 1253235783Skib mode = drm_mode_find_dmt(connector->dev, 1254235783Skib est3_modes[m].w, 1255235783Skib est3_modes[m].h, 1256277487Skib est3_modes[m].r, 1257277487Skib est3_modes[m].rb); 1258235783Skib if (mode) { 1259235783Skib drm_mode_probed_add(connector, mode); 1260235783Skib modes++; 1261235783Skib } 1262235783Skib } 1263235783Skib } 1264235783Skib } 1265235783Skib 1266235783Skib return modes; 1267235783Skib} 1268235783Skib 1269235783Skibstatic void 1270235783Skibdo_established_modes(struct detailed_timing *timing, void *c) 1271235783Skib{ 1272235783Skib struct detailed_mode_closure *closure = c; 1273235783Skib struct detailed_non_pixel *data = &timing->data.other_data; 1274235783Skib 1275235783Skib if (data->type == EDID_DETAIL_EST_TIMINGS) 1276235783Skib closure->modes += drm_est3_modes(closure->connector, timing); 1277235783Skib} 1278235783Skib 1279235783Skib/** 1280235783Skib * add_established_modes - get est. modes from EDID and add them 1281235783Skib * @edid: EDID block to scan 1282235783Skib * 1283235783Skib * Each EDID block contains a bitmap of the supported "established modes" list 1284235783Skib * (defined above). Tease them out and add them to the global modes list. 1285235783Skib */ 1286235783Skibstatic int 1287235783Skibadd_established_modes(struct drm_connector *connector, struct edid *edid) 1288235783Skib{ 1289235783Skib struct drm_device *dev = connector->dev; 1290235783Skib unsigned long est_bits = edid->established_timings.t1 | 1291235783Skib (edid->established_timings.t2 << 8) | 1292235783Skib ((edid->established_timings.mfg_rsvd & 0x80) << 9); 1293235783Skib int i, modes = 0; 1294235783Skib struct detailed_mode_closure closure = { 1295235783Skib connector, edid, 0, 0, 0 1296235783Skib }; 1297235783Skib 1298235783Skib for (i = 0; i <= EDID_EST_TIMINGS; i++) { 1299235783Skib if (est_bits & (1<<i)) { 1300235783Skib struct drm_display_mode *newmode; 1301235783Skib newmode = drm_mode_duplicate(dev, &edid_est_modes[i]); 1302235783Skib if (newmode) { 1303235783Skib drm_mode_probed_add(connector, newmode); 1304235783Skib modes++; 1305235783Skib } 1306235783Skib } 1307235783Skib } 1308235783Skib 1309235783Skib if (version_greater(edid, 1, 0)) 1310235783Skib drm_for_each_detailed_block((u8 *)edid, 1311235783Skib do_established_modes, &closure); 1312235783Skib 1313235783Skib return modes + closure.modes; 1314235783Skib} 1315235783Skib 1316235783Skibstatic void 1317235783Skibdo_standard_modes(struct detailed_timing *timing, void *c) 1318235783Skib{ 1319235783Skib struct detailed_mode_closure *closure = c; 1320235783Skib struct detailed_non_pixel *data = &timing->data.other_data; 1321235783Skib struct drm_connector *connector = closure->connector; 1322235783Skib struct edid *edid = closure->edid; 1323235783Skib 1324235783Skib if (data->type == EDID_DETAIL_STD_MODES) { 1325235783Skib int i; 1326235783Skib for (i = 0; i < 6; i++) { 1327235783Skib struct std_timing *std; 1328235783Skib struct drm_display_mode *newmode; 1329235783Skib 1330235783Skib std = &data->data.timings[i]; 1331235783Skib newmode = drm_mode_std(connector, edid, std, 1332235783Skib edid->revision); 1333235783Skib if (newmode) { 1334235783Skib drm_mode_probed_add(connector, newmode); 1335235783Skib closure->modes++; 1336235783Skib } 1337235783Skib } 1338235783Skib } 1339235783Skib} 1340235783Skib 1341235783Skib/** 1342235783Skib * add_standard_modes - get std. modes from EDID and add them 1343235783Skib * @edid: EDID block to scan 1344235783Skib * 1345235783Skib * Standard modes can be calculated using the appropriate standard (DMT, 1346235783Skib * GTF or CVT. Grab them from @edid and add them to the list. 1347235783Skib */ 1348235783Skibstatic int 1349235783Skibadd_standard_modes(struct drm_connector *connector, struct edid *edid) 1350235783Skib{ 1351235783Skib int i, modes = 0; 1352235783Skib struct detailed_mode_closure closure = { 1353235783Skib connector, edid, 0, 0, 0 1354235783Skib }; 1355235783Skib 1356235783Skib for (i = 0; i < EDID_STD_TIMINGS; i++) { 1357235783Skib struct drm_display_mode *newmode; 1358235783Skib 1359235783Skib newmode = drm_mode_std(connector, edid, 1360235783Skib &edid->standard_timings[i], 1361235783Skib edid->revision); 1362235783Skib if (newmode) { 1363235783Skib drm_mode_probed_add(connector, newmode); 1364235783Skib modes++; 1365235783Skib } 1366235783Skib } 1367235783Skib 1368235783Skib if (version_greater(edid, 1, 0)) 1369235783Skib drm_for_each_detailed_block((u8 *)edid, do_standard_modes, 1370235783Skib &closure); 1371235783Skib 1372235783Skib /* XXX should also look for standard codes in VTB blocks */ 1373235783Skib 1374235783Skib return modes + closure.modes; 1375235783Skib} 1376235783Skib 1377235783Skibstatic int drm_cvt_modes(struct drm_connector *connector, 1378235783Skib struct detailed_timing *timing) 1379235783Skib{ 1380235783Skib int i, j, modes = 0; 1381235783Skib struct drm_display_mode *newmode; 1382235783Skib struct drm_device *dev = connector->dev; 1383235783Skib struct cvt_timing *cvt; 1384235783Skib const int rates[] = { 60, 85, 75, 60, 50 }; 1385235783Skib const u8 empty[3] = { 0, 0, 0 }; 1386235783Skib 1387235783Skib for (i = 0; i < 4; i++) { 1388235783Skib int width = 0, height; 1389235783Skib cvt = &(timing->data.other_data.data.cvt[i]); 1390235783Skib 1391235783Skib if (!memcmp(cvt->code, empty, 3)) 1392235783Skib continue; 1393235783Skib 1394235783Skib height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2; 1395235783Skib switch (cvt->code[1] & 0x0c) { 1396235783Skib case 0x00: 1397235783Skib width = height * 4 / 3; 1398235783Skib break; 1399235783Skib case 0x04: 1400235783Skib width = height * 16 / 9; 1401235783Skib break; 1402235783Skib case 0x08: 1403235783Skib width = height * 16 / 10; 1404235783Skib break; 1405235783Skib case 0x0c: 1406235783Skib width = height * 15 / 9; 1407235783Skib break; 1408235783Skib } 1409235783Skib 1410235783Skib for (j = 1; j < 5; j++) { 1411235783Skib if (cvt->code[2] & (1 << j)) { 1412235783Skib newmode = drm_cvt_mode(dev, width, height, 1413235783Skib rates[j], j == 0, 1414235783Skib false, false); 1415235783Skib if (newmode) { 1416235783Skib drm_mode_probed_add(connector, newmode); 1417235783Skib modes++; 1418235783Skib } 1419235783Skib } 1420235783Skib } 1421235783Skib } 1422235783Skib 1423235783Skib return modes; 1424235783Skib} 1425235783Skib 1426235783Skibstatic void 1427235783Skibdo_cvt_mode(struct detailed_timing *timing, void *c) 1428235783Skib{ 1429235783Skib struct detailed_mode_closure *closure = c; 1430235783Skib struct detailed_non_pixel *data = &timing->data.other_data; 1431235783Skib 1432235783Skib if (data->type == EDID_DETAIL_CVT_3BYTE) 1433235783Skib closure->modes += drm_cvt_modes(closure->connector, timing); 1434235783Skib} 1435235783Skib 1436235783Skibstatic int 1437235783Skibadd_cvt_modes(struct drm_connector *connector, struct edid *edid) 1438235783Skib{ 1439235783Skib struct detailed_mode_closure closure = { 1440235783Skib connector, edid, 0, 0, 0 1441235783Skib }; 1442235783Skib 1443235783Skib if (version_greater(edid, 1, 2)) 1444235783Skib drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure); 1445235783Skib 1446235783Skib /* XXX should also look for CVT codes in VTB blocks */ 1447235783Skib 1448235783Skib return closure.modes; 1449235783Skib} 1450235783Skib 1451235783Skibstatic void 1452235783Skibdo_detailed_mode(struct detailed_timing *timing, void *c) 1453235783Skib{ 1454235783Skib struct detailed_mode_closure *closure = c; 1455235783Skib struct drm_display_mode *newmode; 1456235783Skib 1457235783Skib if (timing->pixel_clock) { 1458235783Skib newmode = drm_mode_detailed(closure->connector->dev, 1459235783Skib closure->edid, timing, 1460235783Skib closure->quirks); 1461235783Skib if (!newmode) 1462235783Skib return; 1463235783Skib 1464235783Skib if (closure->preferred) 1465235783Skib newmode->type |= DRM_MODE_TYPE_PREFERRED; 1466235783Skib 1467235783Skib drm_mode_probed_add(closure->connector, newmode); 1468235783Skib closure->modes++; 1469235783Skib closure->preferred = 0; 1470235783Skib } 1471235783Skib} 1472235783Skib 1473235783Skib/* 1474235783Skib * add_detailed_modes - Add modes from detailed timings 1475235783Skib * @connector: attached connector 1476235783Skib * @edid: EDID block to scan 1477235783Skib * @quirks: quirks to apply 1478235783Skib */ 1479235783Skibstatic int 1480235783Skibadd_detailed_modes(struct drm_connector *connector, struct edid *edid, 1481235783Skib u32 quirks) 1482235783Skib{ 1483235783Skib struct detailed_mode_closure closure = { 1484235783Skib connector, 1485235783Skib edid, 1486235783Skib 1, 1487235783Skib quirks, 1488235783Skib 0 1489235783Skib }; 1490235783Skib 1491235783Skib if (closure.preferred && !version_greater(edid, 1, 3)) 1492235783Skib closure.preferred = 1493235783Skib (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); 1494235783Skib 1495235783Skib drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure); 1496235783Skib 1497235783Skib return closure.modes; 1498235783Skib} 1499235783Skib 1500235783Skib#define HDMI_IDENTIFIER 0x000C03 1501235783Skib#define AUDIO_BLOCK 0x01 1502280183Sdumbbell#define VIDEO_BLOCK 0x02 1503235783Skib#define VENDOR_BLOCK 0x03 1504235783Skib#define SPEAKER_BLOCK 0x04 1505235783Skib#define EDID_BASIC_AUDIO (1 << 6) 1506277487Skib#define EDID_CEA_YCRCB444 (1 << 5) 1507277487Skib#define EDID_CEA_YCRCB422 (1 << 4) 1508235783Skib 1509235783Skib/** 1510235783Skib * Search EDID for CEA extension block. 1511235783Skib */ 1512235783Skibu8 *drm_find_cea_extension(struct edid *edid) 1513235783Skib{ 1514235783Skib u8 *edid_ext = NULL; 1515235783Skib int i; 1516235783Skib 1517235783Skib /* No EDID or EDID extensions */ 1518235783Skib if (edid == NULL || edid->extensions == 0) 1519235783Skib return NULL; 1520235783Skib 1521235783Skib /* Find CEA extension */ 1522235783Skib for (i = 0; i < edid->extensions; i++) { 1523235783Skib edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); 1524235783Skib if (edid_ext[0] == CEA_EXT) 1525235783Skib break; 1526235783Skib } 1527235783Skib 1528235783Skib if (i == edid->extensions) 1529235783Skib return NULL; 1530235783Skib 1531235783Skib return edid_ext; 1532235783Skib} 1533280183SdumbbellEXPORT_SYMBOL(drm_find_cea_extension); 1534235783Skib 1535280183Sdumbbell/* 1536280183Sdumbbell * Looks for a CEA mode matching given drm_display_mode. 1537280183Sdumbbell * Returns its CEA Video ID code, or 0 if not found. 1538280183Sdumbbell */ 1539280183Sdumbbellu8 drm_match_cea_mode(struct drm_display_mode *to_match) 1540280183Sdumbbell{ 1541280187Sglebius const struct drm_display_mode *cea_mode; 1542280183Sdumbbell u8 mode; 1543280183Sdumbbell 1544280183Sdumbbell for (mode = 0; mode < drm_num_cea_modes; mode++) { 1545280187Sglebius cea_mode = (const struct drm_display_mode *)&edid_cea_modes[mode]; 1546280183Sdumbbell 1547280183Sdumbbell if (drm_mode_equal(to_match, cea_mode)) 1548280183Sdumbbell return mode + 1; 1549280183Sdumbbell } 1550280183Sdumbbell return 0; 1551280183Sdumbbell} 1552280183SdumbbellEXPORT_SYMBOL(drm_match_cea_mode); 1553280183Sdumbbell 1554280183Sdumbbell 1555280183Sdumbbellstatic int 1556280183Sdumbbelldo_cea_modes (struct drm_connector *connector, u8 *db, u8 len) 1557280183Sdumbbell{ 1558280183Sdumbbell struct drm_device *dev = connector->dev; 1559280183Sdumbbell u8 * mode, cea_mode; 1560280183Sdumbbell int modes = 0; 1561280183Sdumbbell 1562280183Sdumbbell for (mode = db; mode < db + len; mode++) { 1563280183Sdumbbell cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */ 1564280183Sdumbbell if (cea_mode < drm_num_cea_modes) { 1565280183Sdumbbell struct drm_display_mode *newmode; 1566280183Sdumbbell newmode = drm_mode_duplicate(dev, 1567280183Sdumbbell &edid_cea_modes[cea_mode]); 1568280183Sdumbbell if (newmode) { 1569280183Sdumbbell drm_mode_probed_add(connector, newmode); 1570280183Sdumbbell modes++; 1571280183Sdumbbell } 1572280183Sdumbbell } 1573280183Sdumbbell } 1574280183Sdumbbell 1575280183Sdumbbell return modes; 1576280183Sdumbbell} 1577280183Sdumbbell 1578280183Sdumbbellstatic int 1579280183Sdumbbellcea_db_payload_len(const u8 *db) 1580280183Sdumbbell{ 1581280183Sdumbbell return db[0] & 0x1f; 1582280183Sdumbbell} 1583280183Sdumbbell 1584280183Sdumbbellstatic int 1585280183Sdumbbellcea_db_tag(const u8 *db) 1586280183Sdumbbell{ 1587280183Sdumbbell return db[0] >> 5; 1588280183Sdumbbell} 1589280183Sdumbbell 1590280183Sdumbbellstatic int 1591280183Sdumbbellcea_revision(const u8 *cea) 1592280183Sdumbbell{ 1593280183Sdumbbell return cea[1]; 1594280183Sdumbbell} 1595280183Sdumbbell 1596280183Sdumbbellstatic int 1597280183Sdumbbellcea_db_offsets(const u8 *cea, int *start, int *end) 1598280183Sdumbbell{ 1599280183Sdumbbell /* Data block offset in CEA extension block */ 1600280183Sdumbbell *start = 4; 1601280183Sdumbbell *end = cea[2]; 1602280183Sdumbbell if (*end == 0) 1603280183Sdumbbell *end = 127; 1604280183Sdumbbell if (*end < 4 || *end > 127) 1605280183Sdumbbell return -ERANGE; 1606280183Sdumbbell return 0; 1607280183Sdumbbell} 1608280183Sdumbbell 1609280183Sdumbbell#define for_each_cea_db(cea, i, start, end) \ 1610280183Sdumbbell for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) 1611280183Sdumbbell 1612280183Sdumbbellstatic int 1613280183Sdumbbelladd_cea_modes(struct drm_connector *connector, struct edid *edid) 1614280183Sdumbbell{ 1615280183Sdumbbell u8 * cea = drm_find_cea_extension(edid); 1616280183Sdumbbell u8 * db, dbl; 1617280183Sdumbbell int modes = 0; 1618280183Sdumbbell 1619280183Sdumbbell if (cea && cea_revision(cea) >= 3) { 1620280183Sdumbbell int i, start, end; 1621280183Sdumbbell 1622280183Sdumbbell if (cea_db_offsets(cea, &start, &end)) 1623280183Sdumbbell return 0; 1624280183Sdumbbell 1625280183Sdumbbell for_each_cea_db(cea, i, start, end) { 1626280183Sdumbbell db = &cea[i]; 1627280183Sdumbbell dbl = cea_db_payload_len(db); 1628280183Sdumbbell 1629280183Sdumbbell if (cea_db_tag(db) == VIDEO_BLOCK) 1630280183Sdumbbell modes += do_cea_modes (connector, db+1, dbl); 1631280183Sdumbbell } 1632280183Sdumbbell } 1633280183Sdumbbell 1634280183Sdumbbell return modes; 1635280183Sdumbbell} 1636280183Sdumbbell 1637235783Skibstatic void 1638280183Sdumbbellparse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) 1639235783Skib{ 1640280183Sdumbbell u8 len = cea_db_payload_len(db); 1641235783Skib 1642280183Sdumbbell if (len >= 6) { 1643280183Sdumbbell connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ 1644280183Sdumbbell connector->dvi_dual = db[6] & 1; 1645280183Sdumbbell } 1646280183Sdumbbell if (len >= 7) 1647280183Sdumbbell connector->max_tmds_clock = db[7] * 5; 1648280183Sdumbbell if (len >= 8) { 1649280183Sdumbbell connector->latency_present[0] = db[8] >> 7; 1650280183Sdumbbell connector->latency_present[1] = (db[8] >> 6) & 1; 1651280183Sdumbbell } 1652280183Sdumbbell if (len >= 9) 1653280183Sdumbbell connector->video_latency[0] = db[9]; 1654280183Sdumbbell if (len >= 10) 1655280183Sdumbbell connector->audio_latency[0] = db[10]; 1656280183Sdumbbell if (len >= 11) 1657280183Sdumbbell connector->video_latency[1] = db[11]; 1658280183Sdumbbell if (len >= 12) 1659280183Sdumbbell connector->audio_latency[1] = db[12]; 1660235783Skib 1661235783Skib DRM_DEBUG_KMS("HDMI: DVI dual %d, " 1662235783Skib "max TMDS clock %d, " 1663235783Skib "latency present %d %d, " 1664235783Skib "video latency %d %d, " 1665235783Skib "audio latency %d %d\n", 1666235783Skib connector->dvi_dual, 1667235783Skib connector->max_tmds_clock, 1668235783Skib (int) connector->latency_present[0], 1669235783Skib (int) connector->latency_present[1], 1670235783Skib connector->video_latency[0], 1671235783Skib connector->video_latency[1], 1672235783Skib connector->audio_latency[0], 1673235783Skib connector->audio_latency[1]); 1674235783Skib} 1675235783Skib 1676235783Skibstatic void 1677235783Skibmonitor_name(struct detailed_timing *t, void *data) 1678235783Skib{ 1679235783Skib if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME) 1680235783Skib *(u8 **)data = t->data.other_data.data.str.str; 1681235783Skib} 1682235783Skib 1683280183Sdumbbellstatic bool cea_db_is_hdmi_vsdb(const u8 *db) 1684280183Sdumbbell{ 1685280183Sdumbbell int hdmi_id; 1686280183Sdumbbell 1687280183Sdumbbell if (cea_db_tag(db) != VENDOR_BLOCK) 1688280183Sdumbbell return false; 1689280183Sdumbbell 1690280183Sdumbbell if (cea_db_payload_len(db) < 5) 1691280183Sdumbbell return false; 1692280183Sdumbbell 1693280183Sdumbbell hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16); 1694280183Sdumbbell 1695280183Sdumbbell return hdmi_id == HDMI_IDENTIFIER; 1696280183Sdumbbell} 1697280183Sdumbbell 1698235783Skib/** 1699235783Skib * drm_edid_to_eld - build ELD from EDID 1700235783Skib * @connector: connector corresponding to the HDMI/DP sink 1701235783Skib * @edid: EDID to parse 1702235783Skib * 1703235783Skib * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. 1704235783Skib * Some ELD fields are left to the graphics driver caller: 1705235783Skib * - Conn_Type 1706235783Skib * - HDCP 1707235783Skib * - Port_ID 1708235783Skib */ 1709235783Skibvoid drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) 1710235783Skib{ 1711235783Skib uint8_t *eld = connector->eld; 1712235783Skib u8 *cea; 1713235783Skib u8 *name; 1714235783Skib u8 *db; 1715235783Skib int sad_count = 0; 1716235783Skib int mnl; 1717235783Skib int dbl; 1718235783Skib 1719235783Skib memset(eld, 0, sizeof(connector->eld)); 1720235783Skib 1721235783Skib cea = drm_find_cea_extension(edid); 1722235783Skib if (!cea) { 1723235783Skib DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); 1724235783Skib return; 1725235783Skib } 1726235783Skib 1727235783Skib name = NULL; 1728235783Skib drm_for_each_detailed_block((u8 *)edid, monitor_name, &name); 1729235783Skib for (mnl = 0; name && mnl < 13; mnl++) { 1730235783Skib if (name[mnl] == 0x0a) 1731235783Skib break; 1732235783Skib eld[20 + mnl] = name[mnl]; 1733235783Skib } 1734235783Skib eld[4] = (cea[1] << 5) | mnl; 1735235783Skib DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20); 1736235783Skib 1737235783Skib eld[0] = 2 << 3; /* ELD version: 2 */ 1738235783Skib 1739235783Skib eld[16] = edid->mfg_id[0]; 1740235783Skib eld[17] = edid->mfg_id[1]; 1741235783Skib eld[18] = edid->prod_code[0]; 1742235783Skib eld[19] = edid->prod_code[1]; 1743235783Skib 1744280183Sdumbbell if (cea_revision(cea) >= 3) { 1745280183Sdumbbell int i, start, end; 1746235783Skib 1747280183Sdumbbell if (cea_db_offsets(cea, &start, &end)) { 1748280183Sdumbbell start = 0; 1749280183Sdumbbell end = 0; 1750235783Skib } 1751280183Sdumbbell 1752280183Sdumbbell for_each_cea_db(cea, i, start, end) { 1753280183Sdumbbell db = &cea[i]; 1754280183Sdumbbell dbl = cea_db_payload_len(db); 1755280183Sdumbbell 1756280183Sdumbbell switch (cea_db_tag(db)) { 1757280183Sdumbbell case AUDIO_BLOCK: 1758280183Sdumbbell /* Audio Data Block, contains SADs */ 1759280183Sdumbbell sad_count = dbl / 3; 1760280183Sdumbbell if (dbl >= 1) 1761280183Sdumbbell memcpy(eld + 20 + mnl, &db[1], dbl); 1762280183Sdumbbell break; 1763280183Sdumbbell case SPEAKER_BLOCK: 1764280183Sdumbbell /* Speaker Allocation Data Block */ 1765280183Sdumbbell if (dbl >= 1) 1766280183Sdumbbell eld[7] = db[1]; 1767280183Sdumbbell break; 1768280183Sdumbbell case VENDOR_BLOCK: 1769280183Sdumbbell /* HDMI Vendor-Specific Data Block */ 1770280183Sdumbbell if (cea_db_is_hdmi_vsdb(db)) 1771280183Sdumbbell parse_hdmi_vsdb(connector, db); 1772280183Sdumbbell break; 1773280183Sdumbbell default: 1774280183Sdumbbell break; 1775280183Sdumbbell } 1776280183Sdumbbell } 1777235783Skib } 1778235783Skib eld[5] |= sad_count << 4; 1779235783Skib eld[2] = (20 + mnl + sad_count * 3 + 3) / 4; 1780235783Skib 1781235783Skib DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", (int)eld[2], sad_count); 1782235783Skib} 1783280183SdumbbellEXPORT_SYMBOL(drm_edid_to_eld); 1784235783Skib 1785235783Skib/** 1786235783Skib * drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond 1787235783Skib * @connector: connector associated with the HDMI/DP sink 1788235783Skib * @mode: the display mode 1789235783Skib */ 1790235783Skibint drm_av_sync_delay(struct drm_connector *connector, 1791235783Skib struct drm_display_mode *mode) 1792235783Skib{ 1793235783Skib int i = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); 1794235783Skib int a, v; 1795235783Skib 1796235783Skib if (!connector->latency_present[0]) 1797235783Skib return 0; 1798235783Skib if (!connector->latency_present[1]) 1799235783Skib i = 0; 1800235783Skib 1801235783Skib a = connector->audio_latency[i]; 1802235783Skib v = connector->video_latency[i]; 1803235783Skib 1804235783Skib /* 1805235783Skib * HDMI/DP sink doesn't support audio or video? 1806235783Skib */ 1807235783Skib if (a == 255 || v == 255) 1808235783Skib return 0; 1809235783Skib 1810235783Skib /* 1811235783Skib * Convert raw EDID values to millisecond. 1812235783Skib * Treat unknown latency as 0ms. 1813235783Skib */ 1814235783Skib if (a) 1815235783Skib a = min(2 * (a - 1), 500); 1816235783Skib if (v) 1817235783Skib v = min(2 * (v - 1), 500); 1818235783Skib 1819235783Skib return max(v - a, 0); 1820235783Skib} 1821280183SdumbbellEXPORT_SYMBOL(drm_av_sync_delay); 1822235783Skib 1823235783Skib/** 1824235783Skib * drm_select_eld - select one ELD from multiple HDMI/DP sinks 1825235783Skib * @encoder: the encoder just changed display mode 1826235783Skib * @mode: the adjusted display mode 1827235783Skib * 1828235783Skib * It's possible for one encoder to be associated with multiple HDMI/DP sinks. 1829235783Skib * The policy is now hard coded to simply use the first HDMI/DP sink's ELD. 1830235783Skib */ 1831235783Skibstruct drm_connector *drm_select_eld(struct drm_encoder *encoder, 1832235783Skib struct drm_display_mode *mode) 1833235783Skib{ 1834235783Skib struct drm_connector *connector; 1835235783Skib struct drm_device *dev = encoder->dev; 1836235783Skib 1837235783Skib list_for_each_entry(connector, &dev->mode_config.connector_list, head) 1838235783Skib if (connector->encoder == encoder && connector->eld[0]) 1839235783Skib return connector; 1840235783Skib 1841235783Skib return NULL; 1842235783Skib} 1843280183SdumbbellEXPORT_SYMBOL(drm_select_eld); 1844235783Skib 1845235783Skib/** 1846235783Skib * drm_detect_hdmi_monitor - detect whether monitor is hdmi. 1847235783Skib * @edid: monitor EDID information 1848235783Skib * 1849235783Skib * Parse the CEA extension according to CEA-861-B. 1850235783Skib * Return true if HDMI, false if not or unknown. 1851235783Skib */ 1852235783Skibbool drm_detect_hdmi_monitor(struct edid *edid) 1853235783Skib{ 1854235783Skib u8 *edid_ext; 1855280183Sdumbbell int i; 1856235783Skib int start_offset, end_offset; 1857235783Skib 1858235783Skib edid_ext = drm_find_cea_extension(edid); 1859235783Skib if (!edid_ext) 1860280183Sdumbbell return false; 1861235783Skib 1862280183Sdumbbell if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) 1863280183Sdumbbell return false; 1864235783Skib 1865235783Skib /* 1866235783Skib * Because HDMI identifier is in Vendor Specific Block, 1867235783Skib * search it from all data blocks of CEA extension. 1868235783Skib */ 1869280183Sdumbbell for_each_cea_db(edid_ext, i, start_offset, end_offset) { 1870280183Sdumbbell if (cea_db_is_hdmi_vsdb(&edid_ext[i])) 1871280183Sdumbbell return true; 1872235783Skib } 1873235783Skib 1874280183Sdumbbell return false; 1875235783Skib} 1876280183SdumbbellEXPORT_SYMBOL(drm_detect_hdmi_monitor); 1877235783Skib 1878235783Skib/** 1879235783Skib * drm_detect_monitor_audio - check monitor audio capability 1880235783Skib * 1881235783Skib * Monitor should have CEA extension block. 1882235783Skib * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic 1883235783Skib * audio' only. If there is any audio extension block and supported 1884235783Skib * audio format, assume at least 'basic audio' support, even if 'basic 1885235783Skib * audio' is not defined in EDID. 1886235783Skib * 1887235783Skib */ 1888235783Skibbool drm_detect_monitor_audio(struct edid *edid) 1889235783Skib{ 1890235783Skib u8 *edid_ext; 1891235783Skib int i, j; 1892235783Skib bool has_audio = false; 1893235783Skib int start_offset, end_offset; 1894235783Skib 1895235783Skib edid_ext = drm_find_cea_extension(edid); 1896235783Skib if (!edid_ext) 1897235783Skib goto end; 1898235783Skib 1899235783Skib has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0); 1900235783Skib 1901235783Skib if (has_audio) { 1902235783Skib DRM_DEBUG_KMS("Monitor has basic audio support\n"); 1903235783Skib goto end; 1904235783Skib } 1905235783Skib 1906280183Sdumbbell if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) 1907280183Sdumbbell goto end; 1908235783Skib 1909280183Sdumbbell for_each_cea_db(edid_ext, i, start_offset, end_offset) { 1910280183Sdumbbell if (cea_db_tag(&edid_ext[i]) == AUDIO_BLOCK) { 1911235783Skib has_audio = true; 1912280183Sdumbbell for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3) 1913235783Skib DRM_DEBUG_KMS("CEA audio format %d\n", 1914235783Skib (edid_ext[i + j] >> 3) & 0xf); 1915235783Skib goto end; 1916235783Skib } 1917235783Skib } 1918235783Skibend: 1919235783Skib return has_audio; 1920235783Skib} 1921280183SdumbbellEXPORT_SYMBOL(drm_detect_monitor_audio); 1922235783Skib 1923235783Skib/** 1924235783Skib * drm_add_display_info - pull display info out if present 1925235783Skib * @edid: EDID data 1926235783Skib * @info: display info (attached to connector) 1927235783Skib * 1928235783Skib * Grab any available display info and stuff it into the drm_display_info 1929235783Skib * structure that's part of the connector. Useful for tracking bpp and 1930235783Skib * color spaces. 1931235783Skib */ 1932235783Skibstatic void drm_add_display_info(struct edid *edid, 1933235783Skib struct drm_display_info *info) 1934235783Skib{ 1935235783Skib u8 *edid_ext; 1936235783Skib 1937235783Skib info->width_mm = edid->width_cm * 10; 1938235783Skib info->height_mm = edid->height_cm * 10; 1939235783Skib 1940235783Skib /* driver figures it out in this case */ 1941235783Skib info->bpc = 0; 1942235783Skib info->color_formats = 0; 1943235783Skib 1944277487Skib if (edid->revision < 3) 1945235783Skib return; 1946235783Skib 1947235783Skib if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) 1948235783Skib return; 1949235783Skib 1950277487Skib /* Get data from CEA blocks if present */ 1951277487Skib edid_ext = drm_find_cea_extension(edid); 1952277487Skib if (edid_ext) { 1953277487Skib info->cea_rev = edid_ext[1]; 1954277487Skib 1955277487Skib /* The existence of a CEA block should imply RGB support */ 1956277487Skib info->color_formats = DRM_COLOR_FORMAT_RGB444; 1957277487Skib if (edid_ext[3] & EDID_CEA_YCRCB444) 1958277487Skib info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; 1959277487Skib if (edid_ext[3] & EDID_CEA_YCRCB422) 1960277487Skib info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; 1961277487Skib } 1962277487Skib 1963277487Skib /* Only defined for 1.4 with digital displays */ 1964277487Skib if (edid->revision < 4) 1965277487Skib return; 1966277487Skib 1967235783Skib switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { 1968235783Skib case DRM_EDID_DIGITAL_DEPTH_6: 1969235783Skib info->bpc = 6; 1970235783Skib break; 1971235783Skib case DRM_EDID_DIGITAL_DEPTH_8: 1972235783Skib info->bpc = 8; 1973235783Skib break; 1974235783Skib case DRM_EDID_DIGITAL_DEPTH_10: 1975235783Skib info->bpc = 10; 1976235783Skib break; 1977235783Skib case DRM_EDID_DIGITAL_DEPTH_12: 1978235783Skib info->bpc = 12; 1979235783Skib break; 1980235783Skib case DRM_EDID_DIGITAL_DEPTH_14: 1981235783Skib info->bpc = 14; 1982235783Skib break; 1983235783Skib case DRM_EDID_DIGITAL_DEPTH_16: 1984235783Skib info->bpc = 16; 1985235783Skib break; 1986235783Skib case DRM_EDID_DIGITAL_DEPTH_UNDEF: 1987235783Skib default: 1988235783Skib info->bpc = 0; 1989235783Skib break; 1990235783Skib } 1991235783Skib 1992277487Skib info->color_formats |= DRM_COLOR_FORMAT_RGB444; 1993277487Skib if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) 1994277487Skib info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; 1995277487Skib if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) 1996277487Skib info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; 1997235783Skib} 1998235783Skib 1999235783Skib/** 2000235783Skib * drm_add_edid_modes - add modes from EDID data, if available 2001235783Skib * @connector: connector we're probing 2002235783Skib * @edid: edid data 2003235783Skib * 2004235783Skib * Add the specified modes to the connector's mode list. 2005235783Skib * 2006235783Skib * Return number of modes added or 0 if we couldn't find any. 2007235783Skib */ 2008235783Skibint drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) 2009235783Skib{ 2010235783Skib int num_modes = 0; 2011235783Skib u32 quirks; 2012235783Skib 2013235783Skib if (edid == NULL) { 2014235783Skib return 0; 2015235783Skib } 2016235783Skib if (!drm_edid_is_valid(edid)) { 2017280183Sdumbbell dev_warn(connector->dev->dev, "%s: EDID invalid.\n", 2018235783Skib drm_get_connector_name(connector)); 2019235783Skib return 0; 2020235783Skib } 2021235783Skib 2022235783Skib quirks = edid_get_quirks(edid); 2023235783Skib 2024235783Skib /* 2025235783Skib * EDID spec says modes should be preferred in this order: 2026235783Skib * - preferred detailed mode 2027235783Skib * - other detailed modes from base block 2028235783Skib * - detailed modes from extension blocks 2029235783Skib * - CVT 3-byte code modes 2030235783Skib * - standard timing codes 2031235783Skib * - established timing codes 2032235783Skib * - modes inferred from GTF or CVT range information 2033235783Skib * 2034235783Skib * We get this pretty much right. 2035235783Skib * 2036235783Skib * XXX order for additional mode types in extension blocks? 2037235783Skib */ 2038235783Skib num_modes += add_detailed_modes(connector, edid, quirks); 2039235783Skib num_modes += add_cvt_modes(connector, edid); 2040235783Skib num_modes += add_standard_modes(connector, edid); 2041235783Skib num_modes += add_established_modes(connector, edid); 2042280183Sdumbbell if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) 2043280183Sdumbbell num_modes += add_inferred_modes(connector, edid); 2044280183Sdumbbell num_modes += add_cea_modes(connector, edid); 2045235783Skib 2046235783Skib if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) 2047235783Skib edid_fixup_preferred(connector, quirks); 2048235783Skib 2049235783Skib drm_add_display_info(edid, &connector->display_info); 2050235783Skib 2051235783Skib return num_modes; 2052235783Skib} 2053280183SdumbbellEXPORT_SYMBOL(drm_add_edid_modes); 2054235783Skib 2055235783Skib/** 2056235783Skib * drm_add_modes_noedid - add modes for the connectors without EDID 2057235783Skib * @connector: connector we're probing 2058235783Skib * @hdisplay: the horizontal display limit 2059235783Skib * @vdisplay: the vertical display limit 2060235783Skib * 2061235783Skib * Add the specified modes to the connector's mode list. Only when the 2062235783Skib * hdisplay/vdisplay is not beyond the given limit, it will be added. 2063235783Skib * 2064235783Skib * Return number of modes added or 0 if we couldn't find any. 2065235783Skib */ 2066235783Skibint drm_add_modes_noedid(struct drm_connector *connector, 2067235783Skib int hdisplay, int vdisplay) 2068235783Skib{ 2069235783Skib int i, count, num_modes = 0; 2070235783Skib struct drm_display_mode *mode; 2071235783Skib struct drm_device *dev = connector->dev; 2072235783Skib 2073235783Skib count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); 2074235783Skib if (hdisplay < 0) 2075235783Skib hdisplay = 0; 2076235783Skib if (vdisplay < 0) 2077235783Skib vdisplay = 0; 2078235783Skib 2079235783Skib for (i = 0; i < count; i++) { 2080280183Sdumbbell const struct drm_display_mode *ptr = &drm_dmt_modes[i]; 2081235783Skib if (hdisplay && vdisplay) { 2082235783Skib /* 2083235783Skib * Only when two are valid, they will be used to check 2084235783Skib * whether the mode should be added to the mode list of 2085235783Skib * the connector. 2086235783Skib */ 2087235783Skib if (ptr->hdisplay > hdisplay || 2088235783Skib ptr->vdisplay > vdisplay) 2089235783Skib continue; 2090235783Skib } 2091235783Skib if (drm_mode_vrefresh(ptr) > 61) 2092235783Skib continue; 2093235783Skib mode = drm_mode_duplicate(dev, ptr); 2094235783Skib if (mode) { 2095235783Skib drm_mode_probed_add(connector, mode); 2096235783Skib num_modes++; 2097235783Skib } 2098235783Skib } 2099235783Skib return num_modes; 2100235783Skib} 2101280183SdumbbellEXPORT_SYMBOL(drm_add_modes_noedid); 2102280183Sdumbbell 2103280183Sdumbbell/** 2104280183Sdumbbell * drm_mode_cea_vic - return the CEA-861 VIC of a given mode 2105280183Sdumbbell * @mode: mode 2106280183Sdumbbell * 2107280183Sdumbbell * RETURNS: 2108280183Sdumbbell * The VIC number, 0 in case it's not a CEA-861 mode. 2109280183Sdumbbell */ 2110280183Sdumbbelluint8_t drm_mode_cea_vic(const struct drm_display_mode *mode) 2111280183Sdumbbell{ 2112280183Sdumbbell uint8_t i; 2113280183Sdumbbell 2114280183Sdumbbell for (i = 0; i < drm_num_cea_modes; i++) 2115280183Sdumbbell if (drm_mode_equal(mode, &edid_cea_modes[i])) 2116280183Sdumbbell return i + 1; 2117280183Sdumbbell 2118280183Sdumbbell return 0; 2119280183Sdumbbell} 2120280183SdumbbellEXPORT_SYMBOL(drm_mode_cea_vic); 2121