Merge branch 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux into drm...
authorDave Airlie <airlied@redhat.com>
Mon, 10 Oct 2016 06:40:16 +0000 (16:40 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 10 Oct 2016 06:40:16 +0000 (16:40 +1000)
Just some misc bug fixes for 4.9.

* 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux:
  drm/amdgpu: revert "use more than 64KB fragment size if possible"
  drm/amdgpu: warn if dp aux is still attached on free
  drm/amdgpu/dce11: add missing drm_mode_config_cleanup call
  drm/amdgpu: also track late init state
  drm/amdgpu/virtual_dce: adjust config ifdef
  drm/amdgpu/vce: add support for hw config packet (v2)
  drm/amdgpu: clean up to set fw_offset as 0 twice
  drm/amdgpu: remove DRM_AMD_POWERPLAY
  drm/radeon: Prevent races on pre DCE4 between flip submission and completion.
  drm/radeon: Slightly more robust flip completion handling for < DCE-4

26 files changed:
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_gem.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_regs.h
drivers/gpu/drm/vc4/vc4_render_cl.c
drivers/gpu/drm/vc4/vc4_validate.c
include/drm/bridge/analogix_dp.h
include/drm/drmP.h
include/drm/drm_connector.h
include/drm/drm_crtc.h
include/drm/drm_fb_helper.h
include/uapi/linux/Kbuild

index 4988098..2e3a054 100644 (file)
@@ -168,12 +168,12 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
                }
 
                /* Any defined maximum tmds clock limit we must not exceed? */
-               if (connector->max_tmds_clock > 0) {
+               if (connector->display_info.max_tmds_clock > 0) {
                        /* mode_clock is clock in kHz for mode to be modeset on this connector */
                        mode_clock = amdgpu_connector->pixelclock_for_modeset;
 
                        /* Maximum allowable input clock in kHz */
-                       max_tmds_clock = connector->max_tmds_clock * 1000;
+                       max_tmds_clock = connector->display_info.max_tmds_clock;
 
                        DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
                                  connector->name, mode_clock, max_tmds_clock);
index 0f2e423..001b075 100644 (file)
@@ -98,6 +98,14 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
        return 0;
 }
 
+int analogix_dp_psr_supported(struct device *dev)
+{
+       struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+       return dp->psr_support;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
+
 int analogix_dp_enable_psr(struct device *dev)
 {
        struct analogix_dp_device *dp = dev_get_drvdata(dev);
index 80c7f25..6efdba4 100644 (file)
@@ -89,7 +89,6 @@ void drm_dev_printk(const struct device *dev, const char *level,
 EXPORT_SYMBOL(drm_dev_printk);
 
 void drm_printk(const char *level, unsigned int category,
-               const char *function_name, const char *prefix,
                const char *format, ...)
 {
        struct va_format vaf;
@@ -102,7 +101,9 @@ void drm_printk(const char *level, unsigned int category,
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf);
+       printk("%s" "[" DRM_NAME ":%ps]%s %pV",
+              level, __builtin_return_address(0),
+              strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf);
 
        va_end(args);
 }
index 5054132..ec77bd3 100644 (file)
@@ -3253,16 +3253,12 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
 }
 
 static void
-parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
+drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
 {
        u8 len = cea_db_payload_len(db);
 
-       if (len >= 6) {
+       if (len >= 6)
                connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
-               connector->dvi_dual = db[6] & 1;
-       }
-       if (len >= 7)
-               connector->max_tmds_clock = db[7] * 5;
        if (len >= 8) {
                connector->latency_present[0] = db[8] >> 7;
                connector->latency_present[1] = (db[8] >> 6) & 1;
@@ -3276,19 +3272,15 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
        if (len >= 12)
                connector->audio_latency[1] = db[12];
 
-       DRM_DEBUG_KMS("HDMI: DVI dual %d, "
-                   "max TMDS clock %d, "
-                   "latency present %d %d, "
-                   "video latency %d %d, "
-                   "audio latency %d %d\n",
-                   connector->dvi_dual,
-                   connector->max_tmds_clock,
-             (int) connector->latency_present[0],
-             (int) connector->latency_present[1],
-                   connector->video_latency[0],
-                   connector->video_latency[1],
-                   connector->audio_latency[0],
-                   connector->audio_latency[1]);
+       DRM_DEBUG_KMS("HDMI: latency present %d %d, "
+                     "video latency %d %d, "
+                     "audio latency %d %d\n",
+                     connector->latency_present[0],
+                     connector->latency_present[1],
+                     connector->video_latency[0],
+                     connector->video_latency[1],
+                     connector->audio_latency[0],
+                     connector->audio_latency[1]);
 }
 
 static void
@@ -3358,6 +3350,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
 
        memset(eld, 0, sizeof(connector->eld));
 
+       connector->latency_present[0] = false;
+       connector->latency_present[1] = false;
+       connector->video_latency[0] = 0;
+       connector->audio_latency[0] = 0;
+       connector->video_latency[1] = 0;
+       connector->audio_latency[1] = 0;
+
        cea = drm_find_cea_extension(edid);
        if (!cea) {
                DRM_DEBUG_KMS("ELD: no CEA Extension found\n");
@@ -3407,7 +3406,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
                        case VENDOR_BLOCK:
                                /* HDMI Vendor-Specific Data Block */
                                if (cea_db_is_hdmi_vsdb(db))
-                                       parse_hdmi_vsdb(connector, db);
+                                       drm_parse_hdmi_vsdb_audio(connector, db);
                                break;
                        default:
                                break;
@@ -3721,105 +3720,127 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
 }
 EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
 
-/*
- * Parse the CEA extension according to CEA-861-B.
- * Return true if HDMI deep color supported, false if not or unknown.
- */
-static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
-                                            struct drm_display_info *info,
-                                            struct drm_connector *connector)
+static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
+                                          const u8 *hdmi)
 {
-       u8 *edid_ext, *hdmi;
-       int i;
-       int start_offset, end_offset;
+       struct drm_display_info *info = &connector->display_info;
        unsigned int dc_bpc = 0;
 
-       edid_ext = drm_find_cea_extension(edid);
-       if (!edid_ext)
-               return false;
+       /* HDMI supports at least 8 bpc */
+       info->bpc = 8;
 
-       if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
-               return false;
+       if (cea_db_payload_len(hdmi) < 6)
+               return;
+
+       if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
+               dc_bpc = 10;
+               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
+               DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
+                         connector->name);
+       }
+
+       if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
+               dc_bpc = 12;
+               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
+               DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
+                         connector->name);
+       }
+
+       if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
+               dc_bpc = 16;
+               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
+               DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
+                         connector->name);
+       }
+
+       if (dc_bpc == 0) {
+               DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
+                         connector->name);
+               return;
+       }
+
+       DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
+                 connector->name, dc_bpc);
+       info->bpc = dc_bpc;
 
        /*
-        * Because HDMI identifier is in Vendor Specific Block,
-        * search it from all data blocks of CEA extension.
+        * Deep color support mandates RGB444 support for all video
+        * modes and forbids YCRCB422 support for all video modes per
+        * HDMI 1.3 spec.
         */
