aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhenyu Wang <zhenyuw@linux.intel.com>2010-09-19 02:27:28 -0400
committerChris Wilson <chris@chris-wilson.co.uk>2010-10-19 04:17:32 -0400
commit8fe9790d1652e7c306c862ea102a5e6126b412e1 (patch)
treeb3cdc7c842eef61efbdd63f791a210aa524df89f
parent6d139a87b747aaebc969ac5f4eb8db766fcd9cbd (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.c92
-rw-r--r--include/drm/drm_crtc.h1
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 */
1278bool drm_detect_hdmi_monitor(struct edid *edid) 1277static 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 */
1306bool 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:
1325EXPORT_SYMBOL(drm_detect_hdmi_monitor); 1342EXPORT_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 */
1354bool 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 }
1386end:
1387 return has_audio;
1388}
1389EXPORT_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,
763extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, 763extern 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);
765extern bool drm_detect_hdmi_monitor(struct edid *edid); 765extern bool drm_detect_hdmi_monitor(struct edid *edid);
766extern bool drm_detect_monitor_audio(struct edid *edid);
766extern int drm_mode_page_flip_ioctl(struct drm_device *dev, 767extern 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);
768extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, 769extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,