18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2007-11 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Authors: Dave Airlie 248c2ecf20Sopenharmony_ci * Alex Deucher 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/backlight.h> 288c2ecf20Sopenharmony_ci#include <linux/dmi.h> 298c2ecf20Sopenharmony_ci#include <linux/pci.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h> 328c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 338c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "atom.h" 368c2ecf20Sopenharmony_ci#include "radeon.h" 378c2ecf20Sopenharmony_ci#include "radeon_asic.h" 388c2ecf20Sopenharmony_ci#include "radeon_audio.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciextern int atom_debug; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic u8 438c2ecf20Sopenharmony_ciradeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci u8 backlight_level; 468c2ecf20Sopenharmony_ci u32 bios_2_scratch; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 498c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 508c2ecf20Sopenharmony_ci else 518c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >> 548c2ecf20Sopenharmony_ci ATOM_S2_CURRENT_BL_LEVEL_SHIFT); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return backlight_level; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void 608c2ecf20Sopenharmony_ciradeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, 618c2ecf20Sopenharmony_ci u8 backlight_level) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci u32 bios_2_scratch; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 668c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 678c2ecf20Sopenharmony_ci else 688c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; 718c2ecf20Sopenharmony_ci bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) & 728c2ecf20Sopenharmony_ci ATOM_S2_CURRENT_BL_LEVEL_MASK); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 758c2ecf20Sopenharmony_ci WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); 768c2ecf20Sopenharmony_ci else 778c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciu8 818c2ecf20Sopenharmony_ciatombios_get_backlight_level(struct radeon_encoder *radeon_encoder) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 848c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return radeon_atom_get_backlight_level_from_reg(rdev); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_civoid 938c2ecf20Sopenharmony_ciatombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct drm_encoder *encoder = &radeon_encoder->base; 968c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 978c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 988c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 998c2ecf20Sopenharmony_ci DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; 1008c2ecf20Sopenharmony_ci int index; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 1038c2ecf20Sopenharmony_ci return; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 1068c2ecf20Sopenharmony_ci radeon_encoder->enc_priv) { 1078c2ecf20Sopenharmony_ci dig = radeon_encoder->enc_priv; 1088c2ecf20Sopenharmony_ci dig->backlight_level = level; 1098c2ecf20Sopenharmony_ci radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 1128c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1138c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1148c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1158c2ecf20Sopenharmony_ci if (dig->backlight_level == 0) { 1168c2ecf20Sopenharmony_ci args.ucAction = ATOM_LCD_BLOFF; 1178c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL; 1208c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1218c2ecf20Sopenharmony_ci args.ucAction = ATOM_LCD_BLON; 1228c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1268c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1278c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1288c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1298c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 1308c2ecf20Sopenharmony_ci if (dig->backlight_level == 0) 1318c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); 1328c2ecf20Sopenharmony_ci else { 1338c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0); 1348c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci default: 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic u8 radeon_atom_bl_level(struct backlight_device *bd) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci u8 level; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Convert brightness to hardware level */ 1508c2ecf20Sopenharmony_ci if (bd->props.brightness < 0) 1518c2ecf20Sopenharmony_ci level = 0; 1528c2ecf20Sopenharmony_ci else if (bd->props.brightness > RADEON_MAX_BL_LEVEL) 1538c2ecf20Sopenharmony_ci level = RADEON_MAX_BL_LEVEL; 1548c2ecf20Sopenharmony_ci else 1558c2ecf20Sopenharmony_ci level = bd->props.brightness; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return level; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int radeon_atom_backlight_update_status(struct backlight_device *bd) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 1638c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = pdata->encoder; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd)); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int radeon_atom_backlight_get_brightness(struct backlight_device *bd) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata = bl_get_data(bd); 1738c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = pdata->encoder; 1748c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 1758c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return radeon_atom_get_backlight_level_from_reg(rdev); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic const struct backlight_ops radeon_atom_backlight_ops = { 1818c2ecf20Sopenharmony_ci .get_brightness = radeon_atom_backlight_get_brightness, 1828c2ecf20Sopenharmony_ci .update_status = radeon_atom_backlight_update_status, 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_civoid radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, 1868c2ecf20Sopenharmony_ci struct drm_connector *drm_connector) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 1898c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1908c2ecf20Sopenharmony_ci struct backlight_device *bd; 1918c2ecf20Sopenharmony_ci struct backlight_properties props; 1928c2ecf20Sopenharmony_ci struct radeon_backlight_privdata *pdata; 1938c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 1948c2ecf20Sopenharmony_ci char bl_name[16]; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Mac laptops with multiple GPUs use the gmux driver for backlight 1978c2ecf20Sopenharmony_ci * so don't register a backlight device 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && 2008c2ecf20Sopenharmony_ci (rdev->pdev->device == 0x6741) && 2018c2ecf20Sopenharmony_ci !dmi_match(DMI_PRODUCT_NAME, "iMac12,1")) 2028c2ecf20Sopenharmony_ci return; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (!radeon_encoder->enc_priv) 2058c2ecf20Sopenharmony_ci return; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (!rdev->is_atom_bios) 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); 2148c2ecf20Sopenharmony_ci if (!pdata) { 2158c2ecf20Sopenharmony_ci DRM_ERROR("Memory allocation failed\n"); 2168c2ecf20Sopenharmony_ci goto error; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memset(&props, 0, sizeof(props)); 2208c2ecf20Sopenharmony_ci props.max_brightness = RADEON_MAX_BL_LEVEL; 2218c2ecf20Sopenharmony_ci props.type = BACKLIGHT_RAW; 2228c2ecf20Sopenharmony_ci snprintf(bl_name, sizeof(bl_name), 2238c2ecf20Sopenharmony_ci "radeon_bl%d", dev->primary->index); 2248c2ecf20Sopenharmony_ci bd = backlight_device_register(bl_name, drm_connector->kdev, 2258c2ecf20Sopenharmony_ci pdata, &radeon_atom_backlight_ops, &props); 2268c2ecf20Sopenharmony_ci if (IS_ERR(bd)) { 2278c2ecf20Sopenharmony_ci DRM_ERROR("Backlight registration failed\n"); 2288c2ecf20Sopenharmony_ci goto error; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci pdata->encoder = radeon_encoder; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci dig = radeon_encoder->enc_priv; 2348c2ecf20Sopenharmony_ci dig->bl_dev = bd; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci bd->props.brightness = radeon_atom_backlight_get_brightness(bd); 2378c2ecf20Sopenharmony_ci /* Set a reasonable default here if the level is 0 otherwise 2388c2ecf20Sopenharmony_ci * fbdev will attempt to turn the backlight on after console 2398c2ecf20Sopenharmony_ci * unblanking and it will try and restore 0 which turns the backlight 2408c2ecf20Sopenharmony_ci * off again. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if (bd->props.brightness == 0) 2438c2ecf20Sopenharmony_ci bd->props.brightness = RADEON_MAX_BL_LEVEL; 2448c2ecf20Sopenharmony_ci bd->props.power = FB_BLANK_UNBLANK; 2458c2ecf20Sopenharmony_ci backlight_update_status(bd); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci DRM_INFO("radeon atom DIG backlight initialized\n"); 2488c2ecf20Sopenharmony_ci rdev->mode_info.bl_encoder = radeon_encoder; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cierror: 2538c2ecf20Sopenharmony_ci kfree(pdata); 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 2608c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2618c2ecf20Sopenharmony_ci struct backlight_device *bd = NULL; 2628c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!radeon_encoder->enc_priv) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (!rdev->is_atom_bios) 2688c2ecf20Sopenharmony_ci return; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 2718c2ecf20Sopenharmony_ci return; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci dig = radeon_encoder->enc_priv; 2748c2ecf20Sopenharmony_ci bd = dig->bl_dev; 2758c2ecf20Sopenharmony_ci dig->bl_dev = NULL; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (bd) { 2788c2ecf20Sopenharmony_ci struct radeon_legacy_backlight_privdata *pdata; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci pdata = bl_get_data(bd); 2818c2ecf20Sopenharmony_ci backlight_device_unregister(bd); 2828c2ecf20Sopenharmony_ci kfree(pdata); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci DRM_INFO("radeon atom LVDS backlight unloaded\n"); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */ 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_civoid radeon_atom_backlight_init(struct radeon_encoder *encoder) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void radeon_atom_backlight_exit(struct radeon_encoder *encoder) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci#endif 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/* evil but including atombios.h is much worse */ 3018c2ecf20Sopenharmony_cibool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, 3028c2ecf20Sopenharmony_ci struct drm_display_mode *mode); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic bool radeon_atom_mode_fixup(struct drm_encoder *encoder, 3058c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 3068c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 3098c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 3108c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* set the active encoder to connector routing */ 3138c2ecf20Sopenharmony_ci radeon_encoder_set_active_device(encoder); 3148c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(adjusted_mode, 0); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* hw bug */ 3178c2ecf20Sopenharmony_ci if ((mode->flags & DRM_MODE_FLAG_INTERLACE) 3188c2ecf20Sopenharmony_ci && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) 3198c2ecf20Sopenharmony_ci adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* vertical FP must be at least 1 */ 3228c2ecf20Sopenharmony_ci if (mode->crtc_vsync_start == mode->crtc_vdisplay) 3238c2ecf20Sopenharmony_ci adjusted_mode->crtc_vsync_start++; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* get the native mode for scaling */ 3268c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 3278c2ecf20Sopenharmony_ci radeon_panel_mode_fixup(encoder, adjusted_mode); 3288c2ecf20Sopenharmony_ci } else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 3298c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 3308c2ecf20Sopenharmony_ci if (tv_dac) { 3318c2ecf20Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 3328c2ecf20Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 3338c2ecf20Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M) 3348c2ecf20Sopenharmony_ci radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } else if (radeon_encoder->rmx_type != RMX_OFF) { 3398c2ecf20Sopenharmony_ci radeon_panel_mode_fixup(encoder, adjusted_mode); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (ASIC_IS_DCE3(rdev) && 3438c2ecf20Sopenharmony_ci ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || 3448c2ecf20Sopenharmony_ci (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { 3458c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 3468c2ecf20Sopenharmony_ci radeon_dp_set_link_config(connector, adjusted_mode); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return true; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void 3538c2ecf20Sopenharmony_ciatombios_dac_setup(struct drm_encoder *encoder, int action) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 3568c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3578c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 3588c2ecf20Sopenharmony_ci DAC_ENCODER_CONTROL_PS_ALLOCATION args; 3598c2ecf20Sopenharmony_ci int index = 0; 3608c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 3658c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 3668c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 3678c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 3708c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 3718c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci args.ucAction = action; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) 3788c2ecf20Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_PS2; 3798c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 3808c2ecf20Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_CV; 3818c2ecf20Sopenharmony_ci else { 3828c2ecf20Sopenharmony_ci switch (dac_info->tv_std) { 3838c2ecf20Sopenharmony_ci case TV_STD_PAL: 3848c2ecf20Sopenharmony_ci case TV_STD_PAL_M: 3858c2ecf20Sopenharmony_ci case TV_STD_SCART_PAL: 3868c2ecf20Sopenharmony_ci case TV_STD_SECAM: 3878c2ecf20Sopenharmony_ci case TV_STD_PAL_CN: 3888c2ecf20Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_PAL; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case TV_STD_NTSC: 3918c2ecf20Sopenharmony_ci case TV_STD_NTSC_J: 3928c2ecf20Sopenharmony_ci case TV_STD_PAL_60: 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci args.ucDacStandard = ATOM_DAC1_NTSC; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void 4058c2ecf20Sopenharmony_ciatombios_tv_setup(struct drm_encoder *encoder, int action) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 4088c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 4098c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 4108c2ecf20Sopenharmony_ci TV_ENCODER_CONTROL_PS_ALLOCATION args; 4118c2ecf20Sopenharmony_ci int index = 0; 4128c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci args.sTVEncoder.ucAction = action; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 4218c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_CV; 4228c2ecf20Sopenharmony_ci else { 4238c2ecf20Sopenharmony_ci switch (dac_info->tv_std) { 4248c2ecf20Sopenharmony_ci case TV_STD_NTSC: 4258c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case TV_STD_PAL: 4288c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci case TV_STD_PAL_M: 4318c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci case TV_STD_PAL_60: 4348c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case TV_STD_NTSC_J: 4378c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci case TV_STD_SCART_PAL: 4408c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci case TV_STD_SECAM: 4438c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci case TV_STD_PAL_CN: 4468c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci default: 4498c2ecf20Sopenharmony_ci args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic u8 radeon_atom_get_bpc(struct drm_encoder *encoder) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci int bpc = 8; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (encoder->crtc) { 4658c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 4668c2ecf20Sopenharmony_ci bpc = radeon_crtc->bpc; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci switch (bpc) { 4708c2ecf20Sopenharmony_ci case 0: 4718c2ecf20Sopenharmony_ci return PANEL_BPC_UNDEFINE; 4728c2ecf20Sopenharmony_ci case 6: 4738c2ecf20Sopenharmony_ci return PANEL_6BIT_PER_COLOR; 4748c2ecf20Sopenharmony_ci case 8: 4758c2ecf20Sopenharmony_ci default: 4768c2ecf20Sopenharmony_ci return PANEL_8BIT_PER_COLOR; 4778c2ecf20Sopenharmony_ci case 10: 4788c2ecf20Sopenharmony_ci return PANEL_10BIT_PER_COLOR; 4798c2ecf20Sopenharmony_ci case 12: 4808c2ecf20Sopenharmony_ci return PANEL_12BIT_PER_COLOR; 4818c2ecf20Sopenharmony_ci case 16: 4828c2ecf20Sopenharmony_ci return PANEL_16BIT_PER_COLOR; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ciunion dvo_encoder_control { 4878c2ecf20Sopenharmony_ci ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; 4888c2ecf20Sopenharmony_ci DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; 4898c2ecf20Sopenharmony_ci DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; 4908c2ecf20Sopenharmony_ci DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4; 4918c2ecf20Sopenharmony_ci}; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_civoid 4948c2ecf20Sopenharmony_ciatombios_dvo_setup(struct drm_encoder *encoder, int action) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 4978c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 4988c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 4998c2ecf20Sopenharmony_ci union dvo_encoder_control args; 5008c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 5018c2ecf20Sopenharmony_ci uint8_t frev, crev; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 5068c2ecf20Sopenharmony_ci return; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* some R4xx chips have the wrong frev */ 5098c2ecf20Sopenharmony_ci if (rdev->family <= CHIP_RV410) 5108c2ecf20Sopenharmony_ci frev = 1; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci switch (frev) { 5138c2ecf20Sopenharmony_ci case 1: 5148c2ecf20Sopenharmony_ci switch (crev) { 5158c2ecf20Sopenharmony_ci case 1: 5168c2ecf20Sopenharmony_ci /* R4xx, R5xx */ 5178c2ecf20Sopenharmony_ci args.ext_tmds.sXTmdsEncoder.ucEnable = action; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 5208c2ecf20Sopenharmony_ci args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci case 2: 5258c2ecf20Sopenharmony_ci /* RS600/690/740 */ 5268c2ecf20Sopenharmony_ci args.dvo.sDVOEncoder.ucAction = action; 5278c2ecf20Sopenharmony_ci args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 5288c2ecf20Sopenharmony_ci /* DFP1, CRT1, TV1 depending on the type of port */ 5298c2ecf20Sopenharmony_ci args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 5328c2ecf20Sopenharmony_ci args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci case 3: 5358c2ecf20Sopenharmony_ci /* R6xx */ 5368c2ecf20Sopenharmony_ci args.dvo_v3.ucAction = action; 5378c2ecf20Sopenharmony_ci args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 5388c2ecf20Sopenharmony_ci args.dvo_v3.ucDVOConfig = 0; /* XXX */ 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci case 4: 5418c2ecf20Sopenharmony_ci /* DCE8 */ 5428c2ecf20Sopenharmony_ci args.dvo_v4.ucAction = action; 5438c2ecf20Sopenharmony_ci args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 5448c2ecf20Sopenharmony_ci args.dvo_v4.ucDVOConfig = 0; /* XXX */ 5458c2ecf20Sopenharmony_ci args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder); 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci default: 5488c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci default: 5538c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ciunion lvds_encoder_control { 5618c2ecf20Sopenharmony_ci LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; 5628c2ecf20Sopenharmony_ci LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; 5638c2ecf20Sopenharmony_ci}; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_civoid 5668c2ecf20Sopenharmony_ciatombios_digital_setup(struct drm_encoder *encoder, int action) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 5698c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 5708c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 5718c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 5728c2ecf20Sopenharmony_ci union lvds_encoder_control args; 5738c2ecf20Sopenharmony_ci int index = 0; 5748c2ecf20Sopenharmony_ci int hdmi_detected = 0; 5758c2ecf20Sopenharmony_ci uint8_t frev, crev; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (!dig) 5788c2ecf20Sopenharmony_ci return; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) 5818c2ecf20Sopenharmony_ci hdmi_detected = 1; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 5868c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 5878c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 5888c2ecf20Sopenharmony_ci break; 5898c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 5908c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 5918c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); 5928c2ecf20Sopenharmony_ci break; 5938c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 5948c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 5958c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 5968c2ecf20Sopenharmony_ci else 5978c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 6028c2ecf20Sopenharmony_ci return; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci switch (frev) { 6058c2ecf20Sopenharmony_ci case 1: 6068c2ecf20Sopenharmony_ci case 2: 6078c2ecf20Sopenharmony_ci switch (crev) { 6088c2ecf20Sopenharmony_ci case 1: 6098c2ecf20Sopenharmony_ci args.v1.ucMisc = 0; 6108c2ecf20Sopenharmony_ci args.v1.ucAction = action; 6118c2ecf20Sopenharmony_ci if (hdmi_detected) 6128c2ecf20Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 6138c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 6148c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 6158c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) 6168c2ecf20Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; 6178c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 6188c2ecf20Sopenharmony_ci args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; 6198c2ecf20Sopenharmony_ci } else { 6208c2ecf20Sopenharmony_ci if (dig->linkb) 6218c2ecf20Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 6228c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 6238c2ecf20Sopenharmony_ci args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; 6248c2ecf20Sopenharmony_ci /*if (pScrn->rgbBits == 8) */ 6258c2ecf20Sopenharmony_ci args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci case 2: 6298c2ecf20Sopenharmony_ci case 3: 6308c2ecf20Sopenharmony_ci args.v2.ucMisc = 0; 6318c2ecf20Sopenharmony_ci args.v2.ucAction = action; 6328c2ecf20Sopenharmony_ci if (crev == 3) { 6338c2ecf20Sopenharmony_ci if (dig->coherent_mode) 6348c2ecf20Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci if (hdmi_detected) 6378c2ecf20Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 6388c2ecf20Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 6398c2ecf20Sopenharmony_ci args.v2.ucTruncate = 0; 6408c2ecf20Sopenharmony_ci args.v2.ucSpatial = 0; 6418c2ecf20Sopenharmony_ci args.v2.ucTemporal = 0; 6428c2ecf20Sopenharmony_ci args.v2.ucFRC = 0; 6438c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 6448c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) 6458c2ecf20Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 6468c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { 6478c2ecf20Sopenharmony_ci args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; 6488c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 6498c2ecf20Sopenharmony_ci args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { 6528c2ecf20Sopenharmony_ci args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; 6538c2ecf20Sopenharmony_ci if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 6548c2ecf20Sopenharmony_ci args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; 6558c2ecf20Sopenharmony_ci if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) 6568c2ecf20Sopenharmony_ci args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci } else { 6598c2ecf20Sopenharmony_ci if (dig->linkb) 6608c2ecf20Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 6618c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 6628c2ecf20Sopenharmony_ci args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci default: 6668c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci default: 6718c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciint 6798c2ecf20Sopenharmony_ciatombios_get_encoder_mode(struct drm_encoder *encoder) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 6828c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 6838c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 6848c2ecf20Sopenharmony_ci struct drm_connector *connector; 6858c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector; 6868c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector; 6878c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig_enc; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (radeon_encoder_is_digital(encoder)) { 6908c2ecf20Sopenharmony_ci dig_enc = radeon_encoder->enc_priv; 6918c2ecf20Sopenharmony_ci if (dig_enc->active_mst_links) 6928c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP_MST; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci if (radeon_encoder->is_mst_encoder || radeon_encoder->offset) 6958c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP_MST; 6968c2ecf20Sopenharmony_ci /* dp bridges are always DP */ 6978c2ecf20Sopenharmony_ci if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) 6988c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* DVO is always DVO */ 7018c2ecf20Sopenharmony_ci if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) || 7028c2ecf20Sopenharmony_ci (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) 7038c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVO; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci connector = radeon_get_connector_for_encoder(encoder); 7068c2ecf20Sopenharmony_ci /* if we don't have an active device yet, just use one of 7078c2ecf20Sopenharmony_ci * the connectors tied to the encoder. 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ci if (!connector) 7108c2ecf20Sopenharmony_ci connector = radeon_get_connector_for_encoder_init(encoder); 7118c2ecf20Sopenharmony_ci radeon_connector = to_radeon_connector(connector); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci switch (connector->connector_type) { 7148c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_DVII: 7158c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ 7168c2ecf20Sopenharmony_ci if (radeon_audio != 0) { 7178c2ecf20Sopenharmony_ci if (radeon_connector->use_digital && 7188c2ecf20Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_ENABLE)) 7198c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 7208c2ecf20Sopenharmony_ci else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 7218c2ecf20Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_AUTO)) 7228c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 7238c2ecf20Sopenharmony_ci else if (radeon_connector->use_digital) 7248c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 7258c2ecf20Sopenharmony_ci else 7268c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_CRT; 7278c2ecf20Sopenharmony_ci } else if (radeon_connector->use_digital) { 7288c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 7298c2ecf20Sopenharmony_ci } else { 7308c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_CRT; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_DVID: 7348c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_HDMIA: 7358c2ecf20Sopenharmony_ci default: 7368c2ecf20Sopenharmony_ci if (radeon_audio != 0) { 7378c2ecf20Sopenharmony_ci if (radeon_connector->audio == RADEON_AUDIO_ENABLE) 7388c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 7398c2ecf20Sopenharmony_ci else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 7408c2ecf20Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_AUTO)) 7418c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 7428c2ecf20Sopenharmony_ci else 7438c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_LVDS: 7498c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_LVDS; 7508c2ecf20Sopenharmony_ci break; 7518c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_DisplayPort: 7528c2ecf20Sopenharmony_ci dig_connector = radeon_connector->con_priv; 7538c2ecf20Sopenharmony_ci if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 7548c2ecf20Sopenharmony_ci (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 7558c2ecf20Sopenharmony_ci if (radeon_audio != 0 && 7568c2ecf20Sopenharmony_ci drm_detect_monitor_audio(radeon_connector_edid(connector)) && 7578c2ecf20Sopenharmony_ci ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) 7588c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP_AUDIO; 7598c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP; 7608c2ecf20Sopenharmony_ci } else if (radeon_audio != 0) { 7618c2ecf20Sopenharmony_ci if (radeon_connector->audio == RADEON_AUDIO_ENABLE) 7628c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 7638c2ecf20Sopenharmony_ci else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 7648c2ecf20Sopenharmony_ci (radeon_connector->audio == RADEON_AUDIO_AUTO)) 7658c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_HDMI; 7668c2ecf20Sopenharmony_ci else 7678c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 7688c2ecf20Sopenharmony_ci } else { 7698c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DVI; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_eDP: 7738c2ecf20Sopenharmony_ci if (radeon_audio != 0 && 7748c2ecf20Sopenharmony_ci drm_detect_monitor_audio(radeon_connector_edid(connector)) && 7758c2ecf20Sopenharmony_ci ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) 7768c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP_AUDIO; 7778c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_DP; 7788c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_DVIA: 7798c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_VGA: 7808c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_CRT; 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_Composite: 7838c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_SVIDEO: 7848c2ecf20Sopenharmony_ci case DRM_MODE_CONNECTOR_9PinDIN: 7858c2ecf20Sopenharmony_ci /* fix me */ 7868c2ecf20Sopenharmony_ci return ATOM_ENCODER_MODE_TV; 7878c2ecf20Sopenharmony_ci /*return ATOM_ENCODER_MODE_CV;*/ 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/* 7938c2ecf20Sopenharmony_ci * DIG Encoder/Transmitter Setup 7948c2ecf20Sopenharmony_ci * 7958c2ecf20Sopenharmony_ci * DCE 3.0/3.1 7968c2ecf20Sopenharmony_ci * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. 7978c2ecf20Sopenharmony_ci * Supports up to 3 digital outputs 7988c2ecf20Sopenharmony_ci * - 2 DIG encoder blocks. 7998c2ecf20Sopenharmony_ci * DIG1 can drive UNIPHY link A or link B 8008c2ecf20Sopenharmony_ci * DIG2 can drive UNIPHY link B or LVTMA 8018c2ecf20Sopenharmony_ci * 8028c2ecf20Sopenharmony_ci * DCE 3.2 8038c2ecf20Sopenharmony_ci * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). 8048c2ecf20Sopenharmony_ci * Supports up to 5 digital outputs 8058c2ecf20Sopenharmony_ci * - 2 DIG encoder blocks. 8068c2ecf20Sopenharmony_ci * DIG1/2 can drive UNIPHY0/1/2 link A or link B 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci * DCE 4.0/5.0/6.0 8098c2ecf20Sopenharmony_ci * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). 8108c2ecf20Sopenharmony_ci * Supports up to 6 digital outputs 8118c2ecf20Sopenharmony_ci * - 6 DIG encoder blocks. 8128c2ecf20Sopenharmony_ci * - DIG to PHY mapping is hardcoded 8138c2ecf20Sopenharmony_ci * DIG1 drives UNIPHY0 link A, A+B 8148c2ecf20Sopenharmony_ci * DIG2 drives UNIPHY0 link B 8158c2ecf20Sopenharmony_ci * DIG3 drives UNIPHY1 link A, A+B 8168c2ecf20Sopenharmony_ci * DIG4 drives UNIPHY1 link B 8178c2ecf20Sopenharmony_ci * DIG5 drives UNIPHY2 link A, A+B 8188c2ecf20Sopenharmony_ci * DIG6 drives UNIPHY2 link B 8198c2ecf20Sopenharmony_ci * 8208c2ecf20Sopenharmony_ci * DCE 4.1 8218c2ecf20Sopenharmony_ci * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). 8228c2ecf20Sopenharmony_ci * Supports up to 6 digital outputs 8238c2ecf20Sopenharmony_ci * - 2 DIG encoder blocks. 8248c2ecf20Sopenharmony_ci * llano 8258c2ecf20Sopenharmony_ci * DIG1/2 can drive UNIPHY0/1/2 link A or link B 8268c2ecf20Sopenharmony_ci * ontario 8278c2ecf20Sopenharmony_ci * DIG1 drives UNIPHY0/1/2 link A 8288c2ecf20Sopenharmony_ci * DIG2 drives UNIPHY0/1/2 link B 8298c2ecf20Sopenharmony_ci * 8308c2ecf20Sopenharmony_ci * Routing 8318c2ecf20Sopenharmony_ci * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) 8328c2ecf20Sopenharmony_ci * Examples: 8338c2ecf20Sopenharmony_ci * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI 8348c2ecf20Sopenharmony_ci * crtc1 -> dig1 -> UNIPHY0 link B -> DP 8358c2ecf20Sopenharmony_ci * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS 8368c2ecf20Sopenharmony_ci * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI 8378c2ecf20Sopenharmony_ci */ 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciunion dig_encoder_control { 8408c2ecf20Sopenharmony_ci DIG_ENCODER_CONTROL_PS_ALLOCATION v1; 8418c2ecf20Sopenharmony_ci DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; 8428c2ecf20Sopenharmony_ci DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; 8438c2ecf20Sopenharmony_ci DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; 8448c2ecf20Sopenharmony_ci}; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_civoid 8478c2ecf20Sopenharmony_ciatombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 8508c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 8518c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 8528c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 8538c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 8548c2ecf20Sopenharmony_ci union dig_encoder_control args; 8558c2ecf20Sopenharmony_ci int index = 0; 8568c2ecf20Sopenharmony_ci uint8_t frev, crev; 8578c2ecf20Sopenharmony_ci int dp_clock = 0; 8588c2ecf20Sopenharmony_ci int dp_lane_count = 0; 8598c2ecf20Sopenharmony_ci int hpd_id = RADEON_HPD_NONE; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (connector) { 8628c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 8638c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 8648c2ecf20Sopenharmony_ci radeon_connector->con_priv; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock; 8678c2ecf20Sopenharmony_ci dp_lane_count = dig_connector->dp_lane_count; 8688c2ecf20Sopenharmony_ci hpd_id = radeon_connector->hpd.hpd; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* no dig encoder assigned */ 8728c2ecf20Sopenharmony_ci if (dig->dig_encoder == -1) 8738c2ecf20Sopenharmony_ci return; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 8788c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); 8798c2ecf20Sopenharmony_ci else { 8808c2ecf20Sopenharmony_ci if (dig->dig_encoder) 8818c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); 8828c2ecf20Sopenharmony_ci else 8838c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 8878c2ecf20Sopenharmony_ci return; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci switch (frev) { 8908c2ecf20Sopenharmony_ci case 1: 8918c2ecf20Sopenharmony_ci switch (crev) { 8928c2ecf20Sopenharmony_ci case 1: 8938c2ecf20Sopenharmony_ci args.v1.ucAction = action; 8948c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 8958c2ecf20Sopenharmony_ci if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 8968c2ecf20Sopenharmony_ci args.v3.ucPanelMode = panel_mode; 8978c2ecf20Sopenharmony_ci else 8988c2ecf20Sopenharmony_ci args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) 9018c2ecf20Sopenharmony_ci args.v1.ucLaneNum = dp_lane_count; 9028c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 9038c2ecf20Sopenharmony_ci args.v1.ucLaneNum = 8; 9048c2ecf20Sopenharmony_ci else 9058c2ecf20Sopenharmony_ci args.v1.ucLaneNum = 4; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 9088c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 9098c2ecf20Sopenharmony_ci args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 9128c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 9138c2ecf20Sopenharmony_ci args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 9168c2ecf20Sopenharmony_ci args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci if (dig->linkb) 9208c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; 9218c2ecf20Sopenharmony_ci else 9228c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) 9258c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci case 2: 9298c2ecf20Sopenharmony_ci case 3: 9308c2ecf20Sopenharmony_ci args.v3.ucAction = action; 9318c2ecf20Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 9328c2ecf20Sopenharmony_ci if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 9338c2ecf20Sopenharmony_ci args.v3.ucPanelMode = panel_mode; 9348c2ecf20Sopenharmony_ci else 9358c2ecf20Sopenharmony_ci args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode)) 9388c2ecf20Sopenharmony_ci args.v3.ucLaneNum = dp_lane_count; 9398c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 9408c2ecf20Sopenharmony_ci args.v3.ucLaneNum = 8; 9418c2ecf20Sopenharmony_ci else 9428c2ecf20Sopenharmony_ci args.v3.ucLaneNum = 4; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000)) 9458c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; 9468c2ecf20Sopenharmony_ci if (enc_override != -1) 9478c2ecf20Sopenharmony_ci args.v3.acConfig.ucDigSel = enc_override; 9488c2ecf20Sopenharmony_ci else 9498c2ecf20Sopenharmony_ci args.v3.acConfig.ucDigSel = dig->dig_encoder; 9508c2ecf20Sopenharmony_ci args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci case 4: 9538c2ecf20Sopenharmony_ci args.v4.ucAction = action; 9548c2ecf20Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 9558c2ecf20Sopenharmony_ci if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 9568c2ecf20Sopenharmony_ci args.v4.ucPanelMode = panel_mode; 9578c2ecf20Sopenharmony_ci else 9588c2ecf20Sopenharmony_ci args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) 9618c2ecf20Sopenharmony_ci args.v4.ucLaneNum = dp_lane_count; 9628c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 9638c2ecf20Sopenharmony_ci args.v4.ucLaneNum = 8; 9648c2ecf20Sopenharmony_ci else 9658c2ecf20Sopenharmony_ci args.v4.ucLaneNum = 4; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) { 9688c2ecf20Sopenharmony_ci if (dp_clock == 540000) 9698c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; 9708c2ecf20Sopenharmony_ci else if (dp_clock == 324000) 9718c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ; 9728c2ecf20Sopenharmony_ci else if (dp_clock == 270000) 9738c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; 9748c2ecf20Sopenharmony_ci else 9758c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (enc_override != -1) 9798c2ecf20Sopenharmony_ci args.v4.acConfig.ucDigSel = enc_override; 9808c2ecf20Sopenharmony_ci else 9818c2ecf20Sopenharmony_ci args.v4.acConfig.ucDigSel = dig->dig_encoder; 9828c2ecf20Sopenharmony_ci args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); 9838c2ecf20Sopenharmony_ci if (hpd_id == RADEON_HPD_NONE) 9848c2ecf20Sopenharmony_ci args.v4.ucHPD_ID = 0; 9858c2ecf20Sopenharmony_ci else 9868c2ecf20Sopenharmony_ci args.v4.ucHPD_ID = hpd_id + 1; 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci default: 9898c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 9908c2ecf20Sopenharmony_ci break; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci break; 9938c2ecf20Sopenharmony_ci default: 9948c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 9958c2ecf20Sopenharmony_ci break; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_civoid 10038c2ecf20Sopenharmony_ciatombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci atombios_dig_encoder_setup2(encoder, action, panel_mode, -1); 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ciunion dig_transmitter_control { 10098c2ecf20Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; 10108c2ecf20Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; 10118c2ecf20Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; 10128c2ecf20Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; 10138c2ecf20Sopenharmony_ci DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5; 10148c2ecf20Sopenharmony_ci}; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_civoid 10178c2ecf20Sopenharmony_ciatombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 10208c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 10218c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 10228c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 10238c2ecf20Sopenharmony_ci struct drm_connector *connector; 10248c2ecf20Sopenharmony_ci union dig_transmitter_control args; 10258c2ecf20Sopenharmony_ci int index = 0; 10268c2ecf20Sopenharmony_ci uint8_t frev, crev; 10278c2ecf20Sopenharmony_ci bool is_dp = false; 10288c2ecf20Sopenharmony_ci int pll_id = 0; 10298c2ecf20Sopenharmony_ci int dp_clock = 0; 10308c2ecf20Sopenharmony_ci int dp_lane_count = 0; 10318c2ecf20Sopenharmony_ci int connector_object_id = 0; 10328c2ecf20Sopenharmony_ci int igp_lane_info = 0; 10338c2ecf20Sopenharmony_ci int dig_encoder = dig->dig_encoder; 10348c2ecf20Sopenharmony_ci int hpd_id = RADEON_HPD_NONE; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 10378c2ecf20Sopenharmony_ci connector = radeon_get_connector_for_encoder_init(encoder); 10388c2ecf20Sopenharmony_ci /* just needed to avoid bailing in the encoder check. the encoder 10398c2ecf20Sopenharmony_ci * isn't used for init 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_ci dig_encoder = 0; 10428c2ecf20Sopenharmony_ci } else 10438c2ecf20Sopenharmony_ci connector = radeon_get_connector_for_encoder(encoder); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (connector) { 10468c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 10478c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 10488c2ecf20Sopenharmony_ci radeon_connector->con_priv; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci hpd_id = radeon_connector->hpd.hpd; 10518c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock; 10528c2ecf20Sopenharmony_ci dp_lane_count = dig_connector->dp_lane_count; 10538c2ecf20Sopenharmony_ci connector_object_id = 10548c2ecf20Sopenharmony_ci (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 10558c2ecf20Sopenharmony_ci igp_lane_info = dig_connector->igp_lane_info; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (encoder->crtc) { 10598c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 10608c2ecf20Sopenharmony_ci pll_id = radeon_crtc->pll_id; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* no dig encoder assigned */ 10648c2ecf20Sopenharmony_ci if (dig_encoder == -1) 10658c2ecf20Sopenharmony_ci return; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder))) 10688c2ecf20Sopenharmony_ci is_dp = true; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 10738c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 10748c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 10778c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 10788c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 10798c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 10808c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 10838c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 10888c2ecf20Sopenharmony_ci return; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci switch (frev) { 10918c2ecf20Sopenharmony_ci case 1: 10928c2ecf20Sopenharmony_ci switch (crev) { 10938c2ecf20Sopenharmony_ci case 1: 10948c2ecf20Sopenharmony_ci args.v1.ucAction = action; 10958c2ecf20Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 10968c2ecf20Sopenharmony_ci args.v1.usInitInfo = cpu_to_le16(connector_object_id); 10978c2ecf20Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 10988c2ecf20Sopenharmony_ci args.v1.asMode.ucLaneSel = lane_num; 10998c2ecf20Sopenharmony_ci args.v1.asMode.ucLaneSet = lane_set; 11008c2ecf20Sopenharmony_ci } else { 11018c2ecf20Sopenharmony_ci if (is_dp) 11028c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(dp_clock / 10); 11038c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 11048c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 11058c2ecf20Sopenharmony_ci else 11068c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (dig_encoder) 11128c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; 11138c2ecf20Sopenharmony_ci else 11148c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if ((rdev->flags & RADEON_IS_IGP) && 11178c2ecf20Sopenharmony_ci (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { 11188c2ecf20Sopenharmony_ci if (is_dp || 11198c2ecf20Sopenharmony_ci !radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) { 11208c2ecf20Sopenharmony_ci if (igp_lane_info & 0x1) 11218c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; 11228c2ecf20Sopenharmony_ci else if (igp_lane_info & 0x2) 11238c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; 11248c2ecf20Sopenharmony_ci else if (igp_lane_info & 0x4) 11258c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; 11268c2ecf20Sopenharmony_ci else if (igp_lane_info & 0x8) 11278c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; 11288c2ecf20Sopenharmony_ci } else { 11298c2ecf20Sopenharmony_ci if (igp_lane_info & 0x3) 11308c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; 11318c2ecf20Sopenharmony_ci else if (igp_lane_info & 0xc) 11328c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (dig->linkb) 11378c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; 11388c2ecf20Sopenharmony_ci else 11398c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (is_dp) 11428c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 11438c2ecf20Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 11448c2ecf20Sopenharmony_ci if (dig->coherent_mode) 11458c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 11468c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 11478c2ecf20Sopenharmony_ci args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci break; 11508c2ecf20Sopenharmony_ci case 2: 11518c2ecf20Sopenharmony_ci args.v2.ucAction = action; 11528c2ecf20Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 11538c2ecf20Sopenharmony_ci args.v2.usInitInfo = cpu_to_le16(connector_object_id); 11548c2ecf20Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 11558c2ecf20Sopenharmony_ci args.v2.asMode.ucLaneSel = lane_num; 11568c2ecf20Sopenharmony_ci args.v2.asMode.ucLaneSet = lane_set; 11578c2ecf20Sopenharmony_ci } else { 11588c2ecf20Sopenharmony_ci if (is_dp) 11598c2ecf20Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(dp_clock / 10); 11608c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 11618c2ecf20Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 11628c2ecf20Sopenharmony_ci else 11638c2ecf20Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci args.v2.acConfig.ucEncoderSel = dig_encoder; 11678c2ecf20Sopenharmony_ci if (dig->linkb) 11688c2ecf20Sopenharmony_ci args.v2.acConfig.ucLinkSel = 1; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 11718c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 11728c2ecf20Sopenharmony_ci args.v2.acConfig.ucTransmitterSel = 0; 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 11758c2ecf20Sopenharmony_ci args.v2.acConfig.ucTransmitterSel = 1; 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 11788c2ecf20Sopenharmony_ci args.v2.acConfig.ucTransmitterSel = 2; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (is_dp) { 11838c2ecf20Sopenharmony_ci args.v2.acConfig.fCoherentMode = 1; 11848c2ecf20Sopenharmony_ci args.v2.acConfig.fDPConnector = 1; 11858c2ecf20Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 11868c2ecf20Sopenharmony_ci if (dig->coherent_mode) 11878c2ecf20Sopenharmony_ci args.v2.acConfig.fCoherentMode = 1; 11888c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 11898c2ecf20Sopenharmony_ci args.v2.acConfig.fDualLinkConnector = 1; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci case 3: 11938c2ecf20Sopenharmony_ci args.v3.ucAction = action; 11948c2ecf20Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 11958c2ecf20Sopenharmony_ci args.v3.usInitInfo = cpu_to_le16(connector_object_id); 11968c2ecf20Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 11978c2ecf20Sopenharmony_ci args.v3.asMode.ucLaneSel = lane_num; 11988c2ecf20Sopenharmony_ci args.v3.asMode.ucLaneSet = lane_set; 11998c2ecf20Sopenharmony_ci } else { 12008c2ecf20Sopenharmony_ci if (is_dp) 12018c2ecf20Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(dp_clock / 10); 12028c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 12038c2ecf20Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 12048c2ecf20Sopenharmony_ci else 12058c2ecf20Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (is_dp) 12098c2ecf20Sopenharmony_ci args.v3.ucLaneNum = dp_lane_count; 12108c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 12118c2ecf20Sopenharmony_ci args.v3.ucLaneNum = 8; 12128c2ecf20Sopenharmony_ci else 12138c2ecf20Sopenharmony_ci args.v3.ucLaneNum = 4; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (dig->linkb) 12168c2ecf20Sopenharmony_ci args.v3.acConfig.ucLinkSel = 1; 12178c2ecf20Sopenharmony_ci if (dig_encoder & 1) 12188c2ecf20Sopenharmony_ci args.v3.acConfig.ucEncoderSel = 1; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* Select the PLL for the PHY 12218c2ecf20Sopenharmony_ci * DP PHY should be clocked from external src if there is 12228c2ecf20Sopenharmony_ci * one. 12238c2ecf20Sopenharmony_ci */ 12248c2ecf20Sopenharmony_ci /* On DCE4, if there is an external clock, it generates the DP ref clock */ 12258c2ecf20Sopenharmony_ci if (is_dp && rdev->clock.dp_extclk) 12268c2ecf20Sopenharmony_ci args.v3.acConfig.ucRefClkSource = 2; /* external src */ 12278c2ecf20Sopenharmony_ci else 12288c2ecf20Sopenharmony_ci args.v3.acConfig.ucRefClkSource = pll_id; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 12318c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 12328c2ecf20Sopenharmony_ci args.v3.acConfig.ucTransmitterSel = 0; 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 12358c2ecf20Sopenharmony_ci args.v3.acConfig.ucTransmitterSel = 1; 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 12388c2ecf20Sopenharmony_ci args.v3.acConfig.ucTransmitterSel = 2; 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci if (is_dp) 12438c2ecf20Sopenharmony_ci args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ 12448c2ecf20Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 12458c2ecf20Sopenharmony_ci if (dig->coherent_mode) 12468c2ecf20Sopenharmony_ci args.v3.acConfig.fCoherentMode = 1; 12478c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 12488c2ecf20Sopenharmony_ci args.v3.acConfig.fDualLinkConnector = 1; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci case 4: 12528c2ecf20Sopenharmony_ci args.v4.ucAction = action; 12538c2ecf20Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_INIT) { 12548c2ecf20Sopenharmony_ci args.v4.usInitInfo = cpu_to_le16(connector_object_id); 12558c2ecf20Sopenharmony_ci } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 12568c2ecf20Sopenharmony_ci args.v4.asMode.ucLaneSel = lane_num; 12578c2ecf20Sopenharmony_ci args.v4.asMode.ucLaneSet = lane_set; 12588c2ecf20Sopenharmony_ci } else { 12598c2ecf20Sopenharmony_ci if (is_dp) 12608c2ecf20Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16(dp_clock / 10); 12618c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 12628c2ecf20Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 12638c2ecf20Sopenharmony_ci else 12648c2ecf20Sopenharmony_ci args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (is_dp) 12688c2ecf20Sopenharmony_ci args.v4.ucLaneNum = dp_lane_count; 12698c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 12708c2ecf20Sopenharmony_ci args.v4.ucLaneNum = 8; 12718c2ecf20Sopenharmony_ci else 12728c2ecf20Sopenharmony_ci args.v4.ucLaneNum = 4; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (dig->linkb) 12758c2ecf20Sopenharmony_ci args.v4.acConfig.ucLinkSel = 1; 12768c2ecf20Sopenharmony_ci if (dig_encoder & 1) 12778c2ecf20Sopenharmony_ci args.v4.acConfig.ucEncoderSel = 1; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* Select the PLL for the PHY 12808c2ecf20Sopenharmony_ci * DP PHY should be clocked from external src if there is 12818c2ecf20Sopenharmony_ci * one. 12828c2ecf20Sopenharmony_ci */ 12838c2ecf20Sopenharmony_ci /* On DCE5 DCPLL usually generates the DP ref clock */ 12848c2ecf20Sopenharmony_ci if (is_dp) { 12858c2ecf20Sopenharmony_ci if (rdev->clock.dp_extclk) 12868c2ecf20Sopenharmony_ci args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; 12878c2ecf20Sopenharmony_ci else 12888c2ecf20Sopenharmony_ci args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; 12898c2ecf20Sopenharmony_ci } else 12908c2ecf20Sopenharmony_ci args.v4.acConfig.ucRefClkSource = pll_id; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 12938c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 12948c2ecf20Sopenharmony_ci args.v4.acConfig.ucTransmitterSel = 0; 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 12978c2ecf20Sopenharmony_ci args.v4.acConfig.ucTransmitterSel = 1; 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 13008c2ecf20Sopenharmony_ci args.v4.acConfig.ucTransmitterSel = 2; 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (is_dp) 13058c2ecf20Sopenharmony_ci args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */ 13068c2ecf20Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 13078c2ecf20Sopenharmony_ci if (dig->coherent_mode) 13088c2ecf20Sopenharmony_ci args.v4.acConfig.fCoherentMode = 1; 13098c2ecf20Sopenharmony_ci if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 13108c2ecf20Sopenharmony_ci args.v4.acConfig.fDualLinkConnector = 1; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci case 5: 13148c2ecf20Sopenharmony_ci args.v5.ucAction = action; 13158c2ecf20Sopenharmony_ci if (is_dp) 13168c2ecf20Sopenharmony_ci args.v5.usSymClock = cpu_to_le16(dp_clock / 10); 13178c2ecf20Sopenharmony_ci else 13188c2ecf20Sopenharmony_ci args.v5.usSymClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 13218c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 13228c2ecf20Sopenharmony_ci if (dig->linkb) 13238c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB; 13248c2ecf20Sopenharmony_ci else 13258c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA; 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 13288c2ecf20Sopenharmony_ci if (dig->linkb) 13298c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD; 13308c2ecf20Sopenharmony_ci else 13318c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC; 13328c2ecf20Sopenharmony_ci break; 13338c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 13348c2ecf20Sopenharmony_ci if (dig->linkb) 13358c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF; 13368c2ecf20Sopenharmony_ci else 13378c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE; 13388c2ecf20Sopenharmony_ci break; 13398c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 13408c2ecf20Sopenharmony_ci args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG; 13418c2ecf20Sopenharmony_ci break; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci if (is_dp) 13448c2ecf20Sopenharmony_ci args.v5.ucLaneNum = dp_lane_count; 13458c2ecf20Sopenharmony_ci else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 13468c2ecf20Sopenharmony_ci args.v5.ucLaneNum = 8; 13478c2ecf20Sopenharmony_ci else 13488c2ecf20Sopenharmony_ci args.v5.ucLaneNum = 4; 13498c2ecf20Sopenharmony_ci args.v5.ucConnObjId = connector_object_id; 13508c2ecf20Sopenharmony_ci args.v5.ucDigMode = atombios_get_encoder_mode(encoder); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (is_dp && rdev->clock.dp_extclk) 13538c2ecf20Sopenharmony_ci args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK; 13548c2ecf20Sopenharmony_ci else 13558c2ecf20Sopenharmony_ci args.v5.asConfig.ucPhyClkSrcId = pll_id; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (is_dp) 13588c2ecf20Sopenharmony_ci args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */ 13598c2ecf20Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 13608c2ecf20Sopenharmony_ci if (dig->coherent_mode) 13618c2ecf20Sopenharmony_ci args.v5.asConfig.ucCoherentMode = 1; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci if (hpd_id == RADEON_HPD_NONE) 13648c2ecf20Sopenharmony_ci args.v5.asConfig.ucHPDSel = 0; 13658c2ecf20Sopenharmony_ci else 13668c2ecf20Sopenharmony_ci args.v5.asConfig.ucHPDSel = hpd_id + 1; 13678c2ecf20Sopenharmony_ci args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder); 13688c2ecf20Sopenharmony_ci args.v5.ucDPLaneSet = lane_set; 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci default: 13718c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 13728c2ecf20Sopenharmony_ci break; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci break; 13758c2ecf20Sopenharmony_ci default: 13768c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 13778c2ecf20Sopenharmony_ci break; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_civoid 13848c2ecf20Sopenharmony_ciatombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1); 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cibool 13908c2ecf20Sopenharmony_ciatombios_set_edp_panel_power(struct drm_connector *connector, int action) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 13938c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_connector->base.dev; 13948c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 13958c2ecf20Sopenharmony_ci union dig_transmitter_control args; 13968c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 13978c2ecf20Sopenharmony_ci uint8_t frev, crev; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) 14008c2ecf20Sopenharmony_ci goto done; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if (!ASIC_IS_DCE4(rdev)) 14038c2ecf20Sopenharmony_ci goto done; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && 14068c2ecf20Sopenharmony_ci (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) 14078c2ecf20Sopenharmony_ci goto done; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 14108c2ecf20Sopenharmony_ci goto done; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci args.v1.ucAction = action; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* wait for the panel to power up */ 14198c2ecf20Sopenharmony_ci if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { 14208c2ecf20Sopenharmony_ci int i; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci for (i = 0; i < 300; i++) { 14238c2ecf20Sopenharmony_ci if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) 14248c2ecf20Sopenharmony_ci return true; 14258c2ecf20Sopenharmony_ci mdelay(1); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci return false; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_cidone: 14308c2ecf20Sopenharmony_ci return true; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ciunion external_encoder_control { 14348c2ecf20Sopenharmony_ci EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; 14358c2ecf20Sopenharmony_ci EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; 14368c2ecf20Sopenharmony_ci}; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic void 14398c2ecf20Sopenharmony_ciatombios_external_encoder_setup(struct drm_encoder *encoder, 14408c2ecf20Sopenharmony_ci struct drm_encoder *ext_encoder, 14418c2ecf20Sopenharmony_ci int action) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 14448c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 14458c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 14468c2ecf20Sopenharmony_ci struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); 14478c2ecf20Sopenharmony_ci union external_encoder_control args; 14488c2ecf20Sopenharmony_ci struct drm_connector *connector; 14498c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); 14508c2ecf20Sopenharmony_ci u8 frev, crev; 14518c2ecf20Sopenharmony_ci int dp_clock = 0; 14528c2ecf20Sopenharmony_ci int dp_lane_count = 0; 14538c2ecf20Sopenharmony_ci int connector_object_id = 0; 14548c2ecf20Sopenharmony_ci u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) 14578c2ecf20Sopenharmony_ci connector = radeon_get_connector_for_encoder_init(encoder); 14588c2ecf20Sopenharmony_ci else 14598c2ecf20Sopenharmony_ci connector = radeon_get_connector_for_encoder(encoder); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (connector) { 14628c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 14638c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 14648c2ecf20Sopenharmony_ci radeon_connector->con_priv; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock; 14678c2ecf20Sopenharmony_ci dp_lane_count = dig_connector->dp_lane_count; 14688c2ecf20Sopenharmony_ci connector_object_id = 14698c2ecf20Sopenharmony_ci (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 14758c2ecf20Sopenharmony_ci return; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci switch (frev) { 14788c2ecf20Sopenharmony_ci case 1: 14798c2ecf20Sopenharmony_ci /* no params on frev 1 */ 14808c2ecf20Sopenharmony_ci break; 14818c2ecf20Sopenharmony_ci case 2: 14828c2ecf20Sopenharmony_ci switch (crev) { 14838c2ecf20Sopenharmony_ci case 1: 14848c2ecf20Sopenharmony_ci case 2: 14858c2ecf20Sopenharmony_ci args.v1.sDigEncoder.ucAction = action; 14868c2ecf20Sopenharmony_ci args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 14878c2ecf20Sopenharmony_ci args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) { 14908c2ecf20Sopenharmony_ci if (dp_clock == 270000) 14918c2ecf20Sopenharmony_ci args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 14928c2ecf20Sopenharmony_ci args.v1.sDigEncoder.ucLaneNum = dp_lane_count; 14938c2ecf20Sopenharmony_ci } else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 14948c2ecf20Sopenharmony_ci args.v1.sDigEncoder.ucLaneNum = 8; 14958c2ecf20Sopenharmony_ci else 14968c2ecf20Sopenharmony_ci args.v1.sDigEncoder.ucLaneNum = 4; 14978c2ecf20Sopenharmony_ci break; 14988c2ecf20Sopenharmony_ci case 3: 14998c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucAction = action; 15008c2ecf20Sopenharmony_ci if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) 15018c2ecf20Sopenharmony_ci args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); 15028c2ecf20Sopenharmony_ci else 15038c2ecf20Sopenharmony_ci args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 15048c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) { 15078c2ecf20Sopenharmony_ci if (dp_clock == 270000) 15088c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; 15098c2ecf20Sopenharmony_ci else if (dp_clock == 540000) 15108c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; 15118c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucLaneNum = dp_lane_count; 15128c2ecf20Sopenharmony_ci } else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 15138c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucLaneNum = 8; 15148c2ecf20Sopenharmony_ci else 15158c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucLaneNum = 4; 15168c2ecf20Sopenharmony_ci switch (ext_enum) { 15178c2ecf20Sopenharmony_ci case GRAPH_OBJECT_ENUM_ID1: 15188c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; 15198c2ecf20Sopenharmony_ci break; 15208c2ecf20Sopenharmony_ci case GRAPH_OBJECT_ENUM_ID2: 15218c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; 15228c2ecf20Sopenharmony_ci break; 15238c2ecf20Sopenharmony_ci case GRAPH_OBJECT_ENUM_ID3: 15248c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; 15258c2ecf20Sopenharmony_ci break; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci args.v3.sExtEncoder.ucBitPerColor = radeon_atom_get_bpc(encoder); 15288c2ecf20Sopenharmony_ci break; 15298c2ecf20Sopenharmony_ci default: 15308c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 15318c2ecf20Sopenharmony_ci return; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci break; 15348c2ecf20Sopenharmony_ci default: 15358c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 15368c2ecf20Sopenharmony_ci return; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic void 15428c2ecf20Sopenharmony_ciatombios_yuv_setup(struct drm_encoder *encoder, bool enable) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 15458c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 15468c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 15478c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 15488c2ecf20Sopenharmony_ci ENABLE_YUV_PS_ALLOCATION args; 15498c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); 15508c2ecf20Sopenharmony_ci uint32_t temp, reg; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 15558c2ecf20Sopenharmony_ci reg = R600_BIOS_3_SCRATCH; 15568c2ecf20Sopenharmony_ci else 15578c2ecf20Sopenharmony_ci reg = RADEON_BIOS_3_SCRATCH; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci /* XXX: fix up scratch reg handling */ 15608c2ecf20Sopenharmony_ci temp = RREG32(reg); 15618c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 15628c2ecf20Sopenharmony_ci WREG32(reg, (ATOM_S3_TV1_ACTIVE | 15638c2ecf20Sopenharmony_ci (radeon_crtc->crtc_id << 18))); 15648c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 15658c2ecf20Sopenharmony_ci WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); 15668c2ecf20Sopenharmony_ci else 15678c2ecf20Sopenharmony_ci WREG32(reg, 0); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (enable) 15708c2ecf20Sopenharmony_ci args.ucEnable = ATOM_ENABLE; 15718c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci WREG32(reg, temp); 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_cistatic void 15798c2ecf20Sopenharmony_ciradeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 15828c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 15838c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 15848c2ecf20Sopenharmony_ci DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; 15858c2ecf20Sopenharmony_ci int index = 0; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 15908c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 15918c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 15928c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); 15938c2ecf20Sopenharmony_ci break; 15948c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 15958c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 15968c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 15978c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 16008c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 16038c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 16048c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 16058c2ecf20Sopenharmony_ci else 16068c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); 16078c2ecf20Sopenharmony_ci break; 16088c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 16098c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 16108c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 16118c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 16128c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 16138c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 16148c2ecf20Sopenharmony_ci else 16158c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 16168c2ecf20Sopenharmony_ci break; 16178c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 16188c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 16198c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 16208c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 16218c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 16228c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 16238c2ecf20Sopenharmony_ci else 16248c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 16258c2ecf20Sopenharmony_ci break; 16268c2ecf20Sopenharmony_ci default: 16278c2ecf20Sopenharmony_ci return; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci switch (mode) { 16318c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 16328c2ecf20Sopenharmony_ci args.ucAction = ATOM_ENABLE; 16338c2ecf20Sopenharmony_ci /* workaround for DVOOutputControl on some RS690 systems */ 16348c2ecf20Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { 16358c2ecf20Sopenharmony_ci u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); 16368c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); 16378c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 16388c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_3_SCRATCH, reg); 16398c2ecf20Sopenharmony_ci } else 16408c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 16418c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 16428c2ecf20Sopenharmony_ci if (rdev->mode_info.bl_encoder) { 16438c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci atombios_set_backlight_level(radeon_encoder, dig->backlight_level); 16468c2ecf20Sopenharmony_ci } else { 16478c2ecf20Sopenharmony_ci args.ucAction = ATOM_LCD_BLON; 16488c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci break; 16528c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 16538c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 16548c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 16558c2ecf20Sopenharmony_ci args.ucAction = ATOM_DISABLE; 16568c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 16578c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 16588c2ecf20Sopenharmony_ci args.ucAction = ATOM_LCD_BLOFF; 16598c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci break; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic void 16668c2ecf20Sopenharmony_ciradeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 16698c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 16708c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 16718c2ecf20Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 16728c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 16738c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 16748c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = NULL; 16758c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *radeon_dig_connector = NULL; 16768c2ecf20Sopenharmony_ci bool travis_quirk = false; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (connector) { 16798c2ecf20Sopenharmony_ci radeon_connector = to_radeon_connector(connector); 16808c2ecf20Sopenharmony_ci radeon_dig_connector = radeon_connector->con_priv; 16818c2ecf20Sopenharmony_ci if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == 16828c2ecf20Sopenharmony_ci ENCODER_OBJECT_ID_TRAVIS) && 16838c2ecf20Sopenharmony_ci (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 16848c2ecf20Sopenharmony_ci !ASIC_IS_DCE5(rdev)) 16858c2ecf20Sopenharmony_ci travis_quirk = true; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci switch (mode) { 16898c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 16908c2ecf20Sopenharmony_ci if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { 16918c2ecf20Sopenharmony_ci if (!connector) 16928c2ecf20Sopenharmony_ci dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; 16938c2ecf20Sopenharmony_ci else 16948c2ecf20Sopenharmony_ci dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci /* setup and enable the encoder */ 16978c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); 16988c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, 16998c2ecf20Sopenharmony_ci ATOM_ENCODER_CMD_SETUP_PANEL_MODE, 17008c2ecf20Sopenharmony_ci dig->panel_mode); 17018c2ecf20Sopenharmony_ci if (ext_encoder) { 17028c2ecf20Sopenharmony_ci if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) 17038c2ecf20Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 17048c2ecf20Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 17078c2ecf20Sopenharmony_ci /* setup and enable the encoder */ 17088c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); 17098c2ecf20Sopenharmony_ci } else { 17108c2ecf20Sopenharmony_ci /* setup and enable the encoder and transmitter */ 17118c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); 17128c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 17158c2ecf20Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 17168c2ecf20Sopenharmony_ci atombios_set_edp_panel_power(connector, 17178c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_POWER_ON); 17188c2ecf20Sopenharmony_ci radeon_dig_connector->edp_on = true; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci /* enable the transmitter */ 17228c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 17238c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 17248c2ecf20Sopenharmony_ci /* DP_SET_POWER_D0 is set in radeon_dp_link_train */ 17258c2ecf20Sopenharmony_ci radeon_dp_link_train(encoder, connector); 17268c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 17278c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 17308c2ecf20Sopenharmony_ci if (rdev->mode_info.bl_encoder) 17318c2ecf20Sopenharmony_ci atombios_set_backlight_level(radeon_encoder, dig->backlight_level); 17328c2ecf20Sopenharmony_ci else 17338c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 17348c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci if (ext_encoder) 17378c2ecf20Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); 17388c2ecf20Sopenharmony_ci break; 17398c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 17408c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 17418c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* don't power off encoders with active MST links */ 17448c2ecf20Sopenharmony_ci if (dig->active_mst_links) 17458c2ecf20Sopenharmony_ci return; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 17488c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) 17498c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci if (ext_encoder) 17528c2ecf20Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); 17538c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 17548c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 17558c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && 17588c2ecf20Sopenharmony_ci connector && !travis_quirk) 17598c2ecf20Sopenharmony_ci radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); 17608c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 17618c2ecf20Sopenharmony_ci /* disable the transmitter */ 17628c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 17638c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 17648c2ecf20Sopenharmony_ci } else { 17658c2ecf20Sopenharmony_ci /* disable the encoder and transmitter */ 17668c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, 17678c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 17688c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 17718c2ecf20Sopenharmony_ci if (travis_quirk) 17728c2ecf20Sopenharmony_ci radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); 17738c2ecf20Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 17748c2ecf20Sopenharmony_ci atombios_set_edp_panel_power(connector, 17758c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_POWER_OFF); 17768c2ecf20Sopenharmony_ci radeon_dig_connector->edp_on = false; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci break; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic void 17848c2ecf20Sopenharmony_ciradeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 17878c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17888c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 17898c2ecf20Sopenharmony_ci int encoder_mode = atombios_get_encoder_mode(encoder); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", 17928c2ecf20Sopenharmony_ci radeon_encoder->encoder_id, mode, radeon_encoder->devices, 17938c2ecf20Sopenharmony_ci radeon_encoder->active_device); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if ((radeon_audio != 0) && 17968c2ecf20Sopenharmony_ci ((encoder_mode == ATOM_ENCODER_MODE_HDMI) || 17978c2ecf20Sopenharmony_ci ENCODER_MODE_IS_DP(encoder_mode))) 17988c2ecf20Sopenharmony_ci radeon_audio_dpms(encoder, mode); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 18018c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 18028c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 18038c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 18048c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 18058c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 18068c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 18078c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 18088c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 18098c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms_avivo(encoder, mode); 18108c2ecf20Sopenharmony_ci break; 18118c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 18128c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 18138c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 18148c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 18158c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 18168c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms_dig(encoder, mode); 18178c2ecf20Sopenharmony_ci break; 18188c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 18198c2ecf20Sopenharmony_ci if (ASIC_IS_DCE5(rdev)) { 18208c2ecf20Sopenharmony_ci switch (mode) { 18218c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 18228c2ecf20Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_ENABLE); 18238c2ecf20Sopenharmony_ci break; 18248c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 18258c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 18268c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 18278c2ecf20Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_DISABLE); 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE3(rdev)) 18318c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms_dig(encoder, mode); 18328c2ecf20Sopenharmony_ci else 18338c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms_avivo(encoder, mode); 18348c2ecf20Sopenharmony_ci break; 18358c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 18368c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 18378c2ecf20Sopenharmony_ci if (ASIC_IS_DCE5(rdev)) { 18388c2ecf20Sopenharmony_ci switch (mode) { 18398c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 18408c2ecf20Sopenharmony_ci atombios_dac_setup(encoder, ATOM_ENABLE); 18418c2ecf20Sopenharmony_ci break; 18428c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 18438c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 18448c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 18458c2ecf20Sopenharmony_ci atombios_dac_setup(encoder, ATOM_DISABLE); 18468c2ecf20Sopenharmony_ci break; 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci } else 18498c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms_avivo(encoder, mode); 18508c2ecf20Sopenharmony_ci break; 18518c2ecf20Sopenharmony_ci default: 18528c2ecf20Sopenharmony_ci return; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ciunion crtc_source_param { 18608c2ecf20Sopenharmony_ci SELECT_CRTC_SOURCE_PS_ALLOCATION v1; 18618c2ecf20Sopenharmony_ci SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; 18628c2ecf20Sopenharmony_ci}; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_cistatic void 18658c2ecf20Sopenharmony_ciatombios_set_encoder_crtc_source(struct drm_encoder *encoder) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 18688c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 18698c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 18708c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 18718c2ecf20Sopenharmony_ci union crtc_source_param args; 18728c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); 18738c2ecf20Sopenharmony_ci uint8_t frev, crev; 18748c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 18798c2ecf20Sopenharmony_ci return; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci switch (frev) { 18828c2ecf20Sopenharmony_ci case 1: 18838c2ecf20Sopenharmony_ci switch (crev) { 18848c2ecf20Sopenharmony_ci case 1: 18858c2ecf20Sopenharmony_ci default: 18868c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 18878c2ecf20Sopenharmony_ci args.v1.ucCRTC = radeon_crtc->crtc_id; 18888c2ecf20Sopenharmony_ci else { 18898c2ecf20Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) 18908c2ecf20Sopenharmony_ci args.v1.ucCRTC = radeon_crtc->crtc_id; 18918c2ecf20Sopenharmony_ci else 18928c2ecf20Sopenharmony_ci args.v1.ucCRTC = radeon_crtc->crtc_id << 2; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 18958c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 18968c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 18978c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; 18988c2ecf20Sopenharmony_ci break; 18998c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 19008c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 19018c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) 19028c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; 19038c2ecf20Sopenharmony_ci else 19048c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; 19058c2ecf20Sopenharmony_ci break; 19068c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 19078c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 19088c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 19098c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; 19108c2ecf20Sopenharmony_ci break; 19118c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 19128c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 19138c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 19148c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 19158c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 19168c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 19178c2ecf20Sopenharmony_ci else 19188c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; 19198c2ecf20Sopenharmony_ci break; 19208c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 19218c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 19228c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 19238c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 19248c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 19258c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 19268c2ecf20Sopenharmony_ci else 19278c2ecf20Sopenharmony_ci args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; 19288c2ecf20Sopenharmony_ci break; 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci case 2: 19328c2ecf20Sopenharmony_ci args.v2.ucCRTC = radeon_crtc->crtc_id; 19338c2ecf20Sopenharmony_ci if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) { 19348c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) 19378c2ecf20Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; 19388c2ecf20Sopenharmony_ci else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) 19398c2ecf20Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; 19408c2ecf20Sopenharmony_ci else 19418c2ecf20Sopenharmony_ci args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); 19428c2ecf20Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 19438c2ecf20Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; 19448c2ecf20Sopenharmony_ci } else { 19458c2ecf20Sopenharmony_ci args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 19488c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 19498c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 19508c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 19518c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 19528c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 19538c2ecf20Sopenharmony_ci dig = radeon_encoder->enc_priv; 19548c2ecf20Sopenharmony_ci switch (dig->dig_encoder) { 19558c2ecf20Sopenharmony_ci case 0: 19568c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; 19578c2ecf20Sopenharmony_ci break; 19588c2ecf20Sopenharmony_ci case 1: 19598c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; 19608c2ecf20Sopenharmony_ci break; 19618c2ecf20Sopenharmony_ci case 2: 19628c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; 19638c2ecf20Sopenharmony_ci break; 19648c2ecf20Sopenharmony_ci case 3: 19658c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; 19668c2ecf20Sopenharmony_ci break; 19678c2ecf20Sopenharmony_ci case 4: 19688c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; 19698c2ecf20Sopenharmony_ci break; 19708c2ecf20Sopenharmony_ci case 5: 19718c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; 19728c2ecf20Sopenharmony_ci break; 19738c2ecf20Sopenharmony_ci case 6: 19748c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID; 19758c2ecf20Sopenharmony_ci break; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci break; 19788c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 19798c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; 19808c2ecf20Sopenharmony_ci break; 19818c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 19828c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 19838c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 19848c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 19858c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 19868c2ecf20Sopenharmony_ci else 19878c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; 19888c2ecf20Sopenharmony_ci break; 19898c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 19908c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 19918c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 19928c2ecf20Sopenharmony_ci else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 19938c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 19948c2ecf20Sopenharmony_ci else 19958c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci break; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci break; 20018c2ecf20Sopenharmony_ci default: 20028c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 20038c2ecf20Sopenharmony_ci return; 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci /* update scratch regs with new routing */ 20098c2ecf20Sopenharmony_ci radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 20108c2ecf20Sopenharmony_ci} 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_civoid 20138c2ecf20Sopenharmony_ciatombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 20168c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 20178c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 20188c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); 20198c2ecf20Sopenharmony_ci uint8_t frev, crev; 20208c2ecf20Sopenharmony_ci union crtc_source_param args; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 20258c2ecf20Sopenharmony_ci return; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (frev != 1 && crev != 2) 20288c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci args.v2.ucCRTC = radeon_crtc->crtc_id; 20318c2ecf20Sopenharmony_ci args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci switch (fe) { 20348c2ecf20Sopenharmony_ci case 0: 20358c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; 20368c2ecf20Sopenharmony_ci break; 20378c2ecf20Sopenharmony_ci case 1: 20388c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; 20398c2ecf20Sopenharmony_ci break; 20408c2ecf20Sopenharmony_ci case 2: 20418c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; 20428c2ecf20Sopenharmony_ci break; 20438c2ecf20Sopenharmony_ci case 3: 20448c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; 20458c2ecf20Sopenharmony_ci break; 20468c2ecf20Sopenharmony_ci case 4: 20478c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; 20488c2ecf20Sopenharmony_ci break; 20498c2ecf20Sopenharmony_ci case 5: 20508c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; 20518c2ecf20Sopenharmony_ci break; 20528c2ecf20Sopenharmony_ci case 6: 20538c2ecf20Sopenharmony_ci args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID; 20548c2ecf20Sopenharmony_ci break; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 20578c2ecf20Sopenharmony_ci} 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_cistatic void 20608c2ecf20Sopenharmony_ciatombios_apply_encoder_quirks(struct drm_encoder *encoder, 20618c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 20628c2ecf20Sopenharmony_ci{ 20638c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 20648c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 20658c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 20668c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci /* Funky macbooks */ 20698c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x71C5) && 20708c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x106b) && 20718c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x0080)) { 20728c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { 20738c2ecf20Sopenharmony_ci uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; 20768c2ecf20Sopenharmony_ci lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* set scaler clears this on some chips */ 20838c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev) && 20848c2ecf20Sopenharmony_ci (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { 20858c2ecf20Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) { 20868c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 20878c2ecf20Sopenharmony_ci WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 20888c2ecf20Sopenharmony_ci CIK_INTERLEAVE_EN); 20898c2ecf20Sopenharmony_ci else 20908c2ecf20Sopenharmony_ci WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 20918c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 20928c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 20938c2ecf20Sopenharmony_ci WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 20948c2ecf20Sopenharmony_ci EVERGREEN_INTERLEAVE_EN); 20958c2ecf20Sopenharmony_ci else 20968c2ecf20Sopenharmony_ci WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 20978c2ecf20Sopenharmony_ci } else { 20988c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 20998c2ecf20Sopenharmony_ci WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 21008c2ecf20Sopenharmony_ci AVIVO_D1MODE_INTERLEAVE_EN); 21018c2ecf20Sopenharmony_ci else 21028c2ecf20Sopenharmony_ci WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci} 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_civoid radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx) 21088c2ecf20Sopenharmony_ci{ 21098c2ecf20Sopenharmony_ci if (enc_idx < 0) 21108c2ecf20Sopenharmony_ci return; 21118c2ecf20Sopenharmony_ci rdev->mode_info.active_encoders &= ~(1 << enc_idx); 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ciint radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx) 21158c2ecf20Sopenharmony_ci{ 21168c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 21178c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 21188c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 21198c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 21208c2ecf20Sopenharmony_ci struct drm_encoder *test_encoder; 21218c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 21228c2ecf20Sopenharmony_ci uint32_t dig_enc_in_use = 0; 21238c2ecf20Sopenharmony_ci int enc_idx = -1; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (fe_idx >= 0) { 21268c2ecf20Sopenharmony_ci enc_idx = fe_idx; 21278c2ecf20Sopenharmony_ci goto assigned; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) { 21308c2ecf20Sopenharmony_ci /* DCE6 */ 21318c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 21328c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 21338c2ecf20Sopenharmony_ci if (dig->linkb) 21348c2ecf20Sopenharmony_ci enc_idx = 1; 21358c2ecf20Sopenharmony_ci else 21368c2ecf20Sopenharmony_ci enc_idx = 0; 21378c2ecf20Sopenharmony_ci break; 21388c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 21398c2ecf20Sopenharmony_ci if (dig->linkb) 21408c2ecf20Sopenharmony_ci enc_idx = 3; 21418c2ecf20Sopenharmony_ci else 21428c2ecf20Sopenharmony_ci enc_idx = 2; 21438c2ecf20Sopenharmony_ci break; 21448c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 21458c2ecf20Sopenharmony_ci if (dig->linkb) 21468c2ecf20Sopenharmony_ci enc_idx = 5; 21478c2ecf20Sopenharmony_ci else 21488c2ecf20Sopenharmony_ci enc_idx = 4; 21498c2ecf20Sopenharmony_ci break; 21508c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 21518c2ecf20Sopenharmony_ci enc_idx = 6; 21528c2ecf20Sopenharmony_ci break; 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci goto assigned; 21558c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 21568c2ecf20Sopenharmony_ci /* DCE4/5 */ 21578c2ecf20Sopenharmony_ci if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { 21588c2ecf20Sopenharmony_ci /* ontario follows DCE4 */ 21598c2ecf20Sopenharmony_ci if (rdev->family == CHIP_PALM) { 21608c2ecf20Sopenharmony_ci if (dig->linkb) 21618c2ecf20Sopenharmony_ci enc_idx = 1; 21628c2ecf20Sopenharmony_ci else 21638c2ecf20Sopenharmony_ci enc_idx = 0; 21648c2ecf20Sopenharmony_ci } else 21658c2ecf20Sopenharmony_ci /* llano follows DCE3.2 */ 21668c2ecf20Sopenharmony_ci enc_idx = radeon_crtc->crtc_id; 21678c2ecf20Sopenharmony_ci } else { 21688c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 21698c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 21708c2ecf20Sopenharmony_ci if (dig->linkb) 21718c2ecf20Sopenharmony_ci enc_idx = 1; 21728c2ecf20Sopenharmony_ci else 21738c2ecf20Sopenharmony_ci enc_idx = 0; 21748c2ecf20Sopenharmony_ci break; 21758c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 21768c2ecf20Sopenharmony_ci if (dig->linkb) 21778c2ecf20Sopenharmony_ci enc_idx = 3; 21788c2ecf20Sopenharmony_ci else 21798c2ecf20Sopenharmony_ci enc_idx = 2; 21808c2ecf20Sopenharmony_ci break; 21818c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 21828c2ecf20Sopenharmony_ci if (dig->linkb) 21838c2ecf20Sopenharmony_ci enc_idx = 5; 21848c2ecf20Sopenharmony_ci else 21858c2ecf20Sopenharmony_ci enc_idx = 4; 21868c2ecf20Sopenharmony_ci break; 21878c2ecf20Sopenharmony_ci } 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci goto assigned; 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci /* 21938c2ecf20Sopenharmony_ci * On DCE32 any encoder can drive any block so usually just use crtc id, 21948c2ecf20Sopenharmony_ci * but Apple thinks different at least on iMac10,1 and iMac11,2, so there use linkb, 21958c2ecf20Sopenharmony_ci * otherwise the internal eDP panel will stay dark. 21968c2ecf20Sopenharmony_ci */ 21978c2ecf20Sopenharmony_ci if (ASIC_IS_DCE32(rdev)) { 21988c2ecf20Sopenharmony_ci if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") || 21998c2ecf20Sopenharmony_ci dmi_match(DMI_PRODUCT_NAME, "iMac11,2")) 22008c2ecf20Sopenharmony_ci enc_idx = (dig->linkb) ? 1 : 0; 22018c2ecf20Sopenharmony_ci else 22028c2ecf20Sopenharmony_ci enc_idx = radeon_crtc->crtc_id; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci goto assigned; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci /* on DCE3 - LVTMA can only be driven by DIGB */ 22088c2ecf20Sopenharmony_ci list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 22098c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_test_encoder; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci if (encoder == test_encoder) 22128c2ecf20Sopenharmony_ci continue; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (!radeon_encoder_is_digital(test_encoder)) 22158c2ecf20Sopenharmony_ci continue; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci radeon_test_encoder = to_radeon_encoder(test_encoder); 22188c2ecf20Sopenharmony_ci dig = radeon_test_encoder->enc_priv; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (dig->dig_encoder >= 0) 22218c2ecf20Sopenharmony_ci dig_enc_in_use |= (1 << dig->dig_encoder); 22228c2ecf20Sopenharmony_ci } 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { 22258c2ecf20Sopenharmony_ci if (dig_enc_in_use & 0x2) 22268c2ecf20Sopenharmony_ci DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); 22278c2ecf20Sopenharmony_ci return 1; 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci if (!(dig_enc_in_use & 1)) 22308c2ecf20Sopenharmony_ci return 0; 22318c2ecf20Sopenharmony_ci return 1; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ciassigned: 22348c2ecf20Sopenharmony_ci if (enc_idx == -1) { 22358c2ecf20Sopenharmony_ci DRM_ERROR("Got encoder index incorrect - returning 0\n"); 22368c2ecf20Sopenharmony_ci return 0; 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci if (rdev->mode_info.active_encoders & (1 << enc_idx)) 22398c2ecf20Sopenharmony_ci DRM_ERROR("chosen encoder in use %d\n", enc_idx); 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci rdev->mode_info.active_encoders |= (1 << enc_idx); 22428c2ecf20Sopenharmony_ci return enc_idx; 22438c2ecf20Sopenharmony_ci} 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci/* This only needs to be called once at startup */ 22468c2ecf20Sopenharmony_civoid 22478c2ecf20Sopenharmony_ciradeon_atom_encoder_init(struct radeon_device *rdev) 22488c2ecf20Sopenharmony_ci{ 22498c2ecf20Sopenharmony_ci struct drm_device *dev = rdev->ddev; 22508c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 22538c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 22548c2ecf20Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 22578c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 22588c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 22598c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 22608c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 22618c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 22628c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 22638c2ecf20Sopenharmony_ci break; 22648c2ecf20Sopenharmony_ci default: 22658c2ecf20Sopenharmony_ci break; 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci if (ext_encoder && (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))) 22698c2ecf20Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 22708c2ecf20Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); 22718c2ecf20Sopenharmony_ci } 22728c2ecf20Sopenharmony_ci} 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_cistatic void 22758c2ecf20Sopenharmony_ciradeon_atom_encoder_mode_set(struct drm_encoder *encoder, 22768c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 22778c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 22788c2ecf20Sopenharmony_ci{ 22798c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 22808c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 22818c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 22828c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 22838c2ecf20Sopenharmony_ci int encoder_mode; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci radeon_encoder->pixel_clock = adjusted_mode->clock; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci /* need to call this here rather than in prepare() since we need some crtc info */ 22888c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { 22918c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) 22928c2ecf20Sopenharmony_ci atombios_yuv_setup(encoder, true); 22938c2ecf20Sopenharmony_ci else 22948c2ecf20Sopenharmony_ci atombios_yuv_setup(encoder, false); 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 22988c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 22998c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 23008c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 23018c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 23028c2ecf20Sopenharmony_ci atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); 23038c2ecf20Sopenharmony_ci break; 23048c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 23058c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 23068c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 23078c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 23088c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 23098c2ecf20Sopenharmony_ci /* handled in dpms */ 23108c2ecf20Sopenharmony_ci break; 23118c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 23128c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 23138c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 23148c2ecf20Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_ENABLE); 23158c2ecf20Sopenharmony_ci break; 23168c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 23178c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 23188c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 23198c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 23208c2ecf20Sopenharmony_ci atombios_dac_setup(encoder, ATOM_ENABLE); 23218c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { 23228c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 23238c2ecf20Sopenharmony_ci atombios_tv_setup(encoder, ATOM_ENABLE); 23248c2ecf20Sopenharmony_ci else 23258c2ecf20Sopenharmony_ci atombios_tv_setup(encoder, ATOM_DISABLE); 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci break; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci atombios_apply_encoder_quirks(encoder, adjusted_mode); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci encoder_mode = atombios_get_encoder_mode(encoder); 23338c2ecf20Sopenharmony_ci if (connector && (radeon_audio != 0) && 23348c2ecf20Sopenharmony_ci ((encoder_mode == ATOM_ENCODER_MODE_HDMI) || 23358c2ecf20Sopenharmony_ci ENCODER_MODE_IS_DP(encoder_mode))) 23368c2ecf20Sopenharmony_ci radeon_audio_mode_set(encoder, adjusted_mode); 23378c2ecf20Sopenharmony_ci} 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_cistatic bool 23408c2ecf20Sopenharmony_ciatombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) 23418c2ecf20Sopenharmony_ci{ 23428c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 23438c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 23448c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 23458c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | 23488c2ecf20Sopenharmony_ci ATOM_DEVICE_CV_SUPPORT | 23498c2ecf20Sopenharmony_ci ATOM_DEVICE_CRT_SUPPORT)) { 23508c2ecf20Sopenharmony_ci DAC_LOAD_DETECTION_PS_ALLOCATION args; 23518c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); 23528c2ecf20Sopenharmony_ci uint8_t frev, crev; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 23578c2ecf20Sopenharmony_ci return false; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci args.sDacload.ucMisc = 0; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 23628c2ecf20Sopenharmony_ci (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) 23638c2ecf20Sopenharmony_ci args.sDacload.ucDacType = ATOM_DAC_A; 23648c2ecf20Sopenharmony_ci else 23658c2ecf20Sopenharmony_ci args.sDacload.ucDacType = ATOM_DAC_B; 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) 23688c2ecf20Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); 23698c2ecf20Sopenharmony_ci else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) 23708c2ecf20Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); 23718c2ecf20Sopenharmony_ci else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 23728c2ecf20Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); 23738c2ecf20Sopenharmony_ci if (crev >= 3) 23748c2ecf20Sopenharmony_ci args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 23758c2ecf20Sopenharmony_ci } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 23768c2ecf20Sopenharmony_ci args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); 23778c2ecf20Sopenharmony_ci if (crev >= 3) 23788c2ecf20Sopenharmony_ci args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 23798c2ecf20Sopenharmony_ci } 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci return true; 23848c2ecf20Sopenharmony_ci } else 23858c2ecf20Sopenharmony_ci return false; 23868c2ecf20Sopenharmony_ci} 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_cistatic enum drm_connector_status 23898c2ecf20Sopenharmony_ciradeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) 23908c2ecf20Sopenharmony_ci{ 23918c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 23928c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 23938c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 23948c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 23958c2ecf20Sopenharmony_ci uint32_t bios_0_scratch; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (!atombios_dac_load_detect(encoder, connector)) { 23988c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("detect returned false \n"); 23998c2ecf20Sopenharmony_ci return connector_status_unknown; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 24038c2ecf20Sopenharmony_ci bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 24048c2ecf20Sopenharmony_ci else 24058c2ecf20Sopenharmony_ci bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); 24088c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { 24098c2ecf20Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT1_MASK) 24108c2ecf20Sopenharmony_ci return connector_status_connected; 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { 24138c2ecf20Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT2_MASK) 24148c2ecf20Sopenharmony_ci return connector_status_connected; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 24178c2ecf20Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) 24188c2ecf20Sopenharmony_ci return connector_status_connected; 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 24218c2ecf20Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 24228c2ecf20Sopenharmony_ci return connector_status_connected; /* CTV */ 24238c2ecf20Sopenharmony_ci else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 24248c2ecf20Sopenharmony_ci return connector_status_connected; /* STV */ 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci return connector_status_disconnected; 24278c2ecf20Sopenharmony_ci} 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_cistatic enum drm_connector_status 24308c2ecf20Sopenharmony_ciradeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) 24318c2ecf20Sopenharmony_ci{ 24328c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 24338c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 24348c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 24358c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 24368c2ecf20Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 24378c2ecf20Sopenharmony_ci u32 bios_0_scratch; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci if (!ASIC_IS_DCE4(rdev)) 24408c2ecf20Sopenharmony_ci return connector_status_unknown; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci if (!ext_encoder) 24438c2ecf20Sopenharmony_ci return connector_status_unknown; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) 24468c2ecf20Sopenharmony_ci return connector_status_unknown; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci /* load detect on the dp bridge */ 24498c2ecf20Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 24508c2ecf20Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); 24558c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { 24568c2ecf20Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT1_MASK) 24578c2ecf20Sopenharmony_ci return connector_status_connected; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { 24608c2ecf20Sopenharmony_ci if (bios_0_scratch & ATOM_S0_CRT2_MASK) 24618c2ecf20Sopenharmony_ci return connector_status_connected; 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 24648c2ecf20Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) 24658c2ecf20Sopenharmony_ci return connector_status_connected; 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 24688c2ecf20Sopenharmony_ci if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 24698c2ecf20Sopenharmony_ci return connector_status_connected; /* CTV */ 24708c2ecf20Sopenharmony_ci else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 24718c2ecf20Sopenharmony_ci return connector_status_connected; /* STV */ 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci return connector_status_disconnected; 24748c2ecf20Sopenharmony_ci} 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_civoid 24778c2ecf20Sopenharmony_ciradeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci if (ext_encoder) 24828c2ecf20Sopenharmony_ci /* ddc_setup on the dp bridge */ 24838c2ecf20Sopenharmony_ci atombios_external_encoder_setup(encoder, ext_encoder, 24848c2ecf20Sopenharmony_ci EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci} 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_cistatic void radeon_atom_encoder_prepare(struct drm_encoder *encoder) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 24918c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 24928c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if ((radeon_encoder->active_device & 24958c2ecf20Sopenharmony_ci (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || 24968c2ecf20Sopenharmony_ci (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 24978c2ecf20Sopenharmony_ci ENCODER_OBJECT_ID_NONE)) { 24988c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 24998c2ecf20Sopenharmony_ci if (dig) { 25008c2ecf20Sopenharmony_ci if (dig->dig_encoder >= 0) 25018c2ecf20Sopenharmony_ci radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); 25028c2ecf20Sopenharmony_ci dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1); 25038c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) { 25048c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 25058c2ecf20Sopenharmony_ci dig->afmt = rdev->mode_info.afmt[dig->dig_encoder]; 25068c2ecf20Sopenharmony_ci else 25078c2ecf20Sopenharmony_ci /* RS600/690/740 have only 1 afmt block */ 25088c2ecf20Sopenharmony_ci dig->afmt = rdev->mode_info.afmt[0]; 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, true); 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci if (connector) { 25168c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci /* select the clock/data port if it uses a router */ 25198c2ecf20Sopenharmony_ci if (radeon_connector->router.cd_valid) 25208c2ecf20Sopenharmony_ci radeon_router_select_cd_port(radeon_connector); 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci /* turn eDP panel on for mode set */ 25238c2ecf20Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) 25248c2ecf20Sopenharmony_ci atombios_set_edp_panel_power(connector, 25258c2ecf20Sopenharmony_ci ATOM_TRANSMITTER_ACTION_POWER_ON); 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci /* this is needed for the pll/ss setup to work correctly in some cases */ 25298c2ecf20Sopenharmony_ci atombios_set_encoder_crtc_source(encoder); 25308c2ecf20Sopenharmony_ci /* set up the FMT blocks */ 25318c2ecf20Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) 25328c2ecf20Sopenharmony_ci dce8_program_fmt(encoder); 25338c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE4(rdev)) 25348c2ecf20Sopenharmony_ci dce4_program_fmt(encoder); 25358c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE3(rdev)) 25368c2ecf20Sopenharmony_ci dce3_program_fmt(encoder); 25378c2ecf20Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) 25388c2ecf20Sopenharmony_ci avivo_program_fmt(encoder); 25398c2ecf20Sopenharmony_ci} 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_cistatic void radeon_atom_encoder_commit(struct drm_encoder *encoder) 25428c2ecf20Sopenharmony_ci{ 25438c2ecf20Sopenharmony_ci /* need to call this here as we need the crtc set up */ 25448c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); 25458c2ecf20Sopenharmony_ci radeon_atom_output_lock(encoder, false); 25468c2ecf20Sopenharmony_ci} 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_cistatic void radeon_atom_encoder_disable(struct drm_encoder *encoder) 25498c2ecf20Sopenharmony_ci{ 25508c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 25518c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 25528c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 25538c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci /* check for pre-DCE3 cards with shared encoders; 25568c2ecf20Sopenharmony_ci * can't really use the links individually, so don't disable 25578c2ecf20Sopenharmony_ci * the encoder if it's in use by another connector 25588c2ecf20Sopenharmony_ci */ 25598c2ecf20Sopenharmony_ci if (!ASIC_IS_DCE3(rdev)) { 25608c2ecf20Sopenharmony_ci struct drm_encoder *other_encoder; 25618c2ecf20Sopenharmony_ci struct radeon_encoder *other_radeon_encoder; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { 25648c2ecf20Sopenharmony_ci other_radeon_encoder = to_radeon_encoder(other_encoder); 25658c2ecf20Sopenharmony_ci if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && 25668c2ecf20Sopenharmony_ci drm_helper_encoder_in_use(other_encoder)) 25678c2ecf20Sopenharmony_ci goto disable_done; 25688c2ecf20Sopenharmony_ci } 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 25748c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 25758c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 25768c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 25778c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 25788c2ecf20Sopenharmony_ci atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); 25798c2ecf20Sopenharmony_ci break; 25808c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 25818c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 25828c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 25838c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 25848c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 25858c2ecf20Sopenharmony_ci /* handled in dpms */ 25868c2ecf20Sopenharmony_ci break; 25878c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 25888c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 25898c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 25908c2ecf20Sopenharmony_ci atombios_dvo_setup(encoder, ATOM_DISABLE); 25918c2ecf20Sopenharmony_ci break; 25928c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 25938c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 25948c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 25958c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 25968c2ecf20Sopenharmony_ci atombios_dac_setup(encoder, ATOM_DISABLE); 25978c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 25988c2ecf20Sopenharmony_ci atombios_tv_setup(encoder, ATOM_DISABLE); 25998c2ecf20Sopenharmony_ci break; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_cidisable_done: 26038c2ecf20Sopenharmony_ci if (radeon_encoder_is_digital(encoder)) { 26048c2ecf20Sopenharmony_ci if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { 26058c2ecf20Sopenharmony_ci if (rdev->asic->display.hdmi_enable) 26068c2ecf20Sopenharmony_ci radeon_hdmi_enable(rdev, encoder, false); 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) { 26098c2ecf20Sopenharmony_ci dig = radeon_encoder->enc_priv; 26108c2ecf20Sopenharmony_ci radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); 26118c2ecf20Sopenharmony_ci dig->dig_encoder = -1; 26128c2ecf20Sopenharmony_ci radeon_encoder->active_device = 0; 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci } else 26158c2ecf20Sopenharmony_ci radeon_encoder->active_device = 0; 26168c2ecf20Sopenharmony_ci} 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci/* these are handled by the primary encoders */ 26198c2ecf20Sopenharmony_cistatic void radeon_atom_ext_prepare(struct drm_encoder *encoder) 26208c2ecf20Sopenharmony_ci{ 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci} 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_cistatic void radeon_atom_ext_commit(struct drm_encoder *encoder) 26258c2ecf20Sopenharmony_ci{ 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci} 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_cistatic void 26308c2ecf20Sopenharmony_ciradeon_atom_ext_mode_set(struct drm_encoder *encoder, 26318c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 26328c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 26338c2ecf20Sopenharmony_ci{ 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci} 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_cistatic void radeon_atom_ext_disable(struct drm_encoder *encoder) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_cistatic void 26438c2ecf20Sopenharmony_ciradeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) 26448c2ecf20Sopenharmony_ci{ 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci} 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { 26498c2ecf20Sopenharmony_ci .dpms = radeon_atom_ext_dpms, 26508c2ecf20Sopenharmony_ci .prepare = radeon_atom_ext_prepare, 26518c2ecf20Sopenharmony_ci .mode_set = radeon_atom_ext_mode_set, 26528c2ecf20Sopenharmony_ci .commit = radeon_atom_ext_commit, 26538c2ecf20Sopenharmony_ci .disable = radeon_atom_ext_disable, 26548c2ecf20Sopenharmony_ci /* no detect for TMDS/LVDS yet */ 26558c2ecf20Sopenharmony_ci}; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { 26588c2ecf20Sopenharmony_ci .dpms = radeon_atom_encoder_dpms, 26598c2ecf20Sopenharmony_ci .mode_fixup = radeon_atom_mode_fixup, 26608c2ecf20Sopenharmony_ci .prepare = radeon_atom_encoder_prepare, 26618c2ecf20Sopenharmony_ci .mode_set = radeon_atom_encoder_mode_set, 26628c2ecf20Sopenharmony_ci .commit = radeon_atom_encoder_commit, 26638c2ecf20Sopenharmony_ci .disable = radeon_atom_encoder_disable, 26648c2ecf20Sopenharmony_ci .detect = radeon_atom_dig_detect, 26658c2ecf20Sopenharmony_ci}; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { 26688c2ecf20Sopenharmony_ci .dpms = radeon_atom_encoder_dpms, 26698c2ecf20Sopenharmony_ci .mode_fixup = radeon_atom_mode_fixup, 26708c2ecf20Sopenharmony_ci .prepare = radeon_atom_encoder_prepare, 26718c2ecf20Sopenharmony_ci .mode_set = radeon_atom_encoder_mode_set, 26728c2ecf20Sopenharmony_ci .commit = radeon_atom_encoder_commit, 26738c2ecf20Sopenharmony_ci .detect = radeon_atom_dac_detect, 26748c2ecf20Sopenharmony_ci}; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_civoid radeon_enc_destroy(struct drm_encoder *encoder) 26778c2ecf20Sopenharmony_ci{ 26788c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 26798c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 26808c2ecf20Sopenharmony_ci radeon_atom_backlight_exit(radeon_encoder); 26818c2ecf20Sopenharmony_ci kfree(radeon_encoder->enc_priv); 26828c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 26838c2ecf20Sopenharmony_ci kfree(radeon_encoder); 26848c2ecf20Sopenharmony_ci} 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_atom_enc_funcs = { 26878c2ecf20Sopenharmony_ci .destroy = radeon_enc_destroy, 26888c2ecf20Sopenharmony_ci}; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_cistatic struct radeon_encoder_atom_dac * 26918c2ecf20Sopenharmony_ciradeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) 26928c2ecf20Sopenharmony_ci{ 26938c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 26948c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 26958c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci if (!dac) 26988c2ecf20Sopenharmony_ci return NULL; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci dac->tv_std = radeon_atombios_get_tv_info(rdev); 27018c2ecf20Sopenharmony_ci return dac; 27028c2ecf20Sopenharmony_ci} 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_cistatic struct radeon_encoder_atom_dig * 27058c2ecf20Sopenharmony_ciradeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) 27068c2ecf20Sopenharmony_ci{ 27078c2ecf20Sopenharmony_ci int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 27088c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci if (!dig) 27118c2ecf20Sopenharmony_ci return NULL; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci /* coherent mode by default */ 27148c2ecf20Sopenharmony_ci dig->coherent_mode = true; 27158c2ecf20Sopenharmony_ci dig->dig_encoder = -1; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci if (encoder_enum == 2) 27188c2ecf20Sopenharmony_ci dig->linkb = true; 27198c2ecf20Sopenharmony_ci else 27208c2ecf20Sopenharmony_ci dig->linkb = false; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci return dig; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_civoid 27268c2ecf20Sopenharmony_ciradeon_add_atom_encoder(struct drm_device *dev, 27278c2ecf20Sopenharmony_ci uint32_t encoder_enum, 27288c2ecf20Sopenharmony_ci uint32_t supported_device, 27298c2ecf20Sopenharmony_ci u16 caps) 27308c2ecf20Sopenharmony_ci{ 27318c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 27328c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 27338c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci /* see if we already added it */ 27368c2ecf20Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 27378c2ecf20Sopenharmony_ci radeon_encoder = to_radeon_encoder(encoder); 27388c2ecf20Sopenharmony_ci if (radeon_encoder->encoder_enum == encoder_enum) { 27398c2ecf20Sopenharmony_ci radeon_encoder->devices |= supported_device; 27408c2ecf20Sopenharmony_ci return; 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci } 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci /* add a new one */ 27468c2ecf20Sopenharmony_ci radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); 27478c2ecf20Sopenharmony_ci if (!radeon_encoder) 27488c2ecf20Sopenharmony_ci return; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci encoder = &radeon_encoder->base; 27518c2ecf20Sopenharmony_ci switch (rdev->num_crtc) { 27528c2ecf20Sopenharmony_ci case 1: 27538c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x1; 27548c2ecf20Sopenharmony_ci break; 27558c2ecf20Sopenharmony_ci case 2: 27568c2ecf20Sopenharmony_ci default: 27578c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x3; 27588c2ecf20Sopenharmony_ci break; 27598c2ecf20Sopenharmony_ci case 4: 27608c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0xf; 27618c2ecf20Sopenharmony_ci break; 27628c2ecf20Sopenharmony_ci case 6: 27638c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x3f; 27648c2ecf20Sopenharmony_ci break; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = NULL; 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci radeon_encoder->encoder_enum = encoder_enum; 27708c2ecf20Sopenharmony_ci radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 27718c2ecf20Sopenharmony_ci radeon_encoder->devices = supported_device; 27728c2ecf20Sopenharmony_ci radeon_encoder->rmx_type = RMX_OFF; 27738c2ecf20Sopenharmony_ci radeon_encoder->underscan_type = UNDERSCAN_OFF; 27748c2ecf20Sopenharmony_ci radeon_encoder->is_ext_encoder = false; 27758c2ecf20Sopenharmony_ci radeon_encoder->caps = caps; 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci switch (radeon_encoder->encoder_id) { 27788c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVDS: 27798c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 27808c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 27818c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 27828c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 27838c2ecf20Sopenharmony_ci radeon_encoder->rmx_type = RMX_FULL; 27848c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 27858c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 27868c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 27878c2ecf20Sopenharmony_ci } else { 27888c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 27898c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 27908c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 27918c2ecf20Sopenharmony_ci } 27928c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); 27938c2ecf20Sopenharmony_ci break; 27948c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC1: 27958c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 27968c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 27978c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); 27988c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); 27998c2ecf20Sopenharmony_ci break; 28008c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DAC2: 28018c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 28028c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 28038c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28048c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TVDAC, NULL); 28058c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); 28068c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); 28078c2ecf20Sopenharmony_ci break; 28088c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DVO1: 28098c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 28108c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_DDI: 28118c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 28128c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 28138c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 28148c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 28158c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 28168c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 28178c2ecf20Sopenharmony_ci radeon_encoder->rmx_type = RMX_FULL; 28188c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28198c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 28208c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 28218c2ecf20Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { 28228c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28238c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 28248c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 28258c2ecf20Sopenharmony_ci } else { 28268c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28278c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 28288c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 28298c2ecf20Sopenharmony_ci } 28308c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); 28318c2ecf20Sopenharmony_ci break; 28328c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_SI170B: 28338c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_CH7303: 28348c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: 28358c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: 28368c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_TITFP513: 28378c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_VT1623: 28388c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_HDMI_SI1930: 28398c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_TRAVIS: 28408c2ecf20Sopenharmony_ci case ENCODER_OBJECT_ID_NUTMEG: 28418c2ecf20Sopenharmony_ci /* these are handled by the primary encoders */ 28428c2ecf20Sopenharmony_ci radeon_encoder->is_ext_encoder = true; 28438c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 28448c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28458c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_LVDS, NULL); 28468c2ecf20Sopenharmony_ci else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) 28478c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28488c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_DAC, NULL); 28498c2ecf20Sopenharmony_ci else 28508c2ecf20Sopenharmony_ci drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 28518c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TMDS, NULL); 28528c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); 28538c2ecf20Sopenharmony_ci break; 28548c2ecf20Sopenharmony_ci } 28558c2ecf20Sopenharmony_ci} 2856