drm/kms: add explicit encoder disable function and detach harder.
authorDave Airlie <airlied@redhat.com>
Mon, 31 Aug 2009 05:16:30 +0000 (15:16 +1000)
committerDave Airlie <airlied@linux.ie>
Tue, 1 Sep 2009 23:42:59 +0000 (09:42 +1000)
For shared tv-out and VGA encoders, we really need to know if
the encoder is just being switched off temporarily in blanking
or if we are really disabling it hard.

Also we need to try harder to disconnect encoders from unused
connectors so we can share more efficently.

(shared encoders stuff is coming in radeon tv-out support)

Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/drm_crtc_helper.c
include/drm/drm_crtc_helper.h

index 205349ea1075f29c114774627307b05ce1247967..eea5e6c4099c6da2c307391dd176b68a6c3b3799 100644 (file)
@@ -260,13 +260,27 @@ EXPORT_SYMBOL(drm_helper_crtc_in_use);
 void drm_helper_disable_unused_functions(struct drm_device *dev)
 {
        struct drm_encoder *encoder;
+       struct drm_connector *connector;
        struct drm_encoder_helper_funcs *encoder_funcs;
        struct drm_crtc *crtc;
 
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       continue;
+               if (connector->status == connector_status_disconnected)
+                       connector->encoder = NULL;
+       }
+
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                encoder_funcs = encoder->helper_private;
-               if (!drm_helper_encoder_in_use(encoder))
-                       (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+               if (!drm_helper_encoder_in_use(encoder)) {
+                       if (encoder_funcs->disable)
+                               (*encoder_funcs->disable)(encoder);
+                       else
+                               (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+               }
+               /* disconnector encoder from any connector */
+               encoder->crtc = NULL;
        }
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -411,7 +425,7 @@ static int drm_pick_crtcs(struct drm_device *dev,
        c = 0;
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 
-               if ((connector->encoder->possible_crtcs & (1 << c)) == 0) {
+               if ((encoder->possible_crtcs & (1 << c)) == 0) {
                        c++;
                        continue;
                }
@@ -496,8 +510,10 @@ static void drm_setup_crtcs(struct drm_device *dev)
                                  mode->name, crtc->base.id);
                        crtc->desired_mode = mode;
                        connector->encoder->crtc = crtc;
-               } else
+               } else {
                        connector->encoder->crtc = NULL;
+                       connector->encoder = NULL;
+               }
                i++;
        }
 
index e44a4f87303c82c142577fcff97a84d2dea29e3c..4c8dacaf4f583314966340e470aaee5430018389 100644 (file)
@@ -79,6 +79,8 @@ struct drm_encoder_helper_funcs {
        /* detect for DAC style encoders */
        enum drm_connector_status (*detect)(struct drm_encoder *encoder,
                                            struct drm_connector *connector);
+       /* disable encoder when not in use - more explicit than dpms off */
+       void (*disable)(struct drm_encoder *encoder);
 };
 
 struct drm_connector_helper_funcs {