diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2010-02-05 04:21:19 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-02-08 18:31:20 -0500 |
commit | 3c537889e17232e9073f75ae8710ea0f008c5a29 (patch) | |
tree | 9d3c25825b466b8ddc3fdc8224d4484c99173b08 /drivers | |
parent | 2739d49cd7f1f44876cad614b072da698967b370 (diff) |
drm/radeon/kms: add support for hardcoded edids in rom (v2)
Some servers hardcode an edid in rom so that they will
work properly with KVMs. This is a port of the relevant
code from the ddx.
[airlied: reworked to validate edid at boot stage - and
remove special quirk, if there is a valid EDID in the BIOS rom
we'll just try and use it.]
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_combios.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 6 |
4 files changed, 66 insertions, 17 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f665b05592f3..f41e91ceaea6 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -60,8 +60,7 @@ | |||
60 | #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) | 60 | #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) |
61 | /* use +hsync +vsync for detailed mode */ | 61 | /* use +hsync +vsync for detailed mode */ |
62 | #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) | 62 | #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) |
63 | /* define the number of Extension EDID block */ | 63 | |
64 | #define MAX_EDID_EXT_NUM 4 | ||
65 | 64 | ||
66 | #define LEVEL_DMT 0 | 65 | #define LEVEL_DMT 0 |
67 | #define LEVEL_GTF 1 | 66 | #define LEVEL_GTF 1 |
@@ -114,14 +113,14 @@ static const u8 edid_header[] = { | |||
114 | }; | 113 | }; |
115 | 114 | ||
116 | /** | 115 | /** |
117 | * edid_is_valid - sanity check EDID data | 116 | * drm_edid_is_valid - sanity check EDID data |
118 | * @edid: EDID data | 117 | * @edid: EDID data |
119 | * | 118 | * |
120 | * Sanity check the EDID block by looking at the header, the version number | 119 | * Sanity check the EDID block by looking at the header, the version number |
121 | * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's | 120 | * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's |
122 | * valid. | 121 | * valid. |
123 | */ | 122 | */ |
124 | static bool edid_is_valid(struct edid *edid) | 123 | bool drm_edid_is_valid(struct edid *edid) |
125 | { | 124 | { |
126 | int i, score = 0; | 125 | int i, score = 0; |
127 | u8 csum = 0; | 126 | u8 csum = 0; |
@@ -163,6 +162,7 @@ bad: | |||
163 | } | 162 | } |
164 | return 0; | 163 | return 0; |
165 | } | 164 | } |
165 | EXPORT_SYMBOL(drm_edid_is_valid); | ||
166 | 166 | ||
167 | /** | 167 | /** |
168 | * edid_vendor - match a string against EDID's obfuscated vendor field | 168 | * edid_vendor - match a string against EDID's obfuscated vendor field |
@@ -1069,8 +1069,8 @@ static int add_detailed_info_eedid(struct drm_connector *connector, | |||
1069 | } | 1069 | } |
1070 | 1070 | ||
1071 | /* Chose real EDID extension number */ | 1071 | /* Chose real EDID extension number */ |
1072 | edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ? | 1072 | edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ? |
1073 | MAX_EDID_EXT_NUM : edid->extensions; | 1073 | DRM_MAX_EDID_EXT_NUM : edid->extensions; |
1074 | 1074 | ||
1075 | /* Find CEA extension */ | 1075 | /* Find CEA extension */ |
1076 | for (i = 0; i < edid_ext_num; i++) { | 1076 | for (i = 0; i < edid_ext_num; i++) { |
@@ -1152,7 +1152,7 @@ static int drm_ddc_read_edid(struct drm_connector *connector, | |||
1152 | for (i = 0; i < 4; i++) { | 1152 | for (i = 0; i < 4; i++) { |
1153 | if (drm_do_probe_ddc_edid(adapter, buf, len)) | 1153 | if (drm_do_probe_ddc_edid(adapter, buf, len)) |
1154 | return -1; | 1154 | return -1; |
1155 | if (edid_is_valid((struct edid *)buf)) | 1155 | if (drm_edid_is_valid((struct edid *)buf)) |
1156 | return 0; | 1156 | return 0; |
1157 | } | 1157 | } |
1158 | 1158 | ||
@@ -1177,7 +1177,7 @@ struct edid *drm_get_edid(struct drm_connector *connector, | |||
1177 | int ret; | 1177 | int ret; |
1178 | struct edid *edid; | 1178 | struct edid *edid; |
1179 | 1179 | ||
1180 | edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1), | 1180 | edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1), |
1181 | GFP_KERNEL); | 1181 | GFP_KERNEL); |
1182 | if (edid == NULL) { | 1182 | if (edid == NULL) { |
1183 | dev_warn(&connector->dev->pdev->dev, | 1183 | dev_warn(&connector->dev->pdev->dev, |
@@ -1195,14 +1195,14 @@ struct edid *drm_get_edid(struct drm_connector *connector, | |||
1195 | if (edid->extensions != 0) { | 1195 | if (edid->extensions != 0) { |
1196 | int edid_ext_num = edid->extensions; | 1196 | int edid_ext_num = edid->extensions; |
1197 | 1197 | ||
1198 | if (edid_ext_num > MAX_EDID_EXT_NUM) { | 1198 | if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) { |
1199 | dev_warn(&connector->dev->pdev->dev, | 1199 | dev_warn(&connector->dev->pdev->dev, |
1200 | "The number of extension(%d) is " | 1200 | "The number of extension(%d) is " |
1201 | "over max (%d), actually read number (%d)\n", | 1201 | "over max (%d), actually read number (%d)\n", |
1202 | edid_ext_num, MAX_EDID_EXT_NUM, | 1202 | edid_ext_num, DRM_MAX_EDID_EXT_NUM, |
1203 | MAX_EDID_EXT_NUM); | 1203 | DRM_MAX_EDID_EXT_NUM); |
1204 | /* Reset EDID extension number to be read */ | 1204 | /* Reset EDID extension number to be read */ |
1205 | edid_ext_num = MAX_EDID_EXT_NUM; | 1205 | edid_ext_num = DRM_MAX_EDID_EXT_NUM; |
1206 | } | 1206 | } |
1207 | /* Read EDID including extensions too */ | 1207 | /* Read EDID including extensions too */ |
1208 | ret = drm_ddc_read_edid(connector, adapter, (char *)edid, | 1208 | ret = drm_ddc_read_edid(connector, adapter, (char *)edid, |
@@ -1245,8 +1245,8 @@ bool drm_detect_hdmi_monitor(struct edid *edid) | |||
1245 | goto end; | 1245 | goto end; |
1246 | 1246 | ||
1247 | /* Chose real EDID extension number */ | 1247 | /* Chose real EDID extension number */ |
1248 | edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ? | 1248 | edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ? |
1249 | MAX_EDID_EXT_NUM : edid->extensions; | 1249 | DRM_MAX_EDID_EXT_NUM : edid->extensions; |
1250 | 1250 | ||
1251 | /* Find CEA extension */ | 1251 | /* Find CEA extension */ |
1252 | for (i = 0; i < edid_ext_num; i++) { | 1252 | for (i = 0; i < edid_ext_num; i++) { |
@@ -1303,7 +1303,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
1303 | if (edid == NULL) { | 1303 | if (edid == NULL) { |
1304 | return 0; | 1304 | return 0; |
1305 | } | 1305 | } |
1306 | if (!edid_is_valid(edid)) { | 1306 | if (!drm_edid_is_valid(edid)) { |
1307 | dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", | 1307 | dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", |
1308 | drm_get_connector_name(connector)); | 1308 | drm_get_connector_name(connector)); |
1309 | return 0; | 1309 | return 0; |
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index e208d730f514..257ce1774e40 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c | |||
@@ -443,6 +443,39 @@ static uint16_t combios_get_table_offset(struct drm_device *dev, | |||
443 | 443 | ||
444 | } | 444 | } |
445 | 445 | ||
446 | bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) | ||
447 | { | ||
448 | int edid_info; | ||
449 | struct edid *edid; | ||
450 | edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE); | ||
451 | if (!edid_info) | ||
452 | return false; | ||
453 | |||
454 | edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1), | ||
455 | GFP_KERNEL); | ||
456 | if (edid == NULL) | ||
457 | return false; | ||
458 | |||
459 | memcpy((unsigned char *)edid, | ||
460 | (unsigned char *)(rdev->bios + edid_info), EDID_LENGTH); | ||
461 | |||
462 | if (!drm_edid_is_valid(edid)) { | ||
463 | kfree(edid); | ||
464 | return false; | ||
465 | } | ||
466 | |||
467 | rdev->mode_info.bios_hardcoded_edid = edid; | ||
468 | return true; | ||
469 | } | ||
470 | |||
471 | struct edid * | ||
472 | radeon_combios_get_hardcoded_edid(struct radeon_device *rdev) | ||
473 | { | ||
474 | if (rdev->mode_info.bios_hardcoded_edid) | ||
475 | return rdev->mode_info.bios_hardcoded_edid; | ||
476 | return NULL; | ||
477 | } | ||
478 | |||
446 | static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev, | 479 | static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev, |
447 | int ddc_line) | 480 | int ddc_line) |
448 | { | 481 | { |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index ec3166bfaa49..79634da7c311 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -352,6 +352,8 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) | |||
352 | 352 | ||
353 | int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) | 353 | int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) |
354 | { | 354 | { |
355 | struct drm_device *dev = radeon_connector->base.dev; | ||
356 | struct radeon_device *rdev = dev->dev_private; | ||
355 | int ret = 0; | 357 | int ret = 0; |
356 | 358 | ||
357 | if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || | 359 | if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || |
@@ -366,7 +368,9 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) | |||
366 | if (!radeon_connector->edid) { | 368 | if (!radeon_connector->edid) { |
367 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); | 369 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
368 | } | 370 | } |
369 | 371 | /* some servers provide a hardcoded edid in rom for KVMs */ | |
372 | if (!radeon_connector->edid) | ||
373 | radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev); | ||
370 | if (radeon_connector->edid) { | 374 | if (radeon_connector->edid) { |
371 | drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); | 375 | drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); |
372 | ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); | 376 | ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); |
@@ -829,6 +833,12 @@ int radeon_modeset_init(struct radeon_device *rdev) | |||
829 | return ret; | 833 | return ret; |
830 | } | 834 | } |
831 | 835 | ||
836 | /* check combios for a valid hardcoded EDID - Sun servers */ | ||
837 | if (!rdev->is_atom_bios) { | ||
838 | /* check for hardcoded EDID in BIOS */ | ||
839 | radeon_combios_check_hardcoded_edid(rdev); | ||
840 | } | ||
841 | |||
832 | if (rdev->flags & RADEON_SINGLE_CRTC) | 842 | if (rdev->flags & RADEON_SINGLE_CRTC) |
833 | num_crtc = 1; | 843 | num_crtc = 1; |
834 | 844 | ||
@@ -850,6 +860,8 @@ int radeon_modeset_init(struct radeon_device *rdev) | |||
850 | 860 | ||
851 | void radeon_modeset_fini(struct radeon_device *rdev) | 861 | void radeon_modeset_fini(struct radeon_device *rdev) |
852 | { | 862 | { |
863 | kfree(rdev->mode_info.bios_hardcoded_edid); | ||
864 | |||
853 | if (rdev->mode_info.mode_config_initialized) { | 865 | if (rdev->mode_info.mode_config_initialized) { |
854 | radeon_hpd_fini(rdev); | 866 | radeon_hpd_fini(rdev); |
855 | drm_mode_config_cleanup(rdev->ddev); | 867 | drm_mode_config_cleanup(rdev->ddev); |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index b884bacf09ff..71439ba2feeb 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -207,7 +207,8 @@ struct radeon_mode_info { | |||
207 | struct drm_property *tv_std_property; | 207 | struct drm_property *tv_std_property; |
208 | /* legacy TMDS PLL detect */ | 208 | /* legacy TMDS PLL detect */ |
209 | struct drm_property *tmds_pll_property; | 209 | struct drm_property *tmds_pll_property; |
210 | 210 | /* hardcoded DFP edid from BIOS */ | |
211 | struct edid *bios_hardcoded_edid; | ||
211 | }; | 212 | }; |
212 | 213 | ||
213 | #define MAX_H_CODE_TIMING_LEN 32 | 214 | #define MAX_H_CODE_TIMING_LEN 32 |
@@ -479,6 +480,9 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, | |||
479 | extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, | 480 | extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, |
480 | int x, int y); | 481 | int x, int y); |
481 | 482 | ||
483 | extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); | ||
484 | extern struct edid * | ||
485 | radeon_combios_get_hardcoded_edid(struct radeon_device *rdev); | ||
482 | extern bool radeon_atom_get_clock_info(struct drm_device *dev); | 486 | extern bool radeon_atom_get_clock_info(struct drm_device *dev); |
483 | extern bool radeon_combios_get_clock_info(struct drm_device *dev); | 487 | extern bool radeon_combios_get_clock_info(struct drm_device *dev); |
484 | extern struct radeon_encoder_atom_dig * | 488 | extern struct radeon_encoder_atom_dig * |