From 45b2673fa4dd9adfbf9680186bb8fe3a6c51dfd7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 4 May 2010 15:55:20 -0400 Subject: [PATCH] drm/radeon/kms: add special workaround for triple head servers Some rn50 servers need a special workaround. This adds the workaround from the ddx. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r100.c | 121 +++++++++++++++------------ drivers/gpu/drm/radeon/radeon.h | 6 ++ drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 22 +++++ 3 files changed, 95 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 71c076f..018afc7 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2164,7 +2164,6 @@ int r100_asic_reset(struct radeon_device *rdev) void r100_set_common_regs(struct radeon_device *rdev) { struct drm_device *dev = rdev->ddev; - bool force_dac2 = false; u32 tmp; /* set these so they don't interfere with anything */ @@ -2181,61 +2180,75 @@ void r100_set_common_regs(struct radeon_device *rdev) * don't report it in the bios connector * table. */ - switch (dev->pdev->device) { - /* RN50 */ - case 0x515e: - case 0x5969: - force_dac2 = true; - break; - /* RV100*/ - case 0x5159: - case 0x515a: - /* DELL triple head servers */ - if ((dev->pdev->subsystem_vendor == 0x1028 /* DELL */) && - ((dev->pdev->subsystem_device == 0x016c) || - (dev->pdev->subsystem_device == 0x016d) || - (dev->pdev->subsystem_device == 0x016e) || - (dev->pdev->subsystem_device == 0x016f) || - (dev->pdev->subsystem_device == 0x0170) || - (dev->pdev->subsystem_device == 0x017d) || - (dev->pdev->subsystem_device == 0x017e) || - (dev->pdev->subsystem_device == 0x0183) || - (dev->pdev->subsystem_device == 0x018a) || - (dev->pdev->subsystem_device == 0x019a))) - force_dac2 = true; - break; - } + if (rdev->family <= CHIP_RS200) { + rdev->config.r100.triple_head_server = false; + switch (dev->pdev->device) { + /* RN50 */ + case 0x515e: + case 0x5969: + rdev->config.r100.triple_head_server = true; + break; + /* RV100*/ + case 0x5159: + case 0x515a: + /* DELL/HP triple head servers */ + if ((dev->pdev->subsystem_vendor == 0x1028 /* DELL */) && + ((dev->pdev->subsystem_device == 0x016c) || + (dev->pdev->subsystem_device == 0x016d) || + (dev->pdev->subsystem_device == 0x016e) || + (dev->pdev->subsystem_device == 0x016f) || + (dev->pdev->subsystem_device == 0x0170) || + (dev->pdev->subsystem_device == 0x017d) || + (dev->pdev->subsystem_device == 0x017e) || + (dev->pdev->subsystem_device == 0x0183) || + (dev->pdev->subsystem_device == 0x018a) || + (dev->pdev->subsystem_device == 0x019a))) + rdev->config.r100.triple_head_server = true; + if ((dev->pdev->subsystem_vendor == 0x103c /* HP */) && + ((dev->pdev->subsystem_device == 0x31fb) || + (dev->pdev->subsystem_device == 0x1304))) + rdev->config.r100.triple_head_server = true; + break; + } - if (force_dac2) { - u32 disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); - u32 tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); - u32 dac2_cntl = RREG32(RADEON_DAC_CNTL2); + if (rdev->config.r100.triple_head_server) { + u32 disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + u32 tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + u32 dac2_cntl = RREG32(RADEON_DAC_CNTL2); + u32 crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + + /* For CRT on DAC2, don't turn it on if BIOS didn't + enable it, even it's detected. + */ + + /* force it to crtc0 */ + dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; + dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + + /* set up the TV DAC */ + tv_dac_cntl &= ~(RADEON_TV_DAC_PEDESTAL | + RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGADJ_MASK | + RADEON_TV_DAC_DACADJ_MASK); + tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2 | + (0x58 << 16)); - /* For CRT on DAC2, don't turn it on if BIOS didn't - enable it, even it's detected. - */ + rdev->config.r100.tv_dac_cntl = tv_dac_cntl; + rdev->config.r100.disp_hw_debug = disp_hw_debug; + rdev->config.r100.dac2_cntl = dac2_cntl; + rdev->config.r100.crtc2_gen_cntl = crtc2_gen_cntl; - /* force it to crtc0 */ - dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; - dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; - disp_hw_debug |= RADEON_CRT2_DISP1_SEL; - - /* set up the TV DAC */ - tv_dac_cntl &= ~(RADEON_TV_DAC_PEDESTAL | - RADEON_TV_DAC_STD_MASK | - RADEON_TV_DAC_RDACPD | - RADEON_TV_DAC_GDACPD | - RADEON_TV_DAC_BDACPD | - RADEON_TV_DAC_BGADJ_MASK | - RADEON_TV_DAC_DACADJ_MASK); - tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | - RADEON_TV_DAC_NHOLD | - RADEON_TV_DAC_STD_PS2 | - (0x58 << 16)); - - WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); - WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); - WREG32(RADEON_DAC_CNTL2, dac2_cntl); + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + } } /* switch PM block to ACPI mode */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 24b81ea..fb1095c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -832,6 +832,12 @@ struct r100_asic { unsigned reg_safe_bm_size; u32 hdp_cntl; struct r100_gpu_lockup lockup; + /* rn50 triple head servers */ + bool triple_head_server; + u32 tv_dac_cntl; + u32 disp_hw_debug; + u32 dac2_cntl; + u32 crtc2_gen_cntl; }; struct r300_asic { diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index f4f9cb2..a0b9f33 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -982,11 +982,32 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +static void rn50_set_triple_head_server_config(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + + switch (dev->pdev->device) { + case 0x515e: + case 0x5969: + case 0x5159: + case 0x515a: + if (rdev->config.r100.triple_head_server) { + WREG32(RADEON_TV_DAC_CNTL, rdev->config.r100.tv_dac_cntl); + WREG32(RADEON_DISP_HW_DEBUG, rdev->config.r100.disp_hw_debug); + WREG32(RADEON_DAC_CNTL2, rdev->config.r100.dac2_cntl); + WREG32(RADEON_CRTC2_GEN_CNTL, rdev->config.r100.crtc2_gen_cntl); + } + break; + } +} + static int radeon_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb) { + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); /* TODO TV */ @@ -996,6 +1017,7 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc, radeon_overscan_setup(crtc, adjusted_mode); if (radeon_crtc->crtc_id == 0) { radeon_legacy_rmx_mode_set(crtc, adjusted_mode); + rn50_set_triple_head_server_config(rdev); } else { if (radeon_crtc->rmx_type != RMX_OFF) { /* FIXME: only first crtc has rmx what should we -- 1.5.6.3