Merge tag 'topic/drm-misc-2016-01-17' of git://anongit.freedesktop.org/drm-intel...
authorDave Airlie <airlied@redhat.com>
Sun, 17 Jan 2016 21:01:16 +0000 (07:01 +1000)
committerDave Airlie <airlied@redhat.com>
Sun, 17 Jan 2016 21:01:16 +0000 (07:01 +1000)
Since your main drm-next pull isn't out of the door yet I figured I might
as well flush out drm-misc instead of delaying for 4.6. It's really just
random stuff all over, biggest thing probably connector_mask tracking from
Maarten.

* tag 'topic/drm-misc-2016-01-17' of git://anongit.freedesktop.org/drm-intel: (24 commits)
  drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  drm/sysfs: use kobj_to_dev()
  drm/i915: Init power domains early in driver load
  drm: Do not set connector->encoder in drivers
  apple-gmux: Add initial documentation
  drm: move MODULE_PARM_DESC to other file
  drm/edid: index CEA/HDMI mode tables using the VIC
  drm/atomic: Remove drm_atomic_connectors_for_crtc.
  drm/i915: Update connector_mask during readout, v2.
  drm: Remove opencoded drm_gem_object_release_handle()
  drm: Do not set outparam on error during GEM handle allocation
  drm/docs: more leftovers from the big vtable documentation pile
  drm/atomic-helper: Reject legacy flips on a disabled pipe
  drm/atomic: add connector mask to drm_crtc_state.
  drm/tegra: Use __drm_atomic_helper_reset_connector for subclassing connector state, v2.
  drm/atomic: Add __drm_atomic_helper_connector_reset, v2.
  drm/i915: Set connector_state->connector using the helper.
  drm: Use a normal idr allocation for the obj->name
  drm: Only bump object-reference count when adding first handle
  drm: Balance error path for GEM handle allocation
  ...

32 files changed:
Documentation/DocBook/gpu.tmpl
drivers/gpu/drm/bridge/dw-hdmi.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/gma500/power.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/imx/imx-drm-core.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/radeon/radeon_dp_mst.c
drivers/gpu/drm/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/sti/sti_drv.c
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/vga/vga_switcheroo.c
drivers/platform/x86/apple-gmux.c
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_modeset_helper_vtables.h

index 6c6e81a9eaf474937a64311ec07795f003dce777..a8669330b456eff026895af70af1121559998d2e 100644 (file)
@@ -1578,194 +1578,6 @@ void intel_crt_init(struct drm_device *dev)
       To use it, a driver must provide bottom functions for all of the three KMS
       entities.
     </para>
-    <sect2>
-      <title>Legacy CRTC Helper Operations</title>
-      <itemizedlist>
-        <listitem id="drm-helper-crtc-mode-fixup">
-          <synopsis>bool (*mode_fixup)(struct drm_crtc *crtc,
-                       const struct drm_display_mode *mode,
-                       struct drm_display_mode *adjusted_mode);</synopsis>
-          <para>
-            Let CRTCs adjust the requested mode or reject it completely. This
-            operation returns true if the mode is accepted (possibly after being
-            adjusted) or false if it is rejected.
-          </para>
-          <para>
-            The <methodname>mode_fixup</methodname> operation should reject the
-            mode if it can't reasonably use it. The definition of "reasonable"
-            is currently fuzzy in this context. One possible behaviour would be
-            to set the adjusted mode to the panel timings when a fixed-mode
-            panel is used with hardware capable of scaling. Another behaviour
-            would be to accept any input mode and adjust it to the closest mode
-            supported by the hardware (FIXME: This needs to be clarified).
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
-                     struct drm_framebuffer *old_fb)</synopsis>
-          <para>
-            Move the CRTC on the current frame buffer (stored in
-            <literal>crtc-&gt;fb</literal>) to position (x,y). Any of the frame
-            buffer, x position or y position may have been modified.
-          </para>
-          <para>
-            This helper operation is optional. If not provided, the
-            <function>drm_crtc_helper_set_config</function> function will fall
-            back to the <methodname>mode_set</methodname> helper operation.
-          </para>
-          <note><para>
-            FIXME: Why are x and y passed as arguments, as they can be accessed
-            through <literal>crtc-&gt;x</literal> and
-            <literal>crtc-&gt;y</literal>?
-          </para></note>
-        </listitem>
-        <listitem>
-          <synopsis>void (*prepare)(struct drm_crtc *crtc);</synopsis>
-          <para>
-            Prepare the CRTC for mode setting. This operation is called after
-            validating the requested mode. Drivers use it to perform
-            device-specific operations required before setting the new mode.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                struct drm_display_mode *adjusted_mode, int x, int y,
-                struct drm_framebuffer *old_fb);</synopsis>
-          <para>
-            Set a new mode, position and frame buffer. Depending on the device
-            requirements, the mode can be stored internally by the driver and
-            applied in the <methodname>commit</methodname> operation, or
-            programmed to the hardware immediately.
-          </para>
-          <para>
-            The <methodname>mode_set</methodname> operation returns 0 on success
-           or a negative error code if an error occurs.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>void (*commit)(struct drm_crtc *crtc);</synopsis>
-          <para>
-            Commit a mode. This operation is called after setting the new mode.
-            Upon return the device must use the new mode and be fully
-            operational.
-          </para>
-        </listitem>
-      </itemizedlist>
-    </sect2>
-    <sect2>
-      <title>Encoder Helper Operations</title>
-      <itemizedlist>
-        <listitem>
-          <synopsis>bool (*mode_fixup)(struct drm_encoder *encoder,
-                       const struct drm_display_mode *mode,
-                       struct drm_display_mode *adjusted_mode);</synopsis>
-          <para>
-            Let encoders adjust the requested mode or reject it completely. This
-            operation returns true if the mode is accepted (possibly after being
-            adjusted) or false if it is rejected. See the
-            <link linkend="drm-helper-crtc-mode-fixup">mode_fixup CRTC helper
-            operation</link> for an explanation of the allowed adjustments.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>void (*prepare)(struct drm_encoder *encoder);</synopsis>
-          <para>
-            Prepare the encoder for mode setting. This operation is called after
-            validating the requested mode. Drivers use it to perform
-            device-specific operations required before setting the new mode.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>void (*mode_set)(struct drm_encoder *encoder,
-                 struct drm_display_mode *mode,
-                 struct drm_display_mode *adjusted_mode);</synopsis>
-          <para>
-            Set a new mode. Depending on the device requirements, the mode can
-            be stored internally by the driver and applied in the
-            <methodname>commit</methodname> operation, or programmed to the
-            hardware immediately.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>void (*commit)(struct drm_encoder *encoder);</synopsis>
-          <para>
-            Commit a mode. This operation is called after setting the new mode.
-            Upon return the device must use the new mode and be fully
-            operational.
-          </para>
-        </listitem>
-      </itemizedlist>
-    </sect2>
-    <sect2>
-      <title>Connector Helper Operations</title>
-      <itemizedlist>
-        <listitem>
-          <synopsis>struct drm_encoder *(*best_encoder)(struct drm_connector *connector);</synopsis>
-          <para>
-            Return a pointer to the best encoder for the connecter. Device that
-            map connectors to encoders 1:1 simply return the pointer to the
-            associated encoder. This operation is mandatory.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>int (*get_modes)(struct drm_connector *connector);</synopsis>
-          <para>
-            Fill the connector's <structfield>probed_modes</structfield> list
-            by parsing EDID data with <function>drm_add_edid_modes</function>,
-            adding standard VESA DMT modes with <function>drm_add_modes_noedid</function>,
-            or calling <function>drm_mode_probed_add</function> directly for every
-            supported mode and return the number of modes it has detected. This
-            operation is mandatory.
-          </para>
-          <para>
-            Note that the caller function will automatically add standard VESA
-            DMT modes up to 1024x768 if the <methodname>get_modes</methodname>
-            helper operation returns no mode and if the connector status is
-            connector_status_connected. There is no need to call
-            <function>drm_add_edid_modes</function> manually in that case.
-          </para>
-          <para>
-            The <structfield>vrefresh</structfield> value is computed by
-            <function>drm_helper_probe_single_connector_modes</function>.
-          </para>
-          <para>
-            When parsing EDID data, <function>drm_add_edid_modes</function> fills the
-            connector <structfield>display_info</structfield>
-            <structfield>width_mm</structfield> and
-            <structfield>height_mm</structfield> fields. When creating modes
-            manually the <methodname>get_modes</methodname> helper operation must
-            set the <structfield>display_info</structfield>
-            <structfield>width_mm</structfield> and
-            <structfield>height_mm</structfield> fields if they haven't been set
-            already (for instance at initialization time when a fixed-size panel is
-            attached to the connector). The mode <structfield>width_mm</structfield>
-            and <structfield>height_mm</structfield> fields are only used internally
-            during EDID parsing and should not be set when creating modes manually.
-          </para>
-        </listitem>
-        <listitem>
-          <synopsis>int (*mode_valid)(struct drm_connector *connector,
-                 struct drm_display_mode *mode);</synopsis>
-          <para>
-            Verify whether a mode is valid for the connector. Return MODE_OK for
-            supported modes and one of the enum drm_mode_status values (MODE_*)
-            for unsupported modes. This operation is optional.
-          </para>
-          <para>
-            As the mode rejection reason is currently not used beside for
-            immediately removing the unsupported mode, an implementation can
-            return MODE_BAD regardless of the exact reason why the mode is not
-            valid.
-          </para>
-          <note><para>
-            Note that the <methodname>mode_valid</methodname> helper operation is
-            only called for modes detected by the device, and
-            <emphasis>not</emphasis> for modes set by the user through the CRTC
-            <methodname>set_config</methodname> operation.
-          </para></note>
-        </listitem>
-      </itemizedlist>
-    </sect2>
     <sect2>
       <title>Atomic Modeset Helper Functions Reference</title>
       <sect3>