-       for_each_cea_db(edid_ext, i, start_offset, end_offset) {
-               if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
-                       /* HDMI supports at least 8 bpc */
-                       info->bpc = 8;
-
-                       hdmi = &edid_ext[i];
-                       if (cea_db_payload_len(hdmi) < 6)
-                               return false;
-
-                       if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
-                               dc_bpc = 10;
-                               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
-                               DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
-                                                 connector->name);
-                       }
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
 
-                       if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
-                               dc_bpc = 12;
-                               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
-                               DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
-                                                 connector->name);
-                       }
+       /* YCRCB444 is optional according to spec. */
+       if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+               DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
+                         connector->name);
+       }
 
-                       if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
-                               dc_bpc = 16;
-                               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
-                               DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
-                                                 connector->name);
-                       }
+       /*
+        * Spec says that if any deep color mode is supported at all,
+        * then deep color 36 bit must be supported.
+        */
+       if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
+               DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
+                         connector->name);
+       }
+}
 
-                       if (dc_bpc > 0) {
-                               DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
-                                                 connector->name, dc_bpc);
-                               info->bpc = dc_bpc;
-
-                               /*
-                                * Deep color support mandates RGB444 support for all video
-                                * modes and forbids YCRCB422 support for all video modes per
-                                * HDMI 1.3 spec.
-                                */
-                               info->color_formats = DRM_COLOR_FORMAT_RGB444;
-
-                               /* YCRCB444 is optional according to spec. */
-                               if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
-                                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
-                                       DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
-                                                         connector->name);
-                               }
+static void
+drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
+{
+       struct drm_display_info *info = &connector->display_info;
+       u8 len = cea_db_payload_len(db);
 
-                               /*
-                                * Spec says that if any deep color mode is supported at all,
-                                * then deep color 36 bit must be supported.
-                                */
-                               if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
-                                       DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
-                                                         connector->name);
-                               }
+       if (len >= 6)
+               info->dvi_dual = db[6] & 1;
+       if (len >= 7)
+               info->max_tmds_clock = db[7] * 5000;
 
-                               return true;
-                       }
-                       else {
-                               DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
-                                                 connector->name);
-                       }
-               }
-       }
+       DRM_DEBUG_KMS("HDMI: DVI dual %d, "
+                     "max TMDS clock %d kHz\n",
+                     info->dvi_dual,
+                     info->max_tmds_clock);
 
-       return false;
+       drm_parse_hdmi_deep_color_info(connector, db);
 }
 
