diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 2730199..1cc1148 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1241,7 +1241,7 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) bg = dac_info->ucDAC1_BG_Adjustment; dac = dac_info->ucDAC1_DAC_Adjustment; p_dac->ps2_pdac_adj = (bg << 8) | (dac); - + p_dac->force_data = dac_info->usDAC1_FORCE_Data; } return p_dac; } @@ -1423,6 +1423,7 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) if (!tv_dac) return NULL; + tv_dac->force_data = dac_info->usDAC2_CRT2_FORCE_Data; bg = dac_info->ucDAC2_CRT2_BG_Adjustment; dac = dac_info->ucDAC2_CRT2_DAC_Adjustment; tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index f2ea756..f8b387e 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1400,67 +1400,253 @@ atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *conn struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_connector *radeon_connector = to_radeon_connector(connector); + DAC_LOAD_DETECTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + uint8_t frev, crev, ps_size; - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | - ATOM_DEVICE_CV_SUPPORT | - ATOM_DEVICE_CRT_SUPPORT)) { - DAC_LOAD_DETECTION_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); - uint8_t frev, crev, ps_size; - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header_stack(rdev->mode_info.atom_context, index, &frev, &crev, &ps_size, NULL)) - return false; + memset(&args, 0, sizeof(args)); - /* r4xx and some early rv5xx probe all DACs, this can cause distrubances in the force, - also on other DACs. - we can detect these tables as they have a 0 sized param stack */ - if (ps_size == 0) { - DRM_DEBUG("DAC load detection isn't properly supported on this GPU\n"); - return false; - } + if (!atom_parse_cmd_header_stack(rdev->mode_info.atom_context, index, &frev, &crev, &ps_size, NULL)) + return false; - args.sDacload.ucMisc = 0; + /* r4xx and some early rv5xx probe all DACs, this can cause distrubances in the force, + also on other DACs. - we can detect these tables as they have a 0 sized param stack */ + if (ps_size == 0) { + DRM_DEBUG("DAC load detection isn't properly supported on this GPU\n"); + return false; + } - if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) - args.sDacload.ucDacType = ATOM_DAC_A; - else - args.sDacload.ucDacType = ATOM_DAC_B; - - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); - else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); - else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); - if (crev >= 3) - args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); - if (crev >= 3) - args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } + args.sDacload.ucMisc = 0; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) + args.sDacload.ucDacType = ATOM_DAC_A; + else + args.sDacload.ucDacType = ATOM_DAC_B; + + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); + else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); + else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } - return true; - } else - return false; -} + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + return true; + } + + static enum drm_connector_status + radeon_r4xx_primary_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 vclk_ecp_cntl, crtc_ext_cntl; + uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp, result; + enum drm_connector_status found = connector_status_disconnected; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); + dac_cntl = RREG32(RADEON_DAC_CNTL); + dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); + + tmp = RREG32(RADEON_DISP_OUTPUT_CNTL); + tmp &= ~RADEON_DISP_DAC_SOURCE_MASK; + WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + + tmp = dac_macro_cntl & ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + WREG32(RADEON_DAC_MACRO_CNTL, tmp); + + tmp = vclk_ecp_cntl & + ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + + tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; + WREG32(RADEON_CRTC_EXT_CNTL, tmp); + + tmp = dac_ext_cntl & ~RADEON_DAC_FORCE_DATA_MASK; + if (radeon_encoder->enc_priv) { + struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv; + tmp |= p_dac->force_data << RADEON_DAC_FORCE_DATA_SHIFT; + } + tmp |= (RADEON_DAC_FORCE_DATA_EN | + RADEON_DAC_FORCE_DATA_SEL_RGB); + WREG32(RADEON_DAC_EXT_CNTL, tmp); + + udelay(2000); + + tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); + tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; + WREG32(RADEON_DAC_CNTL, tmp); + + udelay(5000); + + result = RREG32(RADEON_DAC_CNTL); + + WREG32(RADEON_DAC_CNTL, dac_cntl); + WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); + + result &= (RADEON_DAC_CMP_R | RADEON_DAC_CMP_G | RADEON_DAC_CMP_B); + + if (result) + found = connector_status_connected; + return found; + } + + static enum drm_connector_status + radeon_r4xx_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) + { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t dac_cntl2, crtc2_gen_cntl, tv_dac_cntl, tmp, dac_ext_cntl, result; + enum drm_connector_status found = connector_status_disconnected; + struct radeon_encoder_tv_dac *tv_dac = (struct radeon_encoder_tv_dac *)radeon_encoder->enc_priv; + + dac_cntl2 = RREG32(RADEON_DAC_CNTL2); + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); + /* magic */ + tmp = RREG32(0x1a8); + tmp |= 0x8 << 16; + WREG32(0x1a8, tmp); + tmp = RREG32(0x1b0); + tmp |= 0x8 << 16; + WREG32(0x1b0, tmp); + tmp = RREG32(0x1ac); + tmp |= 0x8 << 16; + WREG32(0x1ac, tmp); + + tmp = (RADEON_TV_DAC_STD_PS2 | + tv_dac->ps2_tvdac_adj | + R420_TV_DAC_TVENABLE); + + WREG32(RADEON_TV_DAC_CNTL, tmp); + + tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL; + WREG32(RADEON_DAC_CNTL2, tmp); + + tmp = crtc2_gen_cntl | RADEON_CRTC2_CRT2_ON; + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + + tmp = dac_ext_cntl & ~RADEON_DAC_FORCE_DATA_MASK; + tmp |= tv_dac->force_data << RADEON_DAC_FORCE_DATA_SHIFT; + + tmp &= 0xff; + tmp |= RADEON_DAC2_FORCE_BLANK_OFF_EN | + RADEON_DAC2_FORCE_DATA_EN | + RADEON_DAC_FORCE_DATA_SEL_RGB; + WREG32(RADEON_DAC_EXT_CNTL, tmp); + + mdelay(2); + + tmp = RREG32(RADEON_TV_DAC_CNTL); + tmp |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | RADEON_TV_MONITOR_DETECT_EN; + WREG32(RADEON_TV_DAC_CNTL, tmp); + + mdelay(10); + + result = RREG32(RADEON_TV_DAC_CNTL) & (RADEON_TV_DAC_RDACDET| RADEON_TV_DAC_GDACDET| + RADEON_TV_DAC_BDACDET); + if (result == (RADEON_TV_DAC_RDACDET| RADEON_TV_DAC_GDACDET| + RADEON_TV_DAC_BDACDET)) + found = connector_status_connected; + + return found; + +#if 0 + /* TV1 support */ + tmp = RREG32(0x1ac); + tmp &= ~(1 << 19); + WREG32(0x1ac, tmp); + + tmp = dac_ext_cntl & ~RADEON_DAC_FORCE_DATA_MASK; + tmp |= 0x1f5 << RADEON_DAC_FORCE_DATA_SHIFT; + WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + + tmp = RREG32(RADEON_TV_DAC_CNTL); + tmp &= ~(RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | RADEON_TV_MONITOR_DETECT_EN); + WREG32(RADEON_TV_DAC_CNTL); + + udelay(2000); + + tmp = RREG32(RADEON_TV_DAC_CNTL); + tmp |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | RADEON_TV_MONITOR_DETECT_EN; + + udelay(10000); + + result = RREG32(RADEON_TV_DAC_CNTL); + if ((result & 0x4000) == 0x4000) { + s0 = ATOM_S0_TV1_SVIDEO; + } + if ((result & 0x8000) == 0x8000) { + s0 = ATOM_S0_TV1_COMPOSITE; + } +#endif + +#if 0 + /* CV support */ + +#endif + } + + static enum drm_connector_status + radeon_r4xx_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) + { + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (!(radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | + ATOM_DEVICE_CV_SUPPORT | + ATOM_DEVICE_CRT_SUPPORT))) + /* TODO CV SUPPORT */ + return false; + + + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) + return radeon_r4xx_primary_dac_detect(encoder, connector); + else + return radeon_r4xx_tv_dac_detect(encoder, connector); + } + + + static enum drm_connector_status + radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) + { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + uint32_t bios_0_scratch; -static enum drm_connector_status -radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - uint32_t bios_0_scratch; + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | + ATOM_DEVICE_CV_SUPPORT | + ATOM_DEVICE_CRT_SUPPORT)) { - if (!atombios_dac_load_detect(encoder, connector)) { - DRM_DEBUG("dac detect returned false\n"); - return connector_status_disconnected; + if (!atombios_dac_load_detect(encoder, connector)) { + if (rdev->family >= CHIP_R420 && + rdev->family <= CHIP_RV410) + return radeon_r4xx_dac_detect(encoder, connector); +// else if (rdev->family == CHIP_RV515) +// return radeon_rv515_dac_detect(encoder, connector); + + DRM_DEBUG("dac detect returned false\n"); + return connector_status_disconnected; + } } if (rdev->family >= CHIP_R600) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index e545a79..824504c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -264,6 +264,7 @@ struct radeon_crtc { struct radeon_encoder_primary_dac { /* legacy primary dac */ uint32_t ps2_pdac_adj; + uint16_t force_data; }; struct radeon_encoder_lvds { @@ -286,6 +287,7 @@ struct radeon_encoder_tv_dac { uint32_t ps2_tvdac_adj; uint32_t ntsc_tvdac_adj; uint32_t pal_tvdac_adj; + uint32_t force_data; int h_pos; int v_pos; diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index eabbc9c..665586e 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -576,6 +576,9 @@ # define RADEON_DAC_RANGE_CNTL_MASK 0x03 # define RADEON_DAC_BLANKING (1 << 2) # define RADEON_DAC_CMP_EN (1 << 3) +# define RADEON_DAC_CMP_R (1 << 4) +# define RADEON_DAC_CMP_G (1 << 5) +# define RADEON_DAC_CMP_B (1 << 6) # define RADEON_DAC_CMP_OUTPUT (1 << 7) # define RADEON_DAC_8BIT_EN (1 << 8) # define RADEON_DAC_TVO_EN (1 << 10)