162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2007-11 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 762306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 862306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 962306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1062306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1362306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1962306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2062306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2162306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Authors: Dave Airlie 2462306a36Sopenharmony_ci * Alex Deucher 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/backlight.h> 2862306a36Sopenharmony_ci#include <linux/dmi.h> 2962306a36Sopenharmony_ci#include <linux/pci.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <drm/drm_crtc_helper.h> 3262306a36Sopenharmony_ci#include <drm/drm_file.h> 3362306a36Sopenharmony_ci#include <drm/drm_modeset_helper_vtables.h> 3462306a36Sopenharmony_ci#include <drm/radeon_drm.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <acpi/video.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "atom.h" 3962306a36Sopenharmony_ci#include "radeon_atombios.h" 4062306a36Sopenharmony_ci#include "radeon.h" 4162306a36Sopenharmony_ci#include "radeon_asic.h" 4262306a36Sopenharmony_ci#include "radeon_audio.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciextern int atom_debug; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic u8 4762306a36Sopenharmony_ciradeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci u8 backlight_level; 5062306a36Sopenharmony_ci u32 bios_2_scratch; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 5362306a36Sopenharmony_ci bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 5462306a36Sopenharmony_ci else 5562306a36Sopenharmony_ci bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >> 5862306a36Sopenharmony_ci ATOM_S2_CURRENT_BL_LEVEL_SHIFT); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return backlight_level; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void 6462306a36Sopenharmony_ciradeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, 6562306a36Sopenharmony_ci u8 backlight_level) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci u32 bios_2_scratch; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 7062306a36Sopenharmony_ci bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; 7562306a36Sopenharmony_ci bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) & 7662306a36Sopenharmony_ci ATOM_S2_CURRENT_BL_LEVEL_MASK); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 7962306a36Sopenharmony_ci WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); 8062306a36Sopenharmony_ci else 8162306a36Sopenharmony_ci WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciu8 8562306a36Sopenharmony_ciatombios_get_backlight_level(struct radeon_encoder *radeon_encoder) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 8862306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return radeon_atom_get_backlight_level_from_reg(rdev); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid 9762306a36Sopenharmony_ciatombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct drm_encoder *encoder = &radeon_encoder->base; 10062306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 10162306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 10262306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 10362306a36Sopenharmony_ci DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; 10462306a36Sopenharmony_ci int index; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 10762306a36Sopenharmony_ci return; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 11062306a36Sopenharmony_ci radeon_encoder->enc_priv) { 11162306a36Sopenharmony_ci dig = radeon_encoder->enc_priv; 11262306a36Sopenharmony_ci dig->backlight_level = level; 11362306a36Sopenharmony_ci radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 11662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 11762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 11862306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 11962306a36Sopenharmony_ci if (dig->backlight_level == 0) { 12062306a36Sopenharmony_ci args.ucAction = ATOM_LCD_BLOFF; 12162306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 12262306a36Sopenharmony_ci } else { 12362306a36Sopenharmony_ci args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL; 12462306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 12562306a36Sopenharmony_ci args.ucAction = ATOM_LCD_BLON; 12662306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 13062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 13162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 13262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 13362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 13462306a36Sopenharmony_ci if (dig->backlight_level == 0) 13562306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); 13662306a36Sopenharmony_ci else { 13762306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0); 13862306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci default: 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic u8 radeon_atom_bl_level(struct backlight_device *bd) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci u8 level; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Convert brightness to hardware level */ 15262306a36Sopenharmony_ci if (bd->props.brightness < 0) 15362306a36Sopenharmony_ci level = 0; 15462306a36Sopenharmony_ci else if (bd->props.brightness > RADEON_MAX_BL_LEVEL) 15562306a36Sopenharmony_ci level = RADEON_MAX_BL_LEVEL; 15662306a36Sopenharmony_ci else 15762306a36Sopenharmony_ci level = bd->props.brightness; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return level; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int radeon_atom_backlight_update_status(struct backlight_device *bd) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 16562306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = pdata->encoder; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd)); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int radeon_atom_backlight_get_brightness(struct backlight_device *bd) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 17562306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = pdata->encoder; 17662306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 17762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return radeon_atom_get_backlight_level_from_reg(rdev); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const struct backlight_ops radeon_atom_backlight_ops = { 18362306a36Sopenharmony_ci .get_brightness = radeon_atom_backlight_get_brightness, 18462306a36Sopenharmony_ci .update_status = radeon_atom_backlight_update_status, 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_civoid radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, 18862306a36Sopenharmony_ci struct drm_connector *drm_connector) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 19162306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 19262306a36Sopenharmony_ci struct backlight_device *bd; 19362306a36Sopenharmony_ci struct backlight_properties props; 19462306a36Sopenharmony_ci struct radeon_backlight_privdata *pdata; 19562306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 19662306a36Sopenharmony_ci char bl_name[16]; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Mac laptops with multiple GPUs use the gmux driver for backlight 19962306a36Sopenharmony_ci * so don't register a backlight device 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && 20262306a36Sopenharmony_ci (rdev->pdev->device == 0x6741) && 20362306a36Sopenharmony_ci !dmi_match(DMI_PRODUCT_NAME, "iMac12,1")) 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (!radeon_encoder->enc_priv) 20762306a36Sopenharmony_ci return; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!rdev->is_atom_bios) 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 21362306a36Sopenharmony_ci return; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!acpi_video_backlight_use_native()) { 21662306a36Sopenharmony_ci drm_info(dev, "Skipping radeon atom DIG backlight registration\n"); 21762306a36Sopenharmony_ci return; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); 22162306a36Sopenharmony_ci if (!pdata) { 22262306a36Sopenharmony_ci DRM_ERROR("Memory allocation failed\n"); 22362306a36Sopenharmony_ci goto error; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci memset(&props, 0, sizeof(props)); 22762306a36Sopenharmony_ci props.max_brightness = RADEON_MAX_BL_LEVEL; 22862306a36Sopenharmony_ci props.type = BACKLIGHT_RAW; 22962306a36Sopenharmony_ci snprintf(bl_name, sizeof(bl_name), 23062306a36Sopenharmony_ci "radeon_bl%d", dev->primary->index); 23162306a36Sopenharmony_ci bd = backlight_device_register(bl_name, drm_connector->kdev, 23262306a36Sopenharmony_ci pdata, &radeon_atom_backlight_ops, &props); 23362306a36Sopenharmony_ci if (IS_ERR(bd)) { 23462306a36Sopenharmony_ci DRM_ERROR("Backlight registration failed\n"); 23562306a36Sopenharmony_ci goto error; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci pdata->encoder = radeon_encoder; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci dig = radeon_encoder->enc_priv; 24162306a36Sopenharmony_ci dig->bl_dev = bd; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci bd->props.brightness = radeon_atom_backlight_get_brightness(bd); 24462306a36Sopenharmony_ci /* Set a reasonable default here if the level is 0 otherwise 24562306a36Sopenharmony_ci * fbdev will attempt to turn the backlight on after console 24662306a36Sopenharmony_ci * unblanking and it will try and restore 0 which turns the backlight 24762306a36Sopenharmony_ci * off again. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci if (bd->props.brightness == 0) 25062306a36Sopenharmony_ci bd->props.brightness = RADEON_MAX_BL_LEVEL; 25162306a36Sopenharmony_ci bd->props.power = FB_BLANK_UNBLANK; 25262306a36Sopenharmony_ci backlight_update_status(bd); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci DRM_INFO("radeon atom DIG backlight initialized\n"); 25562306a36Sopenharmony_ci rdev->mode_info.bl_encoder = radeon_encoder; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cierror: 26062306a36Sopenharmony_ci kfree(pdata); 26162306a36Sopenharmony_ci return; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 26762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 26862306a36Sopenharmony_ci struct backlight_device *bd = NULL; 26962306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (!radeon_encoder->enc_priv) 27262306a36Sopenharmony_ci return; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!rdev->is_atom_bios) 27562306a36Sopenharmony_ci return; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 27862306a36Sopenharmony_ci return; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci dig = radeon_encoder->enc_priv; 28162306a36Sopenharmony_ci bd = dig->bl_dev; 28262306a36Sopenharmony_ci dig->bl_dev = NULL; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (bd) { 28562306a36Sopenharmony_ci struct radeon_legacy_backlight_privdata *pdata; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci pdata = bl_get_data(bd); 28862306a36Sopenharmony_ci backlight_device_unregister(bd); 28962306a36Sopenharmony_ci kfree(pdata); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci DRM_INFO("radeon atom LVDS backlight unloaded\n"); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic bool radeon_atom_mode_fixup(struct drm_encoder *encoder, 29662306a36Sopenharmony_ci const struct drm_display_mode *mode, 29762306a36Sopenharmony_ci struct drm_display_mode *adjusted_mode) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 30062306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 30162306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* set the active encoder to connector routing */ 30462306a36Sopenharmony_ci radeon_encoder_set_active_device(encoder); 30562306a36Sopenharmony_ci drm_mode_set_crtcinfo(adjusted_mode, 0); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* hw bug */ 30862306a36Sopenharmony_ci if ((mode->flags & DRM_MODE_FLAG_INTERLACE) 30962306a36Sopenharmony_ci && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) 31062306a36Sopenharmony_ci adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* vertical FP must be at least 1 */ 31362306a36Sopenharmony_ci if (mode->crtc_vsync_start == mode->crtc_vdisplay) 31462306a36Sopenharmony_ci adjusted_mode->crtc_vsync_start++; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* get the native mode for scaling */ 31762306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 31862306a36Sopenharmony_ci radeon_panel_mode_fixup(encoder, adjusted_mode); 31962306a36Sopenharmony_ci } else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 32062306a36Sopenharmony_ci struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 32162306a36Sopenharmony_ci if (tv_dac) { 32262306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 32362306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 32462306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M) 32562306a36Sopenharmony_ci radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci } else if (radeon_encoder->rmx_type != RMX_OFF) { 33062306a36Sopenharmony_ci radeon_panel_mode_fixup(encoder, adjusted_mode); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (ASIC_IS_DCE3(rdev) && 33462306a36Sopenharmony_ci ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || 33562306a36Sopenharmony_ci (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { 33662306a36Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 33762306a36Sopenharmony_ci radeon_dp_set_link_config(connector, adjusted_mode); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return true; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void 34462306a36Sopenharmony_ciatombios_dac_setup(struct drm_encoder *encoder, int action) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 34762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 34862306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 34962306a36Sopenharmony_ci DAC_ENCODER_CONTROL_PS_ALLOCATION args; 35062306a36Sopenharmony_ci int index = 0; 35162306a36Sopenharmony_ci struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 35662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 35762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 35862306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 36162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 36262306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci args.ucAction = action; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) 36962306a36Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_PS2; 37062306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 37162306a36Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_CV; 37262306a36Sopenharmony_ci else { 37362306a36Sopenharmony_ci switch (dac_info->tv_std) { 37462306a36Sopenharmony_ci case TV_STD_PAL: 37562306a36Sopenharmony_ci case TV_STD_PAL_M: 37662306a36Sopenharmony_ci case TV_STD_SCART_PAL: 37762306a36Sopenharmony_ci case TV_STD_SECAM: 37862306a36Sopenharmony_ci case TV_STD_PAL_CN: 37962306a36Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_PAL; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci case TV_STD_NTSC: 38262306a36Sopenharmony_ci case TV_STD_NTSC_J: 38362306a36Sopenharmony_ci case TV_STD_PAL_60: 38462306a36Sopenharmony_ci default: 38562306a36Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_NTSC; 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic void 39662306a36Sopenharmony_ciatombios_tv_setup(struct drm_encoder *encoder, int action) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 39962306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 40062306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 40162306a36Sopenharmony_ci TV_ENCODER_CONTROL_PS_ALLOCATION args; 40262306a36Sopenharmony_ci int index = 0; 40362306a36Sopenharmony_ci struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci args.sTVEncoder.ucAction = action; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 41262306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_CV; 41362306a36Sopenharmony_ci else { 41462306a36Sopenharmony_ci switch (dac_info->tv_std) { 41562306a36Sopenharmony_ci case TV_STD_NTSC: 41662306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci case TV_STD_PAL: 41962306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case TV_STD_PAL_M: 42262306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci case TV_STD_PAL_60: 42562306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci case TV_STD_NTSC_J: 42862306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci case TV_STD_SCART_PAL: 43162306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case TV_STD_SECAM: 43462306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci case TV_STD_PAL_CN: 43762306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci default: 44062306a36Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic u8 radeon_atom_get_bpc(struct drm_encoder *encoder) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci int bpc = 8; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (encoder->crtc) { 45662306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 45762306a36Sopenharmony_ci bpc = radeon_crtc->bpc; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci switch (bpc) { 46162306a36Sopenharmony_ci case 0: 46262306a36Sopenharmony_ci return PANEL_BPC_UNDEFINE; 46362306a36Sopenharmony_ci case 6: 46462306a36Sopenharmony_ci return PANEL_6BIT_PER_COLOR; 46562306a36Sopenharmony_ci case 8: 46662306a36Sopenharmony_ci default: 46762306a36Sopenharmony_ci return PANEL_8BIT_PER_COLOR; 46862306a36Sopenharmony_ci case 10: 46962306a36Sopenharmony_ci return PANEL_10BIT_PER_COLOR; 47062306a36Sopenharmony_ci case 12: 47162306a36Sopenharmony_ci return PANEL_12BIT_PER_COLOR; 47262306a36Sopenharmony_ci case 16: 47362306a36Sopenharmony_ci return PANEL_16BIT_PER_COLOR; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ciunion dvo_encoder_control { 47862306a36Sopenharmony_ci ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; 47962306a36Sopenharmony_ci DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; 48062306a36Sopenharmony_ci DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; 48162306a36Sopenharmony_ci DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4; 48262306a36Sopenharmony_ci}; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_civoid 48562306a36Sopenharmony_ciatombios_dvo_setup(struct drm_encoder *encoder, int action) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 48862306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 48962306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 49062306a36Sopenharmony_ci union dvo_encoder_control args; 49162306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 49262306a36Sopenharmony_ci uint8_t frev, crev; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 49762306a36Sopenharmony_ci return; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* some R4xx chips have the wrong frev */ 50062306a36Sopenharmony_ci if (rdev->family <= CHIP_RV410) 50162306a36Sopenharmony_ci frev = 1; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci switch (frev) { 50462306a36Sopenharmony_ci case 1: 50562306a36Sopenharmony_ci switch (crev) { 50662306a36Sopenharmony_ci case 1: 50762306a36Sopenharmony_ci /* R4xx, R5xx */ 50862306a36Sopenharmony_ci args.ext_tmds.sXTmdsEncoder.ucEnable = action; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 51162306a36Sopenharmony_ci args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci case 2: 51662306a36Sopenharmony_ci /* RS600/690/740 */ 51762306a36Sopenharmony_ci args.dvo.sDVOEncoder.ucAction = action; 51862306a36Sopenharmony_ci args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 51962306a36Sopenharmony_ci /* DFP1, CRT1, TV1 depending on the type of port */ 52062306a36Sopenharmony_ci args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 52362306a36Sopenharmony_ci args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci case 3: 52662306a36Sopenharmony_ci /* R6xx */ 52762306a36Sopenharmony_ci args.dvo_v3.ucAction = action; 52862306a36Sopenharmony_ci args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 52962306a36Sopenharmony_ci args.dvo_v3.ucDVOConfig = 0; /* XXX */ 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci case 4: 53262306a36Sopenharmony_ci /* DCE8 */ 53362306a36Sopenharmony_ci args.dvo_v4.ucAction = action; 53462306a36Sopenharmony_ci args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 53562306a36Sopenharmony_ci args.dvo_v4.ucDVOConfig = 0; /* XXX */ 53662306a36Sopenharmony_ci args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci default: 53962306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci default: 54462306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ciunion lvds_encoder_control { 55262306a36Sopenharmony_ci LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; 55362306a36Sopenharmony_ci LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; 55462306a36Sopenharmony_ci}; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_civoid 55762306a36Sopenharmony_ciatombios_digital_setup(struct drm_encoder *encoder, int action) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 56062306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 56162306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 56262306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 56362306a36Sopenharmony_ci union lvds_encoder_control args; 56462306a36Sopenharmony_ci int index = 0; 56562306a36Sopenharmony_ci int hdmi_detected = 0; 56662306a36Sopenharmony_ci uint8_t frev, crev; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (!dig) 56962306a36Sopenharmony_ci return; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) 57262306a36Sopenharmony_ci hdmi_detected = 1; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 57762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 57862306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 58162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 58262306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 58562306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 58662306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 58762306a36Sopenharmony_ci else 58862306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 59362306a36Sopenharmony_ci return; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci switch (frev) { 59662306a36Sopenharmony_ci case 1: 59762306a36Sopenharmony_ci case 2: 59862306a36Sopenharmony_ci switch (crev) { 59962306a36Sopenharmony_ci case 1: 60062306a36Sopenharmony_ci args.v1.ucMisc = 0; 60162306a36Sopenharmony_ci args.v1.ucAction = action; 60262306a36Sopenharmony_ci if (hdmi_detected) 60362306a36Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 60462306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 60562306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 60662306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) 60762306a36Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; 60862306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 60962306a36Sopenharmony_ci args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; 61062306a36Sopenharmony_ci } else { 61162306a36Sopenharmony_ci if (dig->linkb) 61262306a36Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 61362306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 61462306a36Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; 61562306a36Sopenharmony_ci /*if (pScrn->rgbBits == 8) */ 61662306a36Sopenharmony_ci args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case 2: 62062306a36Sopenharmony_ci case 3: 62162306a36Sopenharmony_ci args.v2.ucMisc = 0; 62262306a36Sopenharmony_ci args.v2.ucAction = action; 62362306a36Sopenharmony_ci if (crev == 3) { 62462306a36Sopenharmony_ci if (dig->coherent_mode) 62562306a36Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci if (hdmi_detected) 62862306a36Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 62962306a36Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 63062306a36Sopenharmony_ci args.v2.ucTruncate = 0; 63162306a36Sopenharmony_ci args.v2.ucSpatial = 0; 63262306a36Sopenharmony_ci args.v2.ucTemporal = 0; 63362306a36Sopenharmony_ci args.v2.ucFRC = 0; 63462306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 63562306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) 63662306a36Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 63762306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { 63862306a36Sopenharmony_ci args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; 63962306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 64062306a36Sopenharmony_ci args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { 64362306a36Sopenharmony_ci args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; 64462306a36Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 64562306a36Sopenharmony_ci args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; 64662306a36Sopenharmony_ci if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) 64762306a36Sopenharmony_ci args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci } else { 65062306a36Sopenharmony_ci if (dig->linkb) 65162306a36Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 65262306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 65362306a36Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci default: 66262306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 66362306a36Sopenharmony_ci break; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ciint 67062306a36Sopenharmony_ciatombios_get_encoder_mode(struct drm_encoder *encoder) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 67362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 67462306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 67562306a36Sopenharmony_ci struct drm_connector *connector; 67662306a36Sopenharmony_ci struct radeon_connector *radeon_connector; 67762306a36Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* dp bridges are always DP */ 68062306a36Sopenharmony_ci if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) 68162306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DP; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* DVO is always DVO */ 68462306a36Sopenharmony_ci if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) || 68562306a36Sopenharmony_ci (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) 68662306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVO; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci connector = radeon_get_connector_for_encoder(encoder); 68962306a36Sopenharmony_ci /* if we don't have an active device yet, just use one of 69062306a36Sopenharmony_ci * the connectors tied to the encoder. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci if (!connector) 69362306a36Sopenharmony_ci connector = radeon_get_connector_for_encoder_init(encoder); 69462306a36Sopenharmony_ci radeon_connector = to_radeon_connector(connector); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci switch (connector->connector_type) { 69762306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_DVII: 69862306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ 69962306a36Sopenharmony_ci if (radeon_audio != 0) { 70062306a36Sopenharmony_ci if (radeon_connector->use_digital && 70162306a36Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_ENABLE)) 70262306a36Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 70362306a36Sopenharmony_ci else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 70462306a36Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_AUTO)) 70562306a36Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 70662306a36Sopenharmony_ci else if (radeon_connector->use_digital) 70762306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 70862306a36Sopenharmony_ci else 70962306a36Sopenharmony_ci return ATOM_ENCODER_MODE_CRT; 71062306a36Sopenharmony_ci } else if (radeon_connector->use_digital) { 71162306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci return ATOM_ENCODER_MODE_CRT; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci break; 71662306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_DVID: 71762306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_HDMIA: 71862306a36Sopenharmony_ci default: 71962306a36Sopenharmony_ci if (radeon_audio != 0) { 72062306a36Sopenharmony_ci if (radeon_connector->audio == RADEON_AUDIO_ENABLE) 72162306a36Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 72262306a36Sopenharmony_ci else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 72362306a36Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_AUTO)) 72462306a36Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 72562306a36Sopenharmony_ci else 72662306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 72762306a36Sopenharmony_ci } else { 72862306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_LVDS: 73262306a36Sopenharmony_ci return ATOM_ENCODER_MODE_LVDS; 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_DisplayPort: 73562306a36Sopenharmony_ci dig_connector = radeon_connector->con_priv; 73662306a36Sopenharmony_ci if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 73762306a36Sopenharmony_ci (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 73862306a36Sopenharmony_ci if (radeon_audio != 0 && 73962306a36Sopenharmony_ci drm_detect_monitor_audio(radeon_connector_edid(connector)) && 74062306a36Sopenharmony_ci ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) 74162306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DP_AUDIO; 74262306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DP; 74362306a36Sopenharmony_ci } else if (radeon_audio != 0) { 74462306a36Sopenharmony_ci if (radeon_connector->audio == RADEON_AUDIO_ENABLE) 74562306a36Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 74662306a36Sopenharmony_ci else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 74762306a36Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_AUTO)) 74862306a36Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 74962306a36Sopenharmony_ci else 75062306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 75162306a36Sopenharmony_ci } else { 75262306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_eDP: 75662306a36Sopenharmony_ci if (radeon_audio != 0 && 75762306a36Sopenharmony_ci drm_detect_monitor_audio(radeon_connector_edid(connector)) && 75862306a36Sopenharmony_ci ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) 75962306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DP_AUDIO; 76062306a36Sopenharmony_ci return ATOM_ENCODER_MODE_DP; 76162306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_DVIA: 76262306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_VGA: 76362306a36Sopenharmony_ci return ATOM_ENCODER_MODE_CRT; 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_Composite: 76662306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_SVIDEO: 76762306a36Sopenharmony_ci case DRM_MODE_CONNECTOR_9PinDIN: 76862306a36Sopenharmony_ci /* fix me */ 76962306a36Sopenharmony_ci return ATOM_ENCODER_MODE_TV; 77062306a36Sopenharmony_ci /*return ATOM_ENCODER_MODE_CV;*/ 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci/* 77662306a36Sopenharmony_ci * DIG Encoder/Transmitter Setup 77762306a36Sopenharmony_ci * 77862306a36Sopenharmony_ci * DCE 3.0/3.1 77962306a36Sopenharmony_ci * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. 78062306a36Sopenharmony_ci * Supports up to 3 digital outputs 78162306a36Sopenharmony_ci * - 2 DIG encoder blocks. 78262306a36Sopenharmony_ci * DIG1 can drive UNIPHY link A or link B 78362306a36Sopenharmony_ci * DIG2 can drive UNIPHY link B or LVTMA 78462306a36Sopenharmony_ci * 78562306a36Sopenharmony_ci * DCE 3.2 78662306a36Sopenharmony_ci * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). 78762306a36Sopenharmony_ci * Supports up to 5 digital outputs 78862306a36Sopenharmony_ci * - 2 DIG encoder blocks. 78962306a36Sopenharmony_ci * DIG1/2 can drive UNIPHY0/1/2 link A or link B 79062306a36Sopenharmony_ci * 79162306a36Sopenharmony_ci * DCE 4.0/5.0/6.0 79262306a36Sopenharmony_ci * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). 79362306a36Sopenharmony_ci * Supports up to 6 digital outputs 79462306a36Sopenharmony_ci * - 6 DIG encoder blocks. 79562306a36Sopenharmony_ci * - DIG to PHY mapping is hardcoded 79662306a36Sopenharmony_ci * DIG1 drives UNIPHY0 link A, A+B 79762306a36Sopenharmony_ci * DIG2 drives UNIPHY0 link B 79862306a36Sopenharmony_ci * DIG3 drives UNIPHY1 link A, A+B 79962306a36Sopenharmony_ci * DIG4 drives UNIPHY1 link B 80062306a36Sopenharmony_ci * DIG5 drives UNIPHY2 link A, A+B 80162306a36Sopenharmony_ci * DIG6 drives UNIPHY2 link B 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * DCE 4.1 80462306a36Sopenharmony_ci * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). 80562306a36Sopenharmony_ci * Supports up to 6 digital outputs 80662306a36Sopenharmony_ci * - 2 DIG encoder blocks. 80762306a36Sopenharmony_ci * llano 80862306a36Sopenharmony_ci * DIG1/2 can drive UNIPHY0/1/2 link A or link B 80962306a36Sopenharmony_ci * ontario 81062306a36Sopenharmony_ci * DIG1 drives UNIPHY0/1/2 link A 81162306a36Sopenharmony_ci * DIG2 drives UNIPHY0/1/2 link B 81262306a36Sopenharmony_ci * 81362306a36Sopenharmony_ci * Routing 81462306a36Sopenharmony_ci * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) 81562306a36Sopenharmony_ci * Examples: 81662306a36Sopenharmony_ci * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI 81762306a36Sopenharmony_ci * crtc1 -> dig1 -> UNIPHY0 link B -> DP 81862306a36Sopenharmony_ci * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS 81962306a36Sopenharmony_ci * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ciunion dig_encoder_control { 82362306a36Sopenharmony_ci DIG_ENCODER_CONTROL_PS_ALLOCATION v1; 82462306a36Sopenharmony_ci DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; 82562306a36Sopenharmony_ci DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; 82662306a36Sopenharmony_ci DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; 82762306a36Sopenharmony_ci}; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_civoid 83062306a36Sopenharmony_ciatombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 83362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 83462306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 83562306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 83662306a36Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 83762306a36Sopenharmony_ci union dig_encoder_control args; 83862306a36Sopenharmony_ci int index = 0; 83962306a36Sopenharmony_ci uint8_t frev, crev; 84062306a36Sopenharmony_ci int dp_clock = 0; 84162306a36Sopenharmony_ci int dp_lane_count = 0; 84262306a36Sopenharmony_ci int hpd_id = RADEON_HPD_NONE; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (connector) { 84562306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 84662306a36Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 84762306a36Sopenharmony_ci radeon_connector->con_priv; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci dp_clock = dig_connector->dp_clock; 85062306a36Sopenharmony_ci dp_lane_count = dig_connector->dp_lane_count; 85162306a36Sopenharmony_ci hpd_id = radeon_connector->hpd.hpd; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* no dig encoder assigned */ 85562306a36Sopenharmony_ci if (dig->dig_encoder == -1) 85662306a36Sopenharmony_ci return; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 86162306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); 86262306a36Sopenharmony_ci else { 86362306a36Sopenharmony_ci if (dig->dig_encoder) 86462306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); 86562306a36Sopenharmony_ci else 86662306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 87062306a36Sopenharmony_ci return; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci switch (frev) { 87362306a36Sopenharmony_ci case 1: 87462306a36Sopenharmony_ci switch (crev) { 87562306a36Sopenharmony_ci case 1: 87662306a36Sopenharmony_ci args.v1.ucAction = action; 87762306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 87862306a36Sopenharmony_ci if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 87962306a36Sopenharmony_ci args.v3.ucPanelMode = panel_mode; 88062306a36Sopenharmony_ci else 88162306a36Sopenharmony_ci args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) 88462306a36Sopenharmony_ci args.v1.ucLaneNum = dp_lane_count; 88562306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 88662306a36Sopenharmony_ci args.v1.ucLaneNum = 8; 88762306a36Sopenharmony_ci else 88862306a36Sopenharmony_ci args.v1.ucLaneNum = 4; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 89162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 89262306a36Sopenharmony_ci args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 89562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 89662306a36Sopenharmony_ci args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; 89762306a36Sopenharmony_ci break; 89862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 89962306a36Sopenharmony_ci args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci if (dig->linkb) 90362306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; 90462306a36Sopenharmony_ci else 90562306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) 90862306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci case 2: 91262306a36Sopenharmony_ci case 3: 91362306a36Sopenharmony_ci args.v3.ucAction = action; 91462306a36Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 91562306a36Sopenharmony_ci if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 91662306a36Sopenharmony_ci args.v3.ucPanelMode = panel_mode; 91762306a36Sopenharmony_ci else 91862306a36Sopenharmony_ci args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode)) 92162306a36Sopenharmony_ci args.v3.ucLaneNum = dp_lane_count; 92262306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 92362306a36Sopenharmony_ci args.v3.ucLaneNum = 8; 92462306a36Sopenharmony_ci else 92562306a36Sopenharmony_ci args.v3.ucLaneNum = 4; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000)) 92862306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; 92962306a36Sopenharmony_ci if (enc_override != -1) 93062306a36Sopenharmony_ci args.v3.acConfig.ucDigSel = enc_override; 93162306a36Sopenharmony_ci else 93262306a36Sopenharmony_ci args.v3.acConfig.ucDigSel = dig->dig_encoder; 93362306a36Sopenharmony_ci args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci case 4: 93662306a36Sopenharmony_ci args.v4.ucAction = action; 93762306a36Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 93862306a36Sopenharmony_ci if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 93962306a36Sopenharmony_ci args.v4.ucPanelMode = panel_mode; 94062306a36Sopenharmony_ci else 94162306a36Sopenharmony_ci args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) 94462306a36Sopenharmony_ci args.v4.ucLaneNum = dp_lane_count; 94562306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 94662306a36Sopenharmony_ci args.v4.ucLaneNum = 8; 94762306a36Sopenharmony_ci else 94862306a36Sopenharmony_ci args.v4.ucLaneNum = 4; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) { 95162306a36Sopenharmony_ci if (dp_clock == 540000) 95262306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; 95362306a36Sopenharmony_ci else if (dp_clock == 324000) 95462306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ; 95562306a36Sopenharmony_ci else if (dp_clock == 270000) 95662306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; 95762306a36Sopenharmony_ci else 95862306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (enc_override != -1) 96262306a36Sopenharmony_ci args.v4.acConfig.ucDigSel = enc_override; 96362306a36Sopenharmony_ci else 96462306a36Sopenharmony_ci args.v4.acConfig.ucDigSel = dig->dig_encoder; 96562306a36Sopenharmony_ci args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); 96662306a36Sopenharmony_ci if (hpd_id == RADEON_HPD_NONE) 96762306a36Sopenharmony_ci args.v4.ucHPD_ID = 0; 96862306a36Sopenharmony_ci else 96962306a36Sopenharmony_ci args.v4.ucHPD_ID = hpd_id + 1; 97062306a36Sopenharmony_ci break; 97162306a36Sopenharmony_ci default: 97262306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 97362306a36Sopenharmony_ci break; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci default: 97762306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_civoid 98662306a36Sopenharmony_ciatombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci atombios_dig_encoder_setup2(encoder, action, panel_mode, -1); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ciunion dig_transmitter_control { 99262306a36Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; 99362306a36Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; 99462306a36Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; 99562306a36Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; 99662306a36Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5; 99762306a36Sopenharmony_ci}; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_civoid 100062306a36Sopenharmony_ciatombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 100362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 100462306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 100562306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 100662306a36Sopenharmony_ci struct drm_connector *connector; 100762306a36Sopenharmony_ci union dig_transmitter_control args; 100862306a36Sopenharmony_ci int index = 0; 100962306a36Sopenharmony_ci uint8_t frev, crev; 101062306a36Sopenharmony_ci bool is_dp = false; 101162306a36Sopenharmony_ci int pll_id = 0; 101262306a36Sopenharmony_ci int dp_clock = 0; 101362306a36Sopenharmony_ci int dp_lane_count = 0; 101462306a36Sopenharmony_ci int connector_object_id = 0; 101562306a36Sopenharmony_ci int igp_lane_info = 0; 101662306a36Sopenharmony_ci int dig_encoder = dig->dig_encoder; 101762306a36Sopenharmony_ci int hpd_id = RADEON_HPD_NONE; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 102062306a36Sopenharmony_ci connector = radeon_get_connector_for_encoder_init(encoder); 102162306a36Sopenharmony_ci /* just needed to avoid bailing in the encoder check. the encoder 102262306a36Sopenharmony_ci * isn't used for init 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci dig_encoder = 0; 102562306a36Sopenharmony_ci } else 102662306a36Sopenharmony_ci connector = radeon_get_connector_for_encoder(encoder); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (connector) { 102962306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 103062306a36Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 103162306a36Sopenharmony_ci radeon_connector->con_priv; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci hpd_id = radeon_connector->hpd.hpd; 103462306a36Sopenharmony_ci dp_clock = dig_connector->dp_clock; 103562306a36Sopenharmony_ci dp_lane_count = dig_connector->dp_lane_count; 103662306a36Sopenharmony_ci connector_object_id = 103762306a36Sopenharmony_ci (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 103862306a36Sopenharmony_ci igp_lane_info = dig_connector->igp_lane_info; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (encoder->crtc) { 104262306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 104362306a36Sopenharmony_ci pll_id = radeon_crtc->pll_id; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* no dig encoder assigned */ 104762306a36Sopenharmony_ci if (dig_encoder == -1) 104862306a36Sopenharmony_ci return; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder))) 105162306a36Sopenharmony_ci is_dp = true; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 105662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 105762306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 106062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 106162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 106262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 106362306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 106462306a36Sopenharmony_ci break; 106562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 106662306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); 106762306a36Sopenharmony_ci break; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 107162306a36Sopenharmony_ci return; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci switch (frev) { 107462306a36Sopenharmony_ci case 1: 107562306a36Sopenharmony_ci switch (crev) { 107662306a36Sopenharmony_ci case 1: 107762306a36Sopenharmony_ci args.v1.ucAction = action; 107862306a36Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 107962306a36Sopenharmony_ci args.v1.usInitInfo = cpu_to_le16(connector_object_id); 108062306a36Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 108162306a36Sopenharmony_ci args.v1.asMode.ucLaneSel = lane_num; 108262306a36Sopenharmony_ci args.v1.asMode.ucLaneSet = lane_set; 108362306a36Sopenharmony_ci } else { 108462306a36Sopenharmony_ci if (is_dp) 108562306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(dp_clock / 10); 108662306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 108762306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 108862306a36Sopenharmony_ci else 108962306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (dig_encoder) 109562306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; 109662306a36Sopenharmony_ci else 109762306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if ((rdev->flags & RADEON_IS_IGP) && 110062306a36Sopenharmony_ci (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { 110162306a36Sopenharmony_ci if (is_dp || 110262306a36Sopenharmony_ci !radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) { 110362306a36Sopenharmony_ci if (igp_lane_info & 0x1) 110462306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; 110562306a36Sopenharmony_ci else if (igp_lane_info & 0x2) 110662306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; 110762306a36Sopenharmony_ci else if (igp_lane_info & 0x4) 110862306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; 110962306a36Sopenharmony_ci else if (igp_lane_info & 0x8) 111062306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; 111162306a36Sopenharmony_ci } else { 111262306a36Sopenharmony_ci if (igp_lane_info & 0x3) 111362306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; 111462306a36Sopenharmony_ci else if (igp_lane_info & 0xc) 111562306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (dig->linkb) 112062306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; 112162306a36Sopenharmony_ci else 112262306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (is_dp) 112562306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 112662306a36Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 112762306a36Sopenharmony_ci if (dig->coherent_mode) 112862306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 112962306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 113062306a36Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci break; 113362306a36Sopenharmony_ci case 2: 113462306a36Sopenharmony_ci args.v2.ucAction = action; 113562306a36Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 113662306a36Sopenharmony_ci args.v2.usInitInfo = cpu_to_le16(connector_object_id); 113762306a36Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 113862306a36Sopenharmony_ci args.v2.asMode.ucLaneSel = lane_num; 113962306a36Sopenharmony_ci args.v2.asMode.ucLaneSet = lane_set; 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci if (is_dp) 114262306a36Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(dp_clock / 10); 114362306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 114462306a36Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 114562306a36Sopenharmony_ci else 114662306a36Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci args.v2.acConfig.ucEncoderSel = dig_encoder; 115062306a36Sopenharmony_ci if (dig->linkb) 115162306a36Sopenharmony_ci args.v2.acConfig.ucLinkSel = 1; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 115462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 115562306a36Sopenharmony_ci args.v2.acConfig.ucTransmitterSel = 0; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 115862306a36Sopenharmony_ci args.v2.acConfig.ucTransmitterSel = 1; 115962306a36Sopenharmony_ci break; 116062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 116162306a36Sopenharmony_ci args.v2.acConfig.ucTransmitterSel = 2; 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (is_dp) { 116662306a36Sopenharmony_ci args.v2.acConfig.fCoherentMode = 1; 116762306a36Sopenharmony_ci args.v2.acConfig.fDPConnector = 1; 116862306a36Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 116962306a36Sopenharmony_ci if (dig->coherent_mode) 117062306a36Sopenharmony_ci args.v2.acConfig.fCoherentMode = 1; 117162306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 117262306a36Sopenharmony_ci args.v2.acConfig.fDualLinkConnector = 1; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci case 3: 117662306a36Sopenharmony_ci args.v3.ucAction = action; 117762306a36Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 117862306a36Sopenharmony_ci args.v3.usInitInfo = cpu_to_le16(connector_object_id); 117962306a36Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 118062306a36Sopenharmony_ci args.v3.asMode.ucLaneSel = lane_num; 118162306a36Sopenharmony_ci args.v3.asMode.ucLaneSet = lane_set; 118262306a36Sopenharmony_ci } else { 118362306a36Sopenharmony_ci if (is_dp) 118462306a36Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(dp_clock / 10); 118562306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 118662306a36Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 118762306a36Sopenharmony_ci else 118862306a36Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (is_dp) 119262306a36Sopenharmony_ci args.v3.ucLaneNum = dp_lane_count; 119362306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 119462306a36Sopenharmony_ci args.v3.ucLaneNum = 8; 119562306a36Sopenharmony_ci else 119662306a36Sopenharmony_ci args.v3.ucLaneNum = 4; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (dig->linkb) 119962306a36Sopenharmony_ci args.v3.acConfig.ucLinkSel = 1; 120062306a36Sopenharmony_ci if (dig_encoder & 1) 120162306a36Sopenharmony_ci args.v3.acConfig.ucEncoderSel = 1; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Select the PLL for the PHY 120462306a36Sopenharmony_ci * DP PHY should be clocked from external src if there is 120562306a36Sopenharmony_ci * one. 120662306a36Sopenharmony_ci */ 120762306a36Sopenharmony_ci /* On DCE4, if there is an external clock, it generates the DP ref clock */ 120862306a36Sopenharmony_ci if (is_dp && rdev->clock.dp_extclk) 120962306a36Sopenharmony_ci args.v3.acConfig.ucRefClkSource = 2; /* external src */ 121062306a36Sopenharmony_ci else 121162306a36Sopenharmony_ci args.v3.acConfig.ucRefClkSource = pll_id; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 121462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 121562306a36Sopenharmony_ci args.v3.acConfig.ucTransmitterSel = 0; 121662306a36Sopenharmony_ci break; 121762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 121862306a36Sopenharmony_ci args.v3.acConfig.ucTransmitterSel = 1; 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 122162306a36Sopenharmony_ci args.v3.acConfig.ucTransmitterSel = 2; 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (is_dp) 122662306a36Sopenharmony_ci args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ 122762306a36Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 122862306a36Sopenharmony_ci if (dig->coherent_mode) 122962306a36Sopenharmony_ci args.v3.acConfig.fCoherentMode = 1; 123062306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 123162306a36Sopenharmony_ci args.v3.acConfig.fDualLinkConnector = 1; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci break; 123462306a36Sopenharmony_ci case 4: 123562306a36Sopenharmony_ci args.v4.ucAction = action; 123662306a36Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 123762306a36Sopenharmony_ci args.v4.usInitInfo = cpu_to_le16(connector_object_id); 123862306a36Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 123962306a36Sopenharmony_ci args.v4.asMode.ucLaneSel = lane_num; 124062306a36Sopenharmony_ci args.v4.asMode.ucLaneSet = lane_set; 124162306a36Sopenharmony_ci } else { 124262306a36Sopenharmony_ci if (is_dp) 124362306a36Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16(dp_clock / 10); 124462306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 124562306a36Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 124662306a36Sopenharmony_ci else 124762306a36Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (is_dp) 125162306a36Sopenharmony_ci args.v4.ucLaneNum = dp_lane_count; 125262306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 125362306a36Sopenharmony_ci args.v4.ucLaneNum = 8; 125462306a36Sopenharmony_ci else 125562306a36Sopenharmony_ci args.v4.ucLaneNum = 4; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (dig->linkb) 125862306a36Sopenharmony_ci args.v4.acConfig.ucLinkSel = 1; 125962306a36Sopenharmony_ci if (dig_encoder & 1) 126062306a36Sopenharmony_ci args.v4.acConfig.ucEncoderSel = 1; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* Select the PLL for the PHY 126362306a36Sopenharmony_ci * DP PHY should be clocked from external src if there is 126462306a36Sopenharmony_ci * one. 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_ci /* On DCE5 DCPLL usually generates the DP ref clock */ 126762306a36Sopenharmony_ci if (is_dp) { 126862306a36Sopenharmony_ci if (rdev->clock.dp_extclk) 126962306a36Sopenharmony_ci args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; 127062306a36Sopenharmony_ci else 127162306a36Sopenharmony_ci args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; 127262306a36Sopenharmony_ci } else 127362306a36Sopenharmony_ci args.v4.acConfig.ucRefClkSource = pll_id; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 127662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 127762306a36Sopenharmony_ci args.v4.acConfig.ucTransmitterSel = 0; 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 128062306a36Sopenharmony_ci args.v4.acConfig.ucTransmitterSel = 1; 128162306a36Sopenharmony_ci break; 128262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 128362306a36Sopenharmony_ci args.v4.acConfig.ucTransmitterSel = 2; 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (is_dp) 128862306a36Sopenharmony_ci args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */ 128962306a36Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 129062306a36Sopenharmony_ci if (dig->coherent_mode) 129162306a36Sopenharmony_ci args.v4.acConfig.fCoherentMode = 1; 129262306a36Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 129362306a36Sopenharmony_ci args.v4.acConfig.fDualLinkConnector = 1; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci break; 129662306a36Sopenharmony_ci case 5: 129762306a36Sopenharmony_ci args.v5.ucAction = action; 129862306a36Sopenharmony_ci if (is_dp) 129962306a36Sopenharmony_ci args.v5.usSymClock = cpu_to_le16(dp_clock / 10); 130062306a36Sopenharmony_ci else 130162306a36Sopenharmony_ci args.v5.usSymClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 130462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 130562306a36Sopenharmony_ci if (dig->linkb) 130662306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB; 130762306a36Sopenharmony_ci else 130862306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA; 130962306a36Sopenharmony_ci break; 131062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 131162306a36Sopenharmony_ci if (dig->linkb) 131262306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD; 131362306a36Sopenharmony_ci else 131462306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC; 131562306a36Sopenharmony_ci break; 131662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 131762306a36Sopenharmony_ci if (dig->linkb) 131862306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF; 131962306a36Sopenharmony_ci else 132062306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE; 132162306a36Sopenharmony_ci break; 132262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 132362306a36Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG; 132462306a36Sopenharmony_ci break; 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci if (is_dp) 132762306a36Sopenharmony_ci args.v5.ucLaneNum = dp_lane_count; 132862306a36Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 132962306a36Sopenharmony_ci args.v5.ucLaneNum = 8; 133062306a36Sopenharmony_ci else 133162306a36Sopenharmony_ci args.v5.ucLaneNum = 4; 133262306a36Sopenharmony_ci args.v5.ucConnObjId = connector_object_id; 133362306a36Sopenharmony_ci args.v5.ucDigMode = atombios_get_encoder_mode(encoder); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (is_dp && rdev->clock.dp_extclk) 133662306a36Sopenharmony_ci args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK; 133762306a36Sopenharmony_ci else 133862306a36Sopenharmony_ci args.v5.asConfig.ucPhyClkSrcId = pll_id; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci if (is_dp) 134162306a36Sopenharmony_ci args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */ 134262306a36Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 134362306a36Sopenharmony_ci if (dig->coherent_mode) 134462306a36Sopenharmony_ci args.v5.asConfig.ucCoherentMode = 1; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci if (hpd_id == RADEON_HPD_NONE) 134762306a36Sopenharmony_ci args.v5.asConfig.ucHPDSel = 0; 134862306a36Sopenharmony_ci else 134962306a36Sopenharmony_ci args.v5.asConfig.ucHPDSel = hpd_id + 1; 135062306a36Sopenharmony_ci args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder); 135162306a36Sopenharmony_ci args.v5.ucDPLaneSet = lane_set; 135262306a36Sopenharmony_ci break; 135362306a36Sopenharmony_ci default: 135462306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci break; 135862306a36Sopenharmony_ci default: 135962306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 136062306a36Sopenharmony_ci break; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_civoid 136762306a36Sopenharmony_ciatombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1); 137062306a36Sopenharmony_ci} 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_cibool 137362306a36Sopenharmony_ciatombios_set_edp_panel_power(struct drm_connector *connector, int action) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 137662306a36Sopenharmony_ci struct drm_device *dev = radeon_connector->base.dev; 137762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 137862306a36Sopenharmony_ci union dig_transmitter_control args; 137962306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 138062306a36Sopenharmony_ci uint8_t frev, crev; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) 138362306a36Sopenharmony_ci goto done; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci if (!ASIC_IS_DCE4(rdev)) 138662306a36Sopenharmony_ci goto done; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && 138962306a36Sopenharmony_ci (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) 139062306a36Sopenharmony_ci goto done; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 139362306a36Sopenharmony_ci goto done; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci args.v1.ucAction = action; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci /* wait for the panel to power up */ 140262306a36Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { 140362306a36Sopenharmony_ci int i; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci for (i = 0; i < 300; i++) { 140662306a36Sopenharmony_ci if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) 140762306a36Sopenharmony_ci return true; 140862306a36Sopenharmony_ci mdelay(1); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci return false; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_cidone: 141362306a36Sopenharmony_ci return true; 141462306a36Sopenharmony_ci} 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ciunion external_encoder_control { 141762306a36Sopenharmony_ci EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; 141862306a36Sopenharmony_ci EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; 141962306a36Sopenharmony_ci}; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_cistatic void 142262306a36Sopenharmony_ciatombios_external_encoder_setup(struct drm_encoder *encoder, 142362306a36Sopenharmony_ci struct drm_encoder *ext_encoder, 142462306a36Sopenharmony_ci int action) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 142762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 142862306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 142962306a36Sopenharmony_ci struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); 143062306a36Sopenharmony_ci union external_encoder_control args; 143162306a36Sopenharmony_ci struct drm_connector *connector; 143262306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); 143362306a36Sopenharmony_ci u8 frev, crev; 143462306a36Sopenharmony_ci int dp_clock = 0; 143562306a36Sopenharmony_ci int dp_lane_count = 0; 143662306a36Sopenharmony_ci int connector_object_id = 0; 143762306a36Sopenharmony_ci u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) 144062306a36Sopenharmony_ci connector = radeon_get_connector_for_encoder_init(encoder); 144162306a36Sopenharmony_ci else 144262306a36Sopenharmony_ci connector = radeon_get_connector_for_encoder(encoder); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (connector) { 144562306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 144662306a36Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 144762306a36Sopenharmony_ci radeon_connector->con_priv; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci dp_clock = dig_connector->dp_clock; 145062306a36Sopenharmony_ci dp_lane_count = dig_connector->dp_lane_count; 145162306a36Sopenharmony_ci connector_object_id = 145262306a36Sopenharmony_ci (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 145862306a36Sopenharmony_ci return; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci switch (frev) { 146162306a36Sopenharmony_ci case 1: 146262306a36Sopenharmony_ci /* no params on frev 1 */ 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci case 2: 146562306a36Sopenharmony_ci switch (crev) { 146662306a36Sopenharmony_ci case 1: 146762306a36Sopenharmony_ci case 2: 146862306a36Sopenharmony_ci args.v1.sDigEncoder.ucAction = action; 146962306a36Sopenharmony_ci args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 147062306a36Sopenharmony_ci args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) { 147362306a36Sopenharmony_ci if (dp_clock == 270000) 147462306a36Sopenharmony_ci args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 147562306a36Sopenharmony_ci args.v1.sDigEncoder.ucLaneNum = dp_lane_count; 147662306a36Sopenharmony_ci } else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 147762306a36Sopenharmony_ci args.v1.sDigEncoder.ucLaneNum = 8; 147862306a36Sopenharmony_ci else 147962306a36Sopenharmony_ci args.v1.sDigEncoder.ucLaneNum = 4; 148062306a36Sopenharmony_ci break; 148162306a36Sopenharmony_ci case 3: 148262306a36Sopenharmony_ci args.v3.sExtEncoder.ucAction = action; 148362306a36Sopenharmony_ci if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) 148462306a36Sopenharmony_ci args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); 148562306a36Sopenharmony_ci else 148662306a36Sopenharmony_ci args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 148762306a36Sopenharmony_ci args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) { 149062306a36Sopenharmony_ci if (dp_clock == 270000) 149162306a36Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; 149262306a36Sopenharmony_ci else if (dp_clock == 540000) 149362306a36Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; 149462306a36Sopenharmony_ci args.v3.sExtEncoder.ucLaneNum = dp_lane_count; 149562306a36Sopenharmony_ci } else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 149662306a36Sopenharmony_ci args.v3.sExtEncoder.ucLaneNum = 8; 149762306a36Sopenharmony_ci else 149862306a36Sopenharmony_ci args.v3.sExtEncoder.ucLaneNum = 4; 149962306a36Sopenharmony_ci switch (ext_enum) { 150062306a36Sopenharmony_ci case GRAPH_OBJECT_ENUM_ID1: 150162306a36Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; 150262306a36Sopenharmony_ci break; 150362306a36Sopenharmony_ci case GRAPH_OBJECT_ENUM_ID2: 150462306a36Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; 150562306a36Sopenharmony_ci break; 150662306a36Sopenharmony_ci case GRAPH_OBJECT_ENUM_ID3: 150762306a36Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; 150862306a36Sopenharmony_ci break; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci args.v3.sExtEncoder.ucBitPerColor = radeon_atom_get_bpc(encoder); 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci default: 151362306a36Sopenharmony_ci DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 151462306a36Sopenharmony_ci return; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci break; 151762306a36Sopenharmony_ci default: 151862306a36Sopenharmony_ci DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 151962306a36Sopenharmony_ci return; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistatic void 152562306a36Sopenharmony_ciatombios_yuv_setup(struct drm_encoder *encoder, bool enable) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 152862306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 152962306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 153062306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 153162306a36Sopenharmony_ci ENABLE_YUV_PS_ALLOCATION args; 153262306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); 153362306a36Sopenharmony_ci uint32_t temp, reg; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 153862306a36Sopenharmony_ci reg = R600_BIOS_3_SCRATCH; 153962306a36Sopenharmony_ci else 154062306a36Sopenharmony_ci reg = RADEON_BIOS_3_SCRATCH; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* XXX: fix up scratch reg handling */ 154362306a36Sopenharmony_ci temp = RREG32(reg); 154462306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 154562306a36Sopenharmony_ci WREG32(reg, (ATOM_S3_TV1_ACTIVE | 154662306a36Sopenharmony_ci (radeon_crtc->crtc_id << 18))); 154762306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 154862306a36Sopenharmony_ci WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); 154962306a36Sopenharmony_ci else 155062306a36Sopenharmony_ci WREG32(reg, 0); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (enable) 155362306a36Sopenharmony_ci args.ucEnable = ATOM_ENABLE; 155462306a36Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci WREG32(reg, temp); 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic void 156262306a36Sopenharmony_ciradeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 156562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 156662306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 156762306a36Sopenharmony_ci DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; 156862306a36Sopenharmony_ci int index = 0; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 157362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 157462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 157562306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); 157662306a36Sopenharmony_ci break; 157762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 157862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 157962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 158062306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 158162306a36Sopenharmony_ci break; 158262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 158362306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 158462306a36Sopenharmony_ci break; 158562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 158662306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 158762306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 158862306a36Sopenharmony_ci else 158962306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); 159062306a36Sopenharmony_ci break; 159162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 159262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 159362306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 159462306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 159562306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 159662306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 159762306a36Sopenharmony_ci else 159862306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 159962306a36Sopenharmony_ci break; 160062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 160162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 160262306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 160362306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 160462306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 160562306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 160662306a36Sopenharmony_ci else 160762306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 160862306a36Sopenharmony_ci break; 160962306a36Sopenharmony_ci default: 161062306a36Sopenharmony_ci return; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci switch (mode) { 161462306a36Sopenharmony_ci case DRM_MODE_DPMS_ON: 161562306a36Sopenharmony_ci args.ucAction = ATOM_ENABLE; 161662306a36Sopenharmony_ci /* workaround for DVOOutputControl on some RS690 systems */ 161762306a36Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { 161862306a36Sopenharmony_ci u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); 161962306a36Sopenharmony_ci WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); 162062306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 162162306a36Sopenharmony_ci WREG32(RADEON_BIOS_3_SCRATCH, reg); 162262306a36Sopenharmony_ci } else 162362306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 162462306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 162562306a36Sopenharmony_ci if (rdev->mode_info.bl_encoder) { 162662306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci atombios_set_backlight_level(radeon_encoder, dig->backlight_level); 162962306a36Sopenharmony_ci } else { 163062306a36Sopenharmony_ci args.ucAction = ATOM_LCD_BLON; 163162306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci break; 163562306a36Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 163662306a36Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 163762306a36Sopenharmony_ci case DRM_MODE_DPMS_OFF: 163862306a36Sopenharmony_ci args.ucAction = ATOM_DISABLE; 163962306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 164062306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 164162306a36Sopenharmony_ci args.ucAction = ATOM_LCD_BLOFF; 164262306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci break; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic void 164962306a36Sopenharmony_ciradeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 165262306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 165362306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 165462306a36Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 165562306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 165662306a36Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 165762306a36Sopenharmony_ci struct radeon_connector *radeon_connector = NULL; 165862306a36Sopenharmony_ci struct radeon_connector_atom_dig *radeon_dig_connector = NULL; 165962306a36Sopenharmony_ci bool travis_quirk = false; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (connector) { 166262306a36Sopenharmony_ci radeon_connector = to_radeon_connector(connector); 166362306a36Sopenharmony_ci radeon_dig_connector = radeon_connector->con_priv; 166462306a36Sopenharmony_ci if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == 166562306a36Sopenharmony_ci ENCODER_OBJECT_ID_TRAVIS) && 166662306a36Sopenharmony_ci (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 166762306a36Sopenharmony_ci !ASIC_IS_DCE5(rdev)) 166862306a36Sopenharmony_ci travis_quirk = true; 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci switch (mode) { 167262306a36Sopenharmony_ci case DRM_MODE_DPMS_ON: 167362306a36Sopenharmony_ci if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { 167462306a36Sopenharmony_ci if (!connector) 167562306a36Sopenharmony_ci dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; 167662306a36Sopenharmony_ci else 167762306a36Sopenharmony_ci dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci /* setup and enable the encoder */ 168062306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); 168162306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, 168262306a36Sopenharmony_ci ATOM_ENCODER_CMD_SETUP_PANEL_MODE, 168362306a36Sopenharmony_ci dig->panel_mode); 168462306a36Sopenharmony_ci if (ext_encoder) { 168562306a36Sopenharmony_ci if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) 168662306a36Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 168762306a36Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 169062306a36Sopenharmony_ci /* setup and enable the encoder */ 169162306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); 169262306a36Sopenharmony_ci } else { 169362306a36Sopenharmony_ci /* setup and enable the encoder and transmitter */ 169462306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); 169562306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 169862306a36Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 169962306a36Sopenharmony_ci atombios_set_edp_panel_power(connector, 170062306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_POWER_ON); 170162306a36Sopenharmony_ci radeon_dig_connector->edp_on = true; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci /* enable the transmitter */ 170562306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 170662306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 170762306a36Sopenharmony_ci /* DP_SET_POWER_D0 is set in radeon_dp_link_train */ 170862306a36Sopenharmony_ci radeon_dp_link_train(encoder, connector); 170962306a36Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 171062306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 171362306a36Sopenharmony_ci if (rdev->mode_info.bl_encoder) 171462306a36Sopenharmony_ci atombios_set_backlight_level(radeon_encoder, dig->backlight_level); 171562306a36Sopenharmony_ci else 171662306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 171762306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci if (ext_encoder) 172062306a36Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); 172162306a36Sopenharmony_ci break; 172262306a36Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 172362306a36Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 172462306a36Sopenharmony_ci case DRM_MODE_DPMS_OFF: 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 172762306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) 172862306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci if (ext_encoder) 173162306a36Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); 173262306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 173362306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 173462306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && 173762306a36Sopenharmony_ci connector && !travis_quirk) 173862306a36Sopenharmony_ci radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); 173962306a36Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 174062306a36Sopenharmony_ci /* disable the transmitter */ 174162306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 174262306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 174362306a36Sopenharmony_ci } else { 174462306a36Sopenharmony_ci /* disable the encoder and transmitter */ 174562306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 174662306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 174762306a36Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 175062306a36Sopenharmony_ci if (travis_quirk) 175162306a36Sopenharmony_ci radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); 175262306a36Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 175362306a36Sopenharmony_ci atombios_set_edp_panel_power(connector, 175462306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_POWER_OFF); 175562306a36Sopenharmony_ci radeon_dig_connector->edp_on = false; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci break; 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci} 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_cistatic void 176362306a36Sopenharmony_ciradeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 176662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 176762306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 176862306a36Sopenharmony_ci int encoder_mode = atombios_get_encoder_mode(encoder); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", 177162306a36Sopenharmony_ci radeon_encoder->encoder_id, mode, radeon_encoder->devices, 177262306a36Sopenharmony_ci radeon_encoder->active_device); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci if ((radeon_audio != 0) && 177562306a36Sopenharmony_ci ((encoder_mode == ATOM_ENCODER_MODE_HDMI) || 177662306a36Sopenharmony_ci ENCODER_MODE_IS_DP(encoder_mode))) 177762306a36Sopenharmony_ci radeon_audio_dpms(encoder, mode); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 178062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 178162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 178262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 178362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 178462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 178562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 178662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 178762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 178862306a36Sopenharmony_ci radeon_atom_encoder_dpms_avivo(encoder, mode); 178962306a36Sopenharmony_ci break; 179062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 179162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 179262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 179362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 179462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 179562306a36Sopenharmony_ci radeon_atom_encoder_dpms_dig(encoder, mode); 179662306a36Sopenharmony_ci break; 179762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 179862306a36Sopenharmony_ci if (ASIC_IS_DCE5(rdev)) { 179962306a36Sopenharmony_ci switch (mode) { 180062306a36Sopenharmony_ci case DRM_MODE_DPMS_ON: 180162306a36Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_ENABLE); 180262306a36Sopenharmony_ci break; 180362306a36Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 180462306a36Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 180562306a36Sopenharmony_ci case DRM_MODE_DPMS_OFF: 180662306a36Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_DISABLE); 180762306a36Sopenharmony_ci break; 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci } else if (ASIC_IS_DCE3(rdev)) 181062306a36Sopenharmony_ci radeon_atom_encoder_dpms_dig(encoder, mode); 181162306a36Sopenharmony_ci else 181262306a36Sopenharmony_ci radeon_atom_encoder_dpms_avivo(encoder, mode); 181362306a36Sopenharmony_ci break; 181462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 181562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 181662306a36Sopenharmony_ci if (ASIC_IS_DCE5(rdev)) { 181762306a36Sopenharmony_ci switch (mode) { 181862306a36Sopenharmony_ci case DRM_MODE_DPMS_ON: 181962306a36Sopenharmony_ci atombios_dac_setup(encoder, ATOM_ENABLE); 182062306a36Sopenharmony_ci break; 182162306a36Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 182262306a36Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 182362306a36Sopenharmony_ci case DRM_MODE_DPMS_OFF: 182462306a36Sopenharmony_ci atombios_dac_setup(encoder, ATOM_DISABLE); 182562306a36Sopenharmony_ci break; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci } else 182862306a36Sopenharmony_ci radeon_atom_encoder_dpms_avivo(encoder, mode); 182962306a36Sopenharmony_ci break; 183062306a36Sopenharmony_ci default: 183162306a36Sopenharmony_ci return; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci} 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ciunion crtc_source_param { 183962306a36Sopenharmony_ci SELECT_CRTC_SOURCE_PS_ALLOCATION v1; 184062306a36Sopenharmony_ci SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; 184162306a36Sopenharmony_ci}; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic void 184462306a36Sopenharmony_ciatombios_set_encoder_crtc_source(struct drm_encoder *encoder) 184562306a36Sopenharmony_ci{ 184662306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 184762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 184862306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 184962306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 185062306a36Sopenharmony_ci union crtc_source_param args; 185162306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); 185262306a36Sopenharmony_ci uint8_t frev, crev; 185362306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 185862306a36Sopenharmony_ci return; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci switch (frev) { 186162306a36Sopenharmony_ci case 1: 186262306a36Sopenharmony_ci switch (crev) { 186362306a36Sopenharmony_ci case 1: 186462306a36Sopenharmony_ci default: 186562306a36Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 186662306a36Sopenharmony_ci args.v1.ucCRTC = radeon_crtc->crtc_id; 186762306a36Sopenharmony_ci else { 186862306a36Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) 186962306a36Sopenharmony_ci args.v1.ucCRTC = radeon_crtc->crtc_id; 187062306a36Sopenharmony_ci else 187162306a36Sopenharmony_ci args.v1.ucCRTC = radeon_crtc->crtc_id << 2; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 187462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 187562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 187662306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; 187762306a36Sopenharmony_ci break; 187862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 187962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 188062306a36Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) 188162306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; 188262306a36Sopenharmony_ci else 188362306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; 188462306a36Sopenharmony_ci break; 188562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 188662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 188762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 188862306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; 188962306a36Sopenharmony_ci break; 189062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 189162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 189262306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 189362306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 189462306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 189562306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 189662306a36Sopenharmony_ci else 189762306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; 189862306a36Sopenharmony_ci break; 189962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 190062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 190162306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 190262306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 190362306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 190462306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 190562306a36Sopenharmony_ci else 190662306a36Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; 190762306a36Sopenharmony_ci break; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci break; 191062306a36Sopenharmony_ci case 2: 191162306a36Sopenharmony_ci args.v2.ucCRTC = radeon_crtc->crtc_id; 191262306a36Sopenharmony_ci if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) { 191362306a36Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) 191662306a36Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; 191762306a36Sopenharmony_ci else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) 191862306a36Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; 191962306a36Sopenharmony_ci else 192062306a36Sopenharmony_ci args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); 192162306a36Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 192262306a36Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; 192362306a36Sopenharmony_ci } else { 192462306a36Sopenharmony_ci args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 192762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 192862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 192962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 193062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 193162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 193262306a36Sopenharmony_ci dig = radeon_encoder->enc_priv; 193362306a36Sopenharmony_ci switch (dig->dig_encoder) { 193462306a36Sopenharmony_ci case 0: 193562306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; 193662306a36Sopenharmony_ci break; 193762306a36Sopenharmony_ci case 1: 193862306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; 193962306a36Sopenharmony_ci break; 194062306a36Sopenharmony_ci case 2: 194162306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; 194262306a36Sopenharmony_ci break; 194362306a36Sopenharmony_ci case 3: 194462306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; 194562306a36Sopenharmony_ci break; 194662306a36Sopenharmony_ci case 4: 194762306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; 194862306a36Sopenharmony_ci break; 194962306a36Sopenharmony_ci case 5: 195062306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; 195162306a36Sopenharmony_ci break; 195262306a36Sopenharmony_ci case 6: 195362306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID; 195462306a36Sopenharmony_ci break; 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci break; 195762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 195862306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; 195962306a36Sopenharmony_ci break; 196062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 196162306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 196262306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 196362306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 196462306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 196562306a36Sopenharmony_ci else 196662306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; 196762306a36Sopenharmony_ci break; 196862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 196962306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 197062306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 197162306a36Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 197262306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 197362306a36Sopenharmony_ci else 197462306a36Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; 197562306a36Sopenharmony_ci break; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci break; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci break; 198062306a36Sopenharmony_ci default: 198162306a36Sopenharmony_ci DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 198262306a36Sopenharmony_ci return; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci /* update scratch regs with new routing */ 198862306a36Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 198962306a36Sopenharmony_ci} 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic void 199262306a36Sopenharmony_ciatombios_apply_encoder_quirks(struct drm_encoder *encoder, 199362306a36Sopenharmony_ci struct drm_display_mode *mode) 199462306a36Sopenharmony_ci{ 199562306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 199662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 199762306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 199862306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci /* Funky macbooks */ 200162306a36Sopenharmony_ci if ((rdev->pdev->device == 0x71C5) && 200262306a36Sopenharmony_ci (rdev->pdev->subsystem_vendor == 0x106b) && 200362306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x0080)) { 200462306a36Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { 200562306a36Sopenharmony_ci uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; 200862306a36Sopenharmony_ci lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci /* set scaler clears this on some chips */ 201562306a36Sopenharmony_ci if (ASIC_IS_AVIVO(rdev) && 201662306a36Sopenharmony_ci (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { 201762306a36Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) { 201862306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 201962306a36Sopenharmony_ci WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 202062306a36Sopenharmony_ci CIK_INTERLEAVE_EN); 202162306a36Sopenharmony_ci else 202262306a36Sopenharmony_ci WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 202362306a36Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 202462306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 202562306a36Sopenharmony_ci WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 202662306a36Sopenharmony_ci EVERGREEN_INTERLEAVE_EN); 202762306a36Sopenharmony_ci else 202862306a36Sopenharmony_ci WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 202962306a36Sopenharmony_ci } else { 203062306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 203162306a36Sopenharmony_ci WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 203262306a36Sopenharmony_ci AVIVO_D1MODE_INTERLEAVE_EN); 203362306a36Sopenharmony_ci else 203462306a36Sopenharmony_ci WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_civoid radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci if (enc_idx < 0) 204262306a36Sopenharmony_ci return; 204362306a36Sopenharmony_ci rdev->mode_info.active_encoders &= ~(1 << enc_idx); 204462306a36Sopenharmony_ci} 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ciint radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx) 204762306a36Sopenharmony_ci{ 204862306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 204962306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 205062306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 205162306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 205262306a36Sopenharmony_ci struct drm_encoder *test_encoder; 205362306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 205462306a36Sopenharmony_ci uint32_t dig_enc_in_use = 0; 205562306a36Sopenharmony_ci int enc_idx = -1; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci if (fe_idx >= 0) { 205862306a36Sopenharmony_ci enc_idx = fe_idx; 205962306a36Sopenharmony_ci goto assigned; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) { 206262306a36Sopenharmony_ci /* DCE6 */ 206362306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 206462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 206562306a36Sopenharmony_ci if (dig->linkb) 206662306a36Sopenharmony_ci enc_idx = 1; 206762306a36Sopenharmony_ci else 206862306a36Sopenharmony_ci enc_idx = 0; 206962306a36Sopenharmony_ci break; 207062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 207162306a36Sopenharmony_ci if (dig->linkb) 207262306a36Sopenharmony_ci enc_idx = 3; 207362306a36Sopenharmony_ci else 207462306a36Sopenharmony_ci enc_idx = 2; 207562306a36Sopenharmony_ci break; 207662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 207762306a36Sopenharmony_ci if (dig->linkb) 207862306a36Sopenharmony_ci enc_idx = 5; 207962306a36Sopenharmony_ci else 208062306a36Sopenharmony_ci enc_idx = 4; 208162306a36Sopenharmony_ci break; 208262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 208362306a36Sopenharmony_ci enc_idx = 6; 208462306a36Sopenharmony_ci break; 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci goto assigned; 208762306a36Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 208862306a36Sopenharmony_ci /* DCE4/5 */ 208962306a36Sopenharmony_ci if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { 209062306a36Sopenharmony_ci /* ontario follows DCE4 */ 209162306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 209262306a36Sopenharmony_ci if (dig->linkb) 209362306a36Sopenharmony_ci enc_idx = 1; 209462306a36Sopenharmony_ci else 209562306a36Sopenharmony_ci enc_idx = 0; 209662306a36Sopenharmony_ci } else 209762306a36Sopenharmony_ci /* llano follows DCE3.2 */ 209862306a36Sopenharmony_ci enc_idx = radeon_crtc->crtc_id; 209962306a36Sopenharmony_ci } else { 210062306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 210162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 210262306a36Sopenharmony_ci if (dig->linkb) 210362306a36Sopenharmony_ci enc_idx = 1; 210462306a36Sopenharmony_ci else 210562306a36Sopenharmony_ci enc_idx = 0; 210662306a36Sopenharmony_ci break; 210762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 210862306a36Sopenharmony_ci if (dig->linkb) 210962306a36Sopenharmony_ci enc_idx = 3; 211062306a36Sopenharmony_ci else 211162306a36Sopenharmony_ci enc_idx = 2; 211262306a36Sopenharmony_ci break; 211362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 211462306a36Sopenharmony_ci if (dig->linkb) 211562306a36Sopenharmony_ci enc_idx = 5; 211662306a36Sopenharmony_ci else 211762306a36Sopenharmony_ci enc_idx = 4; 211862306a36Sopenharmony_ci break; 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci } 212162306a36Sopenharmony_ci goto assigned; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci /* 212562306a36Sopenharmony_ci * On DCE32 any encoder can drive any block so usually just use crtc id, 212662306a36Sopenharmony_ci * but Apple thinks different at least on iMac10,1 and iMac11,2, so there use linkb, 212762306a36Sopenharmony_ci * otherwise the internal eDP panel will stay dark. 212862306a36Sopenharmony_ci */ 212962306a36Sopenharmony_ci if (ASIC_IS_DCE32(rdev)) { 213062306a36Sopenharmony_ci if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") || 213162306a36Sopenharmony_ci dmi_match(DMI_PRODUCT_NAME, "iMac11,2")) 213262306a36Sopenharmony_ci enc_idx = (dig->linkb) ? 1 : 0; 213362306a36Sopenharmony_ci else 213462306a36Sopenharmony_ci enc_idx = radeon_crtc->crtc_id; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci goto assigned; 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci /* on DCE3 - LVTMA can only be driven by DIGB */ 214062306a36Sopenharmony_ci list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 214162306a36Sopenharmony_ci struct radeon_encoder *radeon_test_encoder; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci if (encoder == test_encoder) 214462306a36Sopenharmony_ci continue; 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (!radeon_encoder_is_digital(test_encoder)) 214762306a36Sopenharmony_ci continue; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci radeon_test_encoder = to_radeon_encoder(test_encoder); 215062306a36Sopenharmony_ci dig = radeon_test_encoder->enc_priv; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci if (dig->dig_encoder >= 0) 215362306a36Sopenharmony_ci dig_enc_in_use |= (1 << dig->dig_encoder); 215462306a36Sopenharmony_ci } 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { 215762306a36Sopenharmony_ci if (dig_enc_in_use & 0x2) 215862306a36Sopenharmony_ci DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); 215962306a36Sopenharmony_ci return 1; 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci if (!(dig_enc_in_use & 1)) 216262306a36Sopenharmony_ci return 0; 216362306a36Sopenharmony_ci return 1; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ciassigned: 216662306a36Sopenharmony_ci if (enc_idx == -1) { 216762306a36Sopenharmony_ci DRM_ERROR("Got encoder index incorrect - returning 0\n"); 216862306a36Sopenharmony_ci return 0; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci if (rdev->mode_info.active_encoders & (1 << enc_idx)) 217162306a36Sopenharmony_ci DRM_ERROR("chosen encoder in use %d\n", enc_idx); 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci rdev->mode_info.active_encoders |= (1 << enc_idx); 217462306a36Sopenharmony_ci return enc_idx; 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci/* This only needs to be called once at startup */ 217862306a36Sopenharmony_civoid 217962306a36Sopenharmony_ciradeon_atom_encoder_init(struct radeon_device *rdev) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci struct drm_device *dev = rdev->ddev; 218262306a36Sopenharmony_ci struct drm_encoder *encoder; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 218562306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 218662306a36Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 218962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 219062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 219162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 219262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 219362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 219462306a36Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 219562306a36Sopenharmony_ci break; 219662306a36Sopenharmony_ci default: 219762306a36Sopenharmony_ci break; 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (ext_encoder && (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))) 220162306a36Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 220262306a36Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci} 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_cistatic void 220762306a36Sopenharmony_ciradeon_atom_encoder_mode_set(struct drm_encoder *encoder, 220862306a36Sopenharmony_ci struct drm_display_mode *mode, 220962306a36Sopenharmony_ci struct drm_display_mode *adjusted_mode) 221062306a36Sopenharmony_ci{ 221162306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 221262306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 221362306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 221462306a36Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 221562306a36Sopenharmony_ci int encoder_mode; 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci radeon_encoder->pixel_clock = adjusted_mode->clock; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci /* need to call this here rather than in prepare() since we need some crtc info */ 222062306a36Sopenharmony_ci radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { 222362306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) 222462306a36Sopenharmony_ci atombios_yuv_setup(encoder, true); 222562306a36Sopenharmony_ci else 222662306a36Sopenharmony_ci atombios_yuv_setup(encoder, false); 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 223062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 223162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 223262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 223362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 223462306a36Sopenharmony_ci atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); 223562306a36Sopenharmony_ci break; 223662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 223762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 223862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 223962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 224062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 224162306a36Sopenharmony_ci /* handled in dpms */ 224262306a36Sopenharmony_ci break; 224362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 224462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 224562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 224662306a36Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_ENABLE); 224762306a36Sopenharmony_ci break; 224862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 224962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 225062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 225162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 225262306a36Sopenharmony_ci atombios_dac_setup(encoder, ATOM_ENABLE); 225362306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { 225462306a36Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 225562306a36Sopenharmony_ci atombios_tv_setup(encoder, ATOM_ENABLE); 225662306a36Sopenharmony_ci else 225762306a36Sopenharmony_ci atombios_tv_setup(encoder, ATOM_DISABLE); 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci break; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci atombios_apply_encoder_quirks(encoder, adjusted_mode); 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci encoder_mode = atombios_get_encoder_mode(encoder); 226562306a36Sopenharmony_ci if (connector && (radeon_audio != 0) && 226662306a36Sopenharmony_ci ((encoder_mode == ATOM_ENCODER_MODE_HDMI) || 226762306a36Sopenharmony_ci ENCODER_MODE_IS_DP(encoder_mode))) 226862306a36Sopenharmony_ci radeon_audio_mode_set(encoder, adjusted_mode); 226962306a36Sopenharmony_ci} 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_cistatic bool 227262306a36Sopenharmony_ciatombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) 227362306a36Sopenharmony_ci{ 227462306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 227562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 227662306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 227762306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | 228062306a36Sopenharmony_ci ATOM_DEVICE_CV_SUPPORT | 228162306a36Sopenharmony_ci ATOM_DEVICE_CRT_SUPPORT)) { 228262306a36Sopenharmony_ci DAC_LOAD_DETECTION_PS_ALLOCATION args; 228362306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); 228462306a36Sopenharmony_ci uint8_t frev, crev; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 228962306a36Sopenharmony_ci return false; 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci args.sDacload.ucMisc = 0; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 229462306a36Sopenharmony_ci (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) 229562306a36Sopenharmony_ci args.sDacload.ucDacType = ATOM_DAC_A; 229662306a36Sopenharmony_ci else 229762306a36Sopenharmony_ci args.sDacload.ucDacType = ATOM_DAC_B; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) 230062306a36Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); 230162306a36Sopenharmony_ci else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) 230262306a36Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); 230362306a36Sopenharmony_ci else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 230462306a36Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); 230562306a36Sopenharmony_ci if (crev >= 3) 230662306a36Sopenharmony_ci args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 230762306a36Sopenharmony_ci } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 230862306a36Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); 230962306a36Sopenharmony_ci if (crev >= 3) 231062306a36Sopenharmony_ci args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci return true; 231662306a36Sopenharmony_ci } else 231762306a36Sopenharmony_ci return false; 231862306a36Sopenharmony_ci} 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_cistatic enum drm_connector_status 232162306a36Sopenharmony_ciradeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 232462306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 232562306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 232662306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 232762306a36Sopenharmony_ci uint32_t bios_0_scratch; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci if (!atombios_dac_load_detect(encoder, connector)) { 233062306a36Sopenharmony_ci DRM_DEBUG_KMS("detect returned false \n"); 233162306a36Sopenharmony_ci return connector_status_unknown; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 233562306a36Sopenharmony_ci bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 233662306a36Sopenharmony_ci else 233762306a36Sopenharmony_ci bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); 234062306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { 234162306a36Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT1_MASK) 234262306a36Sopenharmony_ci return connector_status_connected; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { 234562306a36Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT2_MASK) 234662306a36Sopenharmony_ci return connector_status_connected; 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 234962306a36Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) 235062306a36Sopenharmony_ci return connector_status_connected; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 235362306a36Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 235462306a36Sopenharmony_ci return connector_status_connected; /* CTV */ 235562306a36Sopenharmony_ci else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 235662306a36Sopenharmony_ci return connector_status_connected; /* STV */ 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci return connector_status_disconnected; 235962306a36Sopenharmony_ci} 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_cistatic enum drm_connector_status 236262306a36Sopenharmony_ciradeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) 236362306a36Sopenharmony_ci{ 236462306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 236562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 236662306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 236762306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 236862306a36Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 236962306a36Sopenharmony_ci u32 bios_0_scratch; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci if (!ASIC_IS_DCE4(rdev)) 237262306a36Sopenharmony_ci return connector_status_unknown; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (!ext_encoder) 237562306a36Sopenharmony_ci return connector_status_unknown; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) 237862306a36Sopenharmony_ci return connector_status_unknown; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci /* load detect on the dp bridge */ 238162306a36Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 238262306a36Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); 238762306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { 238862306a36Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT1_MASK) 238962306a36Sopenharmony_ci return connector_status_connected; 239062306a36Sopenharmony_ci } 239162306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { 239262306a36Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT2_MASK) 239362306a36Sopenharmony_ci return connector_status_connected; 239462306a36Sopenharmony_ci } 239562306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 239662306a36Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) 239762306a36Sopenharmony_ci return connector_status_connected; 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 240062306a36Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 240162306a36Sopenharmony_ci return connector_status_connected; /* CTV */ 240262306a36Sopenharmony_ci else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 240362306a36Sopenharmony_ci return connector_status_connected; /* STV */ 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci return connector_status_disconnected; 240662306a36Sopenharmony_ci} 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_civoid 240962306a36Sopenharmony_ciradeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) 241062306a36Sopenharmony_ci{ 241162306a36Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci if (ext_encoder) 241462306a36Sopenharmony_ci /* ddc_setup on the dp bridge */ 241562306a36Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 241662306a36Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_cistatic void radeon_atom_encoder_prepare(struct drm_encoder *encoder) 242162306a36Sopenharmony_ci{ 242262306a36Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 242362306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 242462306a36Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci if ((radeon_encoder->active_device & 242762306a36Sopenharmony_ci (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || 242862306a36Sopenharmony_ci (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 242962306a36Sopenharmony_ci ENCODER_OBJECT_ID_NONE)) { 243062306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 243162306a36Sopenharmony_ci if (dig) { 243262306a36Sopenharmony_ci if (dig->dig_encoder >= 0) 243362306a36Sopenharmony_ci radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); 243462306a36Sopenharmony_ci dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1); 243562306a36Sopenharmony_ci if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) { 243662306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 243762306a36Sopenharmony_ci dig->afmt = rdev->mode_info.afmt[dig->dig_encoder]; 243862306a36Sopenharmony_ci else 243962306a36Sopenharmony_ci /* RS600/690/740 have only 1 afmt block */ 244062306a36Sopenharmony_ci dig->afmt = rdev->mode_info.afmt[0]; 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci } 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci radeon_atom_output_lock(encoder, true); 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci if (connector) { 244862306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci /* select the clock/data port if it uses a router */ 245162306a36Sopenharmony_ci if (radeon_connector->router.cd_valid) 245262306a36Sopenharmony_ci radeon_router_select_cd_port(radeon_connector); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* turn eDP panel on for mode set */ 245562306a36Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) 245662306a36Sopenharmony_ci atombios_set_edp_panel_power(connector, 245762306a36Sopenharmony_ci ATOM_TRANSMITTER_ACTION_POWER_ON); 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci /* this is needed for the pll/ss setup to work correctly in some cases */ 246162306a36Sopenharmony_ci atombios_set_encoder_crtc_source(encoder); 246262306a36Sopenharmony_ci /* set up the FMT blocks */ 246362306a36Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) 246462306a36Sopenharmony_ci dce8_program_fmt(encoder); 246562306a36Sopenharmony_ci else if (ASIC_IS_DCE4(rdev)) 246662306a36Sopenharmony_ci dce4_program_fmt(encoder); 246762306a36Sopenharmony_ci else if (ASIC_IS_DCE3(rdev)) 246862306a36Sopenharmony_ci dce3_program_fmt(encoder); 246962306a36Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) 247062306a36Sopenharmony_ci avivo_program_fmt(encoder); 247162306a36Sopenharmony_ci} 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_cistatic void radeon_atom_encoder_commit(struct drm_encoder *encoder) 247462306a36Sopenharmony_ci{ 247562306a36Sopenharmony_ci /* need to call this here as we need the crtc set up */ 247662306a36Sopenharmony_ci radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); 247762306a36Sopenharmony_ci radeon_atom_output_lock(encoder, false); 247862306a36Sopenharmony_ci} 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_cistatic void radeon_atom_encoder_disable(struct drm_encoder *encoder) 248162306a36Sopenharmony_ci{ 248262306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 248362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 248462306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 248562306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci /* check for pre-DCE3 cards with shared encoders; 248862306a36Sopenharmony_ci * can't really use the links individually, so don't disable 248962306a36Sopenharmony_ci * the encoder if it's in use by another connector 249062306a36Sopenharmony_ci */ 249162306a36Sopenharmony_ci if (!ASIC_IS_DCE3(rdev)) { 249262306a36Sopenharmony_ci struct drm_encoder *other_encoder; 249362306a36Sopenharmony_ci struct radeon_encoder *other_radeon_encoder; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { 249662306a36Sopenharmony_ci other_radeon_encoder = to_radeon_encoder(other_encoder); 249762306a36Sopenharmony_ci if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && 249862306a36Sopenharmony_ci drm_helper_encoder_in_use(other_encoder)) 249962306a36Sopenharmony_ci goto disable_done; 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci } 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 250662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 250762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 250862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 250962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 251062306a36Sopenharmony_ci atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); 251162306a36Sopenharmony_ci break; 251262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 251362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 251462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 251562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 251662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 251762306a36Sopenharmony_ci /* handled in dpms */ 251862306a36Sopenharmony_ci break; 251962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 252062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 252162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 252262306a36Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_DISABLE); 252362306a36Sopenharmony_ci break; 252462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 252562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 252662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 252762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 252862306a36Sopenharmony_ci atombios_dac_setup(encoder, ATOM_DISABLE); 252962306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 253062306a36Sopenharmony_ci atombios_tv_setup(encoder, ATOM_DISABLE); 253162306a36Sopenharmony_ci break; 253262306a36Sopenharmony_ci } 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_cidisable_done: 253562306a36Sopenharmony_ci if (radeon_encoder_is_digital(encoder)) { 253662306a36Sopenharmony_ci if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { 253762306a36Sopenharmony_ci if (rdev->asic->display.hdmi_enable) 253862306a36Sopenharmony_ci radeon_hdmi_enable(rdev, encoder, false); 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) { 254162306a36Sopenharmony_ci dig = radeon_encoder->enc_priv; 254262306a36Sopenharmony_ci radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); 254362306a36Sopenharmony_ci dig->dig_encoder = -1; 254462306a36Sopenharmony_ci radeon_encoder->active_device = 0; 254562306a36Sopenharmony_ci } 254662306a36Sopenharmony_ci } else 254762306a36Sopenharmony_ci radeon_encoder->active_device = 0; 254862306a36Sopenharmony_ci} 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci/* these are handled by the primary encoders */ 255162306a36Sopenharmony_cistatic void radeon_atom_ext_prepare(struct drm_encoder *encoder) 255262306a36Sopenharmony_ci{ 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci} 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_cistatic void radeon_atom_ext_commit(struct drm_encoder *encoder) 255762306a36Sopenharmony_ci{ 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci} 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_cistatic void 256262306a36Sopenharmony_ciradeon_atom_ext_mode_set(struct drm_encoder *encoder, 256362306a36Sopenharmony_ci struct drm_display_mode *mode, 256462306a36Sopenharmony_ci struct drm_display_mode *adjusted_mode) 256562306a36Sopenharmony_ci{ 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci} 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_cistatic void radeon_atom_ext_disable(struct drm_encoder *encoder) 257062306a36Sopenharmony_ci{ 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci} 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_cistatic void 257562306a36Sopenharmony_ciradeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) 257662306a36Sopenharmony_ci{ 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci} 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { 258162306a36Sopenharmony_ci .dpms = radeon_atom_ext_dpms, 258262306a36Sopenharmony_ci .prepare = radeon_atom_ext_prepare, 258362306a36Sopenharmony_ci .mode_set = radeon_atom_ext_mode_set, 258462306a36Sopenharmony_ci .commit = radeon_atom_ext_commit, 258562306a36Sopenharmony_ci .disable = radeon_atom_ext_disable, 258662306a36Sopenharmony_ci /* no detect for TMDS/LVDS yet */ 258762306a36Sopenharmony_ci}; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { 259062306a36Sopenharmony_ci .dpms = radeon_atom_encoder_dpms, 259162306a36Sopenharmony_ci .mode_fixup = radeon_atom_mode_fixup, 259262306a36Sopenharmony_ci .prepare = radeon_atom_encoder_prepare, 259362306a36Sopenharmony_ci .mode_set = radeon_atom_encoder_mode_set, 259462306a36Sopenharmony_ci .commit = radeon_atom_encoder_commit, 259562306a36Sopenharmony_ci .disable = radeon_atom_encoder_disable, 259662306a36Sopenharmony_ci .detect = radeon_atom_dig_detect, 259762306a36Sopenharmony_ci}; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { 260062306a36Sopenharmony_ci .dpms = radeon_atom_encoder_dpms, 260162306a36Sopenharmony_ci .mode_fixup = radeon_atom_mode_fixup, 260262306a36Sopenharmony_ci .prepare = radeon_atom_encoder_prepare, 260362306a36Sopenharmony_ci .mode_set = radeon_atom_encoder_mode_set, 260462306a36Sopenharmony_ci .commit = radeon_atom_encoder_commit, 260562306a36Sopenharmony_ci .detect = radeon_atom_dac_detect, 260662306a36Sopenharmony_ci}; 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_civoid radeon_enc_destroy(struct drm_encoder *encoder) 260962306a36Sopenharmony_ci{ 261062306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 261162306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 261262306a36Sopenharmony_ci radeon_atom_backlight_exit(radeon_encoder); 261362306a36Sopenharmony_ci kfree(radeon_encoder->enc_priv); 261462306a36Sopenharmony_ci drm_encoder_cleanup(encoder); 261562306a36Sopenharmony_ci kfree(radeon_encoder); 261662306a36Sopenharmony_ci} 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_cistatic const struct drm_encoder_funcs radeon_atom_enc_funcs = { 261962306a36Sopenharmony_ci .destroy = radeon_enc_destroy, 262062306a36Sopenharmony_ci}; 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_cistatic struct radeon_encoder_atom_dac * 262362306a36Sopenharmony_ciradeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) 262462306a36Sopenharmony_ci{ 262562306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 262662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 262762306a36Sopenharmony_ci struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci if (!dac) 263062306a36Sopenharmony_ci return NULL; 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci dac->tv_std = radeon_atombios_get_tv_info(rdev); 263362306a36Sopenharmony_ci return dac; 263462306a36Sopenharmony_ci} 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_cistatic struct radeon_encoder_atom_dig * 263762306a36Sopenharmony_ciradeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) 263862306a36Sopenharmony_ci{ 263962306a36Sopenharmony_ci int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 264062306a36Sopenharmony_ci struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci if (!dig) 264362306a36Sopenharmony_ci return NULL; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci /* coherent mode by default */ 264662306a36Sopenharmony_ci dig->coherent_mode = true; 264762306a36Sopenharmony_ci dig->dig_encoder = -1; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci if (encoder_enum == 2) 265062306a36Sopenharmony_ci dig->linkb = true; 265162306a36Sopenharmony_ci else 265262306a36Sopenharmony_ci dig->linkb = false; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci return dig; 265562306a36Sopenharmony_ci} 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_civoid 265862306a36Sopenharmony_ciradeon_add_atom_encoder(struct drm_device *dev, 265962306a36Sopenharmony_ci uint32_t encoder_enum, 266062306a36Sopenharmony_ci uint32_t supported_device, 266162306a36Sopenharmony_ci u16 caps) 266262306a36Sopenharmony_ci{ 266362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 266462306a36Sopenharmony_ci struct drm_encoder *encoder; 266562306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* see if we already added it */ 266862306a36Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 266962306a36Sopenharmony_ci radeon_encoder = to_radeon_encoder(encoder); 267062306a36Sopenharmony_ci if (radeon_encoder->encoder_enum == encoder_enum) { 267162306a36Sopenharmony_ci radeon_encoder->devices |= supported_device; 267262306a36Sopenharmony_ci return; 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci } 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci /* add a new one */ 267862306a36Sopenharmony_ci radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); 267962306a36Sopenharmony_ci if (!radeon_encoder) 268062306a36Sopenharmony_ci return; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci encoder = &radeon_encoder->base; 268362306a36Sopenharmony_ci switch (rdev->num_crtc) { 268462306a36Sopenharmony_ci case 1: 268562306a36Sopenharmony_ci encoder->possible_crtcs = 0x1; 268662306a36Sopenharmony_ci break; 268762306a36Sopenharmony_ci case 2: 268862306a36Sopenharmony_ci default: 268962306a36Sopenharmony_ci encoder->possible_crtcs = 0x3; 269062306a36Sopenharmony_ci break; 269162306a36Sopenharmony_ci case 4: 269262306a36Sopenharmony_ci encoder->possible_crtcs = 0xf; 269362306a36Sopenharmony_ci break; 269462306a36Sopenharmony_ci case 6: 269562306a36Sopenharmony_ci encoder->possible_crtcs = 0x3f; 269662306a36Sopenharmony_ci break; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci radeon_encoder->enc_priv = NULL; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci radeon_encoder->encoder_enum = encoder_enum; 270262306a36Sopenharmony_ci radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 270362306a36Sopenharmony_ci radeon_encoder->devices = supported_device; 270462306a36Sopenharmony_ci radeon_encoder->rmx_type = RMX_OFF; 270562306a36Sopenharmony_ci radeon_encoder->underscan_type = UNDERSCAN_OFF; 270662306a36Sopenharmony_ci radeon_encoder->is_ext_encoder = false; 270762306a36Sopenharmony_ci radeon_encoder->caps = caps; 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci switch (radeon_encoder->encoder_id) { 271062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 271162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 271262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 271362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 271462306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 271562306a36Sopenharmony_ci radeon_encoder->rmx_type = RMX_FULL; 271662306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 271762306a36Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 271862306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 271962306a36Sopenharmony_ci } else { 272062306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 272162306a36Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 272262306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); 272562306a36Sopenharmony_ci break; 272662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 272762306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 272862306a36Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 272962306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); 273062306a36Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); 273162306a36Sopenharmony_ci break; 273262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 273362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 273462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 273562306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 273662306a36Sopenharmony_ci DRM_MODE_ENCODER_TVDAC, NULL); 273762306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); 273862306a36Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); 273962306a36Sopenharmony_ci break; 274062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 274162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 274262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 274362306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 274462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 274562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 274662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 274762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 274862306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 274962306a36Sopenharmony_ci radeon_encoder->rmx_type = RMX_FULL; 275062306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 275162306a36Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 275262306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 275362306a36Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { 275462306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 275562306a36Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 275662306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 275762306a36Sopenharmony_ci } else { 275862306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 275962306a36Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 276062306a36Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); 276362306a36Sopenharmony_ci break; 276462306a36Sopenharmony_ci case ENCODER_OBJECT_ID_SI170B: 276562306a36Sopenharmony_ci case ENCODER_OBJECT_ID_CH7303: 276662306a36Sopenharmony_ci case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: 276762306a36Sopenharmony_ci case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: 276862306a36Sopenharmony_ci case ENCODER_OBJECT_ID_TITFP513: 276962306a36Sopenharmony_ci case ENCODER_OBJECT_ID_VT1623: 277062306a36Sopenharmony_ci case ENCODER_OBJECT_ID_HDMI_SI1930: 277162306a36Sopenharmony_ci case ENCODER_OBJECT_ID_TRAVIS: 277262306a36Sopenharmony_ci case ENCODER_OBJECT_ID_NUTMEG: 277362306a36Sopenharmony_ci /* these are handled by the primary encoders */ 277462306a36Sopenharmony_ci radeon_encoder->is_ext_encoder = true; 277562306a36Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 277662306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 277762306a36Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 277862306a36Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) 277962306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 278062306a36Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 278162306a36Sopenharmony_ci else 278262306a36Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 278362306a36Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 278462306a36Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); 278562306a36Sopenharmony_ci break; 278662306a36Sopenharmony_ci } 278762306a36Sopenharmony_ci} 2788