18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Authors: Dave Airlie 248c2ecf20Sopenharmony_ci * Alex Deucher 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/backlight.h> 288c2ecf20Sopenharmony_ci#include <linux/pci.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h> 318c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 328c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 338c2ecf20Sopenharmony_ci#include <drm/drm_util.h> 348c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "radeon.h" 378c2ecf20Sopenharmony_ci#include "radeon_asic.h" 388c2ecf20Sopenharmony_ci#include "atom.h" 398c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 408c2ecf20Sopenharmony_ci#include <asm/backlight.h> 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void radeon_legacy_encoder_disable(struct drm_encoder *encoder) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 468c2ecf20Sopenharmony_ci const struct drm_encoder_helper_funcs *encoder_funcs; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci encoder_funcs = encoder->helper_private; 498c2ecf20Sopenharmony_ci encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); 508c2ecf20Sopenharmony_ci radeon_encoder->active_device = 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 568c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 578c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 588c2ecf20Sopenharmony_ci uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; 598c2ecf20Sopenharmony_ci int panel_pwr_delay = 2000; 608c2ecf20Sopenharmony_ci bool is_mac = false; 618c2ecf20Sopenharmony_ci uint8_t backlight_level; 628c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); 658c2ecf20Sopenharmony_ci backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (radeon_encoder->enc_priv) { 688c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 698c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; 708c2ecf20Sopenharmony_ci panel_pwr_delay = lvds->panel_pwr_delay; 718c2ecf20Sopenharmony_ci if (lvds->bl_dev) 728c2ecf20Sopenharmony_ci backlight_level = lvds->backlight_level; 738c2ecf20Sopenharmony_ci } else { 748c2ecf20Sopenharmony_ci struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; 758c2ecf20Sopenharmony_ci panel_pwr_delay = lvds->panel_pwr_delay; 768c2ecf20Sopenharmony_ci if (lvds->bl_dev) 778c2ecf20Sopenharmony_ci backlight_level = lvds->backlight_level; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* macs (and possibly some x86 oem systems?) wire up LVDS strangely 828c2ecf20Sopenharmony_ci * Taken from radeonfb. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci if ((rdev->mode_info.connector_table == CT_IBOOK) || 858c2ecf20Sopenharmony_ci (rdev->mode_info.connector_table == CT_POWERBOOK_EXTERNAL) || 868c2ecf20Sopenharmony_ci (rdev->mode_info.connector_table == CT_POWERBOOK_INTERNAL) || 878c2ecf20Sopenharmony_ci (rdev->mode_info.connector_table == CT_POWERBOOK_VGA)) 888c2ecf20Sopenharmony_ci is_mac = true; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci switch (mode) { 918c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 928c2ecf20Sopenharmony_ci disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN); 938c2ecf20Sopenharmony_ci disp_pwr_man |= RADEON_AUTO_PWRUP_EN; 948c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_PWR_MAN, disp_pwr_man); 958c2ecf20Sopenharmony_ci lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); 968c2ecf20Sopenharmony_ci lvds_pll_cntl |= RADEON_LVDS_PLL_EN; 978c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 988c2ecf20Sopenharmony_ci mdelay(1); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); 1018c2ecf20Sopenharmony_ci lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; 1028c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS | 1058c2ecf20Sopenharmony_ci RADEON_LVDS_BL_MOD_LEVEL_MASK); 1068c2ecf20Sopenharmony_ci lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | 1078c2ecf20Sopenharmony_ci RADEON_LVDS_DIGON | RADEON_LVDS_BLON | 1088c2ecf20Sopenharmony_ci (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT)); 1098c2ecf20Sopenharmony_ci if (is_mac) 1108c2ecf20Sopenharmony_ci lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; 1118c2ecf20Sopenharmony_ci mdelay(panel_pwr_delay); 1128c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 1158c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 1168c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 1178c2ecf20Sopenharmony_ci pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); 1188c2ecf20Sopenharmony_ci WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); 1198c2ecf20Sopenharmony_ci lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; 1208c2ecf20Sopenharmony_ci if (is_mac) { 1218c2ecf20Sopenharmony_ci lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN; 1228c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 1238c2ecf20Sopenharmony_ci lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN); 1248c2ecf20Sopenharmony_ci } else { 1258c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 1268c2ecf20Sopenharmony_ci lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci mdelay(panel_pwr_delay); 1298c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 1308c2ecf20Sopenharmony_ci WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); 1318c2ecf20Sopenharmony_ci mdelay(panel_pwr_delay); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 1368c2ecf20Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 1458c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1468c2ecf20Sopenharmony_ci DRM_DEBUG("\n"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (radeon_encoder->enc_priv) { 1498c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 1508c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; 1518c2ecf20Sopenharmony_ci lvds->dpms_mode = mode; 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_ci struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; 1548c2ecf20Sopenharmony_ci lvds->dpms_mode = mode; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci radeon_legacy_lvds_update(encoder, mode); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 1668c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 1678c2ecf20Sopenharmony_ci else 1688c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 1698c2ecf20Sopenharmony_ci radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void radeon_legacy_lvds_commit(struct drm_encoder *encoder) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); 1778c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 1788c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, false); 1798c2ecf20Sopenharmony_ci else 1808c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, false); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, 1848c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 1858c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 1888c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1898c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 1908c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1918c2ecf20Sopenharmony_ci uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); 1968c2ecf20Sopenharmony_ci lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); 1998c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 2008c2ecf20Sopenharmony_ci /* LVDS_GEN_CNTL parameters are computed in LVDSEncoderControl 2018c2ecf20Sopenharmony_ci * need to call that on resume to set up the reg properly. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci radeon_encoder->pixel_clock = adjusted_mode->clock; 2048c2ecf20Sopenharmony_ci atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); 2058c2ecf20Sopenharmony_ci lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; 2088c2ecf20Sopenharmony_ci if (lvds) { 2098c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); 2108c2ecf20Sopenharmony_ci lvds_gen_cntl = lvds->lvds_gen_cntl; 2118c2ecf20Sopenharmony_ci lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | 2128c2ecf20Sopenharmony_ci (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); 2138c2ecf20Sopenharmony_ci lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | 2148c2ecf20Sopenharmony_ci (lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); 2158c2ecf20Sopenharmony_ci } else 2168c2ecf20Sopenharmony_ci lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; 2198c2ecf20Sopenharmony_ci lvds_gen_cntl &= ~(RADEON_LVDS_ON | 2208c2ecf20Sopenharmony_ci RADEON_LVDS_BLON | 2218c2ecf20Sopenharmony_ci RADEON_LVDS_EN | 2228c2ecf20Sopenharmony_ci RADEON_LVDS_RST_FM); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) 2258c2ecf20Sopenharmony_ci lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) { 2288c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 2298c2ecf20Sopenharmony_ci if (radeon_encoder->rmx_type != RMX_OFF) 2308c2ecf20Sopenharmony_ci lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX; 2318c2ecf20Sopenharmony_ci } else 2328c2ecf20Sopenharmony_ci lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; 2338c2ecf20Sopenharmony_ci } else { 2348c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) 2358c2ecf20Sopenharmony_ci lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 2418c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 2428c2ecf20Sopenharmony_ci WREG32(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV410) 2458c2ecf20Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_INDEX, 0); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 2488c2ecf20Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 2498c2ecf20Sopenharmony_ci else 2508c2ecf20Sopenharmony_ci radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic bool radeon_legacy_mode_fixup(struct drm_encoder *encoder, 2548c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 2558c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* set the active encoder to connector routing */ 2608c2ecf20Sopenharmony_ci radeon_encoder_set_active_device(encoder); 2618c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(adjusted_mode, 0); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* get the native mode for LVDS */ 2648c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 2658c2ecf20Sopenharmony_ci radeon_panel_mode_fixup(encoder, adjusted_mode); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return true; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { 2718c2ecf20Sopenharmony_ci .dpms = radeon_legacy_lvds_dpms, 2728c2ecf20Sopenharmony_ci .mode_fixup = radeon_legacy_mode_fixup, 2738c2ecf20Sopenharmony_ci .prepare = radeon_legacy_lvds_prepare, 2748c2ecf20Sopenharmony_ci .mode_set = radeon_legacy_lvds_mode_set, 2758c2ecf20Sopenharmony_ci .commit = radeon_legacy_lvds_commit, 2768c2ecf20Sopenharmony_ci .disable = radeon_legacy_encoder_disable, 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ciu8 2808c2ecf20Sopenharmony_ciradeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 2838c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2848c2ecf20Sopenharmony_ci u8 backlight_level; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> 2878c2ecf20Sopenharmony_ci RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return backlight_level; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_civoid 2938c2ecf20Sopenharmony_ciradeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 2968c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2978c2ecf20Sopenharmony_ci int dpms_mode = DRM_MODE_DPMS_ON; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (radeon_encoder->enc_priv) { 3008c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 3018c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; 3028c2ecf20Sopenharmony_ci if (lvds->backlight_level > 0) 3038c2ecf20Sopenharmony_ci dpms_mode = lvds->dpms_mode; 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci dpms_mode = DRM_MODE_DPMS_OFF; 3068c2ecf20Sopenharmony_ci lvds->backlight_level = level; 3078c2ecf20Sopenharmony_ci } else { 3088c2ecf20Sopenharmony_ci struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; 3098c2ecf20Sopenharmony_ci if (lvds->backlight_level > 0) 3108c2ecf20Sopenharmony_ci dpms_mode = lvds->dpms_mode; 3118c2ecf20Sopenharmony_ci else 3128c2ecf20Sopenharmony_ci dpms_mode = DRM_MODE_DPMS_OFF; 3138c2ecf20Sopenharmony_ci lvds->backlight_level = level; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 3258c2ecf20Sopenharmony_ci uint8_t level; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Convert brightness to hardware level */ 3288c2ecf20Sopenharmony_ci if (bd->props.brightness < 0) 3298c2ecf20Sopenharmony_ci level = 0; 3308c2ecf20Sopenharmony_ci else if (bd->props.brightness > RADEON_MAX_BL_LEVEL) 3318c2ecf20Sopenharmony_ci level = RADEON_MAX_BL_LEVEL; 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci level = bd->props.brightness; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (pdata->negative) 3368c2ecf20Sopenharmony_ci level = RADEON_MAX_BL_LEVEL - level; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return level; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int radeon_legacy_backlight_update_status(struct backlight_device *bd) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 3448c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = pdata->encoder; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci radeon_legacy_set_backlight_level(radeon_encoder, 3478c2ecf20Sopenharmony_ci radeon_legacy_lvds_level(bd)); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int radeon_legacy_backlight_get_brightness(struct backlight_device *bd) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 3558c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = pdata->encoder; 3568c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 3578c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3588c2ecf20Sopenharmony_ci uint8_t backlight_level; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> 3618c2ecf20Sopenharmony_ci RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return pdata->negative ? RADEON_MAX_BL_LEVEL - backlight_level : backlight_level; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct backlight_ops radeon_backlight_ops = { 3678c2ecf20Sopenharmony_ci .get_brightness = radeon_legacy_backlight_get_brightness, 3688c2ecf20Sopenharmony_ci .update_status = radeon_legacy_backlight_update_status, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_civoid radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, 3728c2ecf20Sopenharmony_ci struct drm_connector *drm_connector) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 3758c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3768c2ecf20Sopenharmony_ci struct backlight_device *bd; 3778c2ecf20Sopenharmony_ci struct backlight_properties props; 3788c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata; 3798c2ecf20Sopenharmony_ci uint8_t backlight_level; 3808c2ecf20Sopenharmony_ci char bl_name[16]; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (!radeon_encoder->enc_priv) 3838c2ecf20Sopenharmony_ci return; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 3868c2ecf20Sopenharmony_ci if (!pmac_has_backlight_type("ati") && 3878c2ecf20Sopenharmony_ci !pmac_has_backlight_type("mnca")) 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci#endif 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); 3928c2ecf20Sopenharmony_ci if (!pdata) { 3938c2ecf20Sopenharmony_ci DRM_ERROR("Memory allocation failed\n"); 3948c2ecf20Sopenharmony_ci goto error; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci memset(&props, 0, sizeof(props)); 3988c2ecf20Sopenharmony_ci props.max_brightness = RADEON_MAX_BL_LEVEL; 3998c2ecf20Sopenharmony_ci props.type = BACKLIGHT_RAW; 4008c2ecf20Sopenharmony_ci snprintf(bl_name, sizeof(bl_name), 4018c2ecf20Sopenharmony_ci "radeon_bl%d", dev->primary->index); 4028c2ecf20Sopenharmony_ci bd = backlight_device_register(bl_name, drm_connector->kdev, 4038c2ecf20Sopenharmony_ci pdata, &radeon_backlight_ops, &props); 4048c2ecf20Sopenharmony_ci if (IS_ERR(bd)) { 4058c2ecf20Sopenharmony_ci DRM_ERROR("Backlight registration failed\n"); 4068c2ecf20Sopenharmony_ci goto error; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci pdata->encoder = radeon_encoder; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> 4128c2ecf20Sopenharmony_ci RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* First, try to detect backlight level sense based on the assumption 4158c2ecf20Sopenharmony_ci * that firmware set it up at full brightness 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci if (backlight_level == 0) 4188c2ecf20Sopenharmony_ci pdata->negative = true; 4198c2ecf20Sopenharmony_ci else if (backlight_level == 0xff) 4208c2ecf20Sopenharmony_ci pdata->negative = false; 4218c2ecf20Sopenharmony_ci else { 4228c2ecf20Sopenharmony_ci /* XXX hack... maybe some day we can figure out in what direction 4238c2ecf20Sopenharmony_ci * backlight should work on a given panel? 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci pdata->negative = (rdev->family != CHIP_RV200 && 4268c2ecf20Sopenharmony_ci rdev->family != CHIP_RV250 && 4278c2ecf20Sopenharmony_ci rdev->family != CHIP_RV280 && 4288c2ecf20Sopenharmony_ci rdev->family != CHIP_RV350); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 4318c2ecf20Sopenharmony_ci pdata->negative = (pdata->negative || 4328c2ecf20Sopenharmony_ci of_machine_is_compatible("PowerBook4,3") || 4338c2ecf20Sopenharmony_ci of_machine_is_compatible("PowerBook6,3") || 4348c2ecf20Sopenharmony_ci of_machine_is_compatible("PowerBook6,5")); 4358c2ecf20Sopenharmony_ci#endif 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 4398c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; 4408c2ecf20Sopenharmony_ci lvds->bl_dev = bd; 4418c2ecf20Sopenharmony_ci } else { 4428c2ecf20Sopenharmony_ci struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; 4438c2ecf20Sopenharmony_ci lvds->bl_dev = bd; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci bd->props.brightness = radeon_legacy_backlight_get_brightness(bd); 4478c2ecf20Sopenharmony_ci bd->props.power = FB_BLANK_UNBLANK; 4488c2ecf20Sopenharmony_ci backlight_update_status(bd); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci DRM_INFO("radeon legacy LVDS backlight initialized\n"); 4518c2ecf20Sopenharmony_ci rdev->mode_info.bl_encoder = radeon_encoder; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cierror: 4568c2ecf20Sopenharmony_ci kfree(pdata); 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 4638c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 4648c2ecf20Sopenharmony_ci struct backlight_device *bd = NULL; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!radeon_encoder->enc_priv) 4678c2ecf20Sopenharmony_ci return; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 4708c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; 4718c2ecf20Sopenharmony_ci bd = lvds->bl_dev; 4728c2ecf20Sopenharmony_ci lvds->bl_dev = NULL; 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; 4758c2ecf20Sopenharmony_ci bd = lvds->bl_dev; 4768c2ecf20Sopenharmony_ci lvds->bl_dev = NULL; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (bd) { 4808c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci pdata = bl_get_data(bd); 4838c2ecf20Sopenharmony_ci backlight_device_unregister(bd); 4848c2ecf20Sopenharmony_ci kfree(pdata); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci DRM_INFO("radeon legacy LVDS backlight unloaded\n"); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */ 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_civoid radeon_legacy_backlight_init(struct radeon_encoder *encoder) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic void radeon_legacy_backlight_exit(struct radeon_encoder *encoder) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci#endif 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic void radeon_lvds_enc_destroy(struct drm_encoder *encoder) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (radeon_encoder->enc_priv) { 5088c2ecf20Sopenharmony_ci radeon_legacy_backlight_exit(radeon_encoder); 5098c2ecf20Sopenharmony_ci kfree(radeon_encoder->enc_priv); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 5128c2ecf20Sopenharmony_ci kfree(radeon_encoder); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { 5168c2ecf20Sopenharmony_ci .destroy = radeon_lvds_enc_destroy, 5178c2ecf20Sopenharmony_ci}; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 5228c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 5238c2ecf20Sopenharmony_ci uint32_t crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); 5248c2ecf20Sopenharmony_ci uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL); 5258c2ecf20Sopenharmony_ci uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci switch (mode) { 5308c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 5318c2ecf20Sopenharmony_ci crtc_ext_cntl |= RADEON_CRTC_CRT_ON; 5328c2ecf20Sopenharmony_ci dac_cntl &= ~RADEON_DAC_PDWN; 5338c2ecf20Sopenharmony_ci dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | 5348c2ecf20Sopenharmony_ci RADEON_DAC_PDWN_G | 5358c2ecf20Sopenharmony_ci RADEON_DAC_PDWN_B); 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 5388c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 5398c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 5408c2ecf20Sopenharmony_ci crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON; 5418c2ecf20Sopenharmony_ci dac_cntl |= RADEON_DAC_PDWN; 5428c2ecf20Sopenharmony_ci dac_macro_cntl |= (RADEON_DAC_PDWN_R | 5438c2ecf20Sopenharmony_ci RADEON_DAC_PDWN_G | 5448c2ecf20Sopenharmony_ci RADEON_DAC_PDWN_B); 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* handled in radeon_crtc_dpms() */ 5498c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) 5508c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); 5518c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL, dac_cntl); 5528c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 5558c2ecf20Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 5568c2ecf20Sopenharmony_ci else 5578c2ecf20Sopenharmony_ci radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 5668c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 5678c2ecf20Sopenharmony_ci else 5688c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 5698c2ecf20Sopenharmony_ci radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 5798c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, false); 5808c2ecf20Sopenharmony_ci else 5818c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, false); 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, 5858c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 5868c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 5898c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 5908c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 5918c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 5928c2ecf20Sopenharmony_ci uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) { 5978c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { 5988c2ecf20Sopenharmony_ci disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & 5998c2ecf20Sopenharmony_ci ~(RADEON_DISP_DAC_SOURCE_MASK); 6008c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); 6018c2ecf20Sopenharmony_ci } else { 6028c2ecf20Sopenharmony_ci dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); 6038c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac2_cntl); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci } else { 6068c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { 6078c2ecf20Sopenharmony_ci disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & 6088c2ecf20Sopenharmony_ci ~(RADEON_DISP_DAC_SOURCE_MASK); 6098c2ecf20Sopenharmony_ci disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; 6108c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; 6138c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac2_cntl); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci dac_cntl = (RADEON_DAC_MASK_ALL | 6188c2ecf20Sopenharmony_ci RADEON_DAC_VGA_ADR_EN | 6198c2ecf20Sopenharmony_ci /* TODO 6-bits */ 6208c2ecf20Sopenharmony_ci RADEON_DAC_8BIT_EN); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci WREG32_P(RADEON_DAC_CNTL, 6238c2ecf20Sopenharmony_ci dac_cntl, 6248c2ecf20Sopenharmony_ci RADEON_DAC_RANGE_CNTL | 6258c2ecf20Sopenharmony_ci RADEON_DAC_BLANKING); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (radeon_encoder->enc_priv) { 6288c2ecf20Sopenharmony_ci struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv; 6298c2ecf20Sopenharmony_ci dac_macro_cntl = p_dac->ps2_pdac_adj; 6308c2ecf20Sopenharmony_ci } else 6318c2ecf20Sopenharmony_ci dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); 6328c2ecf20Sopenharmony_ci dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B; 6338c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 6368c2ecf20Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 6378c2ecf20Sopenharmony_ci else 6388c2ecf20Sopenharmony_ci radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, 6428c2ecf20Sopenharmony_ci struct drm_connector *connector) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 6458c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 6468c2ecf20Sopenharmony_ci uint32_t vclk_ecp_cntl, crtc_ext_cntl; 6478c2ecf20Sopenharmony_ci uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp; 6488c2ecf20Sopenharmony_ci enum drm_connector_status found = connector_status_disconnected; 6498c2ecf20Sopenharmony_ci bool color = true; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* just don't bother on RN50 those chip are often connected to remoting 6528c2ecf20Sopenharmony_ci * console hw and often we get failure to load detect those. So to make 6538c2ecf20Sopenharmony_ci * everyone happy report the encoder as always connected. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci if (ASIC_IS_RN50(rdev)) { 6568c2ecf20Sopenharmony_ci return connector_status_connected; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* save the regs we need */ 6608c2ecf20Sopenharmony_ci vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); 6618c2ecf20Sopenharmony_ci crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); 6628c2ecf20Sopenharmony_ci dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); 6638c2ecf20Sopenharmony_ci dac_cntl = RREG32(RADEON_DAC_CNTL); 6648c2ecf20Sopenharmony_ci dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci tmp = vclk_ecp_cntl & 6678c2ecf20Sopenharmony_ci ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); 6688c2ecf20Sopenharmony_ci WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; 6718c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_EXT_CNTL, tmp); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci tmp = RADEON_DAC_FORCE_BLANK_OFF_EN | 6748c2ecf20Sopenharmony_ci RADEON_DAC_FORCE_DATA_EN; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (color) 6778c2ecf20Sopenharmony_ci tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; 6788c2ecf20Sopenharmony_ci else 6798c2ecf20Sopenharmony_ci tmp |= RADEON_DAC_FORCE_DATA_SEL_G; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) 6828c2ecf20Sopenharmony_ci tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); 6838c2ecf20Sopenharmony_ci else if (ASIC_IS_RV100(rdev)) 6848c2ecf20Sopenharmony_ci tmp |= (0x1ac << RADEON_DAC_FORCE_DATA_SHIFT); 6858c2ecf20Sopenharmony_ci else 6868c2ecf20Sopenharmony_ci tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_EXT_CNTL, tmp); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); 6918c2ecf20Sopenharmony_ci tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; 6928c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL, tmp); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci tmp = dac_macro_cntl; 6958c2ecf20Sopenharmony_ci tmp &= ~(RADEON_DAC_PDWN_R | 6968c2ecf20Sopenharmony_ci RADEON_DAC_PDWN_G | 6978c2ecf20Sopenharmony_ci RADEON_DAC_PDWN_B); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_MACRO_CNTL, tmp); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci mdelay(2); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) 7048c2ecf20Sopenharmony_ci found = connector_status_connected; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* restore the regs we used */ 7078c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL, dac_cntl); 7088c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); 7098c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); 7108c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); 7118c2ecf20Sopenharmony_ci WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci return found; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { 7178c2ecf20Sopenharmony_ci .dpms = radeon_legacy_primary_dac_dpms, 7188c2ecf20Sopenharmony_ci .mode_fixup = radeon_legacy_mode_fixup, 7198c2ecf20Sopenharmony_ci .prepare = radeon_legacy_primary_dac_prepare, 7208c2ecf20Sopenharmony_ci .mode_set = radeon_legacy_primary_dac_mode_set, 7218c2ecf20Sopenharmony_ci .commit = radeon_legacy_primary_dac_commit, 7228c2ecf20Sopenharmony_ci .detect = radeon_legacy_primary_dac_detect, 7238c2ecf20Sopenharmony_ci .disable = radeon_legacy_encoder_disable, 7248c2ecf20Sopenharmony_ci}; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { 7288c2ecf20Sopenharmony_ci .destroy = radeon_enc_destroy, 7298c2ecf20Sopenharmony_ci}; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 7348c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 7358c2ecf20Sopenharmony_ci uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL); 7368c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci switch (mode) { 7398c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 7408c2ecf20Sopenharmony_ci fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); 7418c2ecf20Sopenharmony_ci break; 7428c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 7438c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 7448c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 7458c2ecf20Sopenharmony_ci fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); 7468c2ecf20Sopenharmony_ci break; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 7528c2ecf20Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 7538c2ecf20Sopenharmony_ci else 7548c2ecf20Sopenharmony_ci radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 7638c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 7648c2ecf20Sopenharmony_ci else 7658c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 7668c2ecf20Sopenharmony_ci radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 7768c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, 7828c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 7838c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 7868c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 7878c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 7888c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 7898c2ecf20Sopenharmony_ci uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; 7908c2ecf20Sopenharmony_ci int i; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL); 7958c2ecf20Sopenharmony_ci tmp &= 0xfffff; 7968c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV280) { 7978c2ecf20Sopenharmony_ci /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ 7988c2ecf20Sopenharmony_ci tmp ^= (1 << 22); 7998c2ecf20Sopenharmony_ci tmds_pll_cntl ^= (1 << 22); 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (radeon_encoder->enc_priv) { 8038c2ecf20Sopenharmony_ci struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 8068c2ecf20Sopenharmony_ci if (tmds->tmds_pll[i].freq == 0) 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) { 8098c2ecf20Sopenharmony_ci tmp = tmds->tmds_pll[i].value ; 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV280)) { 8168c2ecf20Sopenharmony_ci if (tmp & 0xfff00000) 8178c2ecf20Sopenharmony_ci tmds_pll_cntl = tmp; 8188c2ecf20Sopenharmony_ci else { 8198c2ecf20Sopenharmony_ci tmds_pll_cntl &= 0xfff00000; 8208c2ecf20Sopenharmony_ci tmds_pll_cntl |= tmp; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci } else 8238c2ecf20Sopenharmony_ci tmds_pll_cntl = tmp; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci tmds_transmitter_cntl = RREG32(RADEON_TMDS_TRANSMITTER_CNTL) & 8268c2ecf20Sopenharmony_ci ~(RADEON_TMDS_TRANSMITTER_PLLRST); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200 || 8298c2ecf20Sopenharmony_ci rdev->family == CHIP_R100 || 8308c2ecf20Sopenharmony_ci ASIC_IS_R300(rdev)) 8318c2ecf20Sopenharmony_ci tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); 8328c2ecf20Sopenharmony_ci else /* RV chips got this bit reversed */ 8338c2ecf20Sopenharmony_ci tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci fp_gen_cntl = (RREG32(RADEON_FP_GEN_CNTL) | 8368c2ecf20Sopenharmony_ci (RADEON_FP_CRTC_DONT_SHADOW_VPAR | 8378c2ecf20Sopenharmony_ci RADEON_FP_CRTC_DONT_SHADOW_HEND)); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci fp_gen_cntl &= ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN | 8428c2ecf20Sopenharmony_ci RADEON_FP_DFP_SYNC_SEL | 8438c2ecf20Sopenharmony_ci RADEON_FP_CRT_SYNC_SEL | 8448c2ecf20Sopenharmony_ci RADEON_FP_CRTC_LOCK_8DOT | 8458c2ecf20Sopenharmony_ci RADEON_FP_USE_SHADOW_EN | 8468c2ecf20Sopenharmony_ci RADEON_FP_CRTC_USE_SHADOW_VEND | 8478c2ecf20Sopenharmony_ci RADEON_FP_CRT_SYNC_ALT); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (1) /* FIXME rgbBits == 8 */ 8508c2ecf20Sopenharmony_ci fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ 8518c2ecf20Sopenharmony_ci else 8528c2ecf20Sopenharmony_ci fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) { 8558c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { 8568c2ecf20Sopenharmony_ci fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; 8578c2ecf20Sopenharmony_ci if (radeon_encoder->rmx_type != RMX_OFF) 8588c2ecf20Sopenharmony_ci fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; 8598c2ecf20Sopenharmony_ci else 8608c2ecf20Sopenharmony_ci fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; 8618c2ecf20Sopenharmony_ci } else 8628c2ecf20Sopenharmony_ci fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2; 8638c2ecf20Sopenharmony_ci } else { 8648c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { 8658c2ecf20Sopenharmony_ci fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; 8668c2ecf20Sopenharmony_ci fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; 8678c2ecf20Sopenharmony_ci } else 8688c2ecf20Sopenharmony_ci fp_gen_cntl |= RADEON_FP_SEL_CRTC2; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci WREG32(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl); 8728c2ecf20Sopenharmony_ci WREG32(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl); 8738c2ecf20Sopenharmony_ci WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 8768c2ecf20Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 8778c2ecf20Sopenharmony_ci else 8788c2ecf20Sopenharmony_ci radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = { 8828c2ecf20Sopenharmony_ci .dpms = radeon_legacy_tmds_int_dpms, 8838c2ecf20Sopenharmony_ci .mode_fixup = radeon_legacy_mode_fixup, 8848c2ecf20Sopenharmony_ci .prepare = radeon_legacy_tmds_int_prepare, 8858c2ecf20Sopenharmony_ci .mode_set = radeon_legacy_tmds_int_mode_set, 8868c2ecf20Sopenharmony_ci .commit = radeon_legacy_tmds_int_commit, 8878c2ecf20Sopenharmony_ci .disable = radeon_legacy_encoder_disable, 8888c2ecf20Sopenharmony_ci}; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { 8928c2ecf20Sopenharmony_ci .destroy = radeon_enc_destroy, 8938c2ecf20Sopenharmony_ci}; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 8988c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 8998c2ecf20Sopenharmony_ci uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); 9008c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci switch (mode) { 9038c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 9048c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; 9058c2ecf20Sopenharmony_ci fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); 9068c2ecf20Sopenharmony_ci break; 9078c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 9088c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 9098c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 9108c2ecf20Sopenharmony_ci fp2_gen_cntl |= RADEON_FP2_BLANK_EN; 9118c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); 9128c2ecf20Sopenharmony_ci break; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 9188c2ecf20Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 9198c2ecf20Sopenharmony_ci else 9208c2ecf20Sopenharmony_ci radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 9298c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 9308c2ecf20Sopenharmony_ci else 9318c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 9328c2ecf20Sopenharmony_ci radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 9388c2ecf20Sopenharmony_ci radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 9418c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, false); 9428c2ecf20Sopenharmony_ci else 9438c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, false); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, 9478c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 9488c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 9518c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 9528c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 9538c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 9548c2ecf20Sopenharmony_ci uint32_t fp2_gen_cntl; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 9598c2ecf20Sopenharmony_ci radeon_encoder->pixel_clock = adjusted_mode->clock; 9608c2ecf20Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_ENABLE); 9618c2ecf20Sopenharmony_ci fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); 9628c2ecf20Sopenharmony_ci } else { 9638c2ecf20Sopenharmony_ci fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (1) /* FIXME rgbBits == 8 */ 9668c2ecf20Sopenharmony_ci fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ 9678c2ecf20Sopenharmony_ci else 9688c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~(RADEON_FP2_ON | 9718c2ecf20Sopenharmony_ci RADEON_FP2_DVO_EN | 9728c2ecf20Sopenharmony_ci RADEON_FP2_DVO_RATE_SEL_SDR); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* XXX: these are oem specific */ 9758c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 9768c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x4850) && 9778c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1028) && 9788c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ 9798c2ecf20Sopenharmony_ci fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; 9808c2ecf20Sopenharmony_ci else 9818c2ecf20Sopenharmony_ci fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /*if (mode->clock > 165000) 9848c2ecf20Sopenharmony_ci fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci if (!radeon_combios_external_tmds_setup(encoder)) 9878c2ecf20Sopenharmony_ci radeon_external_tmds_setup(encoder); 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) { 9918c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { 9928c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; 9938c2ecf20Sopenharmony_ci if (radeon_encoder->rmx_type != RMX_OFF) 9948c2ecf20Sopenharmony_ci fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; 9958c2ecf20Sopenharmony_ci else 9968c2ecf20Sopenharmony_ci fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1; 9978c2ecf20Sopenharmony_ci } else 9988c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2; 9998c2ecf20Sopenharmony_ci } else { 10008c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { 10018c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; 10028c2ecf20Sopenharmony_ci fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; 10038c2ecf20Sopenharmony_ci } else 10048c2ecf20Sopenharmony_ci fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 10108c2ecf20Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 10118c2ecf20Sopenharmony_ci else 10128c2ecf20Sopenharmony_ci radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic void radeon_ext_tmds_enc_destroy(struct drm_encoder *encoder) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 10188c2ecf20Sopenharmony_ci /* don't destroy the i2c bus record here, this will be done in radeon_i2c_fini */ 10198c2ecf20Sopenharmony_ci kfree(radeon_encoder->enc_priv); 10208c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 10218c2ecf20Sopenharmony_ci kfree(radeon_encoder); 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = { 10258c2ecf20Sopenharmony_ci .dpms = radeon_legacy_tmds_ext_dpms, 10268c2ecf20Sopenharmony_ci .mode_fixup = radeon_legacy_mode_fixup, 10278c2ecf20Sopenharmony_ci .prepare = radeon_legacy_tmds_ext_prepare, 10288c2ecf20Sopenharmony_ci .mode_set = radeon_legacy_tmds_ext_mode_set, 10298c2ecf20Sopenharmony_ci .commit = radeon_legacy_tmds_ext_commit, 10308c2ecf20Sopenharmony_ci .disable = radeon_legacy_encoder_disable, 10318c2ecf20Sopenharmony_ci}; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { 10358c2ecf20Sopenharmony_ci .destroy = radeon_ext_tmds_enc_destroy, 10368c2ecf20Sopenharmony_ci}; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 10418c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 10428c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 10438c2ecf20Sopenharmony_ci uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; 10448c2ecf20Sopenharmony_ci uint32_t tv_master_cntl = 0; 10458c2ecf20Sopenharmony_ci bool is_tv; 10468c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200) 10518c2ecf20Sopenharmony_ci fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); 10528c2ecf20Sopenharmony_ci else { 10538c2ecf20Sopenharmony_ci if (is_tv) 10548c2ecf20Sopenharmony_ci tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); 10558c2ecf20Sopenharmony_ci else 10568c2ecf20Sopenharmony_ci crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); 10578c2ecf20Sopenharmony_ci tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci switch (mode) { 10618c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 10628c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200) { 10638c2ecf20Sopenharmony_ci fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); 10648c2ecf20Sopenharmony_ci } else { 10658c2ecf20Sopenharmony_ci if (is_tv) 10668c2ecf20Sopenharmony_ci tv_master_cntl |= RADEON_TV_ON; 10678c2ecf20Sopenharmony_ci else 10688c2ecf20Sopenharmony_ci crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R420 || 10718c2ecf20Sopenharmony_ci rdev->family == CHIP_R423 || 10728c2ecf20Sopenharmony_ci rdev->family == CHIP_RV410) 10738c2ecf20Sopenharmony_ci tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | 10748c2ecf20Sopenharmony_ci R420_TV_DAC_GDACPD | 10758c2ecf20Sopenharmony_ci R420_TV_DAC_BDACPD | 10768c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGSLEEP); 10778c2ecf20Sopenharmony_ci else 10788c2ecf20Sopenharmony_ci tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | 10798c2ecf20Sopenharmony_ci RADEON_TV_DAC_GDACPD | 10808c2ecf20Sopenharmony_ci RADEON_TV_DAC_BDACPD | 10818c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGSLEEP); 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 10858c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 10868c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 10878c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200) 10888c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); 10898c2ecf20Sopenharmony_ci else { 10908c2ecf20Sopenharmony_ci if (is_tv) 10918c2ecf20Sopenharmony_ci tv_master_cntl &= ~RADEON_TV_ON; 10928c2ecf20Sopenharmony_ci else 10938c2ecf20Sopenharmony_ci crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R420 || 10968c2ecf20Sopenharmony_ci rdev->family == CHIP_R423 || 10978c2ecf20Sopenharmony_ci rdev->family == CHIP_RV410) 10988c2ecf20Sopenharmony_ci tv_dac_cntl |= (R420_TV_DAC_RDACPD | 10998c2ecf20Sopenharmony_ci R420_TV_DAC_GDACPD | 11008c2ecf20Sopenharmony_ci R420_TV_DAC_BDACPD | 11018c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGSLEEP); 11028c2ecf20Sopenharmony_ci else 11038c2ecf20Sopenharmony_ci tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | 11048c2ecf20Sopenharmony_ci RADEON_TV_DAC_GDACPD | 11058c2ecf20Sopenharmony_ci RADEON_TV_DAC_BDACPD | 11068c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGSLEEP); 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200) { 11128c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); 11138c2ecf20Sopenharmony_ci } else { 11148c2ecf20Sopenharmony_ci if (is_tv) 11158c2ecf20Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); 11168c2ecf20Sopenharmony_ci /* handled in radeon_crtc_dpms() */ 11178c2ecf20Sopenharmony_ci else if (!(rdev->flags & RADEON_SINGLE_CRTC)) 11188c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); 11198c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 11238c2ecf20Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 11248c2ecf20Sopenharmony_ci else 11258c2ecf20Sopenharmony_ci radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 11348c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 11358c2ecf20Sopenharmony_ci else 11368c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 11378c2ecf20Sopenharmony_ci radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 11478c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 11488c2ecf20Sopenharmony_ci else 11498c2ecf20Sopenharmony_ci radeon_combios_output_lock(encoder, true); 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, 11538c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 11548c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 11578c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 11588c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 11598c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 11608c2ecf20Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 11618c2ecf20Sopenharmony_ci uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; 11628c2ecf20Sopenharmony_ci uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0; 11638c2ecf20Sopenharmony_ci bool is_tv = false; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (rdev->family != CHIP_R200) { 11708c2ecf20Sopenharmony_ci tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 11718c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R420 || 11728c2ecf20Sopenharmony_ci rdev->family == CHIP_R423 || 11738c2ecf20Sopenharmony_ci rdev->family == CHIP_RV410) { 11748c2ecf20Sopenharmony_ci tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | 11758c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGADJ_MASK | 11768c2ecf20Sopenharmony_ci R420_TV_DAC_DACADJ_MASK | 11778c2ecf20Sopenharmony_ci R420_TV_DAC_RDACPD | 11788c2ecf20Sopenharmony_ci R420_TV_DAC_GDACPD | 11798c2ecf20Sopenharmony_ci R420_TV_DAC_BDACPD | 11808c2ecf20Sopenharmony_ci R420_TV_DAC_TVENABLE); 11818c2ecf20Sopenharmony_ci } else { 11828c2ecf20Sopenharmony_ci tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | 11838c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGADJ_MASK | 11848c2ecf20Sopenharmony_ci RADEON_TV_DAC_DACADJ_MASK | 11858c2ecf20Sopenharmony_ci RADEON_TV_DAC_RDACPD | 11868c2ecf20Sopenharmony_ci RADEON_TV_DAC_GDACPD | 11878c2ecf20Sopenharmony_ci RADEON_TV_DAC_BDACPD); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (is_tv) { 11938c2ecf20Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 11948c2ecf20Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 11958c2ecf20Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 11968c2ecf20Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) 11978c2ecf20Sopenharmony_ci tv_dac_cntl |= tv_dac->ntsc_tvdac_adj; 11988c2ecf20Sopenharmony_ci else 11998c2ecf20Sopenharmony_ci tv_dac_cntl |= tv_dac->pal_tvdac_adj; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 12028c2ecf20Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J) 12038c2ecf20Sopenharmony_ci tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; 12048c2ecf20Sopenharmony_ci else 12058c2ecf20Sopenharmony_ci tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; 12068c2ecf20Sopenharmony_ci } else 12078c2ecf20Sopenharmony_ci tv_dac_cntl |= (RADEON_TV_DAC_STD_PS2 | 12088c2ecf20Sopenharmony_ci tv_dac->ps2_tvdac_adj); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 12148c2ecf20Sopenharmony_ci gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1; 12158c2ecf20Sopenharmony_ci disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); 12168c2ecf20Sopenharmony_ci } else if (rdev->family != CHIP_R200) 12178c2ecf20Sopenharmony_ci disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); 12188c2ecf20Sopenharmony_ci else if (rdev->family == CHIP_R200) 12198c2ecf20Sopenharmony_ci fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R200) 12228c2ecf20Sopenharmony_ci disp_tv_out_cntl = RREG32(RADEON_DISP_TV_OUT_CNTL); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (is_tv) { 12258c2ecf20Sopenharmony_ci uint32_t dac_cntl; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci dac_cntl = RREG32(RADEON_DAC_CNTL); 12288c2ecf20Sopenharmony_ci dac_cntl &= ~RADEON_DAC_TVO_EN; 12298c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL, dac_cntl); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) 12328c2ecf20Sopenharmony_ci gpiopad_a = RREG32(RADEON_GPIOPAD_A) & ~1; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~RADEON_DAC2_DAC2_CLK_SEL; 12358c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) { 12368c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 12378c2ecf20Sopenharmony_ci disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 12388c2ecf20Sopenharmony_ci disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC | 12398c2ecf20Sopenharmony_ci RADEON_DISP_TV_SOURCE_CRTC); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R200) { 12428c2ecf20Sopenharmony_ci disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; 12438c2ecf20Sopenharmony_ci } else { 12448c2ecf20Sopenharmony_ci disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 12488c2ecf20Sopenharmony_ci disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 12498c2ecf20Sopenharmony_ci disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R200) { 12528c2ecf20Sopenharmony_ci disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; 12538c2ecf20Sopenharmony_ci } else { 12548c2ecf20Sopenharmony_ci disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac2_cntl); 12588c2ecf20Sopenharmony_ci } else { 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) { 12638c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 12648c2ecf20Sopenharmony_ci disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 12658c2ecf20Sopenharmony_ci disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; 12668c2ecf20Sopenharmony_ci } else if (rdev->family == CHIP_R200) { 12678c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | 12688c2ecf20Sopenharmony_ci RADEON_FP2_DVO_RATE_SEL_SDR); 12698c2ecf20Sopenharmony_ci } else 12708c2ecf20Sopenharmony_ci disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 12718c2ecf20Sopenharmony_ci } else { 12728c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 12738c2ecf20Sopenharmony_ci disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 12748c2ecf20Sopenharmony_ci disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; 12758c2ecf20Sopenharmony_ci } else if (rdev->family == CHIP_R200) { 12768c2ecf20Sopenharmony_ci fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | 12778c2ecf20Sopenharmony_ci RADEON_FP2_DVO_RATE_SEL_SDR); 12788c2ecf20Sopenharmony_ci fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; 12798c2ecf20Sopenharmony_ci } else 12808c2ecf20Sopenharmony_ci disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac2_cntl); 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 12868c2ecf20Sopenharmony_ci WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); 12878c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); 12888c2ecf20Sopenharmony_ci } else if (rdev->family != CHIP_R200) 12898c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); 12908c2ecf20Sopenharmony_ci else if (rdev->family == CHIP_R200) 12918c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R200) 12948c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_TV_OUT_CNTL, disp_tv_out_cntl); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (is_tv) 12978c2ecf20Sopenharmony_ci radeon_legacy_tv_mode_set(encoder, mode, adjusted_mode); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 13008c2ecf20Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 13018c2ecf20Sopenharmony_ci else 13028c2ecf20Sopenharmony_ci radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic bool r300_legacy_tv_detect(struct drm_encoder *encoder, 13078c2ecf20Sopenharmony_ci struct drm_connector *connector) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 13108c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 13118c2ecf20Sopenharmony_ci uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; 13128c2ecf20Sopenharmony_ci uint32_t disp_output_cntl, gpiopad_a, tmp; 13138c2ecf20Sopenharmony_ci bool found = false; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* save regs needed */ 13168c2ecf20Sopenharmony_ci gpiopad_a = RREG32(RADEON_GPIOPAD_A); 13178c2ecf20Sopenharmony_ci dac_cntl2 = RREG32(RADEON_DAC_CNTL2); 13188c2ecf20Sopenharmony_ci crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); 13198c2ecf20Sopenharmony_ci dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); 13208c2ecf20Sopenharmony_ci tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 13218c2ecf20Sopenharmony_ci disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci WREG32_P(RADEON_GPIOPAD_A, 0, ~1); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, 13288c2ecf20Sopenharmony_ci RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; 13318c2ecf20Sopenharmony_ci tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; 13328c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_EXT_CNTL, 13358c2ecf20Sopenharmony_ci RADEON_DAC2_FORCE_BLANK_OFF_EN | 13368c2ecf20Sopenharmony_ci RADEON_DAC2_FORCE_DATA_EN | 13378c2ecf20Sopenharmony_ci RADEON_DAC_FORCE_DATA_SEL_RGB | 13388c2ecf20Sopenharmony_ci (0xec << RADEON_DAC_FORCE_DATA_SHIFT)); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, 13418c2ecf20Sopenharmony_ci RADEON_TV_DAC_STD_NTSC | 13428c2ecf20Sopenharmony_ci (8 << RADEON_TV_DAC_BGADJ_SHIFT) | 13438c2ecf20Sopenharmony_ci (6 << RADEON_TV_DAC_DACADJ_SHIFT)); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci RREG32(RADEON_TV_DAC_CNTL); 13468c2ecf20Sopenharmony_ci mdelay(4); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, 13498c2ecf20Sopenharmony_ci RADEON_TV_DAC_NBLANK | 13508c2ecf20Sopenharmony_ci RADEON_TV_DAC_NHOLD | 13518c2ecf20Sopenharmony_ci RADEON_TV_MONITOR_DETECT_EN | 13528c2ecf20Sopenharmony_ci RADEON_TV_DAC_STD_NTSC | 13538c2ecf20Sopenharmony_ci (8 << RADEON_TV_DAC_BGADJ_SHIFT) | 13548c2ecf20Sopenharmony_ci (6 << RADEON_TV_DAC_DACADJ_SHIFT)); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci RREG32(RADEON_TV_DAC_CNTL); 13578c2ecf20Sopenharmony_ci mdelay(6); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_TV_DAC_CNTL); 13608c2ecf20Sopenharmony_ci if ((tmp & RADEON_TV_DAC_GDACDET) != 0) { 13618c2ecf20Sopenharmony_ci found = true; 13628c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("S-video TV connection detected\n"); 13638c2ecf20Sopenharmony_ci } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { 13648c2ecf20Sopenharmony_ci found = true; 13658c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Composite TV connection detected\n"); 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 13698c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); 13708c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); 13718c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); 13728c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac_cntl2); 13738c2ecf20Sopenharmony_ci WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); 13748c2ecf20Sopenharmony_ci return found; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic bool radeon_legacy_tv_detect(struct drm_encoder *encoder, 13788c2ecf20Sopenharmony_ci struct drm_connector *connector) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 13818c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 13828c2ecf20Sopenharmony_ci uint32_t tv_dac_cntl, dac_cntl2; 13838c2ecf20Sopenharmony_ci uint32_t config_cntl, tv_pre_dac_mux_cntl, tv_master_cntl, tmp; 13848c2ecf20Sopenharmony_ci bool found = false; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) 13878c2ecf20Sopenharmony_ci return r300_legacy_tv_detect(encoder, connector); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci dac_cntl2 = RREG32(RADEON_DAC_CNTL2); 13908c2ecf20Sopenharmony_ci tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); 13918c2ecf20Sopenharmony_ci tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 13928c2ecf20Sopenharmony_ci config_cntl = RREG32(RADEON_CONFIG_CNTL); 13938c2ecf20Sopenharmony_ci tv_pre_dac_mux_cntl = RREG32(RADEON_TV_PRE_DAC_MUX_CNTL); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL; 13968c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, tmp); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci tmp = tv_master_cntl | RADEON_TV_ON; 13998c2ecf20Sopenharmony_ci tmp &= ~(RADEON_TV_ASYNC_RST | 14008c2ecf20Sopenharmony_ci RADEON_RESTART_PHASE_FIX | 14018c2ecf20Sopenharmony_ci RADEON_CRT_FIFO_CE_EN | 14028c2ecf20Sopenharmony_ci RADEON_TV_FIFO_CE_EN | 14038c2ecf20Sopenharmony_ci RADEON_RE_SYNC_NOW_SEL_MASK); 14048c2ecf20Sopenharmony_ci tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST; 14058c2ecf20Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, tmp); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | 14088c2ecf20Sopenharmony_ci RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC | 14098c2ecf20Sopenharmony_ci (8 << RADEON_TV_DAC_BGADJ_SHIFT); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK) 14128c2ecf20Sopenharmony_ci tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT); 14138c2ecf20Sopenharmony_ci else 14148c2ecf20Sopenharmony_ci tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT); 14158c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tmp); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN | 14188c2ecf20Sopenharmony_ci RADEON_RED_MX_FORCE_DAC_DATA | 14198c2ecf20Sopenharmony_ci RADEON_GRN_MX_FORCE_DAC_DATA | 14208c2ecf20Sopenharmony_ci RADEON_BLU_MX_FORCE_DAC_DATA | 14218c2ecf20Sopenharmony_ci (0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT); 14228c2ecf20Sopenharmony_ci WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tmp); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci mdelay(3); 14258c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_TV_DAC_CNTL); 14268c2ecf20Sopenharmony_ci if (tmp & RADEON_TV_DAC_GDACDET) { 14278c2ecf20Sopenharmony_ci found = true; 14288c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("S-video TV connection detected\n"); 14298c2ecf20Sopenharmony_ci } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { 14308c2ecf20Sopenharmony_ci found = true; 14318c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Composite TV connection detected\n"); 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl); 14358c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 14368c2ecf20Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); 14378c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac_cntl2); 14388c2ecf20Sopenharmony_ci return found; 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cistatic bool radeon_legacy_ext_dac_detect(struct drm_encoder *encoder, 14428c2ecf20Sopenharmony_ci struct drm_connector *connector) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 14458c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 14468c2ecf20Sopenharmony_ci uint32_t gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl; 14478c2ecf20Sopenharmony_ci uint32_t disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c; 14488c2ecf20Sopenharmony_ci uint32_t disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f; 14498c2ecf20Sopenharmony_ci uint32_t tmp, crtc2_h_total_disp, crtc2_v_total_disp; 14508c2ecf20Sopenharmony_ci uint32_t crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid; 14518c2ecf20Sopenharmony_ci bool found = false; 14528c2ecf20Sopenharmony_ci int i; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* save the regs we need */ 14558c2ecf20Sopenharmony_ci gpio_monid = RREG32(RADEON_GPIO_MONID); 14568c2ecf20Sopenharmony_ci fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); 14578c2ecf20Sopenharmony_ci disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); 14588c2ecf20Sopenharmony_ci crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); 14598c2ecf20Sopenharmony_ci disp_lin_trans_grph_a = RREG32(RADEON_DISP_LIN_TRANS_GRPH_A); 14608c2ecf20Sopenharmony_ci disp_lin_trans_grph_b = RREG32(RADEON_DISP_LIN_TRANS_GRPH_B); 14618c2ecf20Sopenharmony_ci disp_lin_trans_grph_c = RREG32(RADEON_DISP_LIN_TRANS_GRPH_C); 14628c2ecf20Sopenharmony_ci disp_lin_trans_grph_d = RREG32(RADEON_DISP_LIN_TRANS_GRPH_D); 14638c2ecf20Sopenharmony_ci disp_lin_trans_grph_e = RREG32(RADEON_DISP_LIN_TRANS_GRPH_E); 14648c2ecf20Sopenharmony_ci disp_lin_trans_grph_f = RREG32(RADEON_DISP_LIN_TRANS_GRPH_F); 14658c2ecf20Sopenharmony_ci crtc2_h_total_disp = RREG32(RADEON_CRTC2_H_TOTAL_DISP); 14668c2ecf20Sopenharmony_ci crtc2_v_total_disp = RREG32(RADEON_CRTC2_V_TOTAL_DISP); 14678c2ecf20Sopenharmony_ci crtc2_h_sync_strt_wid = RREG32(RADEON_CRTC2_H_SYNC_STRT_WID); 14688c2ecf20Sopenharmony_ci crtc2_v_sync_strt_wid = RREG32(RADEON_CRTC2_V_SYNC_STRT_WID); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_GPIO_MONID); 14718c2ecf20Sopenharmony_ci tmp &= ~RADEON_GPIO_A_0; 14728c2ecf20Sopenharmony_ci WREG32(RADEON_GPIO_MONID, tmp); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, (RADEON_FP2_ON | 14758c2ecf20Sopenharmony_ci RADEON_FP2_PANEL_FORMAT | 14768c2ecf20Sopenharmony_ci R200_FP2_SOURCE_SEL_TRANS_UNIT | 14778c2ecf20Sopenharmony_ci RADEON_FP2_DVO_EN | 14788c2ecf20Sopenharmony_ci R200_FP2_DVO_RATE_SEL_SDR)); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, (RADEON_DISP_DAC_SOURCE_RMX | 14818c2ecf20Sopenharmony_ci RADEON_DISP_TRANS_MATRIX_GRAPHICS)); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_EN | 14848c2ecf20Sopenharmony_ci RADEON_CRTC2_DISP_REQ_EN_B)); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); 14878c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); 14888c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); 14898c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); 14908c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); 14918c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); 14948c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); 14958c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); 14968c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci for (i = 0; i < 200; i++) { 14998c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_GPIO_MONID); 15008c2ecf20Sopenharmony_ci if (tmp & RADEON_GPIO_Y_0) 15018c2ecf20Sopenharmony_ci found = true; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if (found) 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (!drm_can_sleep()) 15078c2ecf20Sopenharmony_ci mdelay(1); 15088c2ecf20Sopenharmony_ci else 15098c2ecf20Sopenharmony_ci msleep(1); 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* restore the regs we used */ 15138c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a); 15148c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b); 15158c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c); 15168c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d); 15178c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e); 15188c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f); 15198c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp); 15208c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp); 15218c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid); 15228c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid); 15238c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); 15248c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); 15258c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); 15268c2ecf20Sopenharmony_ci WREG32(RADEON_GPIO_MONID, gpio_monid); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci return found; 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_cistatic enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, 15328c2ecf20Sopenharmony_ci struct drm_connector *connector) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 15358c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 15368c2ecf20Sopenharmony_ci uint32_t crtc2_gen_cntl = 0, tv_dac_cntl, dac_cntl2, dac_ext_cntl; 15378c2ecf20Sopenharmony_ci uint32_t gpiopad_a = 0, pixclks_cntl, tmp; 15388c2ecf20Sopenharmony_ci uint32_t disp_output_cntl = 0, disp_hw_debug = 0, crtc_ext_cntl = 0; 15398c2ecf20Sopenharmony_ci enum drm_connector_status found = connector_status_disconnected; 15408c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 15418c2ecf20Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 15428c2ecf20Sopenharmony_ci bool color = true; 15438c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* find out if crtc2 is in use or if this encoder is using it */ 15468c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 15478c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 15488c2ecf20Sopenharmony_ci if ((radeon_crtc->crtc_id == 1) && crtc->enabled) { 15498c2ecf20Sopenharmony_ci if (encoder->crtc != crtc) { 15508c2ecf20Sopenharmony_ci return connector_status_disconnected; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_SVIDEO || 15568c2ecf20Sopenharmony_ci connector->connector_type == DRM_MODE_CONNECTOR_Composite || 15578c2ecf20Sopenharmony_ci connector->connector_type == DRM_MODE_CONNECTOR_9PinDIN) { 15588c2ecf20Sopenharmony_ci bool tv_detect; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT)) 15618c2ecf20Sopenharmony_ci return connector_status_disconnected; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci tv_detect = radeon_legacy_tv_detect(encoder, connector); 15648c2ecf20Sopenharmony_ci if (tv_detect && tv_dac) 15658c2ecf20Sopenharmony_ci found = connector_status_connected; 15668c2ecf20Sopenharmony_ci return found; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci /* don't probe if the encoder is being used for something else not CRT related */ 15708c2ecf20Sopenharmony_ci if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_CRT_SUPPORT)) { 15718c2ecf20Sopenharmony_ci DRM_INFO("not detecting due to %08x\n", radeon_encoder->active_device); 15728c2ecf20Sopenharmony_ci return connector_status_disconnected; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci /* R200 uses an external DAC for secondary DAC */ 15768c2ecf20Sopenharmony_ci if (rdev->family == CHIP_R200) { 15778c2ecf20Sopenharmony_ci if (radeon_legacy_ext_dac_detect(encoder, connector)) 15788c2ecf20Sopenharmony_ci found = connector_status_connected; 15798c2ecf20Sopenharmony_ci return found; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* save the regs we need */ 15838c2ecf20Sopenharmony_ci pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_SINGLE_CRTC) { 15868c2ecf20Sopenharmony_ci crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); 15878c2ecf20Sopenharmony_ci } else { 15888c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 15898c2ecf20Sopenharmony_ci gpiopad_a = RREG32(RADEON_GPIOPAD_A); 15908c2ecf20Sopenharmony_ci disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); 15918c2ecf20Sopenharmony_ci } else { 15928c2ecf20Sopenharmony_ci disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 15978c2ecf20Sopenharmony_ci dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); 15988c2ecf20Sopenharmony_ci dac_cntl2 = RREG32(RADEON_DAC_CNTL2); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb 16018c2ecf20Sopenharmony_ci | RADEON_PIX2CLK_DAC_ALWAYS_ONb); 16028c2ecf20Sopenharmony_ci WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_SINGLE_CRTC) { 16058c2ecf20Sopenharmony_ci tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; 16068c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_EXT_CNTL, tmp); 16078c2ecf20Sopenharmony_ci } else { 16088c2ecf20Sopenharmony_ci tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; 16098c2ecf20Sopenharmony_ci tmp |= RADEON_CRTC2_CRT2_ON | 16108c2ecf20Sopenharmony_ci (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); 16118c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, tmp); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 16148c2ecf20Sopenharmony_ci WREG32_P(RADEON_GPIOPAD_A, 1, ~1); 16158c2ecf20Sopenharmony_ci tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; 16168c2ecf20Sopenharmony_ci tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; 16178c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); 16188c2ecf20Sopenharmony_ci } else { 16198c2ecf20Sopenharmony_ci tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; 16208c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_HW_DEBUG, tmp); 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci tmp = RADEON_TV_DAC_NBLANK | 16258c2ecf20Sopenharmony_ci RADEON_TV_DAC_NHOLD | 16268c2ecf20Sopenharmony_ci RADEON_TV_MONITOR_DETECT_EN | 16278c2ecf20Sopenharmony_ci RADEON_TV_DAC_STD_PS2; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tmp); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN | 16328c2ecf20Sopenharmony_ci RADEON_DAC2_FORCE_DATA_EN; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if (color) 16358c2ecf20Sopenharmony_ci tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; 16368c2ecf20Sopenharmony_ci else 16378c2ecf20Sopenharmony_ci tmp |= RADEON_DAC_FORCE_DATA_SEL_G; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) 16408c2ecf20Sopenharmony_ci tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); 16418c2ecf20Sopenharmony_ci else 16428c2ecf20Sopenharmony_ci tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_EXT_CNTL, tmp); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; 16478c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, tmp); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci mdelay(10); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 16528c2ecf20Sopenharmony_ci if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) 16538c2ecf20Sopenharmony_ci found = connector_status_connected; 16548c2ecf20Sopenharmony_ci } else { 16558c2ecf20Sopenharmony_ci if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) 16568c2ecf20Sopenharmony_ci found = connector_status_connected; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* restore regs we used */ 16608c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac_cntl2); 16618c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); 16628c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_SINGLE_CRTC) { 16658c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); 16668c2ecf20Sopenharmony_ci } else { 16678c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); 16688c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 16698c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); 16708c2ecf20Sopenharmony_ci WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); 16718c2ecf20Sopenharmony_ci } else { 16728c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci return found; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = { 16838c2ecf20Sopenharmony_ci .dpms = radeon_legacy_tv_dac_dpms, 16848c2ecf20Sopenharmony_ci .mode_fixup = radeon_legacy_mode_fixup, 16858c2ecf20Sopenharmony_ci .prepare = radeon_legacy_tv_dac_prepare, 16868c2ecf20Sopenharmony_ci .mode_set = radeon_legacy_tv_dac_mode_set, 16878c2ecf20Sopenharmony_ci .commit = radeon_legacy_tv_dac_commit, 16888c2ecf20Sopenharmony_ci .detect = radeon_legacy_tv_dac_detect, 16898c2ecf20Sopenharmony_ci .disable = radeon_legacy_encoder_disable, 16908c2ecf20Sopenharmony_ci}; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { 16948c2ecf20Sopenharmony_ci .destroy = radeon_enc_destroy, 16958c2ecf20Sopenharmony_ci}; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic struct radeon_encoder_int_tmds *radeon_legacy_get_tmds_info(struct radeon_encoder *encoder) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->base.dev; 17018c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17028c2ecf20Sopenharmony_ci struct radeon_encoder_int_tmds *tmds = NULL; 17038c2ecf20Sopenharmony_ci bool ret; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci if (!tmds) 17088c2ecf20Sopenharmony_ci return NULL; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 17118c2ecf20Sopenharmony_ci ret = radeon_atombios_get_tmds_info(encoder, tmds); 17128c2ecf20Sopenharmony_ci else 17138c2ecf20Sopenharmony_ci ret = radeon_legacy_get_tmds_info_from_combios(encoder, tmds); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (!ret) 17168c2ecf20Sopenharmony_ci radeon_legacy_get_tmds_info_from_table(encoder, tmds); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return tmds; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_cistatic struct radeon_encoder_ext_tmds *radeon_legacy_get_ext_tmds_info(struct radeon_encoder *encoder) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->base.dev; 17248c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17258c2ecf20Sopenharmony_ci struct radeon_encoder_ext_tmds *tmds = NULL; 17268c2ecf20Sopenharmony_ci bool ret; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 17298c2ecf20Sopenharmony_ci return NULL; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci tmds = kzalloc(sizeof(struct radeon_encoder_ext_tmds), GFP_KERNEL); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (!tmds) 17348c2ecf20Sopenharmony_ci return NULL; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci ret = radeon_legacy_get_ext_tmds_info_from_combios(encoder, tmds); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (!ret) 17398c2ecf20Sopenharmony_ci radeon_legacy_get_ext_tmds_info_from_table(encoder, tmds); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci return tmds; 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_civoid 17458c2ecf20Sopenharmony_ciradeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17488c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 17498c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* see if we already added it */ 17528c2ecf20Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 17538c2ecf20Sopenharmony_ci radeon_encoder = to_radeon_encoder(encoder); 17548c2ecf20Sopenharmony_ci if (radeon_encoder->encoder_enum == encoder_enum) { 17558c2ecf20Sopenharmony_ci radeon_encoder->devices |= supported_device; 17568c2ecf20Sopenharmony_ci return; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* add a new one */ 17628c2ecf20Sopenharmony_ci radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); 17638c2ecf20Sopenharmony_ci if (!radeon_encoder) 17648c2ecf20Sopenharmony_ci return; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci encoder = &radeon_encoder->base; 17678c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_SINGLE_CRTC) 17688c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x1; 17698c2ecf20Sopenharmony_ci else 17708c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x3; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = NULL; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci radeon_encoder->encoder_enum = encoder_enum; 17758c2ecf20Sopenharmony_ci radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 17768c2ecf20Sopenharmony_ci radeon_encoder->devices = supported_device; 17778c2ecf20Sopenharmony_ci radeon_encoder->rmx_type = RMX_OFF; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 17808c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 17818c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x1; 17828c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, 17838c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 17848c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); 17858c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 17868c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 17878c2ecf20Sopenharmony_ci else 17888c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder); 17898c2ecf20Sopenharmony_ci radeon_encoder->rmx_type = RMX_FULL; 17908c2ecf20Sopenharmony_ci break; 17918c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 17928c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, 17938c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 17948c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); 17958c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_legacy_get_tmds_info(radeon_encoder); 17968c2ecf20Sopenharmony_ci break; 17978c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 17988c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, 17998c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 18008c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); 18018c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 18028c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder); 18038c2ecf20Sopenharmony_ci else 18048c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder); 18058c2ecf20Sopenharmony_ci break; 18068c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 18078c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, 18088c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TVDAC, NULL); 18098c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); 18108c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) 18118c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder); 18128c2ecf20Sopenharmony_ci else 18138c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder); 18148c2ecf20Sopenharmony_ci break; 18158c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 18168c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, 18178c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 18188c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs); 18198c2ecf20Sopenharmony_ci if (!rdev->is_atom_bios) 18208c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_legacy_get_ext_tmds_info(radeon_encoder); 18218c2ecf20Sopenharmony_ci break; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci} 1824