Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
51861d4
Breadcrumbs
linux
/
drivers
/
gpu
/
drm
/
radeon
/
radeon_legacy_encoders.c
Copy path
Blame
Blame
Latest commit
History
History
1810 lines (1522 loc) · 55.6 KB
Breadcrumbs
linux
/
drivers
/
gpu
/
drm
/
radeon
/
radeon_legacy_encoders.c
Top
File metadata and controls
Code
Blame
1810 lines (1522 loc) · 55.6 KB
Raw
/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher */ #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) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_encoder_helper_funcs *encoder_funcs; encoder_funcs = encoder->helper_private; encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); radeon_encoder->active_device = 0; } 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; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 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; } } /* macs (and possibly some x86 oem systems?) wire up LVDS strangely * Taken from radeonfb. */ if ((rdev->mode_info.connector_table == CT_IBOOK) || (rdev->mode_info.connector_table == CT_POWERBOOK_EXTERNAL) || (rdev->mode_info.connector_table == CT_POWERBOOK_INTERNAL) || (rdev->mode_info.connector_table == CT_POWERBOOK_VGA)) is_mac = true; switch (mode) { case DRM_MODE_DPMS_ON: disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN); disp_pwr_man |= RADEON_AUTO_PWRUP_EN; WREG32(RADEON_DISP_PWR_MAN, disp_pwr_man); lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl |= RADEON_LVDS_PLL_EN; WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 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 &= ~(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; mdelay(panel_pwr_delay); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: 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 |= RADEON_LVDS_DISPLAY_DIS; if (is_mac) { lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN; WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN); } else { WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); } mdelay(panel_pwr_delay); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); mdelay(panel_pwr_delay); break; } if (rdev->is_atom_bios) radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } 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; if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, false); else radeon_combios_output_lock(encoder, false); } static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; DRM_DEBUG_KMS("\n"); lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); if (rdev->is_atom_bios) { /* LVDS_GEN_CNTL parameters are computed in LVDSEncoderControl * need to call that on resume to set up the reg properly. */ radeon_encoder->pixel_clock = adjusted_mode->clock; atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); } else { struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; if (lvds) { DRM_DEBUG_KMS("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); lvds_gen_cntl = lvds->lvds_gen_cntl; lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | (lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); } else lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); } lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_RST_FM); if (ASIC_IS_R300(rdev)) lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK); if (radeon_crtc->crtc_id == 0) { if (ASIC_IS_R300(rdev)) { if (radeon_encoder->rmx_type != RMX_OFF) lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX; } else lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; } else { if (ASIC_IS_R300(rdev)) lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2; else lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; } WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); WREG32(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl); if (rdev->family == CHIP_RV410) WREG32(RADEON_CLOCK_CNTL_INDEX, 0); if (rdev->is_atom_bios) radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); else radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); } static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); /* set the active encoder to connector routing */ radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); /* get the native mode for LVDS */ if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) radeon_panel_mode_fixup(encoder, adjusted_mode); return true; } static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { .dpms = radeon_legacy_lvds_dpms, .mode_fixup = radeon_legacy_mode_fixup, .prepare = radeon_legacy_lvds_prepare, .mode_set = radeon_legacy_lvds_mode_set, .commit = radeon_legacy_lvds_commit, .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_lvds_enc_destroy, }; static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL); uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); DRM_DEBUG_KMS("\n"); switch (mode) { case DRM_MODE_DPMS_ON: crtc_ext_cntl |= RADEON_CRTC_CRT_ON; dac_cntl &= ~RADEON_DAC_PDWN; dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON; dac_cntl |= RADEON_DAC_PDWN; dac_macro_cntl |= (RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); break; } /* 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); if (rdev->is_atom_bios) radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, false); else radeon_combios_output_lock(encoder, false); } static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; DRM_DEBUG_KMS("\n"); if (radeon_crtc->crtc_id == 0) { if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & ~(RADEON_DISP_DAC_SOURCE_MASK); WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); } else { dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); WREG32(RADEON_DAC_CNTL2, dac2_cntl); } } else { if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & ~(RADEON_DISP_DAC_SOURCE_MASK); disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); } else { dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; WREG32(RADEON_DAC_CNTL2, dac2_cntl); } } dac_cntl = (RADEON_DAC_MASK_ALL | RADEON_DAC_VGA_ADR_EN | /* TODO 6-bits */ RADEON_DAC_8BIT_EN); WREG32_P(RADEON_DAC_CNTL, dac_cntl, RADEON_DAC_RANGE_CNTL | RADEON_DAC_BLANKING); if (radeon_encoder->enc_priv) { struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv; dac_macro_cntl = p_dac->ps2_pdac_adj; } else dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B; WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); if (rdev->is_atom_bios) radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); else radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); } static enum drm_connector_status radeon_legacy_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; 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); dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); dac_cntl = RREG32(RADEON_DAC_CNTL); dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); 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 = RADEON_DAC_FORCE_BLANK_OFF_EN | RADEON_DAC_FORCE_DATA_EN; if (color) tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; else tmp |= RADEON_DAC_FORCE_DATA_SEL_G; 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); WREG32(RADEON_DAC_EXT_CNTL, tmp); 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); tmp = dac_macro_cntl; tmp &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); WREG32(RADEON_DAC_MACRO_CNTL, tmp); mdelay(2); if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) found = connector_status_connected; /* restore the regs we used */ WREG32(RADEON_DAC_CNTL, dac_cntl); WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); return found; } static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { .dpms = radeon_legacy_primary_dac_dpms, .mode_fixup = radeon_legacy_mode_fixup, .prepare = radeon_legacy_primary_dac_prepare, .mode_set = radeon_legacy_primary_dac_mode_set, .commit = radeon_legacy_primary_dac_commit, .detect = radeon_legacy_primary_dac_detect, .disable = radeon_legacy_encoder_disable, }; static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { .destroy = radeon_enc_destroy, }; static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL); DRM_DEBUG_KMS("\n"); switch (mode) { case DRM_MODE_DPMS_ON: fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); break; } WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); if (rdev->is_atom_bios) radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); } static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; int i; DRM_DEBUG_KMS("\n"); tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL); tmp &= 0xfffff; if (rdev->family == CHIP_RV280) { /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ tmp ^= (1 << 22); tmds_pll_cntl ^= (1 << 22); } if (radeon_encoder->enc_priv) { struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv; for (i = 0; i < 4; i++) { if (tmds->tmds_pll[i].freq == 0) break; if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) { tmp = tmds->tmds_pll[i].value ; break; } } } if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV280)) { if (tmp & 0xfff00000) tmds_pll_cntl = tmp; else { tmds_pll_cntl &= 0xfff00000; tmds_pll_cntl |= tmp; } } else tmds_pll_cntl = tmp; tmds_transmitter_cntl = RREG32(RADEON_TMDS_TRANSMITTER_CNTL) & ~(RADEON_TMDS_TRANSMITTER_PLLRST); if (rdev->family == CHIP_R200 || rdev->family == CHIP_R100 || ASIC_IS_R300(rdev)) tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); else /* RV chips got this bit reversed */ tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN; fp_gen_cntl = (RREG32(RADEON_FP_GEN_CNTL) | (RADEON_FP_CRTC_DONT_SHADOW_VPAR | RADEON_FP_CRTC_DONT_SHADOW_HEND)); fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); fp_gen_cntl &= ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN | RADEON_FP_DFP_SYNC_SEL | RADEON_FP_CRT_SYNC_SEL | RADEON_FP_CRTC_LOCK_8DOT | RADEON_FP_USE_SHADOW_EN | RADEON_FP_CRTC_USE_SHADOW_VEND | RADEON_FP_CRT_SYNC_ALT); if (1) /* FIXME rgbBits == 8 */ fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ else fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ if (radeon_crtc->crtc_id == 0) { if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; if (radeon_encoder->rmx_type != RMX_OFF) fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; else fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; } else fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2; } else { if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; } else fp_gen_cntl |= RADEON_FP_SEL_CRTC2; } WREG32(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl); WREG32(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl); WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); if (rdev->is_atom_bios) radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); else radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); } static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = { .dpms = radeon_legacy_tmds_int_dpms, .mode_fixup = radeon_legacy_mode_fixup, .prepare = radeon_legacy_tmds_int_prepare, .mode_set = radeon_legacy_tmds_int_mode_set, .commit = radeon_legacy_tmds_int_commit, .disable = radeon_legacy_encoder_disable, }; static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { .destroy = radeon_enc_destroy, }; static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); DRM_DEBUG_KMS("\n"); switch (mode) { case DRM_MODE_DPMS_ON: fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: fp2_gen_cntl |= RADEON_FP2_BLANK_EN; fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); break; } WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); if (rdev->is_atom_bios) radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, false); else radeon_combios_output_lock(encoder, false); } static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t fp2_gen_cntl; DRM_DEBUG_KMS("\n"); if (rdev->is_atom_bios) { radeon_encoder->pixel_clock = adjusted_mode->clock; atombios_dvo_setup(encoder, ATOM_ENABLE); fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); } else { fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); if (1) /* FIXME rgbBits == 8 */ fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ else fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN | RADEON_FP2_DVO_RATE_SEL_SDR); /* XXX: these are oem specific */ if (ASIC_IS_R300(rdev)) { if ((dev->pdev->device == 0x4850) && (dev->pdev->subsystem_vendor == 0x1028) && (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; else fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; /*if (mode->clock > 165000) fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ } if (!radeon_combios_external_tmds_setup(encoder)) radeon_external_tmds_setup(encoder); } if (radeon_crtc->crtc_id == 0) { if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; if (radeon_encoder->rmx_type != RMX_OFF) fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; else fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1; } else fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2; } else { if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; } else fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; } WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); if (rdev->is_atom_bios) radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); else radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); } static void radeon_ext_tmds_enc_destroy(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); /* 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); } static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = { .dpms = radeon_legacy_tmds_ext_dpms, .mode_fixup = radeon_legacy_mode_fixup, .prepare = radeon_legacy_tmds_ext_prepare, .mode_set = radeon_legacy_tmds_ext_mode_set, .commit = radeon_legacy_tmds_ext_commit, .disable = radeon_legacy_encoder_disable, }; static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { .destroy = radeon_ext_tmds_enc_destroy, }; static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; uint32_t tv_master_cntl = 0; bool is_tv; DRM_DEBUG_KMS("\n"); is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; if (rdev->family == CHIP_R200) fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); else { if (is_tv) tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); else crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); } switch (mode) { case DRM_MODE_DPMS_ON: if (rdev->family == CHIP_R200) { fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); } else { if (is_tv) tv_master_cntl |= RADEON_TV_ON; else crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; if (rdev->family == CHIP_R420 || rdev->family == CHIP_R423 || rdev->family == CHIP_RV410) tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | R420_TV_DAC_GDACPD | R420_TV_DAC_BDACPD | RADEON_TV_DAC_BGSLEEP); else tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD | RADEON_TV_DAC_BGSLEEP); } break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: if (rdev->family == CHIP_R200) fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); else { if (is_tv) tv_master_cntl &= ~RADEON_TV_ON; else crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; if (rdev->family == CHIP_R420 || rdev->family == CHIP_R423 || rdev->family == CHIP_RV410) tv_dac_cntl |= (R420_TV_DAC_RDACPD | R420_TV_DAC_GDACPD | R420_TV_DAC_BDACPD | RADEON_TV_DAC_BGSLEEP); else tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD | RADEON_TV_DAC_BGSLEEP); } break; } if (rdev->family == CHIP_R200) { WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); } else { if (is_tv) WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); /* 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); } if (rdev->is_atom_bios) radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); if (rdev->is_atom_bios) radeon_atom_output_lock(encoder, true); else radeon_combios_output_lock(encoder, true); } static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0; bool is_tv = false; DRM_DEBUG_KMS("\n"); is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; if (rdev->family != CHIP_R200) { tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); if (rdev->family == CHIP_R420 || rdev->family == CHIP_R423 || rdev->family == CHIP_RV410) { tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | RADEON_TV_DAC_BGADJ_MASK | R420_TV_DAC_DACADJ_MASK | R420_TV_DAC_RDACPD | R420_TV_DAC_GDACPD | R420_TV_DAC_BDACPD | R420_TV_DAC_TVENABLE); } else { tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | RADEON_TV_DAC_BGADJ_MASK | RADEON_TV_DAC_DACADJ_MASK | RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD); } tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD; if (is_tv) { if (tv_dac->tv_std == TV_STD_NTSC || tv_dac->tv_std == TV_STD_NTSC_J || tv_dac->tv_std == TV_STD_PAL_M || tv_dac->tv_std == TV_STD_PAL_60) tv_dac_cntl |= tv_dac->ntsc_tvdac_adj; else tv_dac_cntl |= tv_dac->pal_tvdac_adj; if (tv_dac->tv_std == TV_STD_NTSC || tv_dac->tv_std == TV_STD_NTSC_J) tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; else tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; } else tv_dac_cntl |= (RADEON_TV_DAC_STD_PS2 | tv_dac->ps2_tvdac_adj); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); } if (ASIC_IS_R300(rdev)) { gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1; disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); } else if (rdev->family != CHIP_R200) disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); else if (rdev->family == CHIP_R200) fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); if (rdev->family >= CHIP_R200) disp_tv_out_cntl = RREG32(RADEON_DISP_TV_OUT_CNTL); if (is_tv) { uint32_t dac_cntl; dac_cntl = RREG32(RADEON_DAC_CNTL); dac_cntl &= ~RADEON_DAC_TVO_EN; WREG32(RADEON_DAC_CNTL, dac_cntl); if (ASIC_IS_R300(rdev)) gpiopad_a = RREG32(RADEON_GPIOPAD_A) & ~1; dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~RADEON_DAC2_DAC2_CLK_SEL; if (radeon_crtc->crtc_id == 0) { if (ASIC_IS_R300(rdev)) { disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC | RADEON_DISP_TV_SOURCE_CRTC); } if (rdev->family >= CHIP_R200) { disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; } else { disp_hw_debug |= RADEON_CRT2_DISP1_SEL; } } else { if (ASIC_IS_R300(rdev)) { disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; } if (rdev->family >= CHIP_R200) { disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; } else { disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; } } WREG32(RADEON_DAC_CNTL2, dac2_cntl); } else { dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; if (radeon_crtc->crtc_id == 0) { if (ASIC_IS_R300(rdev)) { disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; } else if (rdev->family == CHIP_R200) { fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | RADEON_FP2_DVO_RATE_SEL_SDR); } else disp_hw_debug |= RADEON_CRT2_DISP1_SEL; } else { if (ASIC_IS_R300(rdev)) { disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; } else if (rdev->family == CHIP_R200) { fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | RADEON_FP2_DVO_RATE_SEL_SDR); fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; } else disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; } WREG32(RADEON_DAC_CNTL2, dac2_cntl); } if (ASIC_IS_R300(rdev)) { WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); } else if (rdev->family != CHIP_R200) WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); else if (rdev->family == CHIP_R200) WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); if (rdev->family >= CHIP_R200) WREG32(RADEON_DISP_TV_OUT_CNTL, disp_tv_out_cntl); if (is_tv) radeon_legacy_tv_mode_set(encoder, mode, adjusted_mode); if (rdev->is_atom_bios) radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); else radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); } static bool r300_legacy_tv_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_output_cntl, gpiopad_a, tmp; bool found = false; /* save regs needed */ gpiopad_a = RREG32(RADEON_GPIOPAD_A); dac_cntl2 = RREG32(RADEON_DAC_CNTL2); crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); WREG32_P(RADEON_GPIOPAD_A, 0, ~1); WREG32(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL); WREG32(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT); tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); WREG32(RADEON_DAC_EXT_CNTL, RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN | RADEON_DAC_FORCE_DATA_SEL_RGB | (0xec << RADEON_DAC_FORCE_DATA_SHIFT)); WREG32(RADEON_TV_DAC_CNTL, RADEON_TV_DAC_STD_NTSC | (8 << RADEON_TV_DAC_BGADJ_SHIFT) | (6 << RADEON_TV_DAC_DACADJ_SHIFT)); RREG32(RADEON_TV_DAC_CNTL); mdelay(4); WREG32(RADEON_TV_DAC_CNTL, RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC | (8 << RADEON_TV_DAC_BGADJ_SHIFT) | (6 << RADEON_TV_DAC_DACADJ_SHIFT)); RREG32(RADEON_TV_DAC_CNTL); mdelay(6); tmp = RREG32(RADEON_TV_DAC_CNTL); if ((tmp & RADEON_TV_DAC_GDACDET) != 0) { found = true; DRM_DEBUG_KMS("S-video TV connection detected\n"); } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { found = true; DRM_DEBUG_KMS("Composite TV connection detected\n"); } WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); WREG32(RADEON_DAC_CNTL2, dac_cntl2); WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); return found; } static bool radeon_legacy_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t tv_dac_cntl, dac_cntl2; uint32_t config_cntl, tv_pre_dac_mux_cntl, tv_master_cntl, tmp; bool found = false; if (ASIC_IS_R300(rdev)) return r300_legacy_tv_detect(encoder, connector); dac_cntl2 = RREG32(RADEON_DAC_CNTL2); tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); config_cntl = RREG32(RADEON_CONFIG_CNTL); tv_pre_dac_mux_cntl = RREG32(RADEON_TV_PRE_DAC_MUX_CNTL); tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL; WREG32(RADEON_DAC_CNTL2, tmp); tmp = tv_master_cntl | RADEON_TV_ON; tmp &= ~(RADEON_TV_ASYNC_RST | RADEON_RESTART_PHASE_FIX | RADEON_CRT_FIFO_CE_EN | RADEON_TV_FIFO_CE_EN | RADEON_RE_SYNC_NOW_SEL_MASK); tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST; WREG32(RADEON_TV_MASTER_CNTL, tmp); tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC | (8 << RADEON_TV_DAC_BGADJ_SHIFT); if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK) tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT); else tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT); WREG32(RADEON_TV_DAC_CNTL, tmp); tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN | RADEON_RED_MX_FORCE_DAC_DATA | RADEON_GRN_MX_FORCE_DAC_DATA | RADEON_BLU_MX_FORCE_DAC_DATA | (0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT); WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tmp); mdelay(3); tmp = RREG32(RADEON_TV_DAC_CNTL); if (tmp & RADEON_TV_DAC_GDACDET) { found = true; DRM_DEBUG_KMS("S-video TV connection detected\n"); } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { found = true; DRM_DEBUG_KMS("Composite TV connection detected\n"); } WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); WREG32(RADEON_DAC_CNTL2, dac_cntl2); 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 = 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; bool color = true; struct drm_crtc *crtc; /* find out if crtc2 is in use or if this encoder is using it */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); if ((radeon_crtc->crtc_id == 1) && crtc->enabled) { if (encoder->crtc != crtc) { return connector_status_disconnected; } } } if (connector->connector_type == DRM_MODE_CONNECTOR_SVIDEO || connector->connector_type == DRM_MODE_CONNECTOR_Composite || connector->connector_type == DRM_MODE_CONNECTOR_9PinDIN) { bool tv_detect; if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT)) return connector_status_disconnected; tv_detect = radeon_legacy_tv_detect(encoder, connector); if (tv_detect && tv_dac) found = connector_status_connected; return found; } /* don't probe if the encoder is being used for something else not CRT related */ if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_CRT_SUPPORT)) { DRM_INFO("not detecting due to %08x\n", radeon_encoder->active_device); 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); 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); tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb | RADEON_PIX2CLK_DAC_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); if (rdev->flags & RADEON_SINGLE_CRTC) { tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; WREG32(RADEON_CRTC_EXT_CNTL, tmp); } else { 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 | RADEON_TV_DAC_NHOLD | RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_PS2; WREG32(RADEON_TV_DAC_CNTL, tmp); tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN; if (color) tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; else tmp |= RADEON_DAC_FORCE_DATA_SEL_G; if (ASIC_IS_R300(rdev)) tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); else tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); WREG32(RADEON_DAC_EXT_CNTL, tmp); tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; WREG32(RADEON_DAC_CNTL2, tmp); mdelay(10); if (ASIC_IS_R300(rdev)) { if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) found = connector_status_connected; } else { if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) found = connector_status_connected; } /* restore regs we used */ WREG32(RADEON_DAC_CNTL2, dac_cntl2); WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); if (rdev->flags & RADEON_SINGLE_CRTC) { WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); } else { 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; } static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = { .dpms = radeon_legacy_tv_dac_dpms, .mode_fixup = radeon_legacy_mode_fixup, .prepare = radeon_legacy_tv_dac_prepare, .mode_set = radeon_legacy_tv_dac_mode_set, .commit = radeon_legacy_tv_dac_commit, .detect = radeon_legacy_tv_dac_detect, .disable = radeon_legacy_encoder_disable, }; static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { .destroy = radeon_enc_destroy, }; static struct radeon_encoder_int_tmds *radeon_legacy_get_tmds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder_int_tmds *tmds = NULL; bool ret; tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); if (!tmds) return NULL; if (rdev->is_atom_bios) ret = radeon_atombios_get_tmds_info(encoder, tmds); else ret = radeon_legacy_get_tmds_info_from_combios(encoder, tmds); if (ret == false) radeon_legacy_get_tmds_info_from_table(encoder, tmds); return tmds; } static struct radeon_encoder_ext_tmds *radeon_legacy_get_ext_tmds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder_ext_tmds *tmds = NULL; bool ret; if (rdev->is_atom_bios) return NULL; tmds = kzalloc(sizeof(struct radeon_encoder_ext_tmds), GFP_KERNEL); if (!tmds) return NULL; ret = radeon_legacy_get_ext_tmds_info_from_combios(encoder, tmds); if (ret == false) radeon_legacy_get_ext_tmds_info_from_table(encoder, tmds); return tmds; } void radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) { struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; struct radeon_encoder *radeon_encoder; /* see if we already added it */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->encoder_enum == encoder_enum) { radeon_encoder->devices |= supported_device; return; } } /* add a new one */ radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) return; encoder = &radeon_encoder->base; if (rdev->flags & RADEON_SINGLE_CRTC) encoder->possible_crtcs = 0x1; else encoder->possible_crtcs = 0x3; radeon_encoder->enc_priv = NULL; radeon_encoder->encoder_enum = encoder_enum; radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_LVDS: encoder->possible_crtcs = 0x1; drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); if (rdev->is_atom_bios) radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); else radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder); radeon_encoder->rmx_type = RMX_FULL; break; case ENCODER_OBJECT_ID_INTERNAL_TMDS1: drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); radeon_encoder->enc_priv = radeon_legacy_get_tmds_info(radeon_encoder); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, DRM_MODE_ENCODER_DAC); drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); if (rdev->is_atom_bios) radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder); else radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder); break; case ENCODER_OBJECT_ID_INTERNAL_DAC2: drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, DRM_MODE_ENCODER_TVDAC); drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); if (rdev->is_atom_bios) radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder); else radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder); break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs); if (!rdev->is_atom_bios) radeon_encoder->enc_priv = radeon_legacy_get_ext_tmds_info(radeon_encoder); break; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
You can’t perform that action at this time.