drm/radeon: add a connector property for dither
authorAlex Deucher <alexander.deucher@amd.com>
Tue, 24 Sep 2013 21:26:26 +0000 (17:26 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 1 Nov 2013 16:43:13 +0000 (12:43 -0400)
Allows you to enable dither in the display hardware
when the monitor supports lower a lower bpc than the
current framebuffer format.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/rs600.c

index ccd0871..6e3c098 100644 (file)
@@ -7427,10 +7427,13 @@ void dce8_program_fmt(struct drm_encoder *encoder)
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int bpc = 0;
        u32 tmp = 0;
-       bool dither = false;
+       enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE;
 
-       if (connector)
+       if (connector) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                bpc = radeon_get_monitor_bpc(connector);
+               dither = radeon_connector->dither;
+       }
 
        /* LVDS/eDP FMT is set up by atom */
        if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
@@ -7446,7 +7449,7 @@ void dce8_program_fmt(struct drm_encoder *encoder)
 
        switch (bpc) {
        case 6:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
                                FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH(0));
@@ -7454,7 +7457,7 @@ void dce8_program_fmt(struct drm_encoder *encoder)
                        tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH(0));
                break;
        case 8:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
                                FMT_RGB_RANDOM_ENABLE |
@@ -7463,7 +7466,7 @@ void dce8_program_fmt(struct drm_encoder *encoder)
                        tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH(1));
                break;
        case 10:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
                                FMT_RGB_RANDOM_ENABLE |
index feedfcc..52fa3be 100644 (file)
@@ -1202,10 +1202,13 @@ void dce4_program_fmt(struct drm_encoder *encoder)
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int bpc = 0;
        u32 tmp = 0;
-       bool dither = false;
+       enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE;
 
-       if (connector)
+       if (connector) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                bpc = radeon_get_monitor_bpc(connector);
+               dither = radeon_connector->dither;
+       }
 
        /* LVDS/eDP FMT is set up by atom */
        if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
@@ -1221,7 +1224,7 @@ void dce4_program_fmt(struct drm_encoder *encoder)
 
        switch (bpc) {
        case 6:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
                                FMT_SPATIAL_DITHER_EN);
@@ -1229,7 +1232,7 @@ void dce4_program_fmt(struct drm_encoder *encoder)
                        tmp |= FMT_TRUNCATE_EN;
                break;
        case 8:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
                                FMT_RGB_RANDOM_ENABLE |
index bdf4b80..af922e2 100644 (file)
@@ -133,10 +133,13 @@ void dce3_program_fmt(struct drm_encoder *encoder)
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int bpc = 0;
        u32 tmp = 0;
-       bool dither = false;
+       enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE;
 
-       if (connector)
+       if (connector) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                bpc = radeon_get_monitor_bpc(connector);
+               dither = radeon_connector->dither;
+       }
 
        /* LVDS FMT is set up by atom */
        if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
@@ -152,14 +155,14 @@ void dce3_program_fmt(struct drm_encoder *encoder)
 
        switch (bpc) {
        case 6:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= FMT_SPATIAL_DITHER_EN;
                else
                        tmp |= FMT_TRUNCATE_EN;
                break;
        case 8:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH);
                else
index 79159b5..43f7600 100644 (file)
@@ -411,6 +411,21 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                }
        }
 
+       if (property == rdev->mode_info.dither_property) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               /* need to find digital encoder on connector */
+               encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+               if (!encoder)
+                       return 0;
+
+               radeon_encoder = to_radeon_encoder(encoder);
+
+               if (radeon_connector->dither != val) {
+                       radeon_connector->dither = val;
+                       radeon_property_change_mode(&radeon_encoder->base);
+               }
+       }
+
        if (property == rdev->mode_info.underscan_property) {
                /* need to find digital encoder on connector */
                encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
@@ -1661,6 +1676,9 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                   rdev->mode_info.audio_property,
                                                   RADEON_AUDIO_DISABLE);
+                       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)
@@ -1759,6 +1777,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.audio_property,
                                                              RADEON_AUDIO_DISABLE);
                        }
+                       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,
@@ -1804,6 +1827,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.audio_property,
                                                              RADEON_AUDIO_DISABLE);
                        }
+                       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)
@@ -1848,6 +1876,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.audio_property,
                                                              RADEON_AUDIO_DISABLE);
                        }
+                       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;
index 0d1aa05..7adbb74 100644 (file)
@@ -1178,6 +1178,12 @@ static struct drm_prop_enum_list radeon_audio_enum_list[] =
        { RADEON_AUDIO_AUTO, "auto" },
 };
 
+/* XXX support different dither options? spatial, temporal, both, etc. */
+static struct drm_prop_enum_list radeon_dither_enum_list[] =
+{      { RADEON_FMT_DITHER_DISABLE, "off" },
+       { RADEON_FMT_DITHER_ENABLE, "on" },
+};
+
 static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
        int sz;
@@ -1234,6 +1240,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
                                         "audio",
                                         radeon_audio_enum_list, sz);
 
+       sz = ARRAY_SIZE(radeon_dither_enum_list);
+       rdev->mode_info.dither_property =
+               drm_property_create_enum(rdev->ddev, 0,
+                                        "dither",
+                                        radeon_dither_enum_list, sz);
+
        return 0;
 }
 
index 03f74b0..8b4e712 100644 (file)
@@ -249,6 +249,8 @@ struct radeon_mode_info {
        struct drm_property *underscan_vborder_property;
        /* audio */
        struct drm_property *audio_property;
+       /* FMT dithering */
+       struct drm_property *dither_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
@@ -479,6 +481,11 @@ enum radeon_connector_audio {
        RADEON_AUDIO_AUTO = 2
 };
 
+enum radeon_connector_dither {
+       RADEON_FMT_DITHER_DISABLE = 0,
+       RADEON_FMT_DITHER_ENABLE = 1,
+};
+
 struct radeon_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -498,6 +505,7 @@ struct radeon_connector {
        struct radeon_router router;
        struct radeon_i2c_chan *router_bus;
        enum radeon_connector_audio audio;
+       enum radeon_connector_dither dither;
 };
 
 struct radeon_framebuffer {
index df01aa3..76cc8d3 100644 (file)
@@ -161,10 +161,13 @@ void avivo_program_fmt(struct drm_encoder *encoder)
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int bpc = 0;
        u32 tmp = 0;
-       bool dither = false;
+       enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE;
 
-       if (connector)
+       if (connector) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                bpc = radeon_get_monitor_bpc(connector);
+               dither = radeon_connector->dither;
+       }
 
        /* LVDS FMT is set up by atom */
        if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
@@ -175,14 +178,14 @@ void avivo_program_fmt(struct drm_encoder *encoder)
 
        switch (bpc) {
        case 6:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
                else
                        tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN;
                break;
        case 8:
-               if (dither)
+               if (dither == RADEON_FMT_DITHER_ENABLE)
                        /* XXX sort out optimal dither settings */
                        tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN |
                                AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH);