From 83325d072185899b706de2956170b246585aaec9 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 24 Oct 2012 18:29:49 +0200 Subject: DRM/Radeon: Fix Load Detection on legacy primary DAC. An uninitialized variable led to broken load detection. Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 0063df9d166d..f278f20ea12a 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -671,6 +671,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; WREG32(RADEON_DAC_CNTL, tmp); + tmp = dac_macro_cntl; tmp &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); -- cgit v1.2.3 From 9c50b1d937cc9656100ba10d9f57484c6d173936 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 24 Oct 2012 18:31:19 +0200 Subject: DRM/Radeon: Fix primary DAC Load Detection for RV100 chips. For Radeon 7500 ATI recommends a DAC_FORCE value of 0x1ac. This value works better on ES1000 (RV100) chips, too, as it doesn't produce any false positives on any cards I have tested. Therefore let's assume that this value is good for all RV100 and RV200 chipset generations. Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index f278f20ea12a..5fdc67bd25d9 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -662,6 +662,8 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc if (ASIC_IS_R300(rdev)) tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else if (ASIC_IS_RV100(rdev)) + tmp |= (0x1ac << RADEON_DAC_FORCE_DATA_SHIFT); else tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); -- cgit v1.2.3 From fc87f13b8dc73706ae06caf229a336965e9b44a6 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 24 Oct 2012 18:32:52 +0200 Subject: DRM/Radeon: On DVI-I use Load Detection when EDID is bogus. The Radeon driver uses the analog/digital flag to determine if the DAC or the TMDS encoder should be enabled on a DVI-I connector. If the EDID is bogus this flag is no longer reliable. This fix adds a fallback to DAC load detection to determine if anything is connected to the DAC. If not and a (bogus) EDID is found it assumes a digital display is connected. This works around problems with some crappy IPMI devices using Radeon ES1000. Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_connectors.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 67cfc1795ecd..b884c362a8c2 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -941,7 +941,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) struct drm_mode_object *obj; int i; enum drm_connector_status ret = connector_status_disconnected; - bool dret = false; + bool dret = false, broken_edid = false; if (!force && radeon_check_hpd_status_unchanged(connector)) return connector->status; @@ -965,6 +965,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector)); radeon_connector->ddc_bus = NULL; + } else { + ret = connector_status_connected; + broken_edid = true; /* defer use_digital to later */ } } else { radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); @@ -1047,13 +1050,24 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) encoder_funcs = encoder->helper_private; if (encoder_funcs->detect) { - if (ret != connector_status_connected) { - ret = encoder_funcs->detect(encoder, connector); - if (ret == connector_status_connected) { - radeon_connector->use_digital = false; + if (!broken_edid) { + if (ret != connector_status_connected) { + /* deal with analog monitors without DDC */ + ret = encoder_funcs->detect(encoder, connector); + if (ret == connector_status_connected) { + radeon_connector->use_digital = false; + } + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } - if (ret != connector_status_disconnected) - radeon_connector->detected_by_load = true; + } else { + enum drm_connector_status lret; + /* assume digital unless load detected otherwise */ + radeon_connector->use_digital = true; + lret = encoder_funcs->detect(encoder, connector); + DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret); + if (lret == connector_status_connected) + radeon_connector->use_digital = false; } break; } -- cgit v1.2.3 From 74e4ca32a406a15efb24a6a6ecf84b4cdabfd4e7 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 24 Oct 2012 16:42:26 +0200 Subject: drivers/gpu/drm/radeon/evergreen_cs.c: Remove unnecessary semicolon A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r1@ statement S; position p,p1; @@ S@p1;@p @script:python r2@ p << r1.p; p1 << r1.p1; @@ if p[0].line != p1[0].line_end: cocci.include_match(False) @@ position r1.p; @@ -;@p // Signed-off-by: Peter Senna Tschudin Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 30271b641913..95e6318b6268 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -264,7 +264,7 @@ static int evergreen_surface_check_2d(struct radeon_cs_parser *p, /* macro tile width & height */ palign = (8 * surf->bankw * track->npipes) * surf->mtilea; halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea; - mtileb = (palign / 8) * (halign / 8) * tileb;; + mtileb = (palign / 8) * (halign / 8) * tileb; mtile_pr = surf->nbx / palign; mtile_ps = (mtile_pr * surf->nby) / halign; surf->layer_size = mtile_ps * mtileb * slice_pt; -- cgit v1.2.3 From dfdcbebc548ff14fd1a7029c95d060e0dd466469 Mon Sep 17 00:00:00 2001 From: Igor Murzov Date: Thu, 25 Oct 2012 17:09:00 +0400 Subject: drm/radeon: fix ATPX function documentation Fix a copy&pasted documentation. Signed-off-by: Igor Murzov Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 37f6a907aea4..15f5ded65e0c 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -352,9 +352,9 @@ static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) } /** - * radeon_atpx_switchto - switch to the requested GPU + * radeon_atpx_power_state - power down/up the requested GPU * - * @id: GPU to switch to + * @id: GPU to power down/up * @state: requested power state (0 = off, 1 = on) * * Execute the necessary ATPX function to power down/up the discrete GPU -- cgit v1.2.3 From d038db86984977646815fff54c1be11bff6b9f5b Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 30 Oct 2012 17:42:26 +0100 Subject: DRM/Radeon: Clean up code in TV DAC load detection. Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 5fdc67bd25d9..85a7307e05f8 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -1425,7 +1425,8 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; - uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; + uint32_t gpiopad_a = 0, pixclks_cntl, tmp; + uint32_t disp_output_cntl = 0, disp_hw_debug = 0; enum drm_connector_status found = connector_status_disconnected; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; @@ -1464,9 +1465,12 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder /* save the regs we need */ pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); - gpiopad_a = ASIC_IS_R300(rdev) ? RREG32(RADEON_GPIOPAD_A) : 0; - disp_output_cntl = ASIC_IS_R300(rdev) ? RREG32(RADEON_DISP_OUTPUT_CNTL) : 0; - disp_hw_debug = ASIC_IS_R300(rdev) ? 0 : RREG32(RADEON_DISP_HW_DEBUG); + if (ASIC_IS_R300(rdev)) { + gpiopad_a = RREG32(RADEON_GPIOPAD_A); + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + } else { + disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + } crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); @@ -1476,16 +1480,13 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder | RADEON_PIX2CLK_DAC_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - if (ASIC_IS_R300(rdev)) - WREG32_P(RADEON_GPIOPAD_A, 1, ~1); - tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; tmp |= RADEON_CRTC2_CRT2_ON | (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); - WREG32(RADEON_CRTC2_GEN_CNTL, tmp); if (ASIC_IS_R300(rdev)) { + WREG32_P(RADEON_GPIOPAD_A, 1, ~1); tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); @@ -1541,6 +1542,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder } else { WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); } + WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); return found; -- cgit v1.2.3 From 701337dc2711096e5288430599dcf07aac5876ab Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 30 Oct 2012 17:42:27 +0100 Subject: DRM/Radeon: Fix TV DAC Load Detection for single CRTC chips. The RN50 has a TV DAC but only a single CRTC. For load detection this DAC is controlled by the primary CRTC. Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 62 +++++++++++++++---------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 85a7307e05f8..3afed70306df 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -1424,9 +1424,9 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; + uint32_t crtc2_gen_cntl = 0, tv_dac_cntl, dac_cntl2, dac_ext_cntl; uint32_t gpiopad_a = 0, pixclks_cntl, tmp; - uint32_t disp_output_cntl = 0, disp_hw_debug = 0; + uint32_t disp_output_cntl = 0, disp_hw_debug = 0, crtc_ext_cntl = 0; enum drm_connector_status found = connector_status_disconnected; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; @@ -1465,13 +1465,18 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder /* save the regs we need */ pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); - if (ASIC_IS_R300(rdev)) { - gpiopad_a = RREG32(RADEON_GPIOPAD_A); - disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + + if (rdev->flags & RADEON_SINGLE_CRTC) { + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); } else { - disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + if (ASIC_IS_R300(rdev)) { + gpiopad_a = RREG32(RADEON_GPIOPAD_A); + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + } else { + disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + } + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); } - crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); dac_cntl2 = RREG32(RADEON_DAC_CNTL2); @@ -1480,19 +1485,24 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder | RADEON_PIX2CLK_DAC_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; - tmp |= RADEON_CRTC2_CRT2_ON | - (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); - WREG32(RADEON_CRTC2_GEN_CNTL, tmp); - - if (ASIC_IS_R300(rdev)) { - WREG32_P(RADEON_GPIOPAD_A, 1, ~1); - tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; - tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; - WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + if (rdev->flags & RADEON_SINGLE_CRTC) { + tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; + WREG32(RADEON_CRTC_EXT_CNTL, tmp); } else { - tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; - WREG32(RADEON_DISP_HW_DEBUG, tmp); + tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; + tmp |= RADEON_CRTC2_CRT2_ON | + (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + + if (ASIC_IS_R300(rdev)) { + WREG32_P(RADEON_GPIOPAD_A, 1, ~1); + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + } else { + tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; + WREG32(RADEON_DISP_HW_DEBUG, tmp); + } } tmp = RADEON_TV_DAC_NBLANK | @@ -1534,13 +1544,17 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder WREG32(RADEON_DAC_CNTL2, dac_cntl2); WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); - WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); - if (ASIC_IS_R300(rdev)) { - WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); - WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + if (rdev->flags & RADEON_SINGLE_CRTC) { + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); } else { - WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + if (ASIC_IS_R300(rdev)) { + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + } else { + WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + } } WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); -- cgit v1.2.3 From f8c4d701ae3477f41fdc95592caa476617988a53 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Mon, 29 Oct 2012 13:46:48 +0100 Subject: DRM/radeon: For single CRTC GPUs move handling of CRTC_CRT_ON to crtc_dpms(). On all dual CRTC GPUs the CRTC_CRT_ON in the RADEON_CRTC_EXT_CNTL register controls the CRTC of the primary DAC. Therefore it is set in the DAC DMPS function. This is different for GPU's with a single CRTC but a primary and a TV DAC: here it controls the single CRTC no matter where it is routed. Therefore we set it here. This avoids an elaborate on/off state tracking since both primary_dac_dpms() and tv_dac_dpms() functions would have to touch this bit. On single CRTC GPUs with just one DAC it's irrelevant where this bit is handled. agd5f: fix warning Signed-off-by: Egbert Eich Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 15 +++++++++++++-- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 7 +++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 5677a424b585..6857cb4efb76 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -295,6 +295,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; + uint32_t crtc_ext_cntl = 0; uint32_t mask; if (radeon_crtc->crtc_id) @@ -307,6 +308,16 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); + /* + * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC. + * Therefore it is set in the DAC DMPS function. + * This is different for GPU's with a single CRTC but a primary and a + * TV DAC: here it controls the single CRTC no matter where it is + * routed. Therefore we set it here. + */ + if (rdev->flags & RADEON_SINGLE_CRTC) + crtc_ext_cntl = RADEON_CRTC_CRT_ON; + switch (mode) { case DRM_MODE_DPMS_ON: radeon_crtc->enabled = true; @@ -317,7 +328,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) else { WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | RADEON_CRTC_DISP_REQ_EN_B)); - WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask); + WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl)); } drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); @@ -331,7 +342,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) else { WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | RADEON_CRTC_DISP_REQ_EN_B)); - WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); + WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl)); } radeon_crtc->enabled = false; /* adjust pm to dpms changes AFTER disabling crtcs */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 3afed70306df..817392fc2d04 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -537,7 +537,9 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode break; } - WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + /* handled in radeon_crtc_dpms() */ + if (!(rdev->flags & RADEON_SINGLE_CRTC)) + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); WREG32(RADEON_DAC_CNTL, dac_cntl); WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); @@ -1095,7 +1097,8 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) } else { if (is_tv) WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); - else + /* handled in radeon_crtc_dpms() */ + else if (!(rdev->flags & RADEON_SINGLE_CRTC)) WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); } -- cgit v1.2.3 From 6d9cdfc27115b5d4a32906b25a6b2f89920b0366 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 31 Oct 2012 11:51:03 -0400 Subject: drm/radeon: add load detection support for ext DAC on R200 (v2) The R200 asics use an external DAC for the secondary DAC. The current KMS code tries to use code for the integrated TV DAC for R200 which leads to unpredictable results since R200 does not have an integrated TV DAC. This patch ports the external DAC load detection support from the UMS driver to KMS. v2: fix typo in loop break logic Signed-off-by: Alex Deucher Reviewed-by: Egbert Eich --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 97 +++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 817392fc2d04..f5ba2241dacc 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -1422,6 +1422,96 @@ static bool radeon_legacy_tv_detect(struct drm_encoder *encoder, return found; } +static bool radeon_legacy_ext_dac_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl; + uint32_t disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c; + uint32_t disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f; + uint32_t tmp, crtc2_h_total_disp, crtc2_v_total_disp; + uint32_t crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid; + bool found = false; + int i; + + /* save the regs we need */ + gpio_monid = RREG32(RADEON_GPIO_MONID); + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + disp_lin_trans_grph_a = RREG32(RADEON_DISP_LIN_TRANS_GRPH_A); + disp_lin_trans_grph_b = RREG32(RADEON_DISP_LIN_TRANS_GRPH_B); + disp_lin_trans_grph_c = RREG32(RADEON_DISP_LIN_TRANS_GRPH_C); + disp_lin_trans_grph_d = RREG32(RADEON_DISP_LIN_TRANS_GRPH_D); + disp_lin_trans_grph_e = RREG32(RADEON_DISP_LIN_TRANS_GRPH_E); + disp_lin_trans_grph_f = RREG32(RADEON_DISP_LIN_TRANS_GRPH_F); + crtc2_h_total_disp = RREG32(RADEON_CRTC2_H_TOTAL_DISP); + crtc2_v_total_disp = RREG32(RADEON_CRTC2_V_TOTAL_DISP); + crtc2_h_sync_strt_wid = RREG32(RADEON_CRTC2_H_SYNC_STRT_WID); + crtc2_v_sync_strt_wid = RREG32(RADEON_CRTC2_V_SYNC_STRT_WID); + + tmp = RREG32(RADEON_GPIO_MONID); + tmp &= ~RADEON_GPIO_A_0; + WREG32(RADEON_GPIO_MONID, tmp); + + WREG32(RADEON_FP2_GEN_CNTL, (RADEON_FP2_ON | + RADEON_FP2_PANEL_FORMAT | + R200_FP2_SOURCE_SEL_TRANS_UNIT | + RADEON_FP2_DVO_EN | + R200_FP2_DVO_RATE_SEL_SDR)); + + WREG32(RADEON_DISP_OUTPUT_CNTL, (RADEON_DISP_DAC_SOURCE_RMX | + RADEON_DISP_TRANS_MATRIX_GRAPHICS)); + + WREG32(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_EN | + RADEON_CRTC2_DISP_REQ_EN_B)); + + WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); + + WREG32(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); + WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); + WREG32(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); + WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); + + for (i = 0; i < 200; i++) { + tmp = RREG32(RADEON_GPIO_MONID); + if (tmp & RADEON_GPIO_Y_0) + found = true; + + if (found) + break; + + if (!drm_can_sleep()) + mdelay(1); + else + msleep(1); + } + + /* restore the regs we used */ + WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f); + WREG32(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp); + WREG32(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp); + WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid); + WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + WREG32(RADEON_GPIO_MONID, gpio_monid); + + return found; +} + static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -1466,6 +1556,13 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder return connector_status_disconnected; } + /* R200 uses an external DAC for secondary DAC */ + if (rdev->family == CHIP_R200) { + if (radeon_legacy_ext_dac_detect(encoder, connector)) + found = connector_status_connected; + return found; + } + /* save the regs we need */ pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); -- cgit v1.2.3