@@ -3625,41 +3437,63 @@ int num_ioctls;</synopsis>
 
   <chapter id="modes_of_use">
     <title>Modes of Use</title>
-  <sect1>
-    <title>Manual switching and manual power control</title>
+    <sect1>
+      <title>Manual switching and manual power control</title>
 !Pdrivers/gpu/vga/vga_switcheroo.c Manual switching and manual power control
-  </sect1>
-  <sect1>
-    <title>Driver power control</title>
+    </sect1>
+    <sect1>
+      <title>Driver power control</title>
 !Pdrivers/gpu/vga/vga_switcheroo.c Driver power control
-  </sect1>
+    </sect1>
   </chapter>
 
-  <chapter id="pubfunctions">
-    <title>Public functions</title>
+  <chapter id="api">
+    <title>API</title>
+    <sect1>
+      <title>Public functions</title>
 !Edrivers/gpu/vga/vga_switcheroo.c
-  </chapter>
-
-  <chapter id="pubstructures">
-    <title>Public structures</title>
+    </sect1>
+    <sect1>
+      <title>Public structures</title>
 !Finclude/linux/vga_switcheroo.h vga_switcheroo_handler
 !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_ops
-  </chapter>
-
-  <chapter id="pubconstants">
-    <title>Public constants</title>
+    </sect1>
+    <sect1>
+      <title>Public constants</title>
 !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id
 !Finclude/linux/vga_switcheroo.h vga_switcheroo_state
-  </chapter>
-
-  <chapter id="privstructures">
-    <title>Private structures</title>
+    </sect1>
+    <sect1>
+      <title>Private structures</title>
 !Fdrivers/gpu/vga/vga_switcheroo.c vgasr_priv
 !Fdrivers/gpu/vga/vga_switcheroo.c vga_switcheroo_client
+    </sect1>
+  </chapter>
+
+  <chapter id="handlers">
+    <title>Handlers</title>
+    <sect1>
+      <title>apple-gmux Handler</title>
+!Pdrivers/platform/x86/apple-gmux.c Overview
+!Pdrivers/platform/x86/apple-gmux.c Interrupt
+      <sect2>
+        <title>Graphics mux</title>
+!Pdrivers/platform/x86/apple-gmux.c Graphics mux
+      </sect2>
+      <sect2>
+        <title>Power control</title>
+!Pdrivers/platform/x86/apple-gmux.c Power control
+      </sect2>
+      <sect2>
+        <title>Backlight control</title>
+!Pdrivers/platform/x86/apple-gmux.c Backlight control
+      </sect2>
+    </sect1>
   </chapter>
 
 !Cdrivers/gpu/vga/vga_switcheroo.c
 !Cinclude/linux/vga_switcheroo.h
+!Cdrivers/platform/x86/apple-gmux.c
 </part>
 
 </book>
index 6fbec99e59c2bd1667485417eae397fa0023764f..b0aac4733020e337b5cc0e99a51ac4ab67f15ba3 100644 (file)
@@ -1667,8 +1667,6 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
                                   &dw_hdmi_connector_funcs,
                                   DRM_MODE_CONNECTOR_HDMIA);
 
-       hdmi->connector.encoder = encoder;
-
        drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
 
        return 0;
index 6a21e5c378c1a2e5daa2d0197f0a304aa5336b10..3f74193885f1ff1df95db09fa76e01174f6353b4 100644 (file)
@@ -508,6 +508,22 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       /*
+        * Reject event generation for when a CRTC is off and stays off.
+        * It wouldn't be hard to implement this, but userspace has a track
+        * record of happily burning through 100% cpu (or worse, crash) when the
+        * display pipe is suspended. To avoid all that fun just reject updates
+        * that ask for events since likely that indicates a bug in the
+        * compositor's drawing loop. This is consistent with the vblank IOCTL
+        * and legacy page_flip IOCTL which also reject service on a disabled
+        * pipe.
+        */
+       if (state->event && !state->active && !crtc->state->active) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] requesting event but off\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -1063,10 +1079,21 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 {
        struct drm_crtc_state *crtc_state;
 
+       if (conn_state->crtc && conn_state->crtc != crtc) {
+               crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state,
+                                                               conn_state->crtc);
+
+               crtc_state->connector_mask &=
+                       ~(1 << drm_connector_index(conn_state->connector));
+       }
+
        if (crtc) {
                crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
                if (IS_ERR(crtc_state))
                        return PTR_ERR(crtc_state);
+
+               crtc_state->connector_mask |=
+                       1 << drm_connector_index(conn_state->connector);
        }
 
        conn_state->crtc = crtc;
@@ -1171,36 +1198,6 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_add_affected_planes);
 
-/**
- * drm_atomic_connectors_for_crtc - count number of connected outputs
- * @state: atomic state
- * @crtc: DRM crtc
- *
- * This function counts all connectors which will be connected to @crtc
- * according to @state. Useful to recompute the enable state for @crtc.
- */
-int
-drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
-                              struct drm_crtc *crtc)
-{
-       struct drm_connector *connector;
-       struct drm_connector_state *conn_state;
-
-       int i, num_connected_connectors = 0;
-
-       for_each_connector_in_state(state, connector, conn_state, i) {
-               if (conn_state->crtc == crtc)
-                       num_connected_connectors++;
-       }
-
-       DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d:%s]\n",
-                        state, num_connected_connectors,
-                        crtc->base.id, crtc->name);
-
-       return num_connected_connectors;
-}
-EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
-
 /**
  * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
  * @state: atomic state
index 268d37f26960f681266790d41d104c4a353c11b6..57cccd68ca522548c6c098ee72798a5b3369def0 100644 (file)
@@ -463,7 +463,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
         * crtc only changed its mode but has the same set of connectors.
         */
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               int num_connectors;
+               bool has_connectors =
+                       !!crtc_state->connector_mask;
 
                /*
                 * We must set ->active_changed after walking connectors for
@@ -492,10 +493,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                if (ret != 0)
                        return ret;
 
-               num_connectors = drm_atomic_connectors_for_crtc(state,
-                                                               crtc);
-
-               if (crtc_state->enable != !!num_connectors) {
+               if (crtc_state->enable != has_connectors) {
                        DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n",
                                         crtc->base.id, crtc->name);
 
@@ -1754,7 +1752,7 @@ static int update_output_state(struct drm_atomic_state *state,
                if (crtc == set->crtc)
                        continue;
 
-               if (!drm_atomic_connectors_for_crtc(state, crtc)) {
+               if (!crtc_state->connector_mask) {
                        ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
                                                                NULL);
                        if (ret < 0)
@@ -2284,6 +2282,15 @@ retry:
                goto fail;
        drm_atomic_set_fb_for_plane(plane_state, fb);
 
+       /* Make sure we don't accidentally do a full modeset. */
+       state->allow_modeset = false;
+       if (!crtc_state->active) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
+                                crtc->base.id);
+               ret = -EINVAL;
+               goto fail;
+       }
+
        ret = drm_atomic_async_commit(state);
        if (ret != 0)
                goto fail;
@@ -2605,6 +2612,28 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
 
+/**
+ * __drm_atomic_helper_connector_reset - reset state on connector
+ * @connector: drm connector
+ * @conn_state: connector state to assign
+ *
+ * Initializes the newly allocated @conn_state and assigns it to
+ * #connector ->state, usually required when initializing the drivers
+ * or when called from the ->reset hook.
+ *
+ * This is useful for drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_reset(struct drm_connector *connector,
+                                   struct drm_connector_state *conn_state)
+{
+       if (conn_state)
+               conn_state->connector = connector;
+
+       connector->state = conn_state;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
+
 /**
  * drm_atomic_helper_connector_reset - default ->reset hook for connectors
  * @connector: drm connector
@@ -2615,11 +2644,11 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
  */
 void drm_atomic_helper_connector_reset(struct drm_connector *connector)
 {
-       kfree(connector->state);
-       connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+       struct drm_connector_state *conn_state =
+               kzalloc(sizeof(*conn_state), GFP_KERNEL);
 
-       if (connector->state)
-               connector->state->connector = connector;
+       kfree(connector->state);
+       __drm_atomic_helper_connector_reset(connector, conn_state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
index 62fa95fa547118f2d47fbb6b62ab811412e6e67b..d40bab29747edb0ea989afd81b0e5b5102dfb555 100644 (file)
@@ -5054,6 +5054,20 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector,
 {
        int i;
 
+       /*
+        * In the past, drivers have attempted to model the static association
+        * of connector to encoder in simple connector/encoder devices using a
+        * direct assignment of connector->encoder = encoder. This connection
+        * is a logical one and the responsibility of the core, so drivers are
+        * expected not to mess with this.
+        *
+        * Note that the error return should've been enough here, but a large
+        * majority of drivers ignores the return value, so add in a big WARN
+        * to get people's attention.
+        */
+       if (WARN_ON(connector->encoder))
+               return -EINVAL;
+
        for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
                if (connector->encoder_ids[i] == 0) {
                        connector->encoder_ids[i] = encoder->base.id;
index bf934cdea21c9b277c5b8f2ee6cc75581c9f1a3a..167c8d3d4a31e7fd14006fa5dedd946fb221301e 100644 (file)
@@ -44,10 +44,6 @@ MODULE_AUTHOR(CORE_AUTHOR);
 MODULE_DESCRIPTION(CORE_DESC);
 MODULE_LICENSE("GPL and additional rights");
 MODULE_PARM_DESC(debug, "Enable debug output");
-MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
-MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
-MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
-
 module_param_named(debug, drm_debug, int, 0600);
 
 static DEFINE_SPINLOCK(drm_minor_lock);
index c214f1246cb4eaeac86b655af8b44c4dcc7fa5e5..04cb4877fabd89d8e27f16c073912a97e199718e 100644 (file)
@@ -637,8 +637,12 @@ static const struct minimode extra_modes[] = {
 /*
  * Probably taken from CEA-861 spec.
  * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
+ *
+ * Index using the VIC.
  */
 static const struct drm_display_mode edid_cea_modes[] = {
+       /* 0 - dummy, VICs start at 1 */
+       { },
        /* 1 - 640x480@60Hz */
        { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
                   752, 800, 0, 480, 490, 492, 525, 0,
@@ -987,9 +991,11 @@ static const struct drm_display_mode edid_cea_modes[] = {
 };
 
 /*
- * HDMI 1.4 4k modes.
+ * HDMI 1.4 4k modes. Index using the VIC.
  */
 static const struct drm_display_mode edid_4k_modes[] = {
+       /* 0 - dummy, VICs start at 1 */
+       { },
        /* 1 - 3840x2160@30Hz */
        { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
                   3840, 4016, 4104, 4400, 0,
@@ -2548,13 +2554,13 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
 static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match,
                                             unsigned int clock_tolerance)
 {
-       u8 mode;
+       u8 vic;
 
        if (!to_match->clock)
                return 0;
 
-       for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
-               const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
+       for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) {
+               const struct drm_display_mode *cea_mode = &edid_cea_modes[vic];
                unsigned int clock1, clock2;
 
                /* Check both 60Hz and 59.94Hz */
@@ -2566,7 +2572,7 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m
                        continue;
 
                if (drm_mode_equal_no_clocks(to_match, cea_mode))
-                       return mode + 1;
+                       return vic;
        }
 
        return 0;
@@ -2581,13 +2587,13 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m
  */
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
 {
-       u8 mode;
+       u8 vic;
 
        if (!to_match->clock)
                return 0;
 
-       for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
-               const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
+       for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) {
+               const struct drm_display_mode *cea_mode = &edid_cea_modes[vic];
                unsigned int clock1, clock2;
 
                /* Check both 60Hz and 59.94Hz */
@@ -2597,12 +2603,17 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
                if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
                     KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
                    drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode))
-                       return mode + 1;
+                       return vic;
        }
        return 0;
 }
 EXPORT_SYMBOL(drm_match_cea_mode);
 
+static bool drm_valid_cea_vic(u8 vic)
+{
+       return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes);
+}
+
 /**
  * drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to
  * the input VIC from the CEA mode list
@@ -2612,10 +2623,7 @@ EXPORT_SYMBOL(drm_match_cea_mode);
  */
 enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code)
 {
-       /* return picture aspect ratio for video_code - 1 to access the
-        * right array element
-       */
-       return edid_cea_modes[video_code-1].picture_aspect_ratio;
+       return edid_cea_modes[video_code].picture_aspect_ratio;
 }
 EXPORT_SYMBOL(drm_get_cea_aspect_ratio);
 
@@ -2639,13 +2647,13 @@ hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode)
 static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match,
                                              unsigned int clock_tolerance)
 {
-       u8 mode;
+       u8 vic;
 
        if (!to_match->clock)
                return 0;
 
-       for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
-               const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
+       for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) {
+               const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic];
                unsigned int clock1, clock2;
 
                /* Make sure to also match alternate clocks */
@@ -2657,7 +2665,7 @@ static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_
                        continue;
 
                if (drm_mode_equal_no_clocks(to_match, hdmi_mode))
-                       return mode + 1;
+                       return vic;
        }
 
        return 0;
