Merge branch 'devel-stable' into devel
[sfrench/cifs-2.6.git] / drivers / gpu / drm / nouveau / nv04_display.c
index c7898b4f6dfbe0e1fb440452368d22077a0b083d..9e28cf772e3cd482af0c1d048634470d0bdf3b2d 100644 (file)
@@ -32,8 +32,6 @@
 #include "nouveau_encoder.h"
 #include "nouveau_connector.h"
 
-#define MULTIPLE_ENCODERS(e) (e & (e - 1))
-
 static void
 nv04_display_store_initial_head_owner(struct drm_device *dev)
 {
@@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
 
        if (dev_priv->chipset != 0x11) {
                dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44);
-               goto ownerknown;
+               return;
        }
 
        /* reading CR44 is broken on nv11, so we attempt to infer it */
@@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
                bool tvA = false;
                bool tvB = false;
 
-               NVLockVgaCrtcs(dev, false);
-
                slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) &
                                                                        0x80;
                if (slaved_on_B)
@@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
                        tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) &
                                        MASK(NV_CIO_CRE_LCD_LCD_SELECT));
 
-               NVLockVgaCrtcs(dev, true);
-
                if (slaved_on_A && !tvA)
                        dev_priv->crtc_owner = 0x0;
                else if (slaved_on_B && !tvB)
@@ -79,14 +73,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
                else
                        dev_priv->crtc_owner = 0x0;
        }
+}
+
+int
+nv04_display_early_init(struct drm_device *dev)
+{
+       /* Make the I2C buses accessible. */
+       if (!nv_gf4_disp_arch(dev)) {
+               uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
+
+               if (!(pmc_enable & 1))
+                       nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1);
+       }
 
-ownerknown:
-       NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner);
+       /* Unlock the VGA CRTCs. */
+       NVLockVgaCrtcs(dev, false);
+
+       /* Make sure the CRTCs aren't in slaved mode. */
+       if (nv_two_heads(dev)) {
+               nv04_display_store_initial_head_owner(dev);
+               NVSetOwner(dev, 0);
+       }
+
+       return 0;
+}
+
+void
+nv04_display_late_takedown(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (nv_two_heads(dev))
+               NVSetOwner(dev, dev_priv->crtc_owner);
 
-       /* we need to ensure the heads are not tied henceforth, or reading any
-        * 8 bit reg on head B will fail
-        * setting a single arbitrary head solves that */
-       NVSetOwner(dev, 0);
+       NVLockVgaCrtcs(dev, true);
 }
 
 int
@@ -94,14 +114,13 @@ nv04_display_create(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct drm_connector *connector, *ct;
        struct drm_encoder *encoder;
        struct drm_crtc *crtc;
        int i, ret;
 
        NV_DEBUG_KMS(dev, "\n");
 
-       if (nv_two_heads(dev))
-               nv04_display_store_initial_head_owner(dev);
        nouveau_hw_save_vga_fonts(dev, 1);
 
        drm_mode_config_init(dev);
@@ -132,19 +151,23 @@ nv04_display_create(struct drm_device *dev)
        for (i = 0; i < dcb->entries; i++) {
                struct dcb_entry *dcbent = &dcb->entry[i];
 
+               connector = nouveau_connector_create(dev, dcbent->connector);
+               if (IS_ERR(connector))
+                       continue;
+
                switch (dcbent->type) {
                case OUTPUT_ANALOG:
-                       ret = nv04_dac_create(dev, dcbent);
+                       ret = nv04_dac_create(connector, dcbent);
                        break;
                case OUTPUT_LVDS:
                case OUTPUT_TMDS:
-                       ret = nv04_dfp_create(dev, dcbent);
+                       ret = nv04_dfp_create(connector, dcbent);
                        break;
                case OUTPUT_TV:
                        if (dcbent->location == DCB_LOC_ON_CHIP)
-                               ret = nv17_tv_create(dev, dcbent);
+                               ret = nv17_tv_create(connector, dcbent);
                        else
-                               ret = nv04_tv_create(dev, dcbent);
+                               ret = nv04_tv_create(connector, dcbent);
                        break;
                default:
                        NV_WARN(dev, "DCB type %d not known\n", dcbent->type);
@@ -155,12 +178,16 @@ nv04_display_create(struct drm_device *dev)
                        continue;
        }
 
-       for (i = 0; i < dcb->connector.entries; i++)
-               nouveau_connector_create(dev, &dcb->connector.entry[i]);
+       list_for_each_entry_safe(connector, ct,
+                                &dev->mode_config.connector_list, head) {
+               if (!connector->encoder_ids[0]) {
+                       NV_WARN(dev, "%s has no encoders, removing\n",
+                               drm_get_connector_name(connector));
+                       connector->funcs->destroy(connector);
+               }
+       }
 
        /* Save previous state */
-       NVLockVgaCrtcs(dev, false);
-
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                crtc->funcs->save(crtc);
 
@@ -191,8 +218,6 @@ nv04_display_destroy(struct drm_device *dev)
        }
 
        /* Restore state */
-       NVLockVgaCrtcs(dev, false);
-
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                struct drm_encoder_helper_funcs *func = encoder->helper_private;
 
@@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev)
        nouveau_hw_save_vga_fonts(dev, 0);
 }
 
-void
-nv04_display_restore(struct drm_device *dev)
+int
+nv04_display_init(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct drm_encoder *encoder;
        struct drm_crtc *crtc;
 
-       NVLockVgaCrtcs(dev, false);
-
        /* meh.. modeset apparently doesn't setup all the regs and depends
         * on pre-existing state, for now load the state of the card *before*
         * nouveau was loaded, and then do a modeset.
@@ -233,12 +255,6 @@ nv04_display_restore(struct drm_device *dev)
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                crtc->funcs->restore(crtc);
 
-       if (nv_two_heads(dev)) {
-               NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n",
-                       dev_priv->crtc_owner);
-               NVSetOwner(dev, dev_priv->crtc_owner);
-       }
-
-       NVLockVgaCrtcs(dev, true);
+       return 0;
 }