73,10 → 73,6 |
#define EDID_QUIRK_FORCE_8BPC (1 << 8) |
/* Force 12bpc */ |
#define EDID_QUIRK_FORCE_12BPC (1 << 9) |
/* Force 6bpc */ |
#define EDID_QUIRK_FORCE_6BPC (1 << 10) |
/* Force 10bpc */ |
#define EDID_QUIRK_FORCE_10BPC (1 << 11) |
|
struct detailed_mode_closure { |
struct drm_connector *connector; |
103,9 → 99,6 |
/* Unknown Acer */ |
{ "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, |
|
/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ |
{ "AEO", 0, EDID_QUIRK_FORCE_6BPC }, |
|
/* Belinea 10 15 55 */ |
{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, |
{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, |
119,9 → 112,6 |
{ "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 | |
EDID_QUIRK_DETAILED_IN_CM }, |
|
/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */ |
{ "LGD", 764, EDID_QUIRK_FORCE_10BPC }, |
|
/* LG Philips LCD LP154W01-A5 */ |
{ "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, |
{ "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, |
149,9 → 139,6 |
|
/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */ |
{ "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC }, |
|
/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/ |
{ "ETR", 13896, EDID_QUIRK_FORCE_8BPC }, |
}; |
|
/* |
650,8 → 637,12 |
/* |
* Probably taken from CEA-861 spec. |
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c. |
* |
* Index using the VIC. |
*/ |
static const struct drm_display_mode edid_cea_modes[] = { |
/* 0 - dummy, VICs start at 1 */ |
{ }, |
/* 1 - 640x480@60Hz */ |
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, |
752, 800, 0, 480, 490, 492, 525, 0, |
1000,9 → 991,11 |
}; |
|
/* |
* HDMI 1.4 4k modes. |
* HDMI 1.4 4k modes. Index using the VIC. |
*/ |
static const struct drm_display_mode edid_4k_modes[] = { |
/* 0 - dummy, VICs start at 1 */ |
{ }, |
/* 1 - 3840x2160@30Hz */ |
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, |
3840, 4016, 4104, 4400, 0, |
2558,6 → 2551,33 |
return clock; |
} |
|
static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match, |
unsigned int clock_tolerance) |
{ |
u8 vic; |
|
if (!to_match->clock) |
return 0; |
|
for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { |
const struct drm_display_mode *cea_mode = &edid_cea_modes[vic]; |
unsigned int clock1, clock2; |
|
/* Check both 60Hz and 59.94Hz */ |
clock1 = cea_mode->clock; |
clock2 = cea_mode_alternate_clock(cea_mode); |
|
if (abs(to_match->clock - clock1) > clock_tolerance && |
abs(to_match->clock - clock2) > clock_tolerance) |
continue; |
|
if (drm_mode_equal_no_clocks(to_match, cea_mode)) |
return vic; |
} |
|
return 0; |
} |
|
/** |
* drm_match_cea_mode - look for a CEA mode matching given mode |
* @to_match: display mode |
2567,13 → 2587,13 |
*/ |
u8 drm_match_cea_mode(const struct drm_display_mode *to_match) |
{ |
u8 mode; |
u8 vic; |
|
if (!to_match->clock) |
return 0; |
|
for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { |
const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; |
for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { |
const struct drm_display_mode *cea_mode = &edid_cea_modes[vic]; |
unsigned int clock1, clock2; |
|
/* Check both 60Hz and 59.94Hz */ |
2583,12 → 2603,17 |
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || |
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && |
drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode)) |
return mode + 1; |
return vic; |
} |
return 0; |
} |
EXPORT_SYMBOL(drm_match_cea_mode); |
|
static bool drm_valid_cea_vic(u8 vic) |
{ |
return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes); |
} |
|
/** |
* drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to |
* the input VIC from the CEA mode list |
2598,10 → 2623,7 |
*/ |
enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) |
{ |
/* return picture aspect ratio for video_code - 1 to access the |
* right array element |
*/ |
return edid_cea_modes[video_code-1].picture_aspect_ratio; |
return edid_cea_modes[video_code].picture_aspect_ratio; |
} |
EXPORT_SYMBOL(drm_get_cea_aspect_ratio); |
|
2622,6 → 2644,33 |
return cea_mode_alternate_clock(hdmi_mode); |
} |
|
static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match, |
unsigned int clock_tolerance) |
{ |
u8 vic; |
|
if (!to_match->clock) |
return 0; |
|
for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) { |
const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic]; |
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; |
|
if (drm_mode_equal_no_clocks(to_match, hdmi_mode)) |
return vic; |
} |
|
return 0; |
} |
|
/* |
* drm_match_hdmi_mode - look for a HDMI mode matching given mode |
* @to_match: display mode |
2632,13 → 2681,13 |
*/ |
static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match) |
{ |
u8 mode; |
u8 vic; |
|
if (!to_match->clock) |
return 0; |
|
for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) { |
const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode]; |
for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) { |
const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic]; |
unsigned int clock1, clock2; |
|
/* Make sure to also match alternate clocks */ |
2648,11 → 2697,16 |
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || |
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && |
drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode)) |
return mode + 1; |
return vic; |
} |
return 0; |
} |
|
static bool drm_valid_hdmi_vic(u8 vic) |
{ |
return vic > 0 && vic < ARRAY_SIZE(edid_4k_modes); |
} |
|
static int |
add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) |
{ |
2672,16 → 2726,16 |
list_for_each_entry(mode, &connector->probed_modes, head) { |
const struct drm_display_mode *cea_mode = NULL; |
struct drm_display_mode *newmode; |
u8 mode_idx = drm_match_cea_mode(mode) - 1; |
u8 vic = drm_match_cea_mode(mode); |
unsigned int clock1, clock2; |
|
if (mode_idx < ARRAY_SIZE(edid_cea_modes)) { |
cea_mode = &edid_cea_modes[mode_idx]; |
if (drm_valid_cea_vic(vic)) { |
cea_mode = &edid_cea_modes[vic]; |
clock2 = cea_mode_alternate_clock(cea_mode); |
} else { |
mode_idx = drm_match_hdmi_mode(mode) - 1; |
if (mode_idx < ARRAY_SIZE(edid_4k_modes)) { |
cea_mode = &edid_4k_modes[mode_idx]; |
vic = drm_match_hdmi_mode(mode); |
if (drm_valid_hdmi_vic(vic)) { |
cea_mode = &edid_4k_modes[vic]; |
clock2 = hdmi_mode_alternate_clock(cea_mode); |
} |
} |
2732,17 → 2786,17 |
{ |
struct drm_device *dev = connector->dev; |
struct drm_display_mode *newmode; |
u8 cea_mode; |
u8 vic; |
|
if (video_db == NULL || video_index >= video_len) |
return NULL; |
|
/* CEA modes are numbered 1..127 */ |
cea_mode = (video_db[video_index] & 127) - 1; |
if (cea_mode >= ARRAY_SIZE(edid_cea_modes)) |
vic = (video_db[video_index] & 127); |
if (!drm_valid_cea_vic(vic)) |
return NULL; |
|
newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); |
newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); |
if (!newmode) |
return NULL; |
|
2837,8 → 2891,7 |
struct drm_device *dev = connector->dev; |
struct drm_display_mode *newmode; |
|
vic--; /* VICs start at 1 */ |
if (vic >= ARRAY_SIZE(edid_4k_modes)) { |
if (!drm_valid_hdmi_vic(vic)) { |
DRM_ERROR("Unknown HDMI VIC: %d\n", vic); |
return 0; |
} |
3129,20 → 3182,24 |
{ |
const struct drm_display_mode *cea_mode; |
int clock1, clock2, clock; |
u8 mode_idx; |
u8 vic; |
const char *type; |
|
mode_idx = drm_match_cea_mode(mode) - 1; |
if (mode_idx < ARRAY_SIZE(edid_cea_modes)) { |
/* |
* allow 5kHz clock difference either way to account for |
* the 10kHz clock resolution limit of detailed timings. |
*/ |
vic = drm_match_cea_mode_clock_tolerance(mode, 5); |
if (drm_valid_cea_vic(vic)) { |
type = "CEA"; |
cea_mode = &edid_cea_modes[mode_idx]; |
cea_mode = &edid_cea_modes[vic]; |
clock1 = cea_mode->clock; |
clock2 = cea_mode_alternate_clock(cea_mode); |
} else { |
mode_idx = drm_match_hdmi_mode(mode) - 1; |
if (mode_idx < ARRAY_SIZE(edid_4k_modes)) { |
vic = drm_match_hdmi_mode_clock_tolerance(mode, 5); |
if (drm_valid_hdmi_vic(vic)) { |
type = "HDMI"; |
cea_mode = &edid_4k_modes[mode_idx]; |
cea_mode = &edid_4k_modes[vic]; |
clock1 = cea_mode->clock; |
clock2 = hdmi_mode_alternate_clock(cea_mode); |
} else { |
3160,7 → 3217,7 |
return; |
|
DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n", |
type, mode_idx + 1, mode->clock, clock); |
type, vic, mode->clock, clock); |
mode->clock = clock; |
} |
|
3833,15 → 3890,9 |
|
drm_add_display_info(edid, &connector->display_info, connector); |
|
if (quirks & EDID_QUIRK_FORCE_6BPC) |
connector->display_info.bpc = 6; |
|
if (quirks & EDID_QUIRK_FORCE_8BPC) |
connector->display_info.bpc = 8; |
|
if (quirks & EDID_QUIRK_FORCE_10BPC) |
connector->display_info.bpc = 10; |
|
if (quirks & EDID_QUIRK_FORCE_12BPC) |
connector->display_info.bpc = 12; |
|