@@ -2673,13 +2681,13 @@ static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_
  */
 static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)
 {
-       u8 mode;
+       u8 vic;
 
        if (!to_match->clock)
                return 0;
 
-       for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
-               const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
+       for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) {
+               const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic];
                unsigned int clock1, clock2;
 
                /* Make sure to also match alternate clocks */
@@ -2689,11 +2697,16 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)
                if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
                     KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
                    drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode))
-                       return mode + 1;
+                       return vic;
        }
        return 0;
 }
 
+static bool drm_valid_hdmi_vic(u8 vic)
+{
+       return vic > 0 && vic < ARRAY_SIZE(edid_4k_modes);
+}
+
 static int
 add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
 {
@@ -2713,16 +2726,16 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
        list_for_each_entry(mode, &connector->probed_modes, head) {
                const struct drm_display_mode *cea_mode = NULL;
                struct drm_display_mode *newmode;
-               u8 mode_idx = drm_match_cea_mode(mode) - 1;
+               u8 vic = drm_match_cea_mode(mode);
                unsigned int clock1, clock2;
 
-               if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
-                       cea_mode = &edid_cea_modes[mode_idx];
+               if (drm_valid_cea_vic(vic)) {
+                       cea_mode = &edid_cea_modes[vic];
                        clock2 = cea_mode_alternate_clock(cea_mode);
                } else {
-                       mode_idx = drm_match_hdmi_mode(mode) - 1;
-                       if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
-                               cea_mode = &edid_4k_modes[mode_idx];
+                       vic = drm_match_hdmi_mode(mode);
+                       if (drm_valid_hdmi_vic(vic)) {
+                               cea_mode = &edid_4k_modes[vic];
                                clock2 = hdmi_mode_alternate_clock(cea_mode);
                        }
                }
@@ -2773,17 +2786,17 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
 {
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *newmode;
-       u8 cea_mode;
+       u8 vic;
 
        if (video_db == NULL || video_index >= video_len)
                return NULL;
 
        /* CEA modes are numbered 1..127 */
-       cea_mode = (video_db[video_index] & 127) - 1;
-       if (cea_mode >= ARRAY_SIZE(edid_cea_modes))
+       vic = (video_db[video_index] & 127);
+       if (!drm_valid_cea_vic(vic))
                return NULL;
 
-       newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+       newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]);
        if (!newmode)
                return NULL;
 
@@ -2878,8 +2891,7 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic)
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *newmode;
 
-       vic--; /* VICs start at 1 */
-       if (vic >= ARRAY_SIZE(edid_4k_modes)) {
+       if (!drm_valid_hdmi_vic(vic)) {
                DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
                return 0;
        }
@@ -3170,24 +3182,24 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
 {
        const struct drm_display_mode *cea_mode;
        int clock1, clock2, clock;
-       u8 mode_idx;
+       u8 vic;
        const char *type;
 
        /*
         * allow 5kHz clock difference either way to account for
         * the 10kHz clock resolution limit of detailed timings.
         */
-       mode_idx = drm_match_cea_mode_clock_tolerance(mode, 5) - 1;
-       if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
+       vic = drm_match_cea_mode_clock_tolerance(mode, 5);
+       if (drm_valid_cea_vic(vic)) {
                type = "CEA";
-               cea_mode = &edid_cea_modes[mode_idx];
+               cea_mode = &edid_cea_modes[vic];
                clock1 = cea_mode->clock;
                clock2 = cea_mode_alternate_clock(cea_mode);
        } else {
-               mode_idx = drm_match_hdmi_mode_clock_tolerance(mode, 5) - 1;
-               if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
+               vic = drm_match_hdmi_mode_clock_tolerance(mode, 5);
+               if (drm_valid_hdmi_vic(vic)) {
                        type = "HDMI";
-                       cea_mode = &edid_4k_modes[mode_idx];
+                       cea_mode = &edid_4k_modes[vic];
                        clock1 = cea_mode->clock;
                        clock2 = hdmi_mode_alternate_clock(cea_mode);
                } else {
@@ -3205,7 +3217,7 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
                return;
 
        DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
-                 type, mode_idx + 1, mode->clock, clock);
+                 type, vic, mode->clock, clock);
        mode->clock = clock;
 }
 
index 5543fa806aec1888deb2d96e3ea351bfdf17a1e8..c895b6fddbd818052335dff264cfe9685fc3af67 100644 (file)
@@ -348,9 +348,6 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
 
        }
 
-       /* disable all the possible outputs/crtcs before entering KMS mode */
-       drm_helper_disable_unused_functions(dev);
-
        ret = drm_fb_helper_initial_config(helper, preferred_bpp);
        if (ret < 0) {
                dev_err(dev->dev, "Failed to set initial hw configuration.\n");
index 69cbab5e5c81f29008247776d81447f21aede835..1e103c4c6ee056d5011178bbbe8675d490f94a8f 100644 (file)
@@ -1251,7 +1251,7 @@ retry:
                        goto fail;
 
                plane = mode_set->crtc->primary;
-               plane_mask |= drm_plane_index(plane);
+               plane_mask |= (1 << drm_plane_index(plane));
                plane->old_fb = plane->fb;
        }
 
