diff options
author | Zhenyu Wang <zhenyuw@linux.intel.com> | 2010-09-19 02:27:28 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-10-19 04:17:32 -0400 |
commit | 8fe9790d1652e7c306c862ea102a5e6126b412e1 (patch) | |
tree | b3cdc7c842eef61efbdd63f791a210aa524df89f | |
parent | 6d139a87b747aaebc969ac5f4eb8db766fcd9cbd (diff) |
drm/edid: add helper function to detect monitor audio capability
To help to determine if digital display port needs to enable
audio output or not. This one adds a helper to get monitor's
audio capability via EDID CEA extension block.
Tested-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 92 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 1 |
2 files changed, 79 insertions, 14 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index fd033ebbdf84..c1a26217a530 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -1267,34 +1267,51 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, | |||
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | #define HDMI_IDENTIFIER 0x000C03 | 1269 | #define HDMI_IDENTIFIER 0x000C03 |
1270 | #define AUDIO_BLOCK 0x01 | ||
1270 | #define VENDOR_BLOCK 0x03 | 1271 | #define VENDOR_BLOCK 0x03 |
1272 | #define EDID_BASIC_AUDIO (1 << 6) | ||
1273 | |||
1271 | /** | 1274 | /** |
1272 | * drm_detect_hdmi_monitor - detect whether monitor is hdmi. | 1275 | * Search EDID for CEA extension block. |
1273 | * @edid: monitor EDID information | ||
1274 | * | ||
1275 | * Parse the CEA extension according to CEA-861-B. | ||
1276 | * Return true if HDMI, false if not or unknown. | ||
1277 | */ | 1276 | */ |
1278 | bool drm_detect_hdmi_monitor(struct edid *edid) | 1277 | static u8 *drm_find_cea_extension(struct edid *edid) |
1279 | { | 1278 | { |
1280 | char *edid_ext = NULL; | 1279 | u8 *edid_ext = NULL; |
1281 | int i, hdmi_id; | 1280 | int i; |
1282 | int start_offset, end_offset; | ||
1283 | bool is_hdmi = false; | ||
1284 | 1281 | ||
1285 | /* No EDID or EDID extensions */ | 1282 | /* No EDID or EDID extensions */ |
1286 | if (edid == NULL || edid->extensions == 0) | 1283 | if (edid == NULL || edid->extensions == 0) |
1287 | goto end; | 1284 | return NULL; |
1288 | 1285 | ||
1289 | /* Find CEA extension */ | 1286 | /* Find CEA extension */ |
1290 | for (i = 0; i < edid->extensions; i++) { | 1287 | for (i = 0; i < edid->extensions; i++) { |
1291 | edid_ext = (char *)edid + EDID_LENGTH * (i + 1); | 1288 | edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); |
1292 | /* This block is CEA extension */ | 1289 | if (edid_ext[0] == CEA_EXT) |
1293 | if (edid_ext[0] == 0x02) | ||
1294 | break; | 1290 | break; |
1295 | } | 1291 | } |
1296 | 1292 | ||
1297 | if (i == edid->extensions) | 1293 | if (i == edid->extensions) |
1294 | return NULL; | ||
1295 | |||
1296 | return edid_ext; | ||
1297 | } | ||
1298 | |||
1299 | /** | ||
1300 | * drm_detect_hdmi_monitor - detect whether monitor is hdmi. | ||
1301 | * @edid: monitor EDID information | ||
1302 | * | ||
1303 | * Parse the CEA extension according to CEA-861-B. | ||
1304 | * Return true if HDMI, false if not or unknown. | ||
1305 | */ | ||
1306 | bool drm_detect_hdmi_monitor(struct edid *edid) | ||
1307 | { | ||
1308 | u8 *edid_ext; | ||
1309 | int i, hdmi_id; | ||
1310 | int start_offset, end_offset; | ||
1311 | bool is_hdmi = false; | ||
1312 | |||
1313 | edid_ext = drm_find_cea_extension(edid); | ||
1314 | if (!edid_ext) | ||
1298 | goto end; | 1315 | goto end; |
1299 | 1316 | ||
1300 | /* Data block offset in CEA extension block */ | 1317 | /* Data block offset in CEA extension block */ |
@@ -1325,6 +1342,53 @@ end: | |||
1325 | EXPORT_SYMBOL(drm_detect_hdmi_monitor); | 1342 | EXPORT_SYMBOL(drm_detect_hdmi_monitor); |
1326 | 1343 | ||
1327 | /** | 1344 | /** |
1345 | * drm_detect_monitor_audio - check monitor audio capability | ||
1346 | * | ||
1347 | * Monitor should have CEA extension block. | ||
1348 | * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic | ||
1349 | * audio' only. If there is any audio extension block and supported | ||
1350 | * audio format, assume at least 'basic audio' support, even if 'basic | ||
1351 | * audio' is not defined in EDID. | ||
1352 | * | ||
1353 | */ | ||
1354 | bool drm_detect_monitor_audio(struct edid *edid) | ||
1355 | { | ||
1356 | u8 *edid_ext; | ||
1357 | int i, j; | ||
1358 | bool has_audio = false; | ||
1359 | int start_offset, end_offset; | ||
1360 | |||
1361 | edid_ext = drm_find_cea_extension(edid); | ||
1362 | if (!edid_ext) | ||
1363 | goto end; | ||
1364 | |||
1365 | has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0); | ||
1366 | |||
1367 | if (has_audio) { | ||
1368 | DRM_DEBUG_KMS("Monitor has basic audio support\n"); | ||
1369 | goto end; | ||
1370 | } | ||
1371 | |||
1372 | /* Data block offset in CEA extension block */ | ||
1373 | start_offset = 4; | ||
1374 | end_offset = edid_ext[2]; | ||
1375 | |||
1376 | for (i = start_offset; i < end_offset; | ||
1377 | i += ((edid_ext[i] & 0x1f) + 1)) { | ||
1378 | if ((edid_ext[i] >> 5) == AUDIO_BLOCK) { | ||
1379 | has_audio = true; | ||
1380 | for (j = 1; j < (edid_ext[i] & 0x1f); j += 3) | ||
1381 | DRM_DEBUG_KMS("CEA audio format %d\n", | ||
1382 | (edid_ext[i + j] >> 3) & 0xf); | ||
1383 | goto end; | ||
1384 | } | ||
1385 | } | ||
1386 | end: | ||
1387 | return has_audio; | ||
1388 | } | ||
1389 | EXPORT_SYMBOL(drm_detect_monitor_audio); | ||
1390 | |||
1391 | /** | ||
1328 | * drm_add_edid_modes - add modes from EDID data, if available | 1392 | * drm_add_edid_modes - add modes from EDID data, if available |
1329 | * @connector: connector we're probing | 1393 | * @connector: connector we're probing |
1330 | * @edid: edid data | 1394 | * @edid: edid data |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 15c4796fd467..029aa688e787 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -763,6 +763,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, | |||
763 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, | 763 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, |
764 | void *data, struct drm_file *file_priv); | 764 | void *data, struct drm_file *file_priv); |
765 | extern bool drm_detect_hdmi_monitor(struct edid *edid); | 765 | extern bool drm_detect_hdmi_monitor(struct edid *edid); |
766 | extern bool drm_detect_monitor_audio(struct edid *edid); | ||
766 | extern int drm_mode_page_flip_ioctl(struct drm_device *dev, | 767 | extern int drm_mode_page_flip_ioctl(struct drm_device *dev, |
767 | void *data, struct drm_file *file_priv); | 768 | void *data, struct drm_file *file_priv); |
768 | extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, | 769 | extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, |