UPSTREAM: drm/edid: Extract SADs properly from multiple audio data blocks
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / drm_edid.c
index d7f95724c63020125b193ba7ebde26011f0b3ea5..794e286dd1e241319fc35ca8252901a17d934f4f 100644 (file)
@@ -1240,12 +1240,6 @@ static const struct drm_display_mode edid_4k_modes[] = {
                   2160, 2168, 2178, 2250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
          .vrefresh = 24, },
-       /* 5 - 3840x2160@60Hz */
-       { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000,
-                  3840, 4016, 4104, 4400, 0,
-                  2160, 2168, 2178, 2250, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 };
 
 /*** DDC fetch and block validation ***/
@@ -3687,7 +3681,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;
 
@@ -3701,6 +3695,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;
@@ -3729,11 +3724,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 */
@@ -3753,13 +3752,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);
 
@@ -4386,12 +4385,14 @@ EXPORT_SYMBOL(drm_set_preferred_mode);
  *                                              data from a DRM display mode
  * @frame: HDMI AVI infoframe
  * @mode: DRM display mode
+ * @is_hdmi2: Sink is HDMI 2.0 compliant
  *
  * Return: 0 on success or a negative error code on failure.
  */
 int
 drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
-                                        const struct drm_display_mode *mode)
+                                        const struct drm_display_mode *mode,
+                                        bool is_hdmi2)
 {
        int err;
 
@@ -4407,6 +4408,14 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
 
        frame->video_code = drm_match_cea_mode(mode);
 
+       /*
+        * HDMI 1.4 VIC range: 1 <= VIC <= 64 (CEA-861-D) but
+        * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we
+        * have to make sure we dont break HDMI 1.4 sinks.
+        */
+       if (!is_hdmi2 && frame->video_code > 64)
+               frame->video_code = 0;
+
        frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
 
        /*