-static void drm_add_display_info(struct edid *edid,
-                                 struct drm_display_info *info,
-                                 struct drm_connector *connector)
+static void drm_parse_cea_ext(struct drm_connector *connector,
+                             struct edid *edid)
 {
-       u8 *edid_ext;
+       struct drm_display_info *info = &connector->display_info;
+       const u8 *edid_ext;
+       int i, start, end;
+
+       edid_ext = drm_find_cea_extension(edid);
+       if (!edid_ext)
+               return;
+
+       info->cea_rev = edid_ext[1];
+
+       /* The existence of a CEA block should imply RGB support */
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
+       if (edid_ext[3] & EDID_CEA_YCRCB444)
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+       if (edid_ext[3] & EDID_CEA_YCRCB422)
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+
+       if (cea_db_offsets(edid_ext, &start, &end))
+               return;
+
+       for_each_cea_db(edid_ext, i, start, end) {
+               const u8 *db = &edid_ext[i];
+
+               if (cea_db_is_hdmi_vsdb(db))
+                       drm_parse_hdmi_vsdb_video(connector, db);
+       }
+}
+
+static void drm_add_display_info(struct drm_connector *connector,
+                                struct edid *edid)
+{
+       struct drm_display_info *info = &connector->display_info;
 
        info->width_mm = edid->width_cm * 10;
        info->height_mm = edid->height_cm * 10;
@@ -3827,6 +3848,9 @@ static void drm_add_display_info(struct edid *edid,
        /* driver figures it out in this case */
        info->bpc = 0;
        info->color_formats = 0;
+       info->cea_rev = 0;
+       info->max_tmds_clock = 0;
+       info->dvi_dual = false;
 
        if (edid->revision < 3)
                return;
@@ -3834,21 +3858,7 @@ static void drm_add_display_info(struct edid *edid,
        if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
                return;
 
-       /* Get data from CEA blocks if present */
-       edid_ext = drm_find_cea_extension(edid);
-       if (edid_ext) {
-               info->cea_rev = edid_ext[1];
-
-               /* The existence of a CEA block should imply RGB support */
-               info->color_formats = DRM_COLOR_FORMAT_RGB444;
-               if (edid_ext[3] & EDID_CEA_YCRCB444)
-                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
-               if (edid_ext[3] & EDID_CEA_YCRCB422)
-                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
-       }
-
-       /* HDMI deep color modes supported? Assign to info, if so */
-       drm_assign_hdmi_deep_color_info(edid, info, connector);
+       drm_parse_cea_ext(connector, edid);
 
        /*
         * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3?
@@ -4084,7 +4094,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       drm_add_display_info(edid, &connector->display_info, connector);
+       drm_add_display_info(connector, edid);
 
        if (quirks & EDID_QUIRK_FORCE_6BPC)
                connector->display_info.bpc = 6;
index 404a1ce..b969a64 100644 (file)
@@ -1008,6 +1008,31 @@ static void send_vblank_event(struct drm_device *dev,
  * period. This helper function implements exactly the required vblank arming
  * behaviour.
  *
+ * NOTE: Drivers using this to send out the event in struct &drm_crtc_state
+ * as part of an atomic commit must ensure that the next vblank happens at
+ * exactly the same time as the atomic commit is committed to the hardware. This
+ * function itself does **not** protect again the next vblank interrupt racing
+ * with either this function call or the atomic commit operation. A possible
+ * sequence could be:
+ *
+ * 1. Driver commits new hardware state into vblank-synchronized registers.
+ * 2. A vblank happens, committing the hardware state. Also the corresponding
+ *    vblank interrupt is fired off and fully processed by the interrupt
+ *    handler.
+ * 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event().
+ * 4. The event is only send out for the next vblank, which is wrong.
+ *
+ * An equivalent race can happen when the driver calls
+ * drm_crtc_arm_vblank_event() before writing out the new hardware state.
+ *
+ * The only way to make this work safely is to prevent the vblank from firing
+ * (and the hardware from committing anything else) until the entire atomic
+ * commit sequence has run to completion. If the hardware does not have such a
+ * feature (e.g. using a "go" bit), then it is unsafe to use this functions.
+ * Instead drivers need to manually send out the event from their interrupt
+ * handler by calling drm_crtc_send_vblank_event() and make sure that there's no
+ * possible race with the hardware committing the atomic update.
+ *
  * Caller must hold event lock. Caller must also hold a vblank reference for
  * the event @e, which will be dropped when the next vblank arrives.
  */
@@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
  * @crtc: the source CRTC of the vblank event
  * @e: the event to send
  *
- * Updates sequence # and timestamp on event, and sends it to userspace.
- * Caller must hold event lock.
+ * Updates sequence # and timestamp on event for the most recently processed
+ * vblank, and sends it to userspace.  Caller must hold event lock.
+ *
+ * See drm_crtc_arm_vblank_event() for a helper which can be used in certain
+ * situation, especially to send out events for atomic commit operations.
  */
 void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
                                struct drm_pending_vblank_event *e)
index 780589b..57201d6 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/export.h>
 #include <linux/dma-buf.h>
+#include <linux/rbtree.h>
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 
  */
 
 struct drm_prime_member {
-       struct list_head entry;
        struct dma_buf *dma_buf;
        uint32_t handle;
+
+       struct rb_node dmabuf_rb;
+       struct rb_node handle_rb;
 };
 
 struct drm_prime_attachment {
@@ -75,6 +78,7 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
                                    struct dma_buf *dma_buf, uint32_t handle)
 {
        struct drm_prime_member *member;
+       struct rb_node **p, *rb;
 
        member = kmalloc(sizeof(*member), GFP_KERNEL);
        if (!member)
@@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
        get_dma_buf(dma_buf);
        member->dma_buf = dma_buf;
        member->handle = handle;
-       list_add(&member->entry, &prime_fpriv->head);
+
+       rb = NULL;
+       p = &prime_fpriv->dmabufs.rb_node;
+       while (*p) {
+               struct drm_prime_member *pos;
+
+               rb = *p;
+               pos = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
+               if (dma_buf > pos->dma_buf)
+                       p = &rb->rb_right;
+               else
+                       p = &rb->rb_left;
+       }
+       rb_link_node(&member->dmabuf_rb, rb, p);
+       rb_insert_color(&member->dmabuf_rb, &prime_fpriv->dmabufs);
+
+       rb = NULL;
+       p = &prime_fpriv->handles.rb_node;
+       while (*p) {
+               struct drm_prime_member *pos;
+
+               rb = *p;
+               pos = rb_entry(rb, struct drm_prime_member, handle_rb);
+               if (handle > pos->handle)
+                       p = &rb->rb_right;
+               else
+                       p = &rb->rb_left;
+       }
+       rb_link_node(&member->handle_rb, rb, p);
+       rb_insert_color(&member->handle_rb, &prime_fpriv->handles);
+
        return 0;
 }
 
 static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv,
                                                      uint32_t handle)
 {
-       struct drm_prime_member *member;
+       struct rb_node *rb;
+
+       rb = prime_fpriv->handles.rb_node;
+       while (rb) {
+               struct drm_prime_member *member;
 
-       list_for_each_entry(member, &prime_fpriv->head, entry) {
+               member = rb_entry(rb, struct drm_prime_member, handle_rb);
                if (member->handle == handle)
                        return member->dma_buf;
+               else if (member->handle < handle)
+                       rb = rb->rb_right;
+               else
+                       rb = rb->rb_left;
        }
 
        return NULL;
@@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
                                       struct dma_buf *dma_buf,
                                       uint32_t *handle)
 {
-       struct drm_prime_member *member;
+       struct rb_node *rb;
+
+       rb = prime_fpriv->dmabufs.rb_node;
+       while (rb) {
+               struct drm_prime_member *member;
 
-       list_for_each_entry(member, &prime_fpriv->head, entry) {
+               member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
                if (member->dma_buf == dma_buf) {
                        *handle = member->handle;
                        return 0;
+               } else if (member->dma_buf < dma_buf) {
+                       rb = rb->rb_right;
+               } else {
+                       rb = rb->rb_left;
                }
        }
+
        return -ENOENT;
 }
 
@@ -166,13 +217,24 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
 void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
                                        struct dma_buf *dma_buf)
 {
-       struct drm_prime_member *member, *safe;
+       struct rb_node *rb;
 
-       list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+       rb = prime_fpriv->dmabufs.rb_node;
+       while (rb) {
+               struct drm_prime_member *member;
+
+               member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
                if (member->dma_buf == dma_buf) {
+                       rb_erase(&member->handle_rb, &prime_fpriv->handles);
+                       rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
+
                        dma_buf_put(dma_buf);
-                       list_del(&member->entry);
                        kfree(member);
+                       return;
+               } else if (member->dma_buf < dma_buf) {
+                       rb = rb->rb_right;
+               } else {
+                       rb = rb->rb_left;
                }
        }
 }
@@ -759,12 +821,13 @@ EXPORT_SYMBOL(drm_prime_gem_destroy);
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
 {
-       INIT_LIST_HEAD(&prime_fpriv->head);
        mutex_init(&prime_fpriv->lock);
+       prime_fpriv->dmabufs = RB_ROOT;
+       prime_fpriv->handles = RB_ROOT;
 }
 
 void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
 {
        /* by now drm_gem_release should've made sure the list is empty */
-       WARN_ON(!list_empty(&prime_fpriv->head));
+       WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs));
 }
index 8d4c35d..ad8d712 100644 (file)
@@ -12654,22 +12654,22 @@ static void
 connected_sink_compute_bpp(struct intel_connector *connector,
                           struct intel_crtc_state *pipe_config)
 {
+       const struct drm_display_info *info = &connector->base.display_info;
        int bpp = pipe_config->pipe_bpp;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
-               connector->base.base.id,
-               connector->base.name);
+                     connector->base.base.id,
+                     connector->base.name);
 
        /* Don't use an invalid EDID bpc value */
-       if (connector->base.display_info.bpc &&
-           connector->base.display_info.bpc * 3 < bpp) {
+       if (info->bpc != 0 && info->bpc * 3 < bpp) {
                DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
-                             bpp, connector->base.display_info.bpc*3);
-               pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
+                             bpp, info->bpc * 3);
+               pipe_config->pipe_bpp = info->bpc * 3;
        }
 
        /* Clamp bpp to 8 on screens without EDID 1.4 */
-       if (connector->base.display_info.bpc == 0 && bpp > 24) {
+       if (info->bpc == 0 && bpp > 24) {
                DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
                              bpp);
                pipe_config->pipe_bpp = 24;
index c51073f..f40a35f 100644 (file)
@@ -1220,10 +1220,17 @@ static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
        int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev));
 
        if (respect_downstream_limits) {
+               struct intel_connector *connector = hdmi->attached_connector;
+               const struct drm_display_info *info = &connector->base.display_info;
+
                if (hdmi->dp_dual_mode.max_tmds_clock)
                        max_tmds_clock = min(max_tmds_clock,
                                             hdmi->dp_dual_mode.max_tmds_clock);
-               if (!hdmi->has_hdmi_sink)
+
+               if (info->max_tmds_clock)
+                       max_tmds_clock = min(max_tmds_clock,
+                                            info->max_tmds_clock);
+               else if (!hdmi->has_hdmi_sink)
                        max_tmds_clock = min(max_tmds_clock, 165000);
        }
 
index 334562d..71227de 100644 (file)
@@ -1086,20 +1086,20 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
        return 0;
 }
 
-void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
+static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
 {
        mtk_hdmi_aud_enable_packet(hdmi, true);
        hdmi->audio_enable = true;
 }
 
-void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
+static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
 {
        mtk_hdmi_aud_enable_packet(hdmi, false);
        hdmi->audio_enable = false;
 }
 
-int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
-                            struct hdmi_audio_param *param)
+static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
+                                   struct hdmi_audio_param *param)
 {
        if (!hdmi->audio_enable) {
                dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
@@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data)
        mtk_hdmi_audio_disable(hdmi);
 }
 
-int mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
+static int
+mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
 {
        struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
 
index b79f3b0..50e96d2 100644 (file)
@@ -198,12 +198,12 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)
                }
 
                /* Any defined maximum tmds clock limit we must not exceed? */
-               if (connector->max_tmds_clock > 0) {
+               if (connector->display_info.max_tmds_clock > 0) {
                        /* mode_clock is clock in kHz for mode to be modeset on this connector */
                        mode_clock = radeon_connector->pixelclock_for_modeset;
 
                        /* Maximum allowable input clock in kHz */
-                       max_tmds_clock = connector->max_tmds_clock * 1000;
+                       max_tmds_clock = connector->display_info.max_tmds_clock;
 
                        DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
                                          connector->name, mode_clock, max_tmds_clock);
index e83be15..8548e82 100644 (file)
@@ -85,6 +85,9 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
        struct rockchip_dp_device *dp = to_dp(encoder);
        unsigned long flags;
 
+       if (!analogix_dp_psr_supported(dp->dev))
+               return;
+
        dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
 
        spin_lock_irqsave(&dp->psr_lock, flags);
index 446b5d7..8c8cbe8 100644 (file)
@@ -309,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = {
 };
 
 #ifdef CONFIG_PM_SLEEP
-void rockchip_drm_fb_suspend(struct drm_device *drm)
+static void rockchip_drm_fb_suspend(struct drm_device *drm)
 {
        struct rockchip_drm_private *priv = drm->dev_private;
 
@@ -318,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm)
        console_unlock();
 }
 
-void rockchip_drm_fb_resume(struct drm_device *drm)
+static void rockchip_drm_fb_resume(struct drm_device *drm)
 {
        struct rockchip_drm_private *priv = drm->dev_private;
 
index 207e01d..a16c69f 100644 (file)
@@ -20,6 +20,7 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_fb.h"
+#include "rockchip_drm_fbdev.h"
 
 #define PREFERRED_BPP          32
 #define to_drm_private(x) \
index 2682f07..7f08d68 100644 (file)
@@ -229,7 +229,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
         * and need to make things up in a approximative but consistent way.
         */
        ret |= DRM_SCANOUTPOS_IN_VBLANK;
-       vblank_lines = mode->crtc_vtotal - mode->crtc_vdisplay;
+       vblank_lines = mode->vtotal - mode->vdisplay;
 
        if (flags & DRM_CALLED_FROM_VBLIRQ) {
                /*
@@ -378,7 +378,7 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
        struct drm_crtc_state *state = crtc->state;
        struct drm_display_mode *mode = &state->adjusted_mode;
        bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
-       u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0));
+       u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
        u32 format = PV_CONTROL_FORMAT_24;
        bool debug_dump_regs = false;
        int clock_select = vc4_get_clock_select(crtc);
@@ -394,47 +394,65 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
        CRTC_WRITE(PV_CONTROL, 0);
 
        CRTC_WRITE(PV_HORZA,
-                  VC4_SET_FIELD(mode->htotal - mode->hsync_end,
+                  VC4_SET_FIELD((mode->htotal -
+                                 mode->hsync_end) * pixel_rep,
                                 PV_HORZA_HBP) |
-                  VC4_SET_FIELD(mode->hsync_end - mode->hsync_start,
+                  VC4_SET_FIELD((mode->hsync_end -
+                                 mode->hsync_start) * pixel_rep,
                                 PV_HORZA_HSYNC));
        CRTC_WRITE(PV_HORZB,
-                  VC4_SET_FIELD(mode->hsync_start - mode->hdisplay,
+                  VC4_SET_FIELD((mode->hsync_start -
+                                 mode->hdisplay) * pixel_rep,
                                 PV_HORZB_HFP) |
-                  VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE));
 
        CRTC_WRITE(PV_VERTA,
-                  VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
+                  VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
                                 PV_VERTA_VBP) |
-                  VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
+                  VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
                                 PV_VERTA_VSYNC));
        CRTC_WRITE(PV_VERTB,
-                  VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
+                  VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
                                 PV_VERTB_VFP) |
-                  VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
+                  VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
 
        if (interlace) {
                CRTC_WRITE(PV_VERTA_EVEN,
-                          VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1,
+                          VC4_SET_FIELD(mode->crtc_vtotal -
+                                        mode->crtc_vsync_end - 1,
                                         PV_VERTA_VBP) |
-                          VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
+                          VC4_SET_FIELD(mode->crtc_vsync_end -
+                                        mode->crtc_vsync_start,
                                         PV_VERTA_VSYNC));
                CRTC_WRITE(PV_VERTB_EVEN,
-                          VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
+                          VC4_SET_FIELD(mode->crtc_vsync_start -
+                                        mode->crtc_vdisplay,
                                         PV_VERTB_VFP) |
-                          VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
+                          VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
+
+               /* We set up first field even mode for HDMI.  VEC's
+                * NTSC mode would want first field odd instead, once
+                * we support it (to do so, set ODD_FIRST and put the
+                * delay in VSYNCD_EVEN instead).
+                */
+               CRTC_WRITE(PV_V_CONTROL,
+                          PV_VCONTROL_CONTINUOUS |
+                          PV_VCONTROL_INTERLACE |
+                          VC4_SET_FIELD(mode->htotal * pixel_rep / 2,
+                                        PV_VCONTROL_ODD_DELAY));
+               CRTC_WRITE(PV_VSYNCD_EVEN, 0);
+       } else {
+               CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS);
        }
 
-       CRTC_WRITE(PV_HACT_ACT, mode->hdisplay);
+       CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
 
-       CRTC_WRITE(PV_V_CONTROL,
-                  PV_VCONTROL_CONTINUOUS |
-                  (interlace ? PV_VCONTROL_INTERLACE : 0));
 
        CRTC_WRITE(PV_CONTROL,
                   VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
                   VC4_SET_FIELD(vc4_get_fifo_full_level(format),
                                 PV_CONTROL_FIFO_LEVEL) |
+                  VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) |
                   PV_CONTROL_CLR_AT_START |
                   PV_CONTROL_TRIGGER_UNDERFLOW |
                   PV_CONTROL_WAIT_HSTART |
@@ -544,16 +562,6 @@ static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
                return false;
        }
 
-       /*
-        * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
-        * coming from user space. We don't want this, as it screws up
-        * vblank timestamping, so fix it up.
-        */
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-
-       DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
-       drm_mode_debug_printmodeline(adjusted_mode);
-
        return true;
 }
 
index 428e249..7c1e4d9 100644 (file)
@@ -122,9 +122,16 @@ to_vc4_dev(struct drm_device *dev)
 struct vc4_bo {
        struct drm_gem_cma_object base;
 
-       /* seqno of the last job to render to this BO. */
+       /* seqno of the last job to render using this BO. */
        uint64_t seqno;
 
+       /* seqno of the last job to use the RCL to write to this BO.
+        *
+        * Note that this doesn't include binner overflow memory
+        * writes.
+        */
+       uint64_t write_seqno;
+
        /* List entry for the BO's position in either
         * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
         */
@@ -216,6 +223,9 @@ struct vc4_exec_info {
        /* Sequence number for this bin/render job. */
        uint64_t seqno;
 
+       /* Latest write_seqno of any BO that binning depends on. */
+       uint64_t bin_dep_seqno;
+
        /* Last current addresses the hardware was processing when the
         * hangcheck timer checked on us.
         */
@@ -230,6 +240,13 @@ struct vc4_exec_info {
        struct drm_gem_cma_object **bo;
        uint32_t bo_count;
 
+       /* List of BOs that are being written by the RCL.  Other than
+        * the binner temporary storage, this is all the BOs written
+        * by the job.
+        */
+       struct drm_gem_cma_object *rcl_write_bo[4];
+       uint32_t rcl_write_bo_count;
+
        /* Pointers for our position in vc4->job_list */
        struct list_head head;
 
@@ -307,18 +324,15 @@ struct vc4_exec_info {
 static inline struct vc4_exec_info *
 vc4_first_bin_job(struct vc4_dev *vc4)
 {
-       if (list_empty(&vc4->bin_job_list))
-               return NULL;
-       return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head);
+       return list_first_entry_or_null(&vc4->bin_job_list,
+                                       struct vc4_exec_info, head);
 }
 
 static inline struct vc4_exec_info *
 vc4_first_render_job(struct vc4_dev *vc4)
 {
-       if (list_empty(&vc4->render_job_list))
-               return NULL;
-       return list_first_entry(&vc4->render_job_list,
-                               struct vc4_exec_info, head);
+       return list_first_entry_or_null(&vc4->render_job_list,
+                                       struct vc4_exec_info, head);
 }
 
 static inline struct vc4_exec_info *
index 77daea6..47a095f 100644 (file)
@@ -467,6 +467,11 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
        list_for_each_entry(bo, &exec->unref_list, unref_head) {
                bo->seqno = seqno;
        }
+
+       for (i = 0; i < exec->rcl_write_bo_count; i++) {
+               bo = to_vc4_bo(&exec->rcl_write_bo[i]->base);
+               bo->write_seqno = seqno;
+       }
 }
 
 /* Queues a struct vc4_exec_info for execution.  If no job is
@@ -669,6 +674,14 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
                goto fail;
 
        ret = vc4_validate_shader_recs(dev, exec);
+       if (ret)
+               goto fail;
+
+       /* Block waiting on any previous rendering into the CS's VBO,
+        * IB, or textures, so that pixels are actually written by the
+        * time we try to read them.
+        */
+       ret = vc4_wait_for_seqno(dev, exec->bin_dep_seqno, ~0ull, true);
 
 fail:
        drm_free_large(temp);
index 68ad106..c4cb2e2 100644 (file)
@@ -62,6 +62,8 @@ struct vc4_hdmi {
 struct vc4_hdmi_encoder {
        struct vc4_encoder base;
        bool hdmi_monitor;
+       bool limited_rgb_range;
+       bool rgb_range_selectable;
 };
 
 static inline struct vc4_hdmi_encoder *
@@ -174,6 +176,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                        return connector_status_disconnected;
        }
 
+       if (drm_probe_ddc(vc4->hdmi->ddc))
+               return connector_status_connected;
+
        if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
                return connector_status_connected;
        else
@@ -202,41 +207,22 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
                return -ENODEV;
 
        vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+
+       if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+               vc4_encoder->rgb_range_selectable =
+                       drm_rgb_quant_range_selectable(edid);
+       }
+
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
 
        return ret;
 }
 
-/*
- * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
- * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
- * screws up vblank timestamping for interlaced modes, so fix it up.
- */
-static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
-                                         uint32_t maxX, uint32_t maxY)
-{
-       struct drm_display_mode *mode;
-       int count;
-
-       count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
-       if (count == 0)
-               return 0;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
-                     connector->base.id, connector->name);
-       list_for_each_entry(mode, &connector->modes, head) {
-               drm_mode_set_crtcinfo(mode, 0);
-               drm_mode_debug_printmodeline(mode);
-       }
-
-       return count;
-}
-
 static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .detect = vc4_hdmi_connector_detect,
-       .fill_modes = vc4_hdmi_connector_probe_modes,
+       .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = vc4_hdmi_connector_destroy,
        .reset = drm_atomic_helper_connector_reset,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -294,25 +280,143 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = {
        .destroy = vc4_hdmi_encoder_destroy,
 };
 
+static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
+                               enum hdmi_infoframe_type type)
+{
+       struct drm_device *dev = encoder->dev;
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       u32 packet_id = type - 0x80;
+
+       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
+
+       return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+                         BIT(packet_id)), 100);
+}
+
+static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
+                                    union hdmi_infoframe *frame)
+{
+       struct drm_device *dev = encoder->dev;
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       u32 packet_id = frame->any.type - 0x80;
+       u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
+       uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
+       ssize_t len, i;
+       int ret;
+
+       WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+                   VC4_HDMI_RAM_PACKET_ENABLE),
+                 "Packet RAM has to be on to store the packet.");
+
+       len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
+       if (len < 0)
+               return;
+
+       ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
+       if (ret) {
+               DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
+               return;
+       }
+
+       for (i = 0; i < len; i += 7) {
+               HDMI_WRITE(packet_reg,
+                          buffer[i + 0] << 0 |
+                          buffer[i + 1] << 8 |
+                          buffer[i + 2] << 16);
+               packet_reg += 4;
+
+               HDMI_WRITE(packet_reg,
+                          buffer[i + 3] << 0 |
+                          buffer[i + 4] << 8 |
+                          buffer[i + 5] << 16 |
+                          buffer[i + 6] << 24);
+               packet_reg += 4;
+       }
+
+       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
+       ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+                       BIT(packet_id)), 100);
+       if (ret)
+               DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
+}
+
+static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+       struct drm_crtc *crtc = encoder->crtc;
+       const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       union hdmi_infoframe frame;
+       int ret;
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       if (ret < 0) {
+               DRM_ERROR("couldn't fill AVI infoframe\n");
+               return;
+       }
+
+       if (vc4_encoder->rgb_range_selectable) {
+               if (vc4_encoder->limited_rgb_range) {
+                       frame.avi.quantization_range =
+                               HDMI_QUANTIZATION_RANGE_LIMITED;
+               } else {
+                       frame.avi.quantization_range =
+                               HDMI_QUANTIZATION_RANGE_FULL;
+               }
+       }
+
+       vc4_hdmi_write_infoframe(encoder, &frame);
+}
+
+static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
+{
+       union hdmi_infoframe frame;
+       int ret;
+
+       ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
+       if (ret < 0) {
+               DRM_ERROR("couldn't fill SPD infoframe\n");
+               return;
+       }
+
+       frame.spd.sdi = HDMI_SPD_SDI_PC;
+
+       vc4_hdmi_write_infoframe(encoder, &frame);
+}
+
+static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
+{
+       vc4_hdmi_set_avi_infoframe(encoder);
+       vc4_hdmi_set_spd_infoframe(encoder);
+}
+
 static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
                                      struct drm_display_mode *unadjusted_mode,
                                      struct drm_display_mode *mode)
 {
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
        struct drm_device *dev = encoder->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        bool debug_dump_regs = false;
        bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
        bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
-       u32 vactive = (mode->vdisplay >>
-                      ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0));
-       u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
+       bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
+       u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
+       u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
                                   VC4_HDMI_VERTA_VSP) |
-                    VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
+                    VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
                                   VC4_HDMI_VERTA_VFP) |
-                    VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL));
+                    VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
        u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
-                    VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
+                    VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
                                   VC4_HDMI_VERTB_VBP));
+       u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
+                         VC4_SET_FIELD(mode->crtc_vtotal -
+                                       mode->crtc_vsync_end -
+                                       interlaced,
+                                       VC4_HDMI_VERTB_VBP));
+       u32 csc_ctl;
 
        if (debug_dump_regs) {
                DRM_INFO("HDMI regs before:\n");
@@ -321,7 +425,8 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 
        HD_WRITE(VC4_HD_VID_CTL, 0);
 
-       clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000);
+       clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000 *
+                    ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1));
 
        HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
                   HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
@@ -331,29 +436,62 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        HDMI_WRITE(VC4_HDMI_HORZA,
                   (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
                   (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) |
-                  VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP));
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep,
+                                VC4_HDMI_HORZA_HAP));
 
        HDMI_WRITE(VC4_HDMI_HORZB,
-                  VC4_SET_FIELD(mode->htotal - mode->hsync_end,
+                  VC4_SET_FIELD((mode->htotal -
+                                 mode->hsync_end) * pixel_rep,
                                 VC4_HDMI_HORZB_HBP) |
-                  VC4_SET_FIELD(mode->hsync_end - mode->hsync_start,
+                  VC4_SET_FIELD((mode->hsync_end -
+                                 mode->hsync_start) * pixel_rep,
                                 VC4_HDMI_HORZB_HSP) |
-                  VC4_SET_FIELD(mode->hsync_start - mode->hdisplay,
+                  VC4_SET_FIELD((mode->hsync_start -
+                                 mode->hdisplay) * pixel_rep,
                                 VC4_HDMI_HORZB_HFP));
 
        HDMI_WRITE(VC4_HDMI_VERTA0, verta);
        HDMI_WRITE(VC4_HDMI_VERTA1, verta);
 
-       HDMI_WRITE(VC4_HDMI_VERTB0, vertb);
+       HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even);
        HDMI_WRITE(VC4_HDMI_VERTB1, vertb);
 
        HD_WRITE(VC4_HD_VID_CTL,
                 (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
                 (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
 
+       csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
+                               VC4_HD_CSC_CTL_ORDER);
+
+       if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
+               /* CEA VICs other than #1 requre limited range RGB
+                * output unless overridden by an AVI infoframe.
+                * Apply a colorspace conversion to squash 0-255 down
+                * to 16-235.  The matrix here is:
+                *
+                * [ 0      0      0.8594 16]
+                * [ 0      0.8594 0      16]
+                * [ 0.8594 0      0      16]
+                * [ 0      0      0       1]
+                */
+               csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
+               csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
+               csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
+                                        VC4_HD_CSC_CTL_MODE);
+
+               HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
+               HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
+               HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
+               vc4_encoder->limited_rgb_range = true;
+       } else {
+               vc4_encoder->limited_rgb_range = false;
+       }
+
        /* The RGB order applies even when CSC is disabled. */
-       HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
-                                              VC4_HD_CSC_CTL_ORDER));
+       HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
 
        HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
 
@@ -368,6 +506,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
        struct drm_device *dev = encoder->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
 
+       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
+
        HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
        HD_WRITE(VC4_HD_VID_CTL,
                 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
@@ -394,7 +534,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                           VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
                ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
-                              VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1);
+                              VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        } else {
@@ -406,7 +546,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                           ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
                ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
-                                VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1);
+                                VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        }
@@ -420,9 +560,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                           HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
                           VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
 
-               /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
-                * up the infoframe.
-                */
+               HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+                          VC4_HDMI_RAM_PACKET_ENABLE);
+
+               vc4_hdmi_set_infoframes(encoder);
 
                drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
                drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
index 160942a..1aa44c2 100644 (file)
 # define PV_CONTROL_CLR_AT_START               BIT(14)
 # define PV_CONTROL_TRIGGER_UNDERFLOW          BIT(13)
 # define PV_CONTROL_WAIT_HSTART                        BIT(12)
+# define PV_CONTROL_PIXEL_REP_MASK             VC4_MASK(5, 4)
+# define PV_CONTROL_PIXEL_REP_SHIFT            4
 # define PV_CONTROL_CLK_SELECT_DSI_VEC         0
 # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI    1
 # define PV_CONTROL_CLK_SELECT_MASK            VC4_MASK(3, 2)
 # define PV_CONTROL_EN                         BIT(0)
 
 #define PV_V_CONTROL                           0x04
+# define PV_VCONTROL_ODD_DELAY_MASK            VC4_MASK(22, 6)
+# define PV_VCONTROL_ODD_DELAY_SHIFT           6
+# define PV_VCONTROL_ODD_FIRST                 BIT(5)
 # define PV_VCONTROL_INTERLACE                 BIT(4)
 # define PV_VCONTROL_CONTINUOUS                        BIT(1)
 # define PV_VCONTROL_VIDEN                     BIT(0)
 #define VC4_HDMI_RAM_PACKET_CONFIG             0x0a0
 # define VC4_HDMI_RAM_PACKET_ENABLE            BIT(16)
 
+#define VC4_HDMI_RAM_PACKET_STATUS             0x0a4
+
 #define VC4_HDMI_HORZA                         0x0c4
 # define VC4_HDMI_HORZA_VPOS                   BIT(14)
 # define VC4_HDMI_HORZA_HPOS                   BIT(13)
 
 #define VC4_HDMI_TX_PHY_RESET_CTL              0x2c0
 
+#define VC4_HDMI_GCP_0                         0x400
+#define VC4_HDMI_PACKET_STRIDE                 0x24
+
 #define VC4_HD_M_CTL                           0x00c
 # define VC4_HD_M_REGISTER_FILE_STANDBY                (3 << 6)
 # define VC4_HD_M_RAM_STANDBY                  (3 << 4)
 # define VC4_HD_CSC_CTL_MODE_SHIFT             2
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB   0
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB   1
-# define VC4_HD_CSC_CTL_MODE_CUSTOM            2
+# define VC4_HD_CSC_CTL_MODE_CUSTOM            3
 # define VC4_HD_CSC_CTL_RGB2YCC                        BIT(1)
 # define VC4_HD_CSC_CTL_ENABLE                 BIT(0)
 
+#define VC4_HD_CSC_12_11                       0x044
+#define VC4_HD_CSC_14_13                       0x048
+#define VC4_HD_CSC_22_21                       0x04c
+#define VC4_HD_CSC_24_23                       0x050
+#define VC4_HD_CSC_32_31                       0x054
+#define VC4_HD_CSC_34_33                       0x058
+
 #define VC4_HD_FRAME_COUNT                     0x068
 
 /* HVS display list information. */
index 0f12418..08886a3 100644 (file)
@@ -45,6 +45,8 @@ struct vc4_rcl_setup {
 
        struct drm_gem_cma_object *rcl;
        u32 next_offset;
+
+       u32 next_write_bo_index;
 };
 
 static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
@@ -407,6 +409,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
        if (!*obj)
                return -EINVAL;
 
+       exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
+
        if (surf->offset & 0xf) {
                DRM_ERROR("MSAA write must be 16b aligned.\n");
                return -EINVAL;
@@ -417,7 +421,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
 
 static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
                                 struct drm_gem_cma_object **obj,
-                                struct drm_vc4_submit_rcl_surface *surf)
+                                struct drm_vc4_submit_rcl_surface *surf,
+                                bool is_write)
 {
        uint8_t tiling = VC4_GET_FIELD(surf->bits,
                                       VC4_LOADSTORE_TILE_BUFFER_TILING);
@@ -440,6 +445,9 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
        if (!*obj)
                return -EINVAL;
 
+       if (is_write)
+               exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
+
        if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
                if (surf == &exec->args->zs_write) {
                        DRM_ERROR("general zs write may not be a full-res.\n");
@@ -542,6 +550,8 @@ vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
        if (!*obj)
                return -EINVAL;
 
+       exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
+
        if (tiling > VC4_TILING_FORMAT_LT) {
                DRM_ERROR("Bad tiling format\n");
                return -EINVAL;
@@ -599,15 +609,18 @@ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
        if (ret)
                return ret;
 
-       ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
+       ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read,
+                                   false);
        if (ret)
                return ret;
 
-       ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
+       ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read,
+                                   false);
        if (ret)
                return ret;
 
-       ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
+       ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write,
+                                   true);
        if (ret)
                return ret;
 
index 9ce1d0a..26503e3 100644 (file)
@@ -267,6 +267,9 @@ validate_indexed_prim_list(VALIDATE_ARGS)
        if (!ib)
                return -EINVAL;
 
+       exec->bin_dep_seqno = max(exec->bin_dep_seqno,
+                                 to_vc4_bo(&ib->base)->write_seqno);
+
        if (offset > ib->base.size ||
            (ib->base.size - offset) / index_size < length) {
                DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n",
@@ -555,8 +558,7 @@ static bool
 reloc_tex(struct vc4_exec_info *exec,
          void *uniform_data_u,
          struct vc4_texture_sample_info *sample,
-         uint32_t texture_handle_index)
-
+         uint32_t texture_handle_index, bool is_cs)
 {
        struct drm_gem_cma_object *tex;
        uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
@@ -714,6 +716,11 @@ reloc_tex(struct vc4_exec_info *exec,
 
        *validated_p0 = tex->paddr + p0;
 
+       if (is_cs) {
+               exec->bin_dep_seqno = max(exec->bin_dep_seqno,
+                                         to_vc4_bo(&tex->base)->write_seqno);
+       }
+
        return true;
  fail:
        DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
@@ -835,7 +842,8 @@ validate_gl_shader_rec(struct drm_device *dev,
                        if (!reloc_tex(exec,
                                       uniform_data_u,
                                       &validated_shader->texture_samples[tex],
-                                      texture_handles_u[tex])) {
+                                      texture_handles_u[tex],
+                                      i == 2)) {
                                return -EINVAL;
                        }
                }
@@ -867,6 +875,9 @@ validate_gl_shader_rec(struct drm_device *dev,
                uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
                uint32_t max_index;
 
+               exec->bin_dep_seqno = max(exec->bin_dep_seqno,
+                                         to_vc4_bo(&vbo->base)->write_seqno);
+
                if (state->addr & 0x8)
                        stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
 
index 9cd8838..f6f0c06 100644 (file)
@@ -38,6 +38,7 @@ struct analogix_dp_plat_data {
                         struct drm_connector *);
 };
 
+int analogix_dp_psr_supported(struct device *dev);
 int analogix_dp_enable_psr(struct device *dev);
 int analogix_dp_disable_psr(struct device *dev);
 
index c53dc90..0e99669 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/platform_device.h>
 #include <linux/poll.h>
 #include <linux/ratelimit.h>
+#include <linux/rbtree.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -140,9 +141,8 @@ void drm_dev_printk(const struct device *dev, const char *level,
                    unsigned int category, const char *function_name,
                    const char *prefix, const char *format, ...);
 
-extern __printf(5, 6)
+extern __printf(3, 4)
 void drm_printk(const char *level, unsigned int category,
-               const char *function_name, const char *prefix,
                const char *format, ...);
 
 /***********************************************************************/
@@ -198,8 +198,7 @@ void drm_printk(const char *level, unsigned int category,
        drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\
                       fmt, ##__VA_ARGS__)
 #define DRM_ERROR(fmt, ...)                                            \
-       drm_printk(KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*", fmt,    \
-                  ##__VA_ARGS__)
+       drm_printk(KERN_ERR, DRM_UT_NONE, fmt,  ##__VA_ARGS__)
 
 /**
  * Rate limited error output.  Like DRM_ERROR() but won't flood the log.
@@ -241,38 +240,38 @@ void drm_printk(const char *level, unsigned int category,
 #define DRM_DEV_DEBUG(dev, fmt, args...)                               \
        drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \
                       ##args)
-#define DRM_DEBUG(fmt, args...)                                                \
-       drm_printk(KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, ##args)
+#define DRM_DEBUG(fmt, ...)                                            \
+       drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...)                                \
        drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "",    \
                       fmt, ##args)
-#define DRM_DEBUG_DRIVER(fmt, args...)                                 \
-       drm_printk(KERN_DEBUG, DRM_UT_DRIVER, __func__, "", fmt, ##args)
+#define DRM_DEBUG_DRIVER(fmt, ...)                                     \
+       drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_DEBUG_KMS(dev, fmt, args...)                           \
        drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt,  \
                       ##args)
-#define DRM_DEBUG_KMS(fmt, args...)                                    \
-       drm_printk(KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, ##args)
+#define DRM_DEBUG_KMS(fmt, ...)                                        \
+       drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_DEBUG_PRIME(dev, fmt, args...)                         \
        drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "",     \
                       fmt, ##args)
-#define DRM_DEBUG_PRIME(fmt, args...)                                  \
-       drm_printk(KERN_DEBUG, DRM_UT_PRIME, __func__, "", fmt, ##args)
+#define DRM_DEBUG_PRIME(fmt, ...)                                      \
+       drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...)                                \
        drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "",    \
                       fmt, ##args)
-#define DRM_DEBUG_ATOMIC(fmt, args...)                                 \
-       drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", fmt, ##args)
+#define DRM_DEBUG_ATOMIC(fmt, ...)                                     \
+       drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_DEBUG_VBL(dev, fmt, args...)                           \
        drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt,  \
                       ##args)
-#define DRM_DEBUG_VBL(fmt, args...)                                    \
-       drm_printk(KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, ##args)
+#define DRM_DEBUG_VBL(fmt, ...)                                        \
+       drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__)
 
 #define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...)    \
 ({                                                                     \
@@ -371,10 +370,10 @@ struct drm_pending_event {
                      we deliver the event, for tracing only */
 };
 
-/* initial implementaton using a linked list - todo hashtab */
 struct drm_prime_file_private {
-       struct list_head head;
        struct mutex lock;
+       struct rb_root dmabufs;
+       struct rb_root handles;
 };
 
 /** File private data */
index 51a15de..287a610 100644 (file)
@@ -166,6 +166,17 @@ struct drm_display_info {
         */
        u32 bus_flags;
 
+       /**
+        * @max_tmds_clock: Maximum TMDS clock rate supported by the
+        * sink in kHz. 0 means undefined.
+        */
+       int max_tmds_clock;
+
+       /**
+        * @dvi_dual: Dual-link DVI sink?
+        */
+       bool dvi_dual;
+
        /**
         * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even
         * more stuff redundant with @bus_formats.
@@ -515,8 +526,6 @@ struct drm_cmdline_mode {
  * @encoder_ids: valid encoders for this connector
  * @encoder: encoder driving this connector, if any
  * @eld: EDID-like data, if present
- * @dvi_dual: dual link DVI, if found
- * @max_tmds_clock: max clock rate, if found
  * @latency_present: AV delay info from ELD, if found
  * @video_latency: video latency info from ELD, if found
  * @audio_latency: audio latency info from ELD, if found
@@ -650,8 +659,6 @@ struct drm_connector {
 #define MAX_ELD_BYTES  128
        /* EDID bits */
        uint8_t eld[MAX_ELD_BYTES];
-       bool dvi_dual;
-       int max_tmds_clock;     /* in MHz */
        bool latency_present[2];
        int video_latency[2];   /* [0]: progressive, [1]: interlaced */
        int audio_latency[2];
index a544b75..61932f5 100644 (file)
@@ -109,8 +109,6 @@ struct drm_plane_helper_funcs;
  * @ctm: Transformation matrix
  * @gamma_lut: Lookup table for converting pixel data after the
  *     conversion matrix
- * @event: optional pointer to a DRM event to signal upon completion of the
- *     state update
  * @state: backpointer to global drm_atomic_state
  *
  * Note that the distinction between @enable and @active is rather subtile:
@@ -159,6 +157,46 @@ struct drm_crtc_state {
        struct drm_property_blob *ctm;
        struct drm_property_blob *gamma_lut;
 
+       /**
+        * @event:
+        *
+        * Optional pointer to a DRM event to signal upon completion of the
+        * state update. The driver must send out the event when the atomic
+        * commit operation completes. There are two cases:
+        *
+        *  - The event is for a CRTC which is being disabled through this
+        *    atomic commit. In that case the event can be send out any time
+        *    after the hardware has stopped scanning out the current
+        *    framebuffers. It should contain the timestamp and counter for the
+        *    last vblank before the display pipeline was shut off.
+        *
+        *  - For a CRTC which is enabled at the end of the commit (even when it
+        *    undergoes an full modeset) the vblank timestamp and counter must
+        *    be for the vblank right before the first frame that scans out the
+        *    new set of buffers. Again the event can only be sent out after the
+        *    hardware has stopped scanning out the old buffers.
+        *
+        *  - Events for disabled CRTCs are not allowed, and drivers can ignore
+        *    that case.
+        *
+        * This can be handled by the drm_crtc_send_vblank_event() function,
+        * which the driver should call on the provided event upon completion of
+        * the atomic commit. Note that if the driver supports vblank signalling
+        * and timestamping the vblank counters and timestamps must agree with
+        * the ones returned from page flip events. With the current vblank
+        * helper infrastructure this can be achieved by holding a vblank
+        * reference while the page flip is pending, acquired through
+        * drm_crtc_vblank_get() and released with drm_crtc_vblank_put().
+        * Drivers are free to implement their own vblank counter and timestamp
+        * tracking though, e.g. if they have accurate timestamp registers in
+        * hardware.
+        *
+        * For hardware which supports some means to synchronize vblank
+        * interrupt delivery with committing display state there's also
+        * drm_crtc_arm_vblank_event(). See the documentation of that function
+        * for a detailed discussion of the constraints it needs to be used
+        * safely.
+        */
        struct drm_pending_vblank_event *event;
 
        struct drm_atomic_state *state;
@@ -835,17 +873,9 @@ struct drm_mode_config_funcs {
         * CRTC index supplied in &drm_event to userspace.
         *
         * The drm core will supply a struct &drm_event in the event
-        * member of each CRTC's &drm_crtc_state structure. This can be handled by the
-        * drm_crtc_send_vblank_event() function, which the driver should call on
-        * the provided event upon completion of the atomic commit. Note that if
-        * the driver supports vblank signalling and timestamping the vblank
-        * counters and timestamps must agree with the ones returned from page
-        * flip events. With the current vblank helper infrastructure this can
-        * be achieved by holding a vblank reference while the page flip is
-        * pending, acquired through drm_crtc_vblank_get() and released with
-        * drm_crtc_vblank_put(). Drivers are free to implement their own vblank
-        * counter and timestamp tracking though, e.g. if they have accurate
-        * timestamp registers in hardware.
+        * member of each CRTC's &drm_crtc_state structure. See the
+        * documentation for &drm_crtc_state for more details about the precise
+        * semantics of this event.
         *
         * NOTE:
         *
index e19458d..3c5f599 100644 (file)
@@ -217,6 +217,19 @@ struct drm_fb_helper {
        bool delayed_hotplug;
 };
 
+/**
+ * @DRM_FB_HELPER_DEFAULT_OPS:
+ *
+ * Helper define to register default implementations of drm_fb_helper
+ * functions. To be used in struct fb_ops of drm drivers.
+ */
+#define DRM_FB_HELPER_DEFAULT_OPS \
+       .fb_check_var   = drm_fb_helper_check_var, \
+       .fb_set_par     = drm_fb_helper_set_par, \
+       .fb_setcmap     = drm_fb_helper_setcmap, \
+       .fb_blank       = drm_fb_helper_blank, \
+       .fb_pan_display = drm_fb_helper_pan_display
+
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
                           const struct drm_fb_helper_funcs *funcs);
index 185f8ea..407ca0d 100644 (file)
@@ -396,6 +396,7 @@ header-y += string.h
 header-y += suspend_ioctls.h
 header-y += swab.h
 header-y += synclink.h
+header-y += sync_file.h
 header-y += sysctl.h
 header-y += sysinfo.h
 header-y += target_core_user.h