drm/edid: Extract SADs properly from multiple audio data blocks
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 9 Mar 2016 20:07:46 +0000 (22:07 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Sun, 13 Mar 2016 18:36:17 +0000 (19:36 +0100)
SADs may span multiple CEA audio data blocks in the EDID.

CEA-861-E says:
"The order of the Data Blocks is not constrained. It is also possible
to have more than one of a specific type of data block if necessary to
include all of the descriptors needed to describe the sink’s capabilities."

Each audio data block can carry up to 10 SADs, whereas the ELD SAD limit
is 15 according to HDA 1.0a spec. So we should support at least two data
blocks. And apparently some devices take a more liberal interpretation
and stuff only one SAD per data block even when they would fit into one.

So let's try to extract all the SADs we can fit into the ELD even when
they span multiple data blocks.

While at it, toss in a comment to explain the 13 byte monitor name
string limit which confused me at first.

Cc: Arturo Pérez <artur999555@gmail.com>
Tested-by: Arturo Pérez <artur999555@gmail.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94197
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1457554066-8739-1-git-send-email-ville.syrjala@linux.intel.com
drivers/gpu/drm/drm_edid.c

index fdb1eb01458690fc10ef6cdcb53b381c76d36a42..414d7f61aa05cbacb78542b1e3154ea700f6e3bd 100644 (file)
@@ -3308,7 +3308,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
        u8 *cea;
        u8 *name;
        u8 *db;
-       int sad_count = 0;
+       int total_sad_count = 0;
        int mnl;
        int dbl;
 
@@ -3322,6 +3322,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
 
        name = NULL;
        drm_for_each_detailed_block((u8 *)edid, monitor_name, &name);
+       /* max: 13 bytes EDID, 16 bytes ELD */
        for (mnl = 0; name && mnl < 13; mnl++) {
                if (name[mnl] == 0x0a)
                        break;
@@ -3350,11 +3351,15 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
                        dbl = cea_db_payload_len(db);
 
                        switch (cea_db_tag(db)) {
+                               int sad_count;
+
                        case AUDIO_BLOCK:
                                /* Audio Data Block, contains SADs */
-                               sad_count = dbl / 3;
-                               if (dbl >= 1)
-                                       memcpy(eld + 20 + mnl, &db[1], dbl);
+                               sad_count = min(dbl / 3, 15 - total_sad_count);
+                               if (sad_count >= 1)
+                                       memcpy(eld + 20 + mnl + total_sad_count * 3,
+                                              &db[1], sad_count * 3);
+                               total_sad_count += sad_count;
                                break;
                        case SPEAKER_BLOCK:
                                /* Speaker Allocation Data Block */
@@ -3371,13 +3376,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
                        }
                }
        }
-       eld[5] |= sad_count << 4;
+       eld[5] |= total_sad_count << 4;
 
        eld[DRM_ELD_BASELINE_ELD_LEN] =
                DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
 
        DRM_DEBUG_KMS("ELD size %d, SAD count %d\n",
-                     drm_eld_size(eld), sad_count);
+                     drm_eld_size(eld), total_sad_count);
 }
 EXPORT_SYMBOL(drm_edid_to_eld);