aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_legacy_encoders.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c489
1 files changed, 439 insertions, 50 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 0b8397000f4..c89971d904c 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -23,11 +23,15 @@
* Authors: Dave Airlie
* Alex Deucher
*/
-#include "drmP.h"
-#include "drm_crtc_helper.h"
-#include "radeon_drm.h"
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/radeon_drm.h>
#include "radeon.h"
#include "atom.h"
+#include <linux/backlight.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
{
@@ -39,7 +43,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
radeon_encoder->active_device = 0;
}
-static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -47,15 +51,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
int panel_pwr_delay = 2000;
bool is_mac = false;
+ uint8_t backlight_level;
DRM_DEBUG_KMS("\n");
+ lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+ backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
if (radeon_encoder->enc_priv) {
if (rdev->is_atom_bios) {
struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
panel_pwr_delay = lvds->panel_pwr_delay;
+ if (lvds->bl_dev)
+ backlight_level = lvds->backlight_level;
} else {
struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
panel_pwr_delay = lvds->panel_pwr_delay;
+ if (lvds->bl_dev)
+ backlight_level = lvds->backlight_level;
}
}
@@ -76,18 +88,20 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
lvds_pll_cntl |= RADEON_LVDS_PLL_EN;
WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
- udelay(1000);
+ mdelay(1);
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
- lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
- lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
+ lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
+ RADEON_LVDS_BL_MOD_LEVEL_MASK);
+ lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
+ RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
+ (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
if (is_mac)
lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
- lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
- udelay(panel_pwr_delay * 1000);
+ mdelay(panel_pwr_delay);
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
break;
case DRM_MODE_DPMS_STANDBY:
@@ -95,7 +109,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
case DRM_MODE_DPMS_OFF:
pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
- lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
if (is_mac) {
lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
@@ -105,10 +118,10 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON);
}
- udelay(panel_pwr_delay * 1000);
+ mdelay(panel_pwr_delay);
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
- udelay(panel_pwr_delay * 1000);
+ mdelay(panel_pwr_delay);
break;
}
@@ -119,6 +132,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
}
+static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct radeon_device *rdev = encoder->dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ DRM_DEBUG("\n");
+
+ if (radeon_encoder->enc_priv) {
+ if (rdev->is_atom_bios) {
+ struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+ lvds->dpms_mode = mode;
+ } else {
+ struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+ lvds->dpms_mode = mode;
+ }
+ }
+
+ radeon_legacy_lvds_update(encoder, mode);
+}
+
static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
{
struct radeon_device *rdev = encoder->dev->dev_private;
@@ -212,7 +244,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
}
static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
+ const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -237,9 +269,243 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
.disable = radeon_legacy_encoder_disable,
};
+u8
+radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder)
+{
+ struct drm_device *dev = radeon_encoder->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ u8 backlight_level;
+
+ backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+ RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+ return backlight_level;
+}
+
+void
+radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level)
+{
+ struct drm_device *dev = radeon_encoder->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ int dpms_mode = DRM_MODE_DPMS_ON;
+
+ if (radeon_encoder->enc_priv) {
+ if (rdev->is_atom_bios) {
+ struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+ if (lvds->backlight_level > 0)
+ dpms_mode = lvds->dpms_mode;
+ else
+ dpms_mode = DRM_MODE_DPMS_OFF;
+ lvds->backlight_level = level;
+ } else {
+ struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+ if (lvds->backlight_level > 0)
+ dpms_mode = lvds->dpms_mode;
+ else
+ dpms_mode = DRM_MODE_DPMS_OFF;
+ lvds->backlight_level = level;
+ }
+ }
+
+ radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
+}
+
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+
+static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
+{
+ struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+ uint8_t level;
+
+ /* Convert brightness to hardware level */
+ if (bd->props.brightness < 0)
+ level = 0;
+ else if (bd->props.brightness > RADEON_MAX_BL_LEVEL)
+ level = RADEON_MAX_BL_LEVEL;
+ else
+ level = bd->props.brightness;
+
+ if (pdata->negative)
+ level = RADEON_MAX_BL_LEVEL - level;
+
+ return level;
+}
+
+static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+{
+ struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+ struct radeon_encoder *radeon_encoder = pdata->encoder;
+
+ radeon_legacy_set_backlight_level(radeon_encoder,
+ radeon_legacy_lvds_level(bd));
+
+ return 0;
+}
+
+static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
+{
+ struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+ struct radeon_encoder *radeon_encoder = pdata->encoder;
+ struct drm_device *dev = radeon_encoder->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ uint8_t backlight_level;
+
+ backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+ RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+ return pdata->negative ? RADEON_MAX_BL_LEVEL - backlight_level : backlight_level;
+}
+
+static const struct backlight_ops radeon_backlight_ops = {
+ .get_brightness = radeon_legacy_backlight_get_brightness,
+ .update_status = radeon_legacy_backlight_update_status,
+};
+
+void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+ struct drm_connector *drm_connector)
+{
+ struct drm_device *dev = radeon_encoder->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct backlight_device *bd;
+ struct backlight_properties props;
+ struct radeon_backlight_privdata *pdata;
+ uint8_t backlight_level;
+ char bl_name[16];
+
+ if (!radeon_encoder->enc_priv)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati") &&
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
+ if (!pdata) {
+ DRM_ERROR("Memory allocation failed\n");
+ goto error;
+ }
+
+ memset(&props, 0, sizeof(props));
+ props.max_brightness = RADEON_MAX_BL_LEVEL;
+ props.type = BACKLIGHT_RAW;
+ snprintf(bl_name, sizeof(bl_name),
+ "radeon_bl%d", dev->primary->index);
+ bd = backlight_device_register(bl_name, drm_connector->kdev,
+ pdata, &radeon_backlight_ops, &props);
+ if (IS_ERR(bd)) {
+ DRM_ERROR("Backlight registration failed\n");
+ goto error;
+ }
+
+ pdata->encoder = radeon_encoder;
+
+ backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+ RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+ /* First, try to detect backlight level sense based on the assumption
+ * that firmware set it up at full brightness
+ */
+ if (backlight_level == 0)
+ pdata->negative = true;
+ else if (backlight_level == 0xff)
+ pdata->negative = false;
+ else {
+ /* XXX hack... maybe some day we can figure out in what direction
+ * backlight should work on a given panel?
+ */
+ pdata->negative = (rdev->family != CHIP_RV200 &&
+ rdev->family != CHIP_RV250 &&
+ rdev->family != CHIP_RV280 &&
+ rdev->family != CHIP_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ pdata->negative = (pdata->negative ||
+ of_machine_is_compatible("PowerBook4,3") ||
+ of_machine_is_compatible("PowerBook6,3") ||
+ of_machine_is_compatible("PowerBook6,5"));
+#endif
+ }
+
+ if (rdev->is_atom_bios) {
+ struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+ lvds->bl_dev = bd;
+ } else {
+ struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+ lvds->bl_dev = bd;
+ }
+
+ bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+
+ DRM_INFO("radeon legacy LVDS backlight initialized\n");
+
+ return;
+
+error:
+ kfree(pdata);
+ return;
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
+{
+ struct drm_device *dev = radeon_encoder->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct backlight_device *bd = NULL;
+
+ if (!radeon_encoder->enc_priv)
+ return;
+
+ if (rdev->is_atom_bios) {
+ struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+ bd = lvds->bl_dev;
+ lvds->bl_dev = NULL;
+ } else {
+ struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+ bd = lvds->bl_dev;
+ lvds->bl_dev = NULL;
+ }
+
+ if (bd) {
+ struct radeon_backlight_privdata *pdata;
+
+ pdata = bl_get_data(bd);
+ backlight_device_unregister(bd);
+ kfree(pdata);
+
+ DRM_INFO("radeon legacy LVDS backlight unloaded\n");
+ }
+}
+
+#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+void radeon_legacy_backlight_init(struct radeon_encoder *encoder)
+{
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder)
+{
+}
+
+#endif
+
+
+static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->enc_priv) {
+ radeon_legacy_backlight_exit(radeon_encoder);
+ kfree(radeon_encoder->enc_priv);
+ }
+ drm_encoder_cleanup(encoder);
+ kfree(radeon_encoder);
+}
static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
- .destroy = radeon_enc_destroy,
+ .destroy = radeon_lvds_enc_destroy,
};
static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
@@ -271,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);
@@ -372,6 +640,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc
enum drm_connector_status found = connector_status_disconnected;
bool color = true;
+ /* just don't bother on RN50 those chip are often connected to remoting
+ * console hw and often we get failure to load detect those. So to make
+ * everyone happy report the encoder as always connected.
+ */
+ if (ASIC_IS_RN50(rdev)) {
+ return connector_status_connected;
+ }
+
/* save the regs we need */
vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
@@ -396,6 +672,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);
@@ -405,13 +683,14 @@ 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);
WREG32(RADEON_DAC_MACRO_CNTL, tmp);
- udelay(2000);
+ mdelay(2);
if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT)
found = connector_status_connected;
@@ -670,7 +949,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
if (rdev->is_atom_bios) {
radeon_encoder->pixel_clock = adjusted_mode->clock;
- atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+ atombios_dvo_setup(encoder, ATOM_ENABLE);
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
} else {
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
@@ -728,11 +1007,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
static void radeon_ext_tmds_enc_destroy(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_ext_tmds *tmds = radeon_encoder->enc_priv;
- if (tmds) {
- if (tmds->i2c_bus)
- radeon_i2c_destroy(tmds->i2c_bus);
- }
+ /* don't destroy the i2c bus record here, this will be done in radeon_i2c_fini */
kfree(radeon_encoder->enc_priv);
drm_encoder_cleanup(encoder);
kfree(radeon_encoder);
@@ -830,7 +1105,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);
}
@@ -1154,13 +1430,104 @@ 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)
{
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 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, 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;
@@ -1197,12 +1564,27 @@ 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);
- 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);
- crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+
+ if (rdev->flags & RADEON_SINGLE_CRTC) {
+ crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+ } else {
+ 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);
dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
@@ -1211,22 +1593,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);
- 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)) {
- 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 |
@@ -1254,7 +1638,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN;
WREG32(RADEON_DAC_CNTL2, tmp);
- udelay(10000);
+ mdelay(10);
if (ASIC_IS_R300(rdev)) {
if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B)
@@ -1268,14 +1652,19 @@ 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);
return found;