index 2e10bba4468b0c6b65aee0d07fa279295c52d2b2..2e8c77e71e1f699fc2837f2b5d67d24e52729a6d 100644 (file)
@@ -220,6 +220,9 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
 static void
 drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
 {
+       struct drm_device *dev = obj->dev;
+       bool final = false;
+
        if (WARN_ON(obj->handle_count == 0))
                return;
 
@@ -229,14 +232,39 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
        * checked for a name
        */
 
-       mutex_lock(&obj->dev->object_name_lock);
+       mutex_lock(&dev->object_name_lock);
        if (--obj->handle_count == 0) {
                drm_gem_object_handle_free(obj);
                drm_gem_object_exported_dma_buf_free(obj);
+               final = true;
        }
-       mutex_unlock(&obj->dev->object_name_lock);
+       mutex_unlock(&dev->object_name_lock);
 
-       drm_gem_object_unreference_unlocked(obj);
+       if (final)
+               drm_gem_object_unreference_unlocked(obj);
+}
+
+/*
+ * Called at device or object close to release the file's
+ * handle references on objects.
+ */
+static int
+drm_gem_object_release_handle(int id, void *ptr, void *data)
+{
+       struct drm_file *file_priv = data;
+       struct drm_gem_object *obj = ptr;
+       struct drm_device *dev = obj->dev;
+
+       if (drm_core_check_feature(dev, DRIVER_PRIME))
+               drm_gem_remove_prime_handles(obj, file_priv);
+       drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+
+       if (dev->driver->gem_close_object)
+               dev->driver->gem_close_object(obj, file_priv);
+
+       drm_gem_object_handle_unreference_unlocked(obj);
+
+       return 0;
 }
 
 /**
@@ -277,14 +305,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
        idr_remove(&filp->object_idr, handle);
        spin_unlock(&filp->table_lock);
 
-       if (drm_core_check_feature(dev, DRIVER_PRIME))
-               drm_gem_remove_prime_handles(obj, filp);
-       drm_vma_node_revoke(&obj->vma_node, filp->filp);
-
-       if (dev->driver->gem_close_object)
-               dev->driver->gem_close_object(obj, filp);
-       drm_gem_object_handle_unreference_unlocked(obj);
-
+       drm_gem_object_release_handle(handle, obj, filp);
        return 0;
 }
 EXPORT_SYMBOL(drm_gem_handle_delete);
@@ -326,9 +347,12 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
                           u32 *handlep)
 {
        struct drm_device *dev = obj->dev;
+       u32 handle;
        int ret;
 
        WARN_ON(!mutex_is_locked(&dev->object_name_lock));
+       if (obj->handle_count++ == 0)
+               drm_gem_object_reference(obj);
 
        /*
         * Get the user-visible handle using idr.  Preload and perform
@@ -338,32 +362,38 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
        spin_lock(&file_priv->table_lock);
 
        ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
-       drm_gem_object_reference(obj);
-       obj->handle_count++;
+
        spin_unlock(&file_priv->table_lock);
        idr_preload_end();
+
        mutex_unlock(&dev->object_name_lock);
-       if (ret < 0) {
-               drm_gem_object_handle_unreference_unlocked(obj);
-               return ret;
-       }
-       *handlep = ret;
+       if (ret < 0)
+               goto err_unref;
+
+       handle = ret;
 
        ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
-       if (ret) {
-               drm_gem_handle_delete(file_priv, *handlep);
-               return ret;
-       }
+       if (ret)
+               goto err_remove;
 
        if (dev->driver->gem_open_object) {
                ret = dev->driver->gem_open_object(obj, file_priv);
-               if (ret) {
-                       drm_gem_handle_delete(file_priv, *handlep);
-                       return ret;
-               }
+               if (ret)
+                       goto err_revoke;
        }
 
+       *handlep = handle;
        return 0;
+
+err_revoke:
+       drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+err_remove:
+       spin_lock(&file_priv->table_lock);
+       idr_remove(&file_priv->object_idr, handle);
+       spin_unlock(&file_priv->table_lock);
+err_unref:
+       drm_gem_object_handle_unreference_unlocked(obj);
+       return ret;
 }
 
 /**
@@ -630,7 +660,6 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
 
        mutex_lock(&dev->object_name_lock);
-       idr_preload(GFP_KERNEL);
        /* prevent races with concurrent gem_close. */
        if (obj->handle_count == 0) {
                ret = -ENOENT;
@@ -638,7 +667,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
        }
 
        if (!obj->name) {
-               ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_NOWAIT);
+               ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_KERNEL);
                if (ret < 0)
                        goto err;
 
@@ -649,7 +678,6 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
        ret = 0;
 
 err:
-       idr_preload_end();
        mutex_unlock(&dev->object_name_lock);
        drm_gem_object_unreference_unlocked(obj);
        return ret;
@@ -714,29 +742,6 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
        spin_lock_init(&file_private->table_lock);
 }
 
-/*
- * Called at device close to release the file's
- * handle references on objects.
- */
-static int
-drm_gem_object_release_handle(int id, void *ptr, void *data)
-{
-       struct drm_file *file_priv = data;
-       struct drm_gem_object *obj = ptr;
-       struct drm_device *dev = obj->dev;
-
-       if (drm_core_check_feature(dev, DRIVER_PRIME))
-               drm_gem_remove_prime_handles(obj, file_priv);
-       drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
-
-       if (dev->driver->gem_close_object)
-               dev->driver->gem_close_object(obj, file_priv);
-
-       drm_gem_object_handle_unreference_unlocked(obj);
-
-       return 0;
-}
-
 /**
  * drm_gem_release - release file-private GEM resources
  * @dev: drm_device which is being closed by userspace
index 607f493ae80132890ad97422f58f9cdf95eefc75..d12a4efa651b015179f776e1fc056da96dc1faf0 100644 (file)
@@ -73,6 +73,9 @@ static int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
 module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
 module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
 module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
+MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
+MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
+MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
 
 static void store_vblank(struct drm_device *dev, unsigned int pipe,
                         u32 vblank_count_inc,
index 0ca64106a97b82500fe4942c9962189bcd6b66c7..d503f8e8c2d1c44cb66fa61ee56c02e7975013f2 100644 (file)
@@ -240,7 +240,7 @@ static ssize_t edid_show(struct file *filp, struct kobject *kobj,
                         struct bin_attribute *attr, char *buf, loff_t off,
                         size_t count)
 {
-       struct device *connector_dev = container_of(kobj, struct device, kobj);
+       struct device *connector_dev = kobj_to_dev(kobj);
        struct drm_connector *connector = to_drm_connector(connector_dev);
        unsigned char *edid;
        size_t size;
index b6b135fcd59c54d3f0f69d5027fe974f81fbfd86..bea8578846d1577feba1d812773d7f8548d8306e 100644 (file)
@@ -187,7 +187,7 @@ static bool gma_resume_pci(struct pci_dev *pdev)
  */
 int gma_power_suspend(struct device *_dev)
 {
-       struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev);
+       struct pci_dev *pdev = to_pci_dev(_dev);
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_psb_private *dev_priv = dev->dev_private;
 
@@ -214,7 +214,7 @@ int gma_power_suspend(struct device *_dev)
  */
 int gma_power_resume(struct device *_dev)
 {
-       struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev);
+       struct pci_dev *pdev = to_pci_dev(_dev);
        struct drm_device *dev = pci_get_drvdata(pdev);
 
        mutex_lock(&power_mutex);
index 012d36d9a75b983e5e5a59216ffcba66002adf19..34e38749a8176f87001e54cb4ea8a7cc86fa744e 100644 (file)
@@ -1446,7 +1446,6 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
        if (ret)
                goto err_sysfs;
 
-       priv->connector.encoder = &priv->encoder;
        drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
 
        return 0;
index 988a3806512ada739d2b93d8190dac9f3ad50354..d70d96fe553bb65515540f048bdfe224f15a48e6 100644 (file)
@@ -406,6 +406,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_gem_stolen;
 
+       intel_setup_gmbus(dev);
+
        /* Important: The output setup functions called by modeset_init need
         * working irqs for e.g. gmbus and dp aux transfers. */
        intel_modeset_init(dev);
