NV50: delay changing gpu<->non-gpu scaling modes until next modeset
authorMaarten Maathuis <madman2003@gmail.com>
Sun, 20 Jul 2008 13:40:40 +0000 (15:40 +0200)
committerMaarten Maathuis <madman2003@gmail.com>
Sun, 20 Jul 2008 13:40:40 +0000 (15:40 +0200)
linux-core/nv50_connector.c
linux-core/nv50_connector.h
linux-core/nv50_crtc.c
linux-core/nv50_crtc.h
linux-core/nv50_kms_wrapper.c

index be133de..309f450 100644 (file)
@@ -185,9 +185,9 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty
 
        /* some reasonable defaults */
        if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS)
-               connector->scaling_mode = SCALE_FULLSCREEN;
+               connector->requested_scaling_mode = SCALE_FULLSCREEN;
        else
-               connector->scaling_mode = SCALE_NON_GPU;
+               connector->requested_scaling_mode = SCALE_NON_GPU;
 
        connector->use_dithering = false;
 
index 02b1561..aac9445 100644 (file)
@@ -47,7 +47,8 @@ struct nv50_connector {
        struct nv50_i2c_channel *i2c_chan;
        struct nv50_output *output;
 
-       int scaling_mode;
+       int requested_scaling_mode;
+
        bool use_dithering;
 
        bool (*detect) (struct nv50_connector *connector);
index ffb976f..c4ca7e7 100644 (file)
@@ -255,7 +255,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
 
        NV50_DEBUG("\n");
 
-       switch (crtc->scaling_mode) {
+       switch (crtc->requested_scaling_mode) {
                case SCALE_ASPECT:
                        nv50_crtc_calc_scale(crtc, &outX, &outY);
                        break;
@@ -283,6 +283,9 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
        OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX);
        OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX);
 
+       /* processed */
+       crtc->scaling_mode = crtc->requested_scaling_mode;
+
        return 0;
 }
 
@@ -492,6 +495,9 @@ int nv50_crtc_create(struct drm_device *dev, int index)
        crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
        crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
 
+       crtc->requested_scaling_mode = SCALE_INVALID;
+       crtc->scaling_mode = SCALE_INVALID;
+
        if (!crtc->mode || !crtc->native_mode) {
                rval = -ENOMEM;
                goto out;
index 8235c9d..b4b8358 100644 (file)
@@ -46,6 +46,10 @@ struct nv50_crtc {
 
        bool use_native_mode;
        bool use_dithering;
+
+       /* Changing scaling modes requires a modeset sometimes. */
+       /* We need to know the currently active hw mode, as well as the requested one by the user. */
+       int requested_scaling_mode;
        int scaling_mode;
 
        struct nv50_cursor *cursor;
index 6e0805f..67836f3 100644 (file)
@@ -635,12 +635,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
                                if (connector->output != output)
                                        continue;
 
-                               crtc->scaling_mode = connector->scaling_mode;
+                               crtc->requested_scaling_mode = connector->requested_scaling_mode;
                                crtc->use_dithering = connector->use_dithering;
                                break;
                        }
 
-                       if (crtc->scaling_mode == SCALE_NON_GPU)
+                       if (crtc->requested_scaling_mode == SCALE_NON_GPU)
                                crtc->use_native_mode = false;
                        else
                                crtc->use_native_mode = true;
@@ -1086,6 +1086,7 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector,
        struct drm_device *dev = drm_connector->dev;
        struct nv50_connector *connector = to_nv50_connector(drm_connector);
        int rval = 0;
+       bool delay_change = false;
 
        /* DPMS */
        if (property == dev->mode_config.dpms_property && drm_connector->encoder) {
@@ -1123,7 +1124,7 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector,
                if (connector->type == CONNECTOR_LVDS && internal_value == SCALE_NON_GPU)
                        return -EINVAL;
 
-               connector->scaling_mode = internal_value;
+               connector->requested_scaling_mode = internal_value;
 
                if (drm_connector->encoder && drm_connector->encoder->crtc)
                        crtc = to_nv50_crtc(drm_connector->encoder->crtc);
@@ -1131,7 +1132,17 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector,
                if (!crtc)
                        return 0;
 
-               crtc->scaling_mode = connector->scaling_mode;
+               crtc->requested_scaling_mode = connector->requested_scaling_mode;
+
+               /* going from and to a gpu scaled regime requires a modesetting, so wait until next modeset */
+               if (crtc->scaling_mode == SCALE_NON_GPU || internal_value == SCALE_NON_GPU) {
+                       DRM_INFO("Moving from or to a non-gpu scaled mode, this will be processed upon next modeset.");
+                       delay_change = true;
+               }
+
+               if (delay_change)
+                       return 0;
+
                rval = crtc->set_scale(crtc);
                if (rval)
                        return rval;
@@ -1194,7 +1205,7 @@ static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector)
 
        connector = to_nv50_connector(drm_connector);
 
-       switch (connector->scaling_mode) {
+       switch (connector->requested_scaling_mode) {
                case SCALE_NON_GPU:
                        drm_mode = DRM_MODE_SCALE_NON_GPU;
                        break;