From 6214bb748783e65466d864c992770c07293ee820 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 24 Sep 2013 17:26:26 -0400 Subject: [PATCH] drm/radeon: add a connector property for dither 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 --- drivers/gpu/drm/radeon/cik.c | 13 +++++---- drivers/gpu/drm/radeon/evergreen.c | 11 +++++--- drivers/gpu/drm/radeon/r600.c | 11 +++++--- drivers/gpu/drm/radeon/radeon_connectors.c | 33 ++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_display.c | 12 ++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 8 ++++++ drivers/gpu/drm/radeon/rs600.c | 11 +++++--- 7 files changed, 82 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index ccd0871d44fe..6e3c09831890 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -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 | diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index feedfcc6554b..52fa3bec64ca 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -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 | diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index bdf4b80202d5..af922e297a12 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -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 diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 79159b5da05b..43f7600803c3 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -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; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0d1aa050d41d..7adbb7417dd5 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -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; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 03f74b0276c5..8b4e712c1e5c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -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 { diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index df01aa398cc5..76cc8d3aafec 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -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); -- 2.39.5