Merge remote branch 'intel/drm-intel-fixes' of /ssd/git/drm-next into drm-fixes
authorDave Airlie <airlied@redhat.com>
Wed, 2 Feb 2011 01:22:34 +0000 (11:22 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 2 Feb 2011 01:22:34 +0000 (11:22 +1000)
* 'intel/drm-intel-fixes' of /ssd/git/drm-next:
  drm/i915: Only bind to function 0 of the PCI device
  drm/i915: Suppress spurious vblank interrupts
  drm: Avoid leak of adjusted mode along quick set_mode paths
  drm: Simplify and defend later checks when disabling a crtc
  drm: Don't switch fb when disabling an output
  drm/i915: Reset crtc after resume
  drm/i915/crt: Force the initial probe after reset
  drm/i915: Reset state after a GPU reset or resume
  drm: Add an interface to reset the device
  drm/i915/sdvo: If at first we don't succeed in reading the response, wait

drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_sdvo.c
include/drm/drmP.h
include/drm/drm_crtc.h

index 2baa670..654faa8 100644 (file)
@@ -2674,3 +2674,23 @@ out:
        mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
+
+void drm_mode_config_reset(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               if (crtc->funcs->reset)
+                       crtc->funcs->reset(crtc);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->funcs->reset)
+                       encoder->funcs->reset(encoder);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->funcs->reset)
+                       connector->funcs->reset(connector);
+}
+EXPORT_SYMBOL(drm_mode_config_reset);
index 952b3d4..b34cc73 100644 (file)
@@ -343,13 +343,12 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        struct drm_encoder *encoder;
        bool ret = true;
 
-       adjusted_mode = drm_mode_duplicate(dev, mode);
-
        crtc->enabled = drm_helper_crtc_in_use(crtc);
-
        if (!crtc->enabled)
                return true;
 
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+
        saved_hwmode = crtc->hwmode;
        saved_mode = crtc->mode;
        saved_x = crtc->x;
@@ -437,10 +436,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
         */
        drm_calc_timestamping_constants(crtc);
 
-       /* XXX free adjustedmode */
-       drm_mode_destroy(dev, adjusted_mode);
        /* FIXME: add subpixel order */
 done:
+       drm_mode_destroy(dev, adjusted_mode);
        if (!ret) {
                crtc->hwmode = saved_hwmode;
                crtc->mode = saved_mode;
@@ -497,14 +495,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
        crtc_funcs = set->crtc->helper_private;
 
+       if (!set->mode)
+               set->fb = NULL;
+
        if (set->fb) {
                DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
                                set->crtc->base.id, set->fb->base.id,
                                (int)set->num_connectors, set->x, set->y);
        } else {
-               DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
-                               set->crtc->base.id, (int)set->num_connectors,
-                               set->x, set->y);
+               DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
+               set->mode = NULL;
+               set->num_connectors = 0;
        }
 
        dev = set->crtc->dev;
