diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/gpu/drm/drm_edid.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 257 |
1 files changed, 208 insertions, 49 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96e963108225..09292193dafe 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/i2c.h> | 32 | #include <linux/i2c.h> |
33 | #include <linux/i2c-algo-bit.h> | ||
34 | #include "drmP.h" | 33 | #include "drmP.h" |
35 | #include "drm_edid.h" | 34 | #include "drm_edid.h" |
36 | #include "drm_edid_modes.h" | 35 | #include "drm_edid_modes.h" |
@@ -185,9 +184,9 @@ drm_edid_block_valid(u8 *raw_edid) | |||
185 | 184 | ||
186 | bad: | 185 | bad: |
187 | if (raw_edid) { | 186 | if (raw_edid) { |
188 | DRM_ERROR("Raw EDID:\n"); | 187 | printk(KERN_ERR "Raw EDID:\n"); |
189 | print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); | 188 | print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); |
190 | printk("\n"); | 189 | printk(KERN_ERR "\n"); |
191 | } | 190 | } |
192 | return 0; | 191 | return 0; |
193 | } | 192 | } |
@@ -231,30 +230,49 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, | |||
231 | int block, int len) | 230 | int block, int len) |
232 | { | 231 | { |
233 | unsigned char start = block * EDID_LENGTH; | 232 | unsigned char start = block * EDID_LENGTH; |
234 | struct i2c_msg msgs[] = { | 233 | int ret, retries = 5; |
235 | { | ||
236 | .addr = DDC_ADDR, | ||
237 | .flags = 0, | ||
238 | .len = 1, | ||
239 | .buf = &start, | ||
240 | }, { | ||
241 | .addr = DDC_ADDR, | ||
242 | .flags = I2C_M_RD, | ||
243 | .len = len, | ||
244 | .buf = buf + start, | ||
245 | } | ||
246 | }; | ||
247 | 234 | ||
248 | if (i2c_transfer(adapter, msgs, 2) == 2) | 235 | /* The core i2c driver will automatically retry the transfer if the |
249 | return 0; | 236 | * adapter reports EAGAIN. However, we find that bit-banging transfers |
237 | * are susceptible to errors under a heavily loaded machine and | ||
238 | * generate spurious NAKs and timeouts. Retrying the transfer | ||
239 | * of the individual block a few times seems to overcome this. | ||
240 | */ | ||
241 | do { | ||
242 | struct i2c_msg msgs[] = { | ||
243 | { | ||
244 | .addr = DDC_ADDR, | ||
245 | .flags = 0, | ||
246 | .len = 1, | ||
247 | .buf = &start, | ||
248 | }, { | ||
249 | .addr = DDC_ADDR, | ||
250 | .flags = I2C_M_RD, | ||
251 | .len = len, | ||
252 | .buf = buf, | ||
253 | } | ||
254 | }; | ||
255 | ret = i2c_transfer(adapter, msgs, 2); | ||
256 | } while (ret != 2 && --retries); | ||
257 | |||
258 | return ret == 2 ? 0 : -1; | ||
259 | } | ||
260 | |||
261 | static bool drm_edid_is_zero(u8 *in_edid, int length) | ||
262 | { | ||
263 | int i; | ||
264 | u32 *raw_edid = (u32 *)in_edid; | ||
250 | 265 | ||
251 | return -1; | 266 | for (i = 0; i < length / 4; i++) |
267 | if (*(raw_edid + i) != 0) | ||
268 | return false; | ||
269 | return true; | ||
252 | } | 270 | } |
253 | 271 | ||
254 | static u8 * | 272 | static u8 * |
255 | drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | 273 | drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) |
256 | { | 274 | { |
257 | int i, j = 0; | 275 | int i, j = 0, valid_extensions = 0; |
258 | u8 *block, *new; | 276 | u8 *block, *new; |
259 | 277 | ||
260 | if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) | 278 | if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) |
@@ -266,6 +284,10 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
266 | goto out; | 284 | goto out; |
267 | if (drm_edid_block_valid(block)) | 285 | if (drm_edid_block_valid(block)) |
268 | break; | 286 | break; |
287 | if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { | ||
288 | connector->null_edid_counter++; | ||
289 | goto carp; | ||
290 | } | ||
269 | } | 291 | } |
270 | if (i == 4) | 292 | if (i == 4) |
271 | goto carp; | 293 | goto carp; |
@@ -281,14 +303,28 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
281 | 303 | ||
282 | for (j = 1; j <= block[0x7e]; j++) { | 304 | for (j = 1; j <= block[0x7e]; j++) { |
283 | for (i = 0; i < 4; i++) { | 305 | for (i = 0; i < 4; i++) { |
284 | if (drm_do_probe_ddc_edid(adapter, block, j, | 306 | if (drm_do_probe_ddc_edid(adapter, |
285 | EDID_LENGTH)) | 307 | block + (valid_extensions + 1) * EDID_LENGTH, |
308 | j, EDID_LENGTH)) | ||
286 | goto out; | 309 | goto out; |
287 | if (drm_edid_block_valid(block + j * EDID_LENGTH)) | 310 | if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) { |
311 | valid_extensions++; | ||
288 | break; | 312 | break; |
313 | } | ||
289 | } | 314 | } |
290 | if (i == 4) | 315 | if (i == 4) |
291 | goto carp; | 316 | dev_warn(connector->dev->dev, |
317 | "%s: Ignoring invalid EDID block %d.\n", | ||
318 | drm_get_connector_name(connector), j); | ||
319 | } | ||
320 | |||
321 | if (valid_extensions != block[0x7e]) { | ||
322 | block[EDID_LENGTH-1] += block[0x7e] - valid_extensions; | ||
323 | block[0x7e] = valid_extensions; | ||
324 | new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); | ||
325 | if (!new) | ||
326 | goto out; | ||
327 | block = new; | ||
292 | } | 328 | } |
293 | 329 | ||
294 | return block; | 330 | return block; |
@@ -436,12 +472,11 @@ static void edid_fixup_preferred(struct drm_connector *connector, | |||
436 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, | 472 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, |
437 | int hsize, int vsize, int fresh) | 473 | int hsize, int vsize, int fresh) |
438 | { | 474 | { |
475 | struct drm_display_mode *mode = NULL; | ||
439 | int i; | 476 | int i; |
440 | struct drm_display_mode *ptr, *mode; | ||
441 | 477 | ||
442 | mode = NULL; | ||
443 | for (i = 0; i < drm_num_dmt_modes; i++) { | 478 | for (i = 0; i < drm_num_dmt_modes; i++) { |
444 | ptr = &drm_dmt_modes[i]; | 479 | const struct drm_display_mode *ptr = &drm_dmt_modes[i]; |
445 | if (hsize == ptr->hdisplay && | 480 | if (hsize == ptr->hdisplay && |
446 | vsize == ptr->vdisplay && | 481 | vsize == ptr->vdisplay && |
447 | fresh == drm_mode_vrefresh(ptr)) { | 482 | fresh == drm_mode_vrefresh(ptr)) { |
@@ -872,7 +907,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | |||
872 | } | 907 | } |
873 | 908 | ||
874 | static bool | 909 | static bool |
875 | mode_is_rb(struct drm_display_mode *mode) | 910 | mode_is_rb(const struct drm_display_mode *mode) |
876 | { | 911 | { |
877 | return (mode->htotal - mode->hdisplay == 160) && | 912 | return (mode->htotal - mode->hdisplay == 160) && |
878 | (mode->hsync_end - mode->hdisplay == 80) && | 913 | (mode->hsync_end - mode->hdisplay == 80) && |
@@ -881,7 +916,8 @@ mode_is_rb(struct drm_display_mode *mode) | |||
881 | } | 916 | } |
882 | 917 | ||
883 | static bool | 918 | static bool |
884 | mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t) | 919 | mode_in_hsync_range(const struct drm_display_mode *mode, |
920 | struct edid *edid, u8 *t) | ||
885 | { | 921 | { |
886 | int hsync, hmin, hmax; | 922 | int hsync, hmin, hmax; |
887 | 923 | ||
@@ -897,7 +933,8 @@ mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t) | |||
897 | } | 933 | } |
898 | 934 | ||
899 | static bool | 935 | static bool |
900 | mode_in_vsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t) | 936 | mode_in_vsync_range(const struct drm_display_mode *mode, |
937 | struct edid *edid, u8 *t) | ||
901 | { | 938 | { |
902 | int vsync, vmin, vmax; | 939 | int vsync, vmin, vmax; |
903 | 940 | ||
@@ -928,7 +965,7 @@ range_pixel_clock(struct edid *edid, u8 *t) | |||
928 | } | 965 | } |
929 | 966 | ||
930 | static bool | 967 | static bool |
931 | mode_in_range(struct drm_display_mode *mode, struct edid *edid, | 968 | mode_in_range(const struct drm_display_mode *mode, struct edid *edid, |
932 | struct detailed_timing *timing) | 969 | struct detailed_timing *timing) |
933 | { | 970 | { |
934 | u32 max_clock; | 971 | u32 max_clock; |
@@ -1268,34 +1305,52 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, | |||
1268 | } | 1305 | } |
1269 | 1306 | ||
1270 | #define HDMI_IDENTIFIER 0x000C03 | 1307 | #define HDMI_IDENTIFIER 0x000C03 |
1308 | #define AUDIO_BLOCK 0x01 | ||
1271 | #define VENDOR_BLOCK 0x03 | 1309 | #define VENDOR_BLOCK 0x03 |
1310 | #define EDID_BASIC_AUDIO (1 << 6) | ||
1311 | |||
1272 | /** | 1312 | /** |
1273 | * drm_detect_hdmi_monitor - detect whether monitor is hdmi. | 1313 | * Search EDID for CEA extension block. |
1274 | * @edid: monitor EDID information | ||
1275 | * | ||
1276 | * Parse the CEA extension according to CEA-861-B. | ||
1277 | * Return true if HDMI, false if not or unknown. | ||
1278 | */ | 1314 | */ |
1279 | bool drm_detect_hdmi_monitor(struct edid *edid) | 1315 | u8 *drm_find_cea_extension(struct edid *edid) |
1280 | { | 1316 | { |
1281 | char *edid_ext = NULL; | 1317 | u8 *edid_ext = NULL; |
1282 | int i, hdmi_id; | 1318 | int i; |
1283 | int start_offset, end_offset; | ||
1284 | bool is_hdmi = false; | ||
1285 | 1319 | ||
1286 | /* No EDID or EDID extensions */ | 1320 | /* No EDID or EDID extensions */ |
1287 | if (edid == NULL || edid->extensions == 0) | 1321 | if (edid == NULL || edid->extensions == 0) |
1288 | goto end; | 1322 | return NULL; |
1289 | 1323 | ||
1290 | /* Find CEA extension */ | 1324 | /* Find CEA extension */ |
1291 | for (i = 0; i < edid->extensions; i++) { | 1325 | for (i = 0; i < edid->extensions; i++) { |
1292 | edid_ext = (char *)edid + EDID_LENGTH * (i + 1); | 1326 | edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); |
1293 | /* This block is CEA extension */ | 1327 | if (edid_ext[0] == CEA_EXT) |
1294 | if (edid_ext[0] == 0x02) | ||
1295 | break; | 1328 | break; |
1296 | } | 1329 | } |
1297 | 1330 | ||
1298 | if (i == edid->extensions) | 1331 | if (i == edid->extensions) |
1332 | return NULL; | ||
1333 | |||
1334 | return edid_ext; | ||
1335 | } | ||
1336 | EXPORT_SYMBOL(drm_find_cea_extension); | ||
1337 | |||
1338 | /** | ||
1339 | * drm_detect_hdmi_monitor - detect whether monitor is hdmi. | ||
1340 | * @edid: monitor EDID information | ||
1341 | * | ||
1342 | * Parse the CEA extension according to CEA-861-B. | ||
1343 | * Return true if HDMI, false if not or unknown. | ||
1344 | */ | ||
1345 | bool drm_detect_hdmi_monitor(struct edid *edid) | ||
1346 | { | ||
1347 | u8 *edid_ext; | ||
1348 | int i, hdmi_id; | ||
1349 | int start_offset, end_offset; | ||
1350 | bool is_hdmi = false; | ||
1351 | |||
1352 | edid_ext = drm_find_cea_extension(edid); | ||
1353 | if (!edid_ext) | ||
1299 | goto end; | 1354 | goto end; |
1300 | 1355 | ||
1301 | /* Data block offset in CEA extension block */ | 1356 | /* Data block offset in CEA extension block */ |
@@ -1326,6 +1381,111 @@ end: | |||
1326 | EXPORT_SYMBOL(drm_detect_hdmi_monitor); | 1381 | EXPORT_SYMBOL(drm_detect_hdmi_monitor); |
1327 | 1382 | ||
1328 | /** | 1383 | /** |
1384 | * drm_detect_monitor_audio - check monitor audio capability | ||
1385 | * | ||
1386 | * Monitor should have CEA extension block. | ||
1387 | * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic | ||
1388 | * audio' only. If there is any audio extension block and supported | ||
1389 | * audio format, assume at least 'basic audio' support, even if 'basic | ||
1390 | * audio' is not defined in EDID. | ||
1391 | * | ||
1392 | */ | ||
1393 | bool drm_detect_monitor_audio(struct edid *edid) | ||
1394 | { | ||
1395 | u8 *edid_ext; | ||
1396 | int i, j; | ||
1397 | bool has_audio = false; | ||
1398 | int start_offset, end_offset; | ||
1399 | |||
1400 | edid_ext = drm_find_cea_extension(edid); | ||
1401 | if (!edid_ext) | ||
1402 | goto end; | ||
1403 | |||
1404 | has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0); | ||
1405 | |||
1406 | if (has_audio) { | ||
1407 | DRM_DEBUG_KMS("Monitor has basic audio support\n"); | ||
1408 | goto end; | ||
1409 | } | ||
1410 | |||
1411 | /* Data block offset in CEA extension block */ | ||
1412 | start_offset = 4; | ||
1413 | end_offset = edid_ext[2]; | ||
1414 | |||
1415 | for (i = start_offset; i < end_offset; | ||
1416 | i += ((edid_ext[i] & 0x1f) + 1)) { | ||
1417 | if ((edid_ext[i] >> 5) == AUDIO_BLOCK) { | ||
1418 | has_audio = true; | ||
1419 | for (j = 1; j < (edid_ext[i] & 0x1f); j += 3) | ||
1420 | DRM_DEBUG_KMS("CEA audio format %d\n", | ||
1421 | (edid_ext[i + j] >> 3) & 0xf); | ||
1422 | goto end; | ||
1423 | } | ||
1424 | } | ||
1425 | end: | ||
1426 | return has_audio; | ||
1427 | } | ||
1428 | EXPORT_SYMBOL(drm_detect_monitor_audio); | ||
1429 | |||
1430 | /** | ||
1431 | * drm_add_display_info - pull display info out if present | ||
1432 | * @edid: EDID data | ||
1433 | * @info: display info (attached to connector) | ||
1434 | * | ||
1435 | * Grab any available display info and stuff it into the drm_display_info | ||
1436 | * structure that's part of the connector. Useful for tracking bpp and | ||
1437 | * color spaces. | ||
1438 | */ | ||
1439 | static void drm_add_display_info(struct edid *edid, | ||
1440 | struct drm_display_info *info) | ||
1441 | { | ||
1442 | info->width_mm = edid->width_cm * 10; | ||
1443 | info->height_mm = edid->height_cm * 10; | ||
1444 | |||
1445 | /* driver figures it out in this case */ | ||
1446 | info->bpc = 0; | ||
1447 | info->color_formats = 0; | ||
1448 | |||
1449 | /* Only defined for 1.4 with digital displays */ | ||
1450 | if (edid->revision < 4) | ||
1451 | return; | ||
1452 | |||
1453 | if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) | ||
1454 | return; | ||
1455 | |||
1456 | switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { | ||
1457 | case DRM_EDID_DIGITAL_DEPTH_6: | ||
1458 | info->bpc = 6; | ||
1459 | break; | ||
1460 | case DRM_EDID_DIGITAL_DEPTH_8: | ||
1461 | info->bpc = 8; | ||
1462 | break; | ||
1463 | case DRM_EDID_DIGITAL_DEPTH_10: | ||
1464 | info->bpc = 10; | ||
1465 | break; | ||
1466 | case DRM_EDID_DIGITAL_DEPTH_12: | ||
1467 | info->bpc = 12; | ||
1468 | break; | ||
1469 | case DRM_EDID_DIGITAL_DEPTH_14: | ||
1470 | info->bpc = 14; | ||
1471 | break; | ||
1472 | case DRM_EDID_DIGITAL_DEPTH_16: | ||
1473 | info->bpc = 16; | ||
1474 | break; | ||
1475 | case DRM_EDID_DIGITAL_DEPTH_UNDEF: | ||
1476 | default: | ||
1477 | info->bpc = 0; | ||
1478 | break; | ||
1479 | } | ||
1480 | |||
1481 | info->color_formats = DRM_COLOR_FORMAT_RGB444; | ||
1482 | if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444) | ||
1483 | info->color_formats = DRM_COLOR_FORMAT_YCRCB444; | ||
1484 | if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422) | ||
1485 | info->color_formats = DRM_COLOR_FORMAT_YCRCB422; | ||
1486 | } | ||
1487 | |||
1488 | /** | ||
1329 | * drm_add_edid_modes - add modes from EDID data, if available | 1489 | * drm_add_edid_modes - add modes from EDID data, if available |
1330 | * @connector: connector we're probing | 1490 | * @connector: connector we're probing |
1331 | * @edid: edid data | 1491 | * @edid: edid data |
@@ -1373,8 +1533,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
1373 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) | 1533 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) |
1374 | edid_fixup_preferred(connector, quirks); | 1534 | edid_fixup_preferred(connector, quirks); |
1375 | 1535 | ||
1376 | connector->display_info.width_mm = edid->width_cm * 10; | 1536 | drm_add_display_info(edid, &connector->display_info); |
1377 | connector->display_info.height_mm = edid->height_cm * 10; | ||
1378 | 1537 | ||
1379 | return num_modes; | 1538 | return num_modes; |
1380 | } | 1539 | } |
@@ -1395,7 +1554,7 @@ int drm_add_modes_noedid(struct drm_connector *connector, | |||
1395 | int hdisplay, int vdisplay) | 1554 | int hdisplay, int vdisplay) |
1396 | { | 1555 | { |
1397 | int i, count, num_modes = 0; | 1556 | int i, count, num_modes = 0; |
1398 | struct drm_display_mode *mode, *ptr; | 1557 | struct drm_display_mode *mode; |
1399 | struct drm_device *dev = connector->dev; | 1558 | struct drm_device *dev = connector->dev; |
1400 | 1559 | ||
1401 | count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | 1560 | count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); |
@@ -1405,7 +1564,7 @@ int drm_add_modes_noedid(struct drm_connector *connector, | |||
1405 | vdisplay = 0; | 1564 | vdisplay = 0; |
1406 | 1565 | ||
1407 | for (i = 0; i < count; i++) { | 1566 | for (i = 0; i < count; i++) { |
1408 | ptr = &drm_dmt_modes[i]; | 1567 | const struct drm_display_mode *ptr = &drm_dmt_modes[i]; |
1409 | if (hdisplay && vdisplay) { | 1568 | if (hdisplay && vdisplay) { |
1410 | /* | 1569 | /* |
1411 | * Only when two are valid, they will be used to check | 1570 | * Only when two are valid, they will be used to check |