drm/nv04-nv40: Prevent invalid DAC/TVDAC combinations.
authorFrancisco Jerez <currojerez@riseup.net>
Sun, 4 Jul 2010 14:14:42 +0000 (16:14 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 13 Jul 2010 00:13:20 +0000 (10:13 +1000)
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv17_tv.c

index e3c8bd4f99c94ec200a9abae7fdeb4b110f0fe02..565981dfd69b8df84a4f9d1ab553143ed4f423b6 100644 (file)
@@ -1076,6 +1076,7 @@ extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *);
 extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder);
 extern int nv04_dac_output_offset(struct drm_encoder *encoder);
 extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable);
+extern bool nv04_dac_in_use(struct drm_encoder *encoder);
 
 /* nv04_dfp.c */
 extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *);
index bcc8090adb233f28bc3b4c5a954b99cc75bf16b9..2d0fee5f09ce6589f8c154c6e38cf9e95c1e4b18 100644 (file)
@@ -314,9 +314,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 {
        struct drm_device *dev = encoder->dev;
        struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
-       uint32_t sample = nv17_dac_sample_load(encoder);
 
-       if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
+       if (nv04_dac_in_use(encoder))
+               return connector_status_disconnected;
+
+       if (nv17_dac_sample_load(encoder) &
+           NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
                NV_INFO(dev, "Load detected on output %c\n",
                        '@' + ffs(dcb->or));
                return connector_status_connected;
@@ -329,6 +332,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode)
 {
+       if (nv04_dac_in_use(encoder))
+               return false;
+
        return true;
 }
 
@@ -427,6 +433,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
        }
 }
 
+/* Check if the DAC corresponding to 'encoder' is being used by
+ * someone else. */
+bool nv04_dac_in_use(struct drm_encoder *encoder)
+{
+       struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
+       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+
+       return nv_gf4_disp_arch(encoder->dev) &&
+               (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
+}
+
 static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
index 44437ff46394d54dda7e76428740a33aaf4ff93d..864867ed951a7b46fb646099e044d6507b5b38ac 100644 (file)
@@ -125,6 +125,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
        struct dcb_entry *dcb = tv_enc->base.dcb;
 
+       if (nv04_dac_in_use(encoder))
+               return connector_status_disconnected;
+
        if (dev_priv->chipset == 0x42 ||
            dev_priv->chipset == 0x43)
                tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe;
@@ -296,6 +299,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
 {
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
 
+       if (nv04_dac_in_use(encoder))
+               return false;
+
        if (tv_norm->kind == CTV_ENC_MODE)
                adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;
        else