drm/radeon: enable display scaling on all connectors (v2)
authorAlex Deucher <alexander.deucher@amd.com>
Wed, 9 Jul 2014 17:21:59 +0000 (13:21 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 5 Aug 2014 12:53:25 +0000 (08:53 -0400)
This enables the display scaler on all connectors for r5xx
and newer asics.  Previously we only enabled the scaler for
fixed mode displays (eDP or LVDS) since they have to use the
scaler to support non-native modes.  Most other displays
are multi-sync or have a built in scaler to support non-native
modes.  The default scaling mode for non-fixed displays is
none which will use the scaler in the monitor.  Note that
we do not populate any fake modes like we do for fixed
displays so it will only use the modes in the edid.  For
other modes, you'll need to populate them manually.

bug:
https://bugs.freedesktop.org/show_bug.cgi?id=80868

v2: properly handle scaling with no modes defined

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/radeon_connectors.c

index 7d68203a3737f39d49594dc25dbdda64365a45b7..34fe641c3b516afdc17d6be6dea20373cb0fe36c 100644 (file)
@@ -331,12 +331,10 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
            && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
                adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
 
-       /* get the native mode for LVDS */
-       if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT))
+       /* get the native mode for scaling */
+       if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
                radeon_panel_mode_fixup(encoder, adjusted_mode);
-
-       /* get the native mode for TV */
-       if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
+       } else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
                struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
                if (tv_dac) {
                        if (tv_dac->tv_std == TV_STD_NTSC ||
@@ -346,6 +344,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
                        else
                                radeon_atom_get_tv_timings(rdev, 1, adjusted_mode);
                }
+       } else if (radeon_encoder->rmx_type != RMX_OFF) {
+               radeon_panel_mode_fixup(encoder, adjusted_mode);
        }
 
        if (ASIC_IS_DCE3(rdev) &&
index c667c43f1c1f86a7ae7ff1f511a193a090ceb51f..92fbe6ec9081011bd9156974c262230fa0b83848 100644 (file)
@@ -271,6 +271,27 @@ static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *conn
        return NULL;
 }
 
+static void radeon_get_native_mode(struct drm_connector *connector)
+{
+       struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+       struct radeon_encoder *radeon_encoder;
+
+       if (encoder == NULL)
+               return;
+
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       if (!list_empty(&connector->probed_modes)) {
+               struct drm_display_mode *preferred_mode =
+                       list_first_entry(&connector->probed_modes,
+                                        struct drm_display_mode, head);
+
+               radeon_encoder->native_mode = *preferred_mode;
+       } else {
+               radeon_encoder->native_mode.clock = 0;
+       }
+}
+
 /*
  * radeon_connector_analog_encoder_conflict_solve
  * - search for other connectors sharing this encoder
@@ -571,6 +592,35 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                radeon_property_change_mode(&radeon_encoder->base);
        }
 
+       if (property == dev->mode_config.scaling_mode_property) {
+               enum radeon_rmx_type rmx_type;
+
+               if (connector->encoder)
+                       radeon_encoder = to_radeon_encoder(connector->encoder);
+               else {
+                       struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+                       radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
+               }
+
+               switch (val) {
+               default:
+               case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
+               case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
+               case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
+               case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
+               }
+               if (radeon_encoder->rmx_type == rmx_type)
+                       return 0;
+
+               if ((rmx_type != DRM_MODE_SCALE_NONE) &&
+                   (radeon_encoder->native_mode.clock == 0))
+                       return 0;
+
+               radeon_encoder->rmx_type = rmx_type;
+
+               radeon_property_change_mode(&radeon_encoder->base);
+       }
+
        return 0;
 }
 
@@ -788,6 +838,8 @@ static int radeon_vga_get_modes(struct drm_connector *connector)
 
        ret = radeon_ddc_get_modes(radeon_connector);
 
+       radeon_get_native_mode(connector);
+
        return ret;
 }
 
@@ -991,6 +1043,9 @@ static int radeon_dvi_get_modes(struct drm_connector *connector)
        int ret;
 
        ret = radeon_ddc_get_modes(radeon_connector);
+
+       radeon_get_native_mode(connector);
+
        return ret;
 }
 
@@ -1358,6 +1413,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
                                radeon_atom_ext_encoder_setup_ddc(encoder);
                }
                ret = radeon_ddc_get_modes(radeon_connector);
+
+               radeon_get_native_mode(connector);
        }
 
        return ret;
@@ -1717,6 +1774,9 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.load_detect_property,
                                                      1);
+                       drm_object_attach_property(&radeon_connector->base.base,
+                                                  dev->mode_config.scaling_mode_property,
+                                                  DRM_MODE_SCALE_NONE);
                        break;
                case DRM_MODE_CONNECTOR_DVII:
                case DRM_MODE_CONNECTOR_DVID:
@@ -1737,6 +1797,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                      rdev->mode_info.underscan_vborder_property,
                                                      0);
 
+                       drm_object_attach_property(&radeon_connector->base.base,
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_NONE);
+
                        drm_object_attach_property(&radeon_connector->base.base,
                                                   rdev->mode_info.dither_property,
                                                   RADEON_FMT_DITHER_DISABLE);
@@ -1787,6 +1851,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.load_detect_property,
                                                      1);
+                       if (ASIC_IS_AVIVO(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          dev->mode_config.scaling_mode_property,
+                                                          DRM_MODE_SCALE_NONE);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
@@ -1805,6 +1873,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.load_detect_property,
                                                      1);
+                       if (ASIC_IS_AVIVO(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          dev->mode_config.scaling_mode_property,
+                                                          DRM_MODE_SCALE_NONE);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->interlace_allowed = true;
@@ -1838,17 +1910,18 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.dither_property,
+                                                          RADEON_FMT_DITHER_DISABLE);
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          dev->mode_config.scaling_mode_property,
+                                                          DRM_MODE_SCALE_NONE);
                        }
                        if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
-                       if (ASIC_IS_AVIVO(rdev)) {
-                               drm_object_attach_property(&radeon_connector->base.base,
-                                                          rdev->mode_info.dither_property,
-                                                          RADEON_FMT_DITHER_DISABLE);
-                       }
                        if (connector_type == DRM_MODE_CONNECTOR_DVII) {
                                radeon_connector->dac_load_detect = true;
                                drm_object_attach_property(&radeon_connector->base.base,
@@ -1888,17 +1961,18 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.dither_property,
+                                                          RADEON_FMT_DITHER_DISABLE);
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          dev->mode_config.scaling_mode_property,
+                                                          DRM_MODE_SCALE_NONE);
                        }
                        if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
-                       if (ASIC_IS_AVIVO(rdev)) {
-                               drm_object_attach_property(&radeon_connector->base.base,
-                                                          rdev->mode_info.dither_property,
-                                                          RADEON_FMT_DITHER_DISABLE);
-                       }
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -1935,18 +2009,18 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.dither_property,
+                                                          RADEON_FMT_DITHER_DISABLE);
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          dev->mode_config.scaling_mode_property,
+                                                          DRM_MODE_SCALE_NONE);
                        }
                        if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
-                       if (ASIC_IS_AVIVO(rdev)) {
-                               drm_object_attach_property(&radeon_connector->base.base,
-                                                          rdev->mode_info.dither_property,
-                                                          RADEON_FMT_DITHER_DISABLE);
-
-                       }
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
                        connector->doublescan_allowed = false;