@@ -455,6 +457,7 @@ cleanup_gem:
 cleanup_irq:
        intel_guc_ucode_fini(dev);
        drm_irq_uninstall(dev);
+       intel_teardown_gmbus(dev);
 cleanup_gem_stolen:
        i915_gem_cleanup_stolen(dev);
 cleanup_vga_switcheroo:
@@ -1028,7 +1031,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        /* Try to make sure MCHBAR is enabled before poking at it */
        intel_setup_mchbar(dev);
-       intel_setup_gmbus(dev);
        intel_opregion_setup(dev);
 
        i915_gem_load(dev);
@@ -1101,7 +1103,6 @@ out_gem_unload:
        if (dev->pdev->msi_enabled)
                pci_disable_msi(dev->pdev);
 
-       intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
        pm_qos_remove_request(&dev_priv->pm_qos);
        destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
@@ -1203,7 +1204,6 @@ int i915_driver_unload(struct drm_device *dev)
 
        intel_csr_ucode_fini(dev_priv);
 
-       intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
 
        destroy_workqueue(dev_priv->hotplug.dp_wq);
index 02f6ccb848a9f37a902a1439256c1888e13b2caf..ceaea7a3641a2aa2eb61bb5ee9a2cc639559e6b3 100644 (file)
@@ -6492,13 +6492,11 @@ static void intel_connector_check_state(struct intel_connector *connector)
 
 int intel_connector_init(struct intel_connector *connector)
 {
-       struct drm_connector_state *connector_state;
+       drm_atomic_helper_connector_reset(&connector->base);
 
-       connector_state = kzalloc(sizeof *connector_state, GFP_KERNEL);
-       if (!connector_state)
+       if (!connector->base.state)
                return -ENOMEM;
 
-       connector->base.state = connector_state;
        return 0;
 }
 
@@ -15446,6 +15444,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
                crtc->base.state->active = crtc->active;
                crtc->base.enabled = crtc->active;
+               crtc->base.state->connector_mask = 0;
 
                /* Because we only establish the connector -> encoder ->
                 * crtc links if something is active, this means the
@@ -15648,7 +15647,21 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
        for_each_intel_connector(dev, connector) {
                if (connector->get_hw_state(connector)) {
                        connector->base.dpms = DRM_MODE_DPMS_ON;
-                       connector->base.encoder = &connector->encoder->base;
+
+                       encoder = connector->encoder;
+                       connector->base.encoder = &encoder->base;
+
+                       if (encoder->base.crtc &&
+                           encoder->base.crtc->state->active) {
+                               /*
+                                * This has to be done during hardware readout
+                                * because anything calling .crtc_disable may
+                                * rely on the connector_mask being accurate.
+                                */
+                               encoder->base.crtc->state->connector_mask |=
+                                       1 << drm_connector_index(&connector->base);
+                       }
+
                } else {
                        connector->base.dpms = DRM_MODE_DPMS_OFF;
                        connector->base.encoder = NULL;
@@ -15893,6 +15906,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
        mutex_lock(&dev->struct_mutex);
        intel_cleanup_gt_powersave(dev);
        mutex_unlock(&dev->struct_mutex);
+
+       intel_teardown_gmbus(dev);
 }
 
 /*
index e2f515d3816fbb7e4ba0860017641e944783ff4c..fa0dabf578dc51c7b2371ecc9a1f1342b345892f 100644 (file)
@@ -534,7 +534,7 @@ static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
        drm_kms_helper_hotplug_event(dev);
 }
 
-static struct drm_dp_mst_topology_cbs mst_cbs = {
+static const struct drm_dp_mst_topology_cbs mst_cbs = {
        .add_connector = intel_dp_add_mst_connector,
        .register_connector = intel_dp_register_mst_connector,
        .destroy_connector = intel_dp_destroy_mst_connector,
index 7be7ac80830430318a62b2c4739431c75d4fda37..2f57d79674175c85c8a5ac1870ac57de3a1b0763 100644 (file)
@@ -305,6 +305,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
                dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
                legacyfb_depth = 16;
        }
+       drm_helper_disable_unused_functions(drm);
        imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
                                drm->mode_config.num_crtc, MAX_CRTC);
        if (IS_ERR(imxdrm->fbhelper)) {
index b74bf8e334f5f34acde05f83d411e26e5b4c14a4..0ffef172afb472fc0de254552e6b2bcaaae92db5 100644 (file)
@@ -204,8 +204,6 @@ static int imx_pd_register(struct drm_device *drm,
 
        drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
 
-       imxpd->connector.encoder = &imxpd->encoder;
-
        return 0;
 }
 
index c236f6fec2458cd2d37dd3d723c7060366540a46..df7a1719c84136186fca3dc42a236a66079bcc6c 100644 (file)
@@ -329,7 +329,7 @@ static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
        drm_kms_helper_hotplug_event(dev);
 }
 
-struct drm_dp_mst_topology_cbs mst_cbs = {
+const struct drm_dp_mst_topology_cbs mst_cbs = {
        .add_connector = radeon_dp_add_mst_connector,
        .register_connector = radeon_dp_register_mst_connector,
        .destroy_connector = radeon_dp_destroy_mst_connector,
index b80802f551436bb959ee79b08aa003dd16891383..db0763794edcb62de69a9f45c825a0b79b631820 100644 (file)
@@ -739,8 +739,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
        if (ret < 0)
                goto err_backlight;
 
-       connector->encoder = encoder;
-
        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
        drm_object_property_set_value(&connector->base,
                sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
index 1469987949d88f8b43cfdd97990e925156a149ec..506b5626f3ed2ed3a188ff9bc1e51144e40b8932 100644 (file)
@@ -160,6 +160,7 @@ static int sti_load(struct drm_device *dev, unsigned long flags)
 
        drm_mode_config_reset(dev);
 
+       drm_helper_disable_unused_functions(dev);
        drm_fbdev_cma_init(dev, 32,
                           dev->mode_config.num_crtc,
                           dev->mode_config.num_connector);
index 50d46ae3786b894c611ea2b54c64ba0346b83a2e..44e1027991959df48ff6cfff074540d9de2bfb3b 100644 (file)
@@ -745,14 +745,13 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
 
 static void tegra_dsi_connector_reset(struct drm_connector *connector)
 {
-       struct tegra_dsi_state *state;
-
-       kfree(connector->state);
-       connector->state = NULL;
+       struct tegra_dsi_state *state =
+               kzalloc(sizeof(*state), GFP_KERNEL);
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (state)
-               connector->state = &state->base;
+       if (state) {
+               kfree(connector->state);
+               __drm_atomic_helper_connector_reset(connector, &state->base);
+       }
 }
 
 static struct drm_connector_state *
index 4ddb21e7f52fe207bf2b034627b8bd09357b803c..d7f5b897c6c57a18c70536b39a2265b1af6268c2 100644 (file)
@@ -294,6 +294,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
                        break;
        }
 
+       drm_helper_disable_unused_functions(dev);
        priv->fbdev = drm_fbdev_cma_init(dev, bpp,
                        dev->mode_config.num_crtc,
                        dev->mode_config.num_connector);
index 8d0d70e51ef29e36c1c6c857f512cf4beb22410a..018145e0b87d35ee49377b23805da2435367c682 100644 (file)
@@ -328,7 +328,7 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
        /* The pixelvalve can only feed one encoder (and encoders are
         * 1:1 with connectors.)
         */