@@ -649,8 +650,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                mode_changed = true;
 
        if (mode_changed) {
-               set->crtc->enabled = (set->mode != NULL);
-               if (set->mode != NULL) {
+               set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
+               if (set->crtc->enabled) {
                        DRM_DEBUG_KMS("attempting to set mode from"
                                        " userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
index 0054e95..3dadfa2 100644 (file)
@@ -1250,7 +1250,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
  */
-void drm_handle_vblank(struct drm_device *dev, int crtc)
+bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
        u32 vblcount;
        s64 diff_ns;
@@ -1258,7 +1258,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        unsigned long irqflags;
 
        if (!dev->num_crtcs)
-               return;
+               return false;
 
        /* Need timestamp lock to prevent concurrent execution with
         * vblank enable/disable, as this would cause inconsistent
@@ -1269,7 +1269,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        /* Vblank irq handling disabled. Nothing to do. */
        if (!dev->vblank_enabled[crtc]) {
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
-               return;
+               return false;
        }
 
        /* Fetch corresponding timestamp for this vblank interval from
@@ -1311,5 +1311,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        drm_handle_vblank_events(dev, crtc);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
index 66796bb..cfb56d0 100644 (file)
@@ -354,6 +354,7 @@ static int i915_drm_thaw(struct drm_device *dev)
                error = i915_gem_init_ringbuffer(dev);
                mutex_unlock(&dev->struct_mutex);
 
+               drm_mode_config_reset(dev);
                drm_irq_install(dev);
 
                /* Resume the modeset for every activated CRTC */
@@ -542,6 +543,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
 
                mutex_unlock(&dev->struct_mutex);
                drm_irq_uninstall(dev);
+               drm_mode_config_reset(dev);
                drm_irq_install(dev);
                mutex_lock(&dev->struct_mutex);
        }
@@ -566,6 +568,14 @@ int i915_reset(struct drm_device *dev, u8 flags)
 static int __devinit
 i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       /* Only bind to function 0 of the device. Early generations
+        * used function 1 as a placeholder for multi-head. This causes
+        * us confusion instead, especially on the systems where both
+        * functions have the same PCI-ID!
+        */
+       if (PCI_FUNC(pdev->devfn))
+               return -ENODEV;
+
        return drm_get_pci_dev(pdev, ent, &driver);
 }
 
index 062f353..97f946d 100644 (file)
@@ -1196,18 +1196,18 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                                intel_finish_page_flip_plane(dev, 1);
                }
 
-               if (pipea_stats & vblank_status) {
+               if (pipea_stats & vblank_status &&
+                   drm_handle_vblank(dev, 0)) {
                        vblank++;
-                       drm_handle_vblank(dev, 0);
                        if (!dev_priv->flip_pending_is_done) {
                                i915_pageflip_stall_check(dev, 0);
                                intel_finish_page_flip(dev, 0);
                        }
                }
 
-               if (pipeb_stats & vblank_status) {
+               if (pipeb_stats & vblank_status &&
+                   drm_handle_vblank(dev, 1)) {
                        vblank++;
-                       drm_handle_vblank(dev, 1);
                        if (!dev_priv->flip_pending_is_done) {
                                i915_pageflip_stall_check(dev, 1);
                                intel_finish_page_flip(dev, 1);
index 17035b8..8a77ff4 100644 (file)
@@ -535,6 +535,15 @@ static int intel_crt_set_property(struct drm_connector *connector,
        return 0;
 }
 
+static void intel_crt_reset(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_crt *crt = intel_attached_crt(connector);
+
+       if (HAS_PCH_SPLIT(dev))
+               crt->force_hotplug_required = 1;
+}
+
 /*
  * Routines for controlling stuff on the analog port
  */
@@ -548,6 +557,7 @@ static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
 };
 
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
+       .reset = intel_crt_reset,
        .dpms = drm_helper_connector_dpms,
        .detect = intel_crt_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
index d7f237d..7e42aa5 100644 (file)
@@ -5551,6 +5551,18 @@ cleanup_work:
        return ret;
 }
 
+static void intel_crtc_reset(struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       /* Reset flags back to the 'unknown' status so that they
+        * will be correctly set on the initial modeset.
+        */
+       intel_crtc->cursor_addr = 0;
+       intel_crtc->dpms_mode = -1;
+       intel_crtc->active = true; /* force the pipe off on setup_init_config */
+}
+
 static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .dpms = intel_crtc_dpms,
        .mode_fixup = intel_crtc_mode_fixup,
@@ -5562,6 +5574,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .reset = intel_crtc_reset,
        .cursor_set = intel_crtc_cursor_set,
        .cursor_move = intel_crtc_cursor_move,
        .gamma_set = intel_crtc_gamma_set,
@@ -5652,9 +5665,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
-       intel_crtc->cursor_addr = 0;
-       intel_crtc->dpms_mode = -1;
-       intel_crtc->active = true; /* force the pipe off on setup_init_config */
+       intel_crtc_reset(&intel_crtc->base);
 
        if (HAS_PCH_SPLIT(dev)) {
                intel_helper_funcs.prepare = ironlake_crtc_prepare;
index 45cd376..6a09c14 100644 (file)
@@ -473,20 +473,6 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
                return false;
        }
 
-       i = 3;
-       while (status == SDVO_CMD_STATUS_PENDING && i--) {
-               if (!intel_sdvo_read_byte(intel_sdvo,
-                                         SDVO_I2C_CMD_STATUS,
-                                         &status))
-                       return false;
-       }
-       if (status != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG_KMS("command returns response %s [%d]\n",
-                             status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
-                             status);
-               return false;
-       }
-
        return true;
 }
 
@@ -497,6 +483,8 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
        u8 status;
        int i;
 
+       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+
        /*
         * The documentation states that all commands will be
         * processed within 15µs, and that we need only poll
@@ -505,14 +493,19 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
         *
         * Check 5 times in case the hardware failed to read the docs.
         */
-       do {
+       if (!intel_sdvo_read_byte(intel_sdvo,
+                                 SDVO_I2C_CMD_STATUS,
+                                 &status))
+               goto log_fail;
+
+       while (status == SDVO_CMD_STATUS_PENDING && retry--) {
+               udelay(15);
                if (!intel_sdvo_read_byte(intel_sdvo,
                                          SDVO_I2C_CMD_STATUS,
                                          &status))
-                       return false;
-       } while (status == SDVO_CMD_STATUS_PENDING && --retry);
+                       goto log_fail;
+       }
 
-       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
                DRM_LOG_KMS("(%s)", cmd_status_names[status]);
        else
@@ -533,7 +526,7 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
        return true;
 
 log_fail:
-       DRM_LOG_KMS("\n");
+       DRM_LOG_KMS("... failed\n");
        return false;
 }
 
@@ -550,6 +543,7 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
 static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
                                              u8 ddc_bus)
 {
+       /* This must be the immediately preceding write before the i2c xfer */
        return intel_sdvo_write_cmd(intel_sdvo,
                                    SDVO_CMD_SET_CONTROL_BUS_SWITCH,
                                    &ddc_bus, 1);
@@ -557,7 +551,10 @@ static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-       return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
+       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
+               return false;
+
+       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
 }
 
 static bool