-       if (drm_atomic_connectors_for_crtc(state->state, crtc) > 1)
+       if (hweight32(state->connector_mask) > 1)
                return -EINVAL;
 
        drm_atomic_crtc_state_for_each_plane(plane, state) {
index 41edd5a3f10097e8c030b076397fec389448319d..d64d9058bce57ef6b424c994c02ff7f6cb36baa5 100644 (file)
@@ -63,7 +63,7 @@
  * for the inactive GPU.) Also, muxes are often used to cut power to the
  * discrete GPU while it is not used.
  *
- * DRM drivers register GPUs with vga_switcheroo, these are heretoforth called
+ * DRM drivers register GPUs with vga_switcheroo, these are henceforth called
  * clients. The mux is called the handler. Muxless machines also register a
  * handler to control the power state of the discrete GPU, its ->switchto
  * callback is a no-op for obvious reasons. The discrete GPU is often equipped
index 976efeb3f2ba3f377f777c91150f7afcb7b400a2..2b921dea10f4970a06b4e529835401799e24e6fe 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
  *  Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
+ *  Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include <acpi/video.h>
 #include <asm/io.h>
 
+/**
+ * DOC: Overview
+ *
+ * :1:  http://www.latticesemi.com/en/Products/FPGAandCPLD/LatticeXP2.aspx
+ * :2:  http://www.renesas.com/products/mpumcu/h8s/h8s2100/h8s2113/index.jsp
+ *
+ * gmux is a microcontroller built into the MacBook Pro to support dual GPUs:
+ * A {1}[Lattice XP2] on pre-retinas, a {2}[Renesas R4F2113] on retinas.
+ *
+ * (The MacPro6,1 2013 also has a gmux, however it is unclear why since it has
+ * dual GPUs but no built-in display.)
+ *
+ * gmux is connected to the LPC bus of the southbridge. Its I/O ports are
+ * accessed differently depending on the microcontroller: Driver functions
+ * to access a pre-retina gmux are infixed `_pio_`, those for a retina gmux
+ * are infixed `_index_`.
+ */
+
 struct apple_gmux_data {
        unsigned long iostart;
        unsigned long iolen;
@@ -247,6 +266,20 @@ static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
        return false;
 }
 
+/**
+ * DOC: Backlight control
+ *
+ * :3:  http://www.ti.com/lit/ds/symlink/lp8543.pdf
+ * :4:  http://www.ti.com/lit/ds/symlink/lp8545.pdf
+ *
+ * On single GPU MacBooks, the PWM signal for the backlight is generated by
+ * the GPU. On dual GPU MacBook Pros by contrast, either GPU may be suspended
+ * to conserve energy. Hence the PWM signal needs to be generated by a separate
+ * backlight driver which is controlled by gmux. The earliest generation
+ * MBP5 2008/09 uses a {3}[TI LP8543] backlight driver. All newer models
+ * use a {4}[TI LP8545].
+ */
+
 static int gmux_get_brightness(struct backlight_device *bd)
 {
        struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -273,6 +306,68 @@ static const struct backlight_ops gmux_bl_ops = {
        .update_status = gmux_update_status,
 };
 
+/**
+ * DOC: Graphics mux
+ *
+ * :5:  http://pimg-fpiw.uspto.gov/fdd/07/870/086/0.pdf
+ * :6:  http://www.nxp.com/documents/data_sheet/CBTL06141.pdf
+ * :7:  http://www.ti.com/lit/ds/symlink/hd3ss212.pdf
+ * :8:  https://www.pericom.com/assets/Datasheets/PI3VDP12412.pdf
+ * :9:  http://www.ti.com/lit/ds/symlink/sn74lv4066a.pdf
+ * :10: http://pdf.datasheetarchive.com/indexerfiles/Datasheets-SW16/DSASW00308511.pdf
+ * :11: http://www.ti.com/lit/ds/symlink/ts3ds10224.pdf
+ *
+ * On pre-retinas, the LVDS outputs of both GPUs feed into gmux which muxes
+ * either of them to the panel. One of the tricks gmux has up its sleeve is
+ * to lengthen the blanking interval of its output during a switch to
+ * synchronize it with the GPU switched to. This allows for a flicker-free
+ * switch that is imperceptible by the user ({5}[US 8,687,007 B2]).
+ *
+ * On retinas, muxing is no longer done by gmux itself, but by a separate
+ * chip which is controlled by gmux. The chip is triple sourced, it is
+ * either an {6}[NXP CBTL06142], {7}[TI HD3SS212] or {8}[Pericom PI3VDP12412].
+ * The panel is driven with eDP instead of LVDS since the pixel clock
+ * required for retina resolution exceeds LVDS' limits.
+ *
+ * Pre-retinas are able to switch the panel's DDC pins separately.
+ * This is handled by a {9}[TI SN74LV4066A] which is controlled by gmux.
+ * The inactive GPU can thus probe the panel's EDID without switching over
+ * the entire panel. Retinas lack this functionality as the chips used for
+ * eDP muxing are incapable of switching the AUX channel separately (see
+ * the linked data sheets, Pericom would be capable but this is unused).
+ * However the retina panel has the NO_AUX_HANDSHAKE_LINK_TRAINING bit set
+ * in its DPCD, allowing the inactive GPU to skip the AUX handshake and
+ * set up the output with link parameters pre-calibrated by the active GPU.
+ *
+ * The external DP port is only fully switchable on the first two unibody
+ * MacBook Pro generations, MBP5 2008/09 and MBP6 2010. This is done by an
+ * {6}[NXP CBTL06141] which is controlled by gmux. It's the predecessor of the
+ * eDP mux on retinas, the difference being support for 2.7 versus 5.4 Gbit/s.
+ *
+ * The following MacBook Pro generations replaced the external DP port with a
+ * combined DP/Thunderbolt port and lost the ability to switch it between GPUs,
+ * connecting it either to the discrete GPU or the Thunderbolt controller.
+ * Oddly enough, while the full port is no longer switchable, AUX and HPD
+ * are still switchable by way of an {10}[NXP CBTL03062] (on pre-retinas
+ * MBP8 2011 and MBP9 2012) or two {11}[TI TS3DS10224] (on retinas) under the
+ * control of gmux. Since the integrated GPU is missing the main link,
+ * external displays appear to it as phantoms which fail to link-train.
+ *
+ * gmux receives the HPD signal of all display connectors and sends an
+ * interrupt on hotplug. On generations which cannot switch external ports,
+ * the discrete GPU can then be woken to drive the newly connected display.
+ * The ability to switch AUX on these generations could be used to improve
+ * reliability of hotplug detection by having the integrated GPU poll the
+ * ports while the discrete GPU is asleep, but currently we do not make use
+ * of this feature.
+ *
+ * gmux' initial switch state on bootup is user configurable via the EFI
+ * variable `gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9` (5th byte,
+ * 1 = IGD, 0 = DIS). Based on this setting, the EFI firmware tells gmux to
+ * switch the panel and the external DP connector and allocates a framebuffer
+ * for the selected GPU.
+ */
+
 static int gmux_switchto(enum vga_switcheroo_client_id id)
 {
        if (id == VGA_SWITCHEROO_IGD) {
@@ -288,6 +383,14 @@ static int gmux_switchto(enum vga_switcheroo_client_id id)
        return 0;
 }
 
+/**
+ * DOC: Power control
+ *
+ * gmux is able to cut power to the discrete GPU. It automatically takes care
+ * of the correct sequence to tear down and bring up the power rails for
+ * core voltage, VRAM and PCIe.
+ */
+
 static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
                                   enum vga_switcheroo_state state)
 {
@@ -352,6 +455,16 @@ static const struct vga_switcheroo_handler gmux_handler = {
        .get_client_id = gmux_get_client_id,
 };
 
+/**
+ * DOC: Interrupt
+ *
+ * gmux is also connected to a GPIO pin of the southbridge and thereby is able
+ * to trigger an ACPI GPE. On the MBP5 2008/09 it's GPIO pin 22 of the Nvidia
+ * MCP79, on all following generations it's GPIO pin 6 of the Intel PCH.
+ * The GPE merely signals that an interrupt occurred, the actual type of event
+ * is identified by reading a gmux register.
+ */
+
 static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
 {
        gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
index d8576ac55693da65c73cb7e66f38108e47e46242..d3eaa5df187a49fca6242c86bfb4e3bd1f64b2d0 100644 (file)
@@ -130,10 +130,6 @@ int __must_check
 drm_atomic_add_affected_planes(struct drm_atomic_state *state,
                               struct drm_crtc *crtc);
 
-int
-drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
-                              struct drm_crtc *crtc);
-
 void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
 
 void
index a286cce98720fc46ac8b6cc981200f929e30b8bd..89d008dc08e2e2c6caa1d1d5eeb1ac3bdedd2474 100644 (file)
@@ -126,6 +126,8 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                          struct drm_plane_state *state);
 
+void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
+                                        struct drm_connector_state *conn_state);
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
index 3b040b3554726e25132b8c11b42588743816e576..c65a212db77e7a99b26735c262cb31a9b2504195 100644 (file)
@@ -306,6 +306,7 @@ struct drm_plane_helper_funcs;
  * @active_changed: crtc_state->active has been toggled.
  * @connectors_changed: connectors to this crtc have been updated
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
+ * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  *     update to ensure framebuffer cleanup isn't done too early
  * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
@@ -339,6 +340,8 @@ struct drm_crtc_state {
         */
        u32 plane_mask;
 
+       u32 connector_mask;
+
        /* last_vblank_count: for vblank waits before cleanup */
        u32 last_vblank_count;
 
@@ -548,7 +551,8 @@ struct drm_crtc_funcs {
         * ->page_flip() operation is already pending the callback should return
         * -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode
         * or just runtime disabled through DPMS respectively the new atomic
-        * "ACTIVE" state) should result in an -EINVAL error code.
+        * "ACTIVE" state) should result in an -EINVAL error code. Note that
+        * drm_atomic_helper_page_flip() checks this already for atomic drivers.
         */
        int (*page_flip)(struct drm_crtc *crtc,
                         struct drm_framebuffer *fb,
index 4fc55a87dfee1e9c883acd981934aa9967241a8e..24ab1787b771936fdf1894aabd6271f65a771993 100644 (file)
@@ -421,7 +421,7 @@ struct drm_dp_payload {
 struct drm_dp_mst_topology_mgr {
 
        struct device *dev;
-       struct drm_dp_mst_topology_cbs *cbs;
+       const struct drm_dp_mst_topology_cbs *cbs;
        int max_dpcd_transaction_bytes;
        struct drm_dp_aux *aux; /* auxch for this topology mgr to use */
        int max_payloads;
index 29e0dc50031d4a39a9a2626f3abb992092ef465c..a126a0d7aed470c77e6551054d9a29057375115f 100644 (file)
@@ -131,6 +131,20 @@ struct drm_crtc_helper_funcs {
         * Atomic drivers which need to inspect and adjust more state should
         * instead use the @atomic_check callback.
         *
+        * Also beware that neither core nor helpers filter modes before
+        * passing them to the driver: While the list of modes that is
+        * advertised to userspace is filtered using the connector's
+        * ->mode_valid() callback, neither the core nor the helpers do any
+        * filtering on modes passed in from userspace when setting a mode. It
+        * is therefore possible for userspace to pass in a mode that was
+        * previously filtered out using ->mode_valid() or add a custom mode
+        * that wasn't probed from EDID or similar to begin with.  Even though
+        * this is an advanced feature and rarely used nowadays, some users rely
+        * on being able to specify modes manually so drivers must be prepared
+        * to deal with it. Specifically this means that all drivers need not
+        * only validate modes in ->mode_valid() but also in ->mode_fixup() to
+        * make sure invalid modes passed in from userspace are rejected.
+        *
         * RETURNS:
         *
         * True if an acceptable configuration is possible, false if the modeset
@@ -188,7 +202,9 @@ struct drm_crtc_helper_funcs {
         * This callback is used by the legacy CRTC helpers to set a new
         * framebuffer and scanout position. It is optional and used as an
         * optimized fast-path instead of a full mode set operation with all the
-        * resulting flickering. Since it can't update other planes it's
+        * resulting flickering. If it is not present
+        * drm_crtc_helper_set_config() will fall back to a full modeset, using
+        * the ->mode_set() callback. Since it can't update other planes it's
         * incompatible with atomic modeset support.
         *
         * This callback is only used by the CRTC helpers and deprecated.
@@ -439,6 +455,20 @@ struct drm_encoder_helper_funcs {
         * Atomic drivers which need to inspect and adjust more state should
         * instead use the @atomic_check callback.
         *
+        * Also beware that neither core nor helpers filter modes before
+        * passing them to the driver: While the list of modes that is
+        * advertised to userspace is filtered using the connector's
+        * ->mode_valid() callback, neither the core nor the helpers do any
+        * filtering on modes passed in from userspace when setting a mode. It
+        * is therefore possible for userspace to pass in a mode that was
+        * previously filtered out using ->mode_valid() or add a custom mode
+        * that wasn't probed from EDID or similar to begin with.  Even though
+        * this is an advanced feature and rarely used nowadays, some users rely
+        * on being able to specify modes manually so drivers must be prepared
+        * to deal with it. Specifically this means that all drivers need not
+        * only validate modes in ->mode_valid() but also in ->mode_fixup() to
+        * make sure invalid modes passed in from userspace are rejected.
+        *
         * RETURNS:
         *
         * True if an acceptable configuration is possible, false if the modeset
@@ -640,8 +670,16 @@ struct drm_connector_helper_funcs {
         * In this function drivers then parse the modes in the EDID and add
         * them by calling drm_add_edid_modes(). But connectors that driver a
         * fixed panel can also manually add specific modes using
-        * drm_mode_probed_add(). Finally drivers that support audio probably
-        * want to update the ELD data, too, using drm_edid_to_eld().
+        * drm_mode_probed_add(). Drivers which manually add modes should also
+        * make sure that the @display_info, @width_mm and @height_mm fields of the
+        * struct #drm_connector are filled in.
+        *
+        * Virtual drivers that just want some standard VESA mode with a given
+        * resolution can call drm_add_modes_noedid(), and mark the preferred
+        * one using drm_set_preferred_mode().
+        *
+        * Finally drivers that support audio probably want to update the ELD
+        * data, too, using drm_edid_to_eld().
         *
         * This function is only called after the ->detect() hook has indicated
         * that a sink is connected and when the EDID isn't overridden through