@@ -859,18 +856,21 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
 
        intel_dip_infoframe_csum(&avi_if);
 
-       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
+       if (!intel_sdvo_set_value(intel_sdvo,
+                                 SDVO_CMD_SET_HBUF_INDEX,
                                  set_buf_index, 2))
                return false;
 
        for (i = 0; i < sizeof(avi_if); i += 8) {
-               if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA,
+               if (!intel_sdvo_set_value(intel_sdvo,
+                                         SDVO_CMD_SET_HBUF_DATA,
                                          data, 8))
                        return false;
                data++;
        }
 
-       return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE,
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_HBUF_TXRATE,
                                    &tx_rate, 1);
 }
 
index a4694c6..fe29aad 100644 (file)
@@ -1367,7 +1367,7 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
 extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
 extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                                     struct timeval *vblanktime);
-extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
 extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern void drm_vblank_off(struct drm_device *dev, int crtc);
index acd7fad..801be59 100644 (file)
@@ -275,6 +275,7 @@ struct drm_pending_vblank_event;
 
 /**
  * drm_crtc_funcs - control CRTCs for a given device
+ * @reset: reset CRTC after state has been invalidate (e.g. resume)
  * @dpms: control display power levels
  * @save: save CRTC state
  * @resore: restore CRTC state
@@ -302,6 +303,8 @@ struct drm_crtc_funcs {
        void (*save)(struct drm_crtc *crtc); /* suspend? */
        /* Restore CRTC state */
        void (*restore)(struct drm_crtc *crtc); /* resume? */
+       /* Reset CRTC state */
+       void (*reset)(struct drm_crtc *crtc);
 
        /* cursor controls */
        int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
@@ -379,6 +382,7 @@ struct drm_crtc {
  * @dpms: set power state (see drm_crtc_funcs above)
  * @save: save connector state
  * @restore: restore connector state
+ * @reset: reset connector after state has been invalidate (e.g. resume)
  * @mode_valid: is this mode valid on the given connector?
  * @mode_fixup: try to fixup proposed mode for this connector
  * @mode_set: set this mode
@@ -396,6 +400,7 @@ struct drm_connector_funcs {
        void (*dpms)(struct drm_connector *connector, int mode);
        void (*save)(struct drm_connector *connector);
        void (*restore)(struct drm_connector *connector);
+       void (*reset)(struct drm_connector *connector);
 
        /* Check to see if anything is attached to the connector.
         * @force is set to false whilst polling, true when checking the
@@ -413,6 +418,7 @@ struct drm_connector_funcs {
 };
 
 struct drm_encoder_funcs {
+       void (*reset)(struct drm_encoder *encoder);
        void (*destroy)(struct drm_encoder *encoder);
 };
 
@@ -656,6 +662,7 @@ extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
                                                   struct drm_display_mode *mode);
 extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
 extern void drm_mode_config_init(struct drm_device *dev);
+extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 extern void drm_mode_set_name(struct drm_display_mode *mode);
 extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);