1926deccbSFrançois Tigeot /* 2926deccbSFrançois Tigeot * Copyright 2007-11 Advanced Micro Devices, Inc. 3926deccbSFrançois Tigeot * Copyright 2008 Red Hat Inc. 4926deccbSFrançois Tigeot * 5926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 6926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 7926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation 8926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 10926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 11926deccbSFrançois Tigeot * 12926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in 13926deccbSFrançois Tigeot * all copies or substantial portions of the Software. 14926deccbSFrançois Tigeot * 15926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE. 22926deccbSFrançois Tigeot * 23926deccbSFrançois Tigeot * Authors: Dave Airlie 24926deccbSFrançois Tigeot * Alex Deucher 25926deccbSFrançois Tigeot */ 26926deccbSFrançois Tigeot #include <drm/drmP.h> 27926deccbSFrançois Tigeot #include <drm/drm_crtc_helper.h> 28926deccbSFrançois Tigeot #include <uapi_drm/radeon_drm.h> 29926deccbSFrançois Tigeot #include "radeon.h" 304cd92098Szrj #include "radeon_asic.h" 31926deccbSFrançois Tigeot #include "atom.h" 32926deccbSFrançois Tigeot 33926deccbSFrançois Tigeot static u8 34926deccbSFrançois Tigeot radeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev) 35926deccbSFrançois Tigeot { 36926deccbSFrançois Tigeot u8 backlight_level; 37926deccbSFrançois Tigeot u32 bios_2_scratch; 38926deccbSFrançois Tigeot 39926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 40926deccbSFrançois Tigeot bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 41926deccbSFrançois Tigeot else 42926deccbSFrançois Tigeot bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 43926deccbSFrançois Tigeot 44926deccbSFrançois Tigeot backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >> 45926deccbSFrançois Tigeot ATOM_S2_CURRENT_BL_LEVEL_SHIFT); 46926deccbSFrançois Tigeot 47926deccbSFrançois Tigeot return backlight_level; 48926deccbSFrançois Tigeot } 49926deccbSFrançois Tigeot 50926deccbSFrançois Tigeot static void 51926deccbSFrançois Tigeot radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, 52926deccbSFrançois Tigeot u8 backlight_level) 53926deccbSFrançois Tigeot { 54926deccbSFrançois Tigeot u32 bios_2_scratch; 55926deccbSFrançois Tigeot 56926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 57926deccbSFrançois Tigeot bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 58926deccbSFrançois Tigeot else 59926deccbSFrançois Tigeot bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 60926deccbSFrançois Tigeot 61926deccbSFrançois Tigeot bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; 62926deccbSFrançois Tigeot bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) & 63926deccbSFrançois Tigeot ATOM_S2_CURRENT_BL_LEVEL_MASK); 64926deccbSFrançois Tigeot 65926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 66926deccbSFrançois Tigeot WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); 67926deccbSFrançois Tigeot else 68926deccbSFrançois Tigeot WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); 69926deccbSFrançois Tigeot } 70926deccbSFrançois Tigeot 71926deccbSFrançois Tigeot u8 72926deccbSFrançois Tigeot atombios_get_backlight_level(struct radeon_encoder *radeon_encoder) 73926deccbSFrançois Tigeot { 74926deccbSFrançois Tigeot struct drm_device *dev = radeon_encoder->base.dev; 75926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 76926deccbSFrançois Tigeot 77926deccbSFrançois Tigeot if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 78926deccbSFrançois Tigeot return 0; 79926deccbSFrançois Tigeot 80926deccbSFrançois Tigeot return radeon_atom_get_backlight_level_from_reg(rdev); 81926deccbSFrançois Tigeot } 82926deccbSFrançois Tigeot 83926deccbSFrançois Tigeot void 84926deccbSFrançois Tigeot atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) 85926deccbSFrançois Tigeot { 86926deccbSFrançois Tigeot struct drm_encoder *encoder = &radeon_encoder->base; 87926deccbSFrançois Tigeot struct drm_device *dev = radeon_encoder->base.dev; 88926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 89926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig; 90926deccbSFrançois Tigeot DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; 91926deccbSFrançois Tigeot int index; 92926deccbSFrançois Tigeot 93926deccbSFrançois Tigeot if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 94926deccbSFrançois Tigeot return; 95926deccbSFrançois Tigeot 96926deccbSFrançois Tigeot if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 97926deccbSFrançois Tigeot radeon_encoder->enc_priv) { 98926deccbSFrançois Tigeot dig = radeon_encoder->enc_priv; 99926deccbSFrançois Tigeot dig->backlight_level = level; 100926deccbSFrançois Tigeot radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level); 101926deccbSFrançois Tigeot 102926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 103926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 104926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 105926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 106926deccbSFrançois Tigeot if (dig->backlight_level == 0) { 107926deccbSFrançois Tigeot args.ucAction = ATOM_LCD_BLOFF; 108926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 109926deccbSFrançois Tigeot } else { 110926deccbSFrançois Tigeot args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL; 111926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 112926deccbSFrançois Tigeot args.ucAction = ATOM_LCD_BLON; 113926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 114926deccbSFrançois Tigeot } 115926deccbSFrançois Tigeot break; 116926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 117926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 118926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 119926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 120926deccbSFrançois Tigeot if (dig->backlight_level == 0) 121926deccbSFrançois Tigeot atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); 122926deccbSFrançois Tigeot else { 123926deccbSFrançois Tigeot atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0); 124926deccbSFrançois Tigeot atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); 125926deccbSFrançois Tigeot } 126926deccbSFrançois Tigeot break; 127926deccbSFrançois Tigeot default: 128926deccbSFrançois Tigeot break; 129926deccbSFrançois Tigeot } 130926deccbSFrançois Tigeot } 131926deccbSFrançois Tigeot } 132926deccbSFrançois Tigeot 133926deccbSFrançois Tigeot #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 134926deccbSFrançois Tigeot 135*ce73550bSFrançois Tigeot #if 0 136926deccbSFrançois Tigeot static u8 radeon_atom_bl_level(struct backlight_device *bd) 137926deccbSFrançois Tigeot { 138926deccbSFrançois Tigeot u8 level; 139926deccbSFrançois Tigeot 140926deccbSFrançois Tigeot /* Convert brightness to hardware level */ 141926deccbSFrançois Tigeot if (bd->props.brightness < 0) 142926deccbSFrançois Tigeot level = 0; 143926deccbSFrançois Tigeot else if (bd->props.brightness > RADEON_MAX_BL_LEVEL) 144926deccbSFrançois Tigeot level = RADEON_MAX_BL_LEVEL; 145926deccbSFrançois Tigeot else 146926deccbSFrançois Tigeot level = bd->props.brightness; 147926deccbSFrançois Tigeot 148926deccbSFrançois Tigeot return level; 149926deccbSFrançois Tigeot } 150926deccbSFrançois Tigeot 151926deccbSFrançois Tigeot static int radeon_atom_backlight_update_status(struct backlight_device *bd) 152926deccbSFrançois Tigeot { 153926deccbSFrançois Tigeot struct radeon_backlight_privdata *pdata = bl_get_data(bd); 154926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = pdata->encoder; 155926deccbSFrançois Tigeot 156926deccbSFrançois Tigeot atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd)); 157926deccbSFrançois Tigeot 158926deccbSFrançois Tigeot return 0; 159926deccbSFrançois Tigeot } 160926deccbSFrançois Tigeot 161926deccbSFrançois Tigeot static int radeon_atom_backlight_get_brightness(struct backlight_device *bd) 162926deccbSFrançois Tigeot { 163926deccbSFrançois Tigeot struct radeon_backlight_privdata *pdata = bl_get_data(bd); 164926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = pdata->encoder; 165926deccbSFrançois Tigeot struct drm_device *dev = radeon_encoder->base.dev; 166926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 167926deccbSFrançois Tigeot 168926deccbSFrançois Tigeot return radeon_atom_get_backlight_level_from_reg(rdev); 169926deccbSFrançois Tigeot } 170926deccbSFrançois Tigeot 171926deccbSFrançois Tigeot static const struct backlight_ops radeon_atom_backlight_ops = { 172926deccbSFrançois Tigeot .get_brightness = radeon_atom_backlight_get_brightness, 173926deccbSFrançois Tigeot .update_status = radeon_atom_backlight_update_status, 174926deccbSFrançois Tigeot }; 175*ce73550bSFrançois Tigeot #endif 176926deccbSFrançois Tigeot 1776a4774b1SImre Vadász /* 1786a4774b1SImre Vadász * Read max backlight level 1796a4774b1SImre Vadász */ 1806a4774b1SImre Vadász static int 1816a4774b1SImre Vadász sysctl_backlight_max(SYSCTL_HANDLER_ARGS) 1826a4774b1SImre Vadász { 1836a4774b1SImre Vadász int err, val; 1846a4774b1SImre Vadász 1856a4774b1SImre Vadász val = RADEON_MAX_BL_LEVEL; 1866a4774b1SImre Vadász err = sysctl_handle_int(oidp, &val, 0, req); 1876a4774b1SImre Vadász return(err); 1886a4774b1SImre Vadász } 1896a4774b1SImre Vadász 1906a4774b1SImre Vadász /* 1916a4774b1SImre Vadász * Read/write backlight level 1926a4774b1SImre Vadász */ 1936a4774b1SImre Vadász static int 1946a4774b1SImre Vadász sysctl_backlight_handler(SYSCTL_HANDLER_ARGS) 1956a4774b1SImre Vadász { 1966a4774b1SImre Vadász struct radeon_encoder *encoder; 1976a4774b1SImre Vadász struct radeon_encoder_atom_dig *dig; 1986a4774b1SImre Vadász int err, val; 1996a4774b1SImre Vadász 2006a4774b1SImre Vadász encoder = (struct radeon_encoder *)arg1; 2016a4774b1SImre Vadász dig = encoder->enc_priv; 2026a4774b1SImre Vadász val = dig->backlight_level; 2036a4774b1SImre Vadász 2046a4774b1SImre Vadász err = sysctl_handle_int(oidp, &val, 0, req); 2056a4774b1SImre Vadász if (err != 0 || req->newptr == NULL) { 2066a4774b1SImre Vadász return(err); 2076a4774b1SImre Vadász } 2086a4774b1SImre Vadász if (dig->backlight_level != val && val >= 0 && 2096a4774b1SImre Vadász val <= RADEON_MAX_BL_LEVEL) { 2106a4774b1SImre Vadász atombios_set_backlight_level(encoder, val); 2116a4774b1SImre Vadász } 2126a4774b1SImre Vadász 2136a4774b1SImre Vadász return(err); 2146a4774b1SImre Vadász } 2156a4774b1SImre Vadász 216926deccbSFrançois Tigeot void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, 217926deccbSFrançois Tigeot struct drm_connector *drm_connector) 218926deccbSFrançois Tigeot { 2196a4774b1SImre Vadász struct drm_device *dev = radeon_encoder->base.dev; 2206a4774b1SImre Vadász struct radeon_device *rdev = dev->dev_private; 2216a4774b1SImre Vadász struct radeon_encoder_atom_dig *dig; 2226a4774b1SImre Vadász 2236a4774b1SImre Vadász if (!radeon_encoder->enc_priv) 2246a4774b1SImre Vadász return; 2256a4774b1SImre Vadász 2266a4774b1SImre Vadász if (!rdev->is_atom_bios) 2276a4774b1SImre Vadász return; 2286a4774b1SImre Vadász 2296a4774b1SImre Vadász if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 2306a4774b1SImre Vadász return; 2316a4774b1SImre Vadász 2326a4774b1SImre Vadász dig = radeon_encoder->enc_priv; 2336a4774b1SImre Vadász dig->backlight_level = radeon_atom_get_backlight_level_from_reg(rdev); 2346a4774b1SImre Vadász 2356a4774b1SImre Vadász DRM_INFO("radeon atom DIG backlight initialized\n"); 2366a4774b1SImre Vadász 2376a4774b1SImre Vadász SYSCTL_ADD_PROC(&drm_connector->dev->sysctl->ctx, &sysctl__hw_children, 2386a4774b1SImre Vadász OID_AUTO, "backlight_max", 2396a4774b1SImre Vadász CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_ANYBODY, 2406a4774b1SImre Vadász radeon_encoder, sizeof(int), 2416a4774b1SImre Vadász sysctl_backlight_max, 2426a4774b1SImre Vadász "I", "Max backlight level"); 2436a4774b1SImre Vadász SYSCTL_ADD_PROC(&drm_connector->dev->sysctl->ctx, &sysctl__hw_children, 2446a4774b1SImre Vadász OID_AUTO, "backlight_level", 2456a4774b1SImre Vadász CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 2466a4774b1SImre Vadász radeon_encoder, sizeof(int), 2476a4774b1SImre Vadász sysctl_backlight_handler, 2486a4774b1SImre Vadász "I", "Backlight level"); 2496a4774b1SImre Vadász return; 250926deccbSFrançois Tigeot } 251926deccbSFrançois Tigeot 252*ce73550bSFrançois Tigeot static void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder) 253*ce73550bSFrançois Tigeot { 254*ce73550bSFrançois Tigeot #if 0 255*ce73550bSFrançois Tigeot struct drm_device *dev = radeon_encoder->base.dev; 256*ce73550bSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 257*ce73550bSFrançois Tigeot struct backlight_device *bd = NULL; 258*ce73550bSFrançois Tigeot struct radeon_encoder_atom_dig *dig; 259*ce73550bSFrançois Tigeot 260*ce73550bSFrançois Tigeot if (!radeon_encoder->enc_priv) 261*ce73550bSFrançois Tigeot return; 262*ce73550bSFrançois Tigeot 263*ce73550bSFrançois Tigeot if (!rdev->is_atom_bios) 264*ce73550bSFrançois Tigeot return; 265*ce73550bSFrançois Tigeot 266*ce73550bSFrançois Tigeot if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) 267*ce73550bSFrançois Tigeot return; 268*ce73550bSFrançois Tigeot 269*ce73550bSFrançois Tigeot dig = radeon_encoder->enc_priv; 270*ce73550bSFrançois Tigeot bd = dig->bl_dev; 271*ce73550bSFrançois Tigeot dig->bl_dev = NULL; 272*ce73550bSFrançois Tigeot 273*ce73550bSFrançois Tigeot if (bd) { 274*ce73550bSFrançois Tigeot struct radeon_legacy_backlight_privdata *pdata; 275*ce73550bSFrançois Tigeot 276*ce73550bSFrançois Tigeot pdata = bl_get_data(bd); 277*ce73550bSFrançois Tigeot backlight_device_unregister(bd); 278*ce73550bSFrançois Tigeot kfree(pdata); 279*ce73550bSFrançois Tigeot 280*ce73550bSFrançois Tigeot DRM_INFO("radeon atom LVDS backlight unloaded\n"); 281*ce73550bSFrançois Tigeot } 282*ce73550bSFrançois Tigeot #endif 283*ce73550bSFrançois Tigeot } 284*ce73550bSFrançois Tigeot 285*ce73550bSFrançois Tigeot #else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */ 286*ce73550bSFrançois Tigeot 287*ce73550bSFrançois Tigeot void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, 288*ce73550bSFrançois Tigeot struct drm_connector *drm_connector) 289*ce73550bSFrançois Tigeot { 290*ce73550bSFrançois Tigeot } 291*ce73550bSFrançois Tigeot 292926deccbSFrançois Tigeot static void radeon_atom_backlight_exit(struct radeon_encoder *encoder) 293926deccbSFrançois Tigeot { 294926deccbSFrançois Tigeot } 295926deccbSFrançois Tigeot 296926deccbSFrançois Tigeot #endif 297926deccbSFrançois Tigeot 298926deccbSFrançois Tigeot 299926deccbSFrançois Tigeot static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, 300926deccbSFrançois Tigeot const struct drm_display_mode *mode, 301926deccbSFrançois Tigeot struct drm_display_mode *adjusted_mode) 302926deccbSFrançois Tigeot { 303926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 304926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 305926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 306926deccbSFrançois Tigeot 307926deccbSFrançois Tigeot /* set the active encoder to connector routing */ 308926deccbSFrançois Tigeot radeon_encoder_set_active_device(encoder); 309926deccbSFrançois Tigeot drm_mode_set_crtcinfo(adjusted_mode, 0); 310926deccbSFrançois Tigeot 311926deccbSFrançois Tigeot /* hw bug */ 312926deccbSFrançois Tigeot if ((mode->flags & DRM_MODE_FLAG_INTERLACE) 313926deccbSFrançois Tigeot && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) 314926deccbSFrançois Tigeot adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; 315926deccbSFrançois Tigeot 316c6f73aabSFrançois Tigeot /* get the native mode for scaling */ 317c6f73aabSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 318926deccbSFrançois Tigeot radeon_panel_mode_fixup(encoder, adjusted_mode); 319c6f73aabSFrançois Tigeot } else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 320926deccbSFrançois Tigeot struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 321926deccbSFrançois Tigeot if (tv_dac) { 322926deccbSFrançois Tigeot if (tv_dac->tv_std == TV_STD_NTSC || 323926deccbSFrançois Tigeot tv_dac->tv_std == TV_STD_NTSC_J || 324926deccbSFrançois Tigeot tv_dac->tv_std == TV_STD_PAL_M) 325926deccbSFrançois Tigeot radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); 326926deccbSFrançois Tigeot else 327926deccbSFrançois Tigeot radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); 328926deccbSFrançois Tigeot } 329c6f73aabSFrançois Tigeot } else if (radeon_encoder->rmx_type != RMX_OFF) { 330c6f73aabSFrançois Tigeot radeon_panel_mode_fixup(encoder, adjusted_mode); 331926deccbSFrançois Tigeot } 332926deccbSFrançois Tigeot 333926deccbSFrançois Tigeot if (ASIC_IS_DCE3(rdev) && 334926deccbSFrançois Tigeot ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || 335926deccbSFrançois Tigeot (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { 336926deccbSFrançois Tigeot struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 337926deccbSFrançois Tigeot radeon_dp_set_link_config(connector, adjusted_mode); 338926deccbSFrançois Tigeot } 339926deccbSFrançois Tigeot 340926deccbSFrançois Tigeot return true; 341926deccbSFrançois Tigeot } 342926deccbSFrançois Tigeot 343926deccbSFrançois Tigeot static void 344926deccbSFrançois Tigeot atombios_dac_setup(struct drm_encoder *encoder, int action) 345926deccbSFrançois Tigeot { 346926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 347926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 348926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 349926deccbSFrançois Tigeot DAC_ENCODER_CONTROL_PS_ALLOCATION args; 350926deccbSFrançois Tigeot int index = 0; 351926deccbSFrançois Tigeot struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; 352926deccbSFrançois Tigeot 353926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 354926deccbSFrançois Tigeot 355926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 356926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 357926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 358926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); 359926deccbSFrançois Tigeot break; 360926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 361926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 362926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); 363926deccbSFrançois Tigeot break; 364926deccbSFrançois Tigeot } 365926deccbSFrançois Tigeot 366926deccbSFrançois Tigeot args.ucAction = action; 367926deccbSFrançois Tigeot 368926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) 369926deccbSFrançois Tigeot args.ucDacStandard = ATOM_DAC1_PS2; 370926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 371926deccbSFrançois Tigeot args.ucDacStandard = ATOM_DAC1_CV; 372926deccbSFrançois Tigeot else { 373926deccbSFrançois Tigeot switch (dac_info->tv_std) { 374926deccbSFrançois Tigeot case TV_STD_PAL: 375926deccbSFrançois Tigeot case TV_STD_PAL_M: 376926deccbSFrançois Tigeot case TV_STD_SCART_PAL: 377926deccbSFrançois Tigeot case TV_STD_SECAM: 378926deccbSFrançois Tigeot case TV_STD_PAL_CN: 379926deccbSFrançois Tigeot args.ucDacStandard = ATOM_DAC1_PAL; 380926deccbSFrançois Tigeot break; 381926deccbSFrançois Tigeot case TV_STD_NTSC: 382926deccbSFrançois Tigeot case TV_STD_NTSC_J: 383926deccbSFrançois Tigeot case TV_STD_PAL_60: 384926deccbSFrançois Tigeot default: 385926deccbSFrançois Tigeot args.ucDacStandard = ATOM_DAC1_NTSC; 386926deccbSFrançois Tigeot break; 387926deccbSFrançois Tigeot } 388926deccbSFrançois Tigeot } 389926deccbSFrançois Tigeot args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 390926deccbSFrançois Tigeot 391926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 392926deccbSFrançois Tigeot 393926deccbSFrançois Tigeot } 394926deccbSFrançois Tigeot 395926deccbSFrançois Tigeot static void 396926deccbSFrançois Tigeot atombios_tv_setup(struct drm_encoder *encoder, int action) 397926deccbSFrançois Tigeot { 398926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 399926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 400926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 401926deccbSFrançois Tigeot TV_ENCODER_CONTROL_PS_ALLOCATION args; 402926deccbSFrançois Tigeot int index = 0; 403926deccbSFrançois Tigeot struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; 404926deccbSFrançois Tigeot 405926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 406926deccbSFrançois Tigeot 407926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); 408926deccbSFrançois Tigeot 409926deccbSFrançois Tigeot args.sTVEncoder.ucAction = action; 410926deccbSFrançois Tigeot 411926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 412926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_CV; 413926deccbSFrançois Tigeot else { 414926deccbSFrançois Tigeot switch (dac_info->tv_std) { 415926deccbSFrançois Tigeot case TV_STD_NTSC: 416926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 417926deccbSFrançois Tigeot break; 418926deccbSFrançois Tigeot case TV_STD_PAL: 419926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; 420926deccbSFrançois Tigeot break; 421926deccbSFrançois Tigeot case TV_STD_PAL_M: 422926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; 423926deccbSFrançois Tigeot break; 424926deccbSFrançois Tigeot case TV_STD_PAL_60: 425926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; 426926deccbSFrançois Tigeot break; 427926deccbSFrançois Tigeot case TV_STD_NTSC_J: 428926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; 429926deccbSFrançois Tigeot break; 430926deccbSFrançois Tigeot case TV_STD_SCART_PAL: 431926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ 432926deccbSFrançois Tigeot break; 433926deccbSFrançois Tigeot case TV_STD_SECAM: 434926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; 435926deccbSFrançois Tigeot break; 436926deccbSFrançois Tigeot case TV_STD_PAL_CN: 437926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; 438926deccbSFrançois Tigeot break; 439926deccbSFrançois Tigeot default: 440926deccbSFrançois Tigeot args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 441926deccbSFrançois Tigeot break; 442926deccbSFrançois Tigeot } 443926deccbSFrançois Tigeot } 444926deccbSFrançois Tigeot 445926deccbSFrançois Tigeot args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 446926deccbSFrançois Tigeot 447926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 448926deccbSFrançois Tigeot 449926deccbSFrançois Tigeot } 450926deccbSFrançois Tigeot 451926deccbSFrançois Tigeot static u8 radeon_atom_get_bpc(struct drm_encoder *encoder) 452926deccbSFrançois Tigeot { 453926deccbSFrançois Tigeot int bpc = 8; 454926deccbSFrançois Tigeot 455c6f73aabSFrançois Tigeot if (encoder->crtc) { 456c6f73aabSFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 457c6f73aabSFrançois Tigeot bpc = radeon_crtc->bpc; 458c6f73aabSFrançois Tigeot } 459926deccbSFrançois Tigeot 460926deccbSFrançois Tigeot switch (bpc) { 461926deccbSFrançois Tigeot case 0: 462926deccbSFrançois Tigeot return PANEL_BPC_UNDEFINE; 463926deccbSFrançois Tigeot case 6: 464926deccbSFrançois Tigeot return PANEL_6BIT_PER_COLOR; 465926deccbSFrançois Tigeot case 8: 466926deccbSFrançois Tigeot default: 467926deccbSFrançois Tigeot return PANEL_8BIT_PER_COLOR; 468926deccbSFrançois Tigeot case 10: 469926deccbSFrançois Tigeot return PANEL_10BIT_PER_COLOR; 470926deccbSFrançois Tigeot case 12: 471926deccbSFrançois Tigeot return PANEL_12BIT_PER_COLOR; 472926deccbSFrançois Tigeot case 16: 473926deccbSFrançois Tigeot return PANEL_16BIT_PER_COLOR; 474926deccbSFrançois Tigeot } 475926deccbSFrançois Tigeot } 476926deccbSFrançois Tigeot 477926deccbSFrançois Tigeot union dvo_encoder_control { 478926deccbSFrançois Tigeot ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; 479926deccbSFrançois Tigeot DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; 480926deccbSFrançois Tigeot DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; 48157e252bfSMichael Neumann DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4; 482926deccbSFrançois Tigeot }; 483926deccbSFrançois Tigeot 484926deccbSFrançois Tigeot void 485926deccbSFrançois Tigeot atombios_dvo_setup(struct drm_encoder *encoder, int action) 486926deccbSFrançois Tigeot { 487926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 488926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 489926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 490926deccbSFrançois Tigeot union dvo_encoder_control args; 491926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 492926deccbSFrançois Tigeot uint8_t frev, crev; 493926deccbSFrançois Tigeot 494926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 495926deccbSFrançois Tigeot 496926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 497926deccbSFrançois Tigeot return; 498926deccbSFrançois Tigeot 499926deccbSFrançois Tigeot /* some R4xx chips have the wrong frev */ 500926deccbSFrançois Tigeot if (rdev->family <= CHIP_RV410) 501926deccbSFrançois Tigeot frev = 1; 502926deccbSFrançois Tigeot 503926deccbSFrançois Tigeot switch (frev) { 504926deccbSFrançois Tigeot case 1: 505926deccbSFrançois Tigeot switch (crev) { 506926deccbSFrançois Tigeot case 1: 507926deccbSFrançois Tigeot /* R4xx, R5xx */ 508926deccbSFrançois Tigeot args.ext_tmds.sXTmdsEncoder.ucEnable = action; 509926deccbSFrançois Tigeot 510926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 511926deccbSFrançois Tigeot args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; 512926deccbSFrançois Tigeot 513926deccbSFrançois Tigeot args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; 514926deccbSFrançois Tigeot break; 515926deccbSFrançois Tigeot case 2: 516926deccbSFrançois Tigeot /* RS600/690/740 */ 517926deccbSFrançois Tigeot args.dvo.sDVOEncoder.ucAction = action; 518926deccbSFrançois Tigeot args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 519926deccbSFrançois Tigeot /* DFP1, CRT1, TV1 depending on the type of port */ 520926deccbSFrançois Tigeot args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; 521926deccbSFrançois Tigeot 522926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 523926deccbSFrançois Tigeot args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; 524926deccbSFrançois Tigeot break; 525926deccbSFrançois Tigeot case 3: 526926deccbSFrançois Tigeot /* R6xx */ 527926deccbSFrançois Tigeot args.dvo_v3.ucAction = action; 528926deccbSFrançois Tigeot args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 529926deccbSFrançois Tigeot args.dvo_v3.ucDVOConfig = 0; /* XXX */ 530926deccbSFrançois Tigeot break; 53157e252bfSMichael Neumann case 4: 53257e252bfSMichael Neumann /* DCE8 */ 53357e252bfSMichael Neumann args.dvo_v4.ucAction = action; 53457e252bfSMichael Neumann args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 53557e252bfSMichael Neumann args.dvo_v4.ucDVOConfig = 0; /* XXX */ 53657e252bfSMichael Neumann args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder); 53757e252bfSMichael Neumann break; 538926deccbSFrançois Tigeot default: 539926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 540926deccbSFrançois Tigeot break; 541926deccbSFrançois Tigeot } 542926deccbSFrançois Tigeot break; 543926deccbSFrançois Tigeot default: 544926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 545926deccbSFrançois Tigeot break; 546926deccbSFrançois Tigeot } 547926deccbSFrançois Tigeot 548926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 549926deccbSFrançois Tigeot } 550926deccbSFrançois Tigeot 551926deccbSFrançois Tigeot union lvds_encoder_control { 552926deccbSFrançois Tigeot LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; 553926deccbSFrançois Tigeot LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; 554926deccbSFrançois Tigeot }; 555926deccbSFrançois Tigeot 556926deccbSFrançois Tigeot void 557926deccbSFrançois Tigeot atombios_digital_setup(struct drm_encoder *encoder, int action) 558926deccbSFrançois Tigeot { 559926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 560926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 561926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 562926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 563926deccbSFrançois Tigeot union lvds_encoder_control args; 564926deccbSFrançois Tigeot int index = 0; 565926deccbSFrançois Tigeot int hdmi_detected = 0; 566926deccbSFrançois Tigeot uint8_t frev, crev; 567926deccbSFrançois Tigeot 568926deccbSFrançois Tigeot if (!dig) 569926deccbSFrançois Tigeot return; 570926deccbSFrançois Tigeot 571926deccbSFrançois Tigeot if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) 572926deccbSFrançois Tigeot hdmi_detected = 1; 573926deccbSFrançois Tigeot 574926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 575926deccbSFrançois Tigeot 576926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 577926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 578926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 579926deccbSFrançois Tigeot break; 580926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 581926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 582926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); 583926deccbSFrançois Tigeot break; 584926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 585926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 586926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 587926deccbSFrançois Tigeot else 588926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); 589926deccbSFrançois Tigeot break; 590926deccbSFrançois Tigeot } 591926deccbSFrançois Tigeot 592926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 593926deccbSFrançois Tigeot return; 594926deccbSFrançois Tigeot 595926deccbSFrançois Tigeot switch (frev) { 596926deccbSFrançois Tigeot case 1: 597926deccbSFrançois Tigeot case 2: 598926deccbSFrançois Tigeot switch (crev) { 599926deccbSFrançois Tigeot case 1: 600926deccbSFrançois Tigeot args.v1.ucMisc = 0; 601926deccbSFrançois Tigeot args.v1.ucAction = action; 602926deccbSFrançois Tigeot if (hdmi_detected) 603926deccbSFrançois Tigeot args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 604926deccbSFrançois Tigeot args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 605926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 606926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) 607926deccbSFrançois Tigeot args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; 608926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 609926deccbSFrançois Tigeot args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; 610926deccbSFrançois Tigeot } else { 611926deccbSFrançois Tigeot if (dig->linkb) 612926deccbSFrançois Tigeot args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 613926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 614926deccbSFrançois Tigeot args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; 615926deccbSFrançois Tigeot /*if (pScrn->rgbBits == 8) */ 616926deccbSFrançois Tigeot args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; 617926deccbSFrançois Tigeot } 618926deccbSFrançois Tigeot break; 619926deccbSFrançois Tigeot case 2: 620926deccbSFrançois Tigeot case 3: 621926deccbSFrançois Tigeot args.v2.ucMisc = 0; 622926deccbSFrançois Tigeot args.v2.ucAction = action; 623926deccbSFrançois Tigeot if (crev == 3) { 624926deccbSFrançois Tigeot if (dig->coherent_mode) 625926deccbSFrançois Tigeot args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; 626926deccbSFrançois Tigeot } 627926deccbSFrançois Tigeot if (hdmi_detected) 628926deccbSFrançois Tigeot args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 629926deccbSFrançois Tigeot args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 630926deccbSFrançois Tigeot args.v2.ucTruncate = 0; 631926deccbSFrançois Tigeot args.v2.ucSpatial = 0; 632926deccbSFrançois Tigeot args.v2.ucTemporal = 0; 633926deccbSFrançois Tigeot args.v2.ucFRC = 0; 634926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 635926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) 636926deccbSFrançois Tigeot args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 637926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { 638926deccbSFrançois Tigeot args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; 639926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 640926deccbSFrançois Tigeot args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; 641926deccbSFrançois Tigeot } 642926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { 643926deccbSFrançois Tigeot args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; 644926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) 645926deccbSFrançois Tigeot args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; 646926deccbSFrançois Tigeot if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) 647926deccbSFrançois Tigeot args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; 648926deccbSFrançois Tigeot } 649926deccbSFrançois Tigeot } else { 650926deccbSFrançois Tigeot if (dig->linkb) 651926deccbSFrançois Tigeot args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 652926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 653926deccbSFrançois Tigeot args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 654926deccbSFrançois Tigeot } 655926deccbSFrançois Tigeot break; 656926deccbSFrançois Tigeot default: 657926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 658926deccbSFrançois Tigeot break; 659926deccbSFrançois Tigeot } 660926deccbSFrançois Tigeot break; 661926deccbSFrançois Tigeot default: 662926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 663926deccbSFrançois Tigeot break; 664926deccbSFrançois Tigeot } 665926deccbSFrançois Tigeot 666926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 667926deccbSFrançois Tigeot } 668926deccbSFrançois Tigeot 669926deccbSFrançois Tigeot int 670926deccbSFrançois Tigeot atombios_get_encoder_mode(struct drm_encoder *encoder) 671926deccbSFrançois Tigeot { 672926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 673926deccbSFrançois Tigeot struct drm_connector *connector; 674926deccbSFrançois Tigeot struct radeon_connector *radeon_connector; 675926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig_connector; 676926deccbSFrançois Tigeot 677926deccbSFrançois Tigeot /* dp bridges are always DP */ 678926deccbSFrançois Tigeot if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) 679926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DP; 680926deccbSFrançois Tigeot 681926deccbSFrançois Tigeot /* DVO is always DVO */ 682926deccbSFrançois Tigeot if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) || 683926deccbSFrançois Tigeot (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) 684926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DVO; 685926deccbSFrançois Tigeot 686926deccbSFrançois Tigeot connector = radeon_get_connector_for_encoder(encoder); 687926deccbSFrançois Tigeot /* if we don't have an active device yet, just use one of 688926deccbSFrançois Tigeot * the connectors tied to the encoder. 689926deccbSFrançois Tigeot */ 690926deccbSFrançois Tigeot if (!connector) 691926deccbSFrançois Tigeot connector = radeon_get_connector_for_encoder_init(encoder); 692926deccbSFrançois Tigeot radeon_connector = to_radeon_connector(connector); 693926deccbSFrançois Tigeot 694926deccbSFrançois Tigeot switch (connector->connector_type) { 695926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 696926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ 6974cd92098Szrj if (radeon_audio != 0) { 6984cd92098Szrj if (radeon_connector->use_digital && 6994cd92098Szrj (radeon_connector->audio == RADEON_AUDIO_ENABLE)) 7004cd92098Szrj return ATOM_ENCODER_MODE_HDMI; 701c6f73aabSFrançois Tigeot else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 7024cd92098Szrj (radeon_connector->audio == RADEON_AUDIO_AUTO)) 703926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_HDMI; 704926deccbSFrançois Tigeot else if (radeon_connector->use_digital) 705926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DVI; 706926deccbSFrançois Tigeot else 707926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_CRT; 7084cd92098Szrj } else if (radeon_connector->use_digital) { 7094cd92098Szrj return ATOM_ENCODER_MODE_DVI; 7104cd92098Szrj } else { 7114cd92098Szrj return ATOM_ENCODER_MODE_CRT; 7124cd92098Szrj } 713926deccbSFrançois Tigeot break; 714926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 715926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIA: 716926deccbSFrançois Tigeot default: 7174cd92098Szrj if (radeon_audio != 0) { 7184cd92098Szrj if (radeon_connector->audio == RADEON_AUDIO_ENABLE) 7194cd92098Szrj return ATOM_ENCODER_MODE_HDMI; 720c6f73aabSFrançois Tigeot else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 7214cd92098Szrj (radeon_connector->audio == RADEON_AUDIO_AUTO)) 722926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_HDMI; 723926deccbSFrançois Tigeot else 724926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DVI; 7254cd92098Szrj } else { 7264cd92098Szrj return ATOM_ENCODER_MODE_DVI; 7274cd92098Szrj } 728926deccbSFrançois Tigeot break; 729926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 730926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_LVDS; 731926deccbSFrançois Tigeot break; 732926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DisplayPort: 733926deccbSFrançois Tigeot dig_connector = radeon_connector->con_priv; 734926deccbSFrançois Tigeot if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 7354cd92098Szrj (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 736926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DP; 7374cd92098Szrj } else if (radeon_audio != 0) { 7384cd92098Szrj if (radeon_connector->audio == RADEON_AUDIO_ENABLE) 7394cd92098Szrj return ATOM_ENCODER_MODE_HDMI; 740c6f73aabSFrançois Tigeot else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && 7414cd92098Szrj (radeon_connector->audio == RADEON_AUDIO_AUTO)) 742926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_HDMI; 743926deccbSFrançois Tigeot else 744926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DVI; 7454cd92098Szrj } else { 7464cd92098Szrj return ATOM_ENCODER_MODE_DVI; 7474cd92098Szrj } 748926deccbSFrançois Tigeot break; 749926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_eDP: 750926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_DP; 751926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 752926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 753926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_CRT; 754926deccbSFrançois Tigeot break; 755926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_Composite: 756926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_SVIDEO: 757926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_9PinDIN: 758926deccbSFrançois Tigeot /* fix me */ 759926deccbSFrançois Tigeot return ATOM_ENCODER_MODE_TV; 760926deccbSFrançois Tigeot /*return ATOM_ENCODER_MODE_CV;*/ 761926deccbSFrançois Tigeot break; 762926deccbSFrançois Tigeot } 763926deccbSFrançois Tigeot } 764926deccbSFrançois Tigeot 765926deccbSFrançois Tigeot /* 766926deccbSFrançois Tigeot * DIG Encoder/Transmitter Setup 767926deccbSFrançois Tigeot * 768926deccbSFrançois Tigeot * DCE 3.0/3.1 769926deccbSFrançois Tigeot * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. 770926deccbSFrançois Tigeot * Supports up to 3 digital outputs 771926deccbSFrançois Tigeot * - 2 DIG encoder blocks. 772926deccbSFrançois Tigeot * DIG1 can drive UNIPHY link A or link B 773926deccbSFrançois Tigeot * DIG2 can drive UNIPHY link B or LVTMA 774926deccbSFrançois Tigeot * 775926deccbSFrançois Tigeot * DCE 3.2 776926deccbSFrançois Tigeot * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). 777926deccbSFrançois Tigeot * Supports up to 5 digital outputs 778926deccbSFrançois Tigeot * - 2 DIG encoder blocks. 779926deccbSFrançois Tigeot * DIG1/2 can drive UNIPHY0/1/2 link A or link B 780926deccbSFrançois Tigeot * 781926deccbSFrançois Tigeot * DCE 4.0/5.0/6.0 782926deccbSFrançois Tigeot * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). 783926deccbSFrançois Tigeot * Supports up to 6 digital outputs 784926deccbSFrançois Tigeot * - 6 DIG encoder blocks. 785926deccbSFrançois Tigeot * - DIG to PHY mapping is hardcoded 786926deccbSFrançois Tigeot * DIG1 drives UNIPHY0 link A, A+B 787926deccbSFrançois Tigeot * DIG2 drives UNIPHY0 link B 788926deccbSFrançois Tigeot * DIG3 drives UNIPHY1 link A, A+B 789926deccbSFrançois Tigeot * DIG4 drives UNIPHY1 link B 790926deccbSFrançois Tigeot * DIG5 drives UNIPHY2 link A, A+B 791926deccbSFrançois Tigeot * DIG6 drives UNIPHY2 link B 792926deccbSFrançois Tigeot * 793926deccbSFrançois Tigeot * DCE 4.1 794926deccbSFrançois Tigeot * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). 795926deccbSFrançois Tigeot * Supports up to 6 digital outputs 796926deccbSFrançois Tigeot * - 2 DIG encoder blocks. 797926deccbSFrançois Tigeot * llano 798926deccbSFrançois Tigeot * DIG1/2 can drive UNIPHY0/1/2 link A or link B 799926deccbSFrançois Tigeot * ontario 800926deccbSFrançois Tigeot * DIG1 drives UNIPHY0/1/2 link A 801926deccbSFrançois Tigeot * DIG2 drives UNIPHY0/1/2 link B 802926deccbSFrançois Tigeot * 803926deccbSFrançois Tigeot * Routing 804926deccbSFrançois Tigeot * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) 805926deccbSFrançois Tigeot * Examples: 806926deccbSFrançois Tigeot * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI 807926deccbSFrançois Tigeot * crtc1 -> dig1 -> UNIPHY0 link B -> DP 808926deccbSFrançois Tigeot * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS 809926deccbSFrançois Tigeot * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI 810926deccbSFrançois Tigeot */ 811926deccbSFrançois Tigeot 812926deccbSFrançois Tigeot union dig_encoder_control { 813926deccbSFrançois Tigeot DIG_ENCODER_CONTROL_PS_ALLOCATION v1; 814926deccbSFrançois Tigeot DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; 815926deccbSFrançois Tigeot DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; 816926deccbSFrançois Tigeot DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; 817926deccbSFrançois Tigeot }; 818926deccbSFrançois Tigeot 819926deccbSFrançois Tigeot void 820ee479021SImre Vadász atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) 821926deccbSFrançois Tigeot { 822926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 823926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 824926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 825926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 826926deccbSFrançois Tigeot struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 827926deccbSFrançois Tigeot union dig_encoder_control args; 828926deccbSFrançois Tigeot int index = 0; 829926deccbSFrançois Tigeot uint8_t frev, crev; 830926deccbSFrançois Tigeot int dp_clock = 0; 831926deccbSFrançois Tigeot int dp_lane_count = 0; 832926deccbSFrançois Tigeot int hpd_id = RADEON_HPD_NONE; 833926deccbSFrançois Tigeot 834926deccbSFrançois Tigeot if (connector) { 835926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 836926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig_connector = 837926deccbSFrançois Tigeot radeon_connector->con_priv; 838926deccbSFrançois Tigeot 839926deccbSFrançois Tigeot dp_clock = dig_connector->dp_clock; 840926deccbSFrançois Tigeot dp_lane_count = dig_connector->dp_lane_count; 841926deccbSFrançois Tigeot hpd_id = radeon_connector->hpd.hpd; 842926deccbSFrançois Tigeot } 843926deccbSFrançois Tigeot 844926deccbSFrançois Tigeot /* no dig encoder assigned */ 845926deccbSFrançois Tigeot if (dig->dig_encoder == -1) 846926deccbSFrançois Tigeot return; 847926deccbSFrançois Tigeot 848926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 849926deccbSFrançois Tigeot 850926deccbSFrançois Tigeot if (ASIC_IS_DCE4(rdev)) 851926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); 852926deccbSFrançois Tigeot else { 853926deccbSFrançois Tigeot if (dig->dig_encoder) 854926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); 855926deccbSFrançois Tigeot else 856926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); 857926deccbSFrançois Tigeot } 858926deccbSFrançois Tigeot 859926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 860926deccbSFrançois Tigeot return; 861926deccbSFrançois Tigeot 862926deccbSFrançois Tigeot switch (frev) { 863926deccbSFrançois Tigeot case 1: 864926deccbSFrançois Tigeot switch (crev) { 865926deccbSFrançois Tigeot case 1: 866926deccbSFrançois Tigeot args.v1.ucAction = action; 867926deccbSFrançois Tigeot args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 868926deccbSFrançois Tigeot if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 869926deccbSFrançois Tigeot args.v3.ucPanelMode = panel_mode; 870926deccbSFrançois Tigeot else 871926deccbSFrançois Tigeot args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); 872926deccbSFrançois Tigeot 873926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) 874926deccbSFrançois Tigeot args.v1.ucLaneNum = dp_lane_count; 875926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 876926deccbSFrançois Tigeot args.v1.ucLaneNum = 8; 877926deccbSFrançois Tigeot else 878926deccbSFrançois Tigeot args.v1.ucLaneNum = 4; 879926deccbSFrançois Tigeot 880ee479021SImre Vadász if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) 881ee479021SImre Vadász args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 882926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 883926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 884926deccbSFrançois Tigeot args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; 885926deccbSFrançois Tigeot break; 886926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 887926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 888926deccbSFrançois Tigeot args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; 889926deccbSFrançois Tigeot break; 890926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 891926deccbSFrançois Tigeot args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; 892926deccbSFrançois Tigeot break; 893926deccbSFrançois Tigeot } 894926deccbSFrançois Tigeot if (dig->linkb) 895926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; 896926deccbSFrançois Tigeot else 897926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; 898926deccbSFrançois Tigeot break; 899926deccbSFrançois Tigeot case 2: 900926deccbSFrançois Tigeot case 3: 901926deccbSFrançois Tigeot args.v3.ucAction = action; 902926deccbSFrançois Tigeot args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 903926deccbSFrançois Tigeot if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 904926deccbSFrançois Tigeot args.v3.ucPanelMode = panel_mode; 905926deccbSFrançois Tigeot else 906926deccbSFrançois Tigeot args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); 907926deccbSFrançois Tigeot 908926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode)) 909926deccbSFrançois Tigeot args.v3.ucLaneNum = dp_lane_count; 910926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 911926deccbSFrançois Tigeot args.v3.ucLaneNum = 8; 912926deccbSFrançois Tigeot else 913926deccbSFrançois Tigeot args.v3.ucLaneNum = 4; 914926deccbSFrançois Tigeot 915926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000)) 916926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; 917926deccbSFrançois Tigeot args.v3.acConfig.ucDigSel = dig->dig_encoder; 918926deccbSFrançois Tigeot args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); 919926deccbSFrançois Tigeot break; 920926deccbSFrançois Tigeot case 4: 921926deccbSFrançois Tigeot args.v4.ucAction = action; 922926deccbSFrançois Tigeot args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 923926deccbSFrançois Tigeot if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) 924926deccbSFrançois Tigeot args.v4.ucPanelMode = panel_mode; 925926deccbSFrançois Tigeot else 926926deccbSFrançois Tigeot args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder); 927926deccbSFrançois Tigeot 928926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) 929926deccbSFrançois Tigeot args.v4.ucLaneNum = dp_lane_count; 930926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 931926deccbSFrançois Tigeot args.v4.ucLaneNum = 8; 932926deccbSFrançois Tigeot else 933926deccbSFrançois Tigeot args.v4.ucLaneNum = 4; 934926deccbSFrançois Tigeot 935926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) { 93657e252bfSMichael Neumann if (dp_clock == 540000) 937926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; 93857e252bfSMichael Neumann else if (dp_clock == 324000) 93957e252bfSMichael Neumann args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ; 94057e252bfSMichael Neumann else if (dp_clock == 270000) 94157e252bfSMichael Neumann args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; 94257e252bfSMichael Neumann else 94357e252bfSMichael Neumann args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ; 944926deccbSFrançois Tigeot } 945926deccbSFrançois Tigeot args.v4.acConfig.ucDigSel = dig->dig_encoder; 946926deccbSFrançois Tigeot args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); 947926deccbSFrançois Tigeot if (hpd_id == RADEON_HPD_NONE) 948926deccbSFrançois Tigeot args.v4.ucHPD_ID = 0; 949926deccbSFrançois Tigeot else 950926deccbSFrançois Tigeot args.v4.ucHPD_ID = hpd_id + 1; 951926deccbSFrançois Tigeot break; 952926deccbSFrançois Tigeot default: 953926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 954926deccbSFrançois Tigeot break; 955926deccbSFrançois Tigeot } 956926deccbSFrançois Tigeot break; 957926deccbSFrançois Tigeot default: 958926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 959926deccbSFrançois Tigeot break; 960926deccbSFrançois Tigeot } 961926deccbSFrançois Tigeot 962926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 963926deccbSFrançois Tigeot 964926deccbSFrançois Tigeot } 965926deccbSFrançois Tigeot 966926deccbSFrançois Tigeot union dig_transmitter_control { 967926deccbSFrançois Tigeot DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; 968926deccbSFrançois Tigeot DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; 969926deccbSFrançois Tigeot DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; 970926deccbSFrançois Tigeot DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; 971926deccbSFrançois Tigeot DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5; 972926deccbSFrançois Tigeot }; 973926deccbSFrançois Tigeot 974926deccbSFrançois Tigeot void 975ee479021SImre Vadász atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) 976926deccbSFrançois Tigeot { 977926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 978926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 979926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 980926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 981926deccbSFrançois Tigeot struct drm_connector *connector; 982926deccbSFrançois Tigeot union dig_transmitter_control args; 983926deccbSFrançois Tigeot int index = 0; 984926deccbSFrançois Tigeot uint8_t frev, crev; 985926deccbSFrançois Tigeot bool is_dp = false; 986926deccbSFrançois Tigeot int pll_id = 0; 987926deccbSFrançois Tigeot int dp_clock = 0; 988926deccbSFrançois Tigeot int dp_lane_count = 0; 989926deccbSFrançois Tigeot int connector_object_id = 0; 990926deccbSFrançois Tigeot int igp_lane_info = 0; 991926deccbSFrançois Tigeot int dig_encoder = dig->dig_encoder; 992926deccbSFrançois Tigeot int hpd_id = RADEON_HPD_NONE; 993926deccbSFrançois Tigeot 994926deccbSFrançois Tigeot if (action == ATOM_TRANSMITTER_ACTION_INIT) { 995926deccbSFrançois Tigeot connector = radeon_get_connector_for_encoder_init(encoder); 996926deccbSFrançois Tigeot /* just needed to avoid bailing in the encoder check. the encoder 997926deccbSFrançois Tigeot * isn't used for init 998926deccbSFrançois Tigeot */ 999926deccbSFrançois Tigeot dig_encoder = 0; 1000926deccbSFrançois Tigeot } else 1001926deccbSFrançois Tigeot connector = radeon_get_connector_for_encoder(encoder); 1002926deccbSFrançois Tigeot 1003926deccbSFrançois Tigeot if (connector) { 1004926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1005926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig_connector = 1006926deccbSFrançois Tigeot radeon_connector->con_priv; 1007926deccbSFrançois Tigeot 1008926deccbSFrançois Tigeot hpd_id = radeon_connector->hpd.hpd; 1009926deccbSFrançois Tigeot dp_clock = dig_connector->dp_clock; 1010926deccbSFrançois Tigeot dp_lane_count = dig_connector->dp_lane_count; 1011926deccbSFrançois Tigeot connector_object_id = 1012926deccbSFrançois Tigeot (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 1013926deccbSFrançois Tigeot igp_lane_info = dig_connector->igp_lane_info; 1014926deccbSFrançois Tigeot } 1015926deccbSFrançois Tigeot 1016926deccbSFrançois Tigeot if (encoder->crtc) { 1017926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 1018926deccbSFrançois Tigeot pll_id = radeon_crtc->pll_id; 1019926deccbSFrançois Tigeot } 1020926deccbSFrançois Tigeot 1021926deccbSFrançois Tigeot /* no dig encoder assigned */ 1022926deccbSFrançois Tigeot if (dig_encoder == -1) 1023926deccbSFrançois Tigeot return; 1024926deccbSFrançois Tigeot 1025926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder))) 1026926deccbSFrançois Tigeot is_dp = true; 1027926deccbSFrançois Tigeot 1028926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 1029926deccbSFrançois Tigeot 1030926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1031926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1032926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 1033926deccbSFrançois Tigeot break; 1034926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1035926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1036926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 103757e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 1038926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 1039926deccbSFrançois Tigeot break; 1040926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1041926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); 1042926deccbSFrançois Tigeot break; 1043926deccbSFrançois Tigeot } 1044926deccbSFrançois Tigeot 1045926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 1046926deccbSFrançois Tigeot return; 1047926deccbSFrançois Tigeot 1048926deccbSFrançois Tigeot switch (frev) { 1049926deccbSFrançois Tigeot case 1: 1050926deccbSFrançois Tigeot switch (crev) { 1051926deccbSFrançois Tigeot case 1: 1052926deccbSFrançois Tigeot args.v1.ucAction = action; 1053926deccbSFrançois Tigeot if (action == ATOM_TRANSMITTER_ACTION_INIT) { 1054926deccbSFrançois Tigeot args.v1.usInitInfo = cpu_to_le16(connector_object_id); 1055926deccbSFrançois Tigeot } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 1056926deccbSFrançois Tigeot args.v1.asMode.ucLaneSel = lane_num; 1057926deccbSFrançois Tigeot args.v1.asMode.ucLaneSet = lane_set; 1058926deccbSFrançois Tigeot } else { 1059926deccbSFrançois Tigeot if (is_dp) 1060926deccbSFrançois Tigeot args.v1.usPixelClock = cpu_to_le16(dp_clock / 10); 1061926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1062926deccbSFrançois Tigeot args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 1063926deccbSFrançois Tigeot else 1064926deccbSFrançois Tigeot args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1065926deccbSFrançois Tigeot } 1066926deccbSFrançois Tigeot 1067926deccbSFrançois Tigeot args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; 1068926deccbSFrançois Tigeot 1069926deccbSFrançois Tigeot if (dig_encoder) 1070926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; 1071926deccbSFrançois Tigeot else 1072926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; 1073926deccbSFrançois Tigeot 1074926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_IGP) && 1075926deccbSFrançois Tigeot (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { 1076926deccbSFrançois Tigeot if (is_dp || 1077926deccbSFrançois Tigeot !radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) { 1078926deccbSFrançois Tigeot if (igp_lane_info & 0x1) 1079926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; 1080926deccbSFrançois Tigeot else if (igp_lane_info & 0x2) 1081926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; 1082926deccbSFrançois Tigeot else if (igp_lane_info & 0x4) 1083926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; 1084926deccbSFrançois Tigeot else if (igp_lane_info & 0x8) 1085926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; 1086926deccbSFrançois Tigeot } else { 1087926deccbSFrançois Tigeot if (igp_lane_info & 0x3) 1088926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; 1089926deccbSFrançois Tigeot else if (igp_lane_info & 0xc) 1090926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; 1091926deccbSFrançois Tigeot } 1092926deccbSFrançois Tigeot } 1093926deccbSFrançois Tigeot 1094926deccbSFrançois Tigeot if (dig->linkb) 1095926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; 1096926deccbSFrançois Tigeot else 1097926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; 1098926deccbSFrançois Tigeot 1099926deccbSFrançois Tigeot if (is_dp) 1100926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 1101926deccbSFrançois Tigeot else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 1102926deccbSFrançois Tigeot if (dig->coherent_mode) 1103926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 1104926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1105926deccbSFrançois Tigeot args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; 1106926deccbSFrançois Tigeot } 1107926deccbSFrançois Tigeot break; 1108926deccbSFrançois Tigeot case 2: 1109926deccbSFrançois Tigeot args.v2.ucAction = action; 1110926deccbSFrançois Tigeot if (action == ATOM_TRANSMITTER_ACTION_INIT) { 1111926deccbSFrançois Tigeot args.v2.usInitInfo = cpu_to_le16(connector_object_id); 1112926deccbSFrançois Tigeot } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 1113926deccbSFrançois Tigeot args.v2.asMode.ucLaneSel = lane_num; 1114926deccbSFrançois Tigeot args.v2.asMode.ucLaneSet = lane_set; 1115926deccbSFrançois Tigeot } else { 1116926deccbSFrançois Tigeot if (is_dp) 1117926deccbSFrançois Tigeot args.v2.usPixelClock = cpu_to_le16(dp_clock / 10); 1118926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1119926deccbSFrançois Tigeot args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 1120926deccbSFrançois Tigeot else 1121926deccbSFrançois Tigeot args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1122926deccbSFrançois Tigeot } 1123926deccbSFrançois Tigeot 1124926deccbSFrançois Tigeot args.v2.acConfig.ucEncoderSel = dig_encoder; 1125926deccbSFrançois Tigeot if (dig->linkb) 1126926deccbSFrançois Tigeot args.v2.acConfig.ucLinkSel = 1; 1127926deccbSFrançois Tigeot 1128926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1129926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1130926deccbSFrançois Tigeot args.v2.acConfig.ucTransmitterSel = 0; 1131926deccbSFrançois Tigeot break; 1132926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1133926deccbSFrançois Tigeot args.v2.acConfig.ucTransmitterSel = 1; 1134926deccbSFrançois Tigeot break; 1135926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1136926deccbSFrançois Tigeot args.v2.acConfig.ucTransmitterSel = 2; 1137926deccbSFrançois Tigeot break; 1138926deccbSFrançois Tigeot } 1139926deccbSFrançois Tigeot 1140926deccbSFrançois Tigeot if (is_dp) { 1141926deccbSFrançois Tigeot args.v2.acConfig.fCoherentMode = 1; 1142926deccbSFrançois Tigeot args.v2.acConfig.fDPConnector = 1; 1143926deccbSFrançois Tigeot } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 1144926deccbSFrançois Tigeot if (dig->coherent_mode) 1145926deccbSFrançois Tigeot args.v2.acConfig.fCoherentMode = 1; 1146926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1147926deccbSFrançois Tigeot args.v2.acConfig.fDualLinkConnector = 1; 1148926deccbSFrançois Tigeot } 1149926deccbSFrançois Tigeot break; 1150926deccbSFrançois Tigeot case 3: 1151926deccbSFrançois Tigeot args.v3.ucAction = action; 1152926deccbSFrançois Tigeot if (action == ATOM_TRANSMITTER_ACTION_INIT) { 1153926deccbSFrançois Tigeot args.v3.usInitInfo = cpu_to_le16(connector_object_id); 1154926deccbSFrançois Tigeot } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 1155926deccbSFrançois Tigeot args.v3.asMode.ucLaneSel = lane_num; 1156926deccbSFrançois Tigeot args.v3.asMode.ucLaneSet = lane_set; 1157926deccbSFrançois Tigeot } else { 1158926deccbSFrançois Tigeot if (is_dp) 1159926deccbSFrançois Tigeot args.v3.usPixelClock = cpu_to_le16(dp_clock / 10); 1160926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1161926deccbSFrançois Tigeot args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 1162926deccbSFrançois Tigeot else 1163926deccbSFrançois Tigeot args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1164926deccbSFrançois Tigeot } 1165926deccbSFrançois Tigeot 1166926deccbSFrançois Tigeot if (is_dp) 1167926deccbSFrançois Tigeot args.v3.ucLaneNum = dp_lane_count; 1168926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1169926deccbSFrançois Tigeot args.v3.ucLaneNum = 8; 1170926deccbSFrançois Tigeot else 1171926deccbSFrançois Tigeot args.v3.ucLaneNum = 4; 1172926deccbSFrançois Tigeot 1173926deccbSFrançois Tigeot if (dig->linkb) 1174926deccbSFrançois Tigeot args.v3.acConfig.ucLinkSel = 1; 1175926deccbSFrançois Tigeot if (dig_encoder & 1) 1176926deccbSFrançois Tigeot args.v3.acConfig.ucEncoderSel = 1; 1177926deccbSFrançois Tigeot 1178926deccbSFrançois Tigeot /* Select the PLL for the PHY 1179926deccbSFrançois Tigeot * DP PHY should be clocked from external src if there is 1180926deccbSFrançois Tigeot * one. 1181926deccbSFrançois Tigeot */ 1182926deccbSFrançois Tigeot /* On DCE4, if there is an external clock, it generates the DP ref clock */ 1183926deccbSFrançois Tigeot if (is_dp && rdev->clock.dp_extclk) 1184926deccbSFrançois Tigeot args.v3.acConfig.ucRefClkSource = 2; /* external src */ 1185926deccbSFrançois Tigeot else 1186926deccbSFrançois Tigeot args.v3.acConfig.ucRefClkSource = pll_id; 1187926deccbSFrançois Tigeot 1188926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1189926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1190926deccbSFrançois Tigeot args.v3.acConfig.ucTransmitterSel = 0; 1191926deccbSFrançois Tigeot break; 1192926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1193926deccbSFrançois Tigeot args.v3.acConfig.ucTransmitterSel = 1; 1194926deccbSFrançois Tigeot break; 1195926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1196926deccbSFrançois Tigeot args.v3.acConfig.ucTransmitterSel = 2; 1197926deccbSFrançois Tigeot break; 1198926deccbSFrançois Tigeot } 1199926deccbSFrançois Tigeot 1200926deccbSFrançois Tigeot if (is_dp) 1201926deccbSFrançois Tigeot args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ 1202926deccbSFrançois Tigeot else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 1203926deccbSFrançois Tigeot if (dig->coherent_mode) 1204926deccbSFrançois Tigeot args.v3.acConfig.fCoherentMode = 1; 1205926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1206926deccbSFrançois Tigeot args.v3.acConfig.fDualLinkConnector = 1; 1207926deccbSFrançois Tigeot } 1208926deccbSFrançois Tigeot break; 1209926deccbSFrançois Tigeot case 4: 1210926deccbSFrançois Tigeot args.v4.ucAction = action; 1211926deccbSFrançois Tigeot if (action == ATOM_TRANSMITTER_ACTION_INIT) { 1212926deccbSFrançois Tigeot args.v4.usInitInfo = cpu_to_le16(connector_object_id); 1213926deccbSFrançois Tigeot } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 1214926deccbSFrançois Tigeot args.v4.asMode.ucLaneSel = lane_num; 1215926deccbSFrançois Tigeot args.v4.asMode.ucLaneSet = lane_set; 1216926deccbSFrançois Tigeot } else { 1217926deccbSFrançois Tigeot if (is_dp) 1218926deccbSFrançois Tigeot args.v4.usPixelClock = cpu_to_le16(dp_clock / 10); 1219926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1220926deccbSFrançois Tigeot args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); 1221926deccbSFrançois Tigeot else 1222926deccbSFrançois Tigeot args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1223926deccbSFrançois Tigeot } 1224926deccbSFrançois Tigeot 1225926deccbSFrançois Tigeot if (is_dp) 1226926deccbSFrançois Tigeot args.v4.ucLaneNum = dp_lane_count; 1227926deccbSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1228926deccbSFrançois Tigeot args.v4.ucLaneNum = 8; 1229926deccbSFrançois Tigeot else 1230926deccbSFrançois Tigeot args.v4.ucLaneNum = 4; 1231926deccbSFrançois Tigeot 1232926deccbSFrançois Tigeot if (dig->linkb) 1233926deccbSFrançois Tigeot args.v4.acConfig.ucLinkSel = 1; 1234926deccbSFrançois Tigeot if (dig_encoder & 1) 1235926deccbSFrançois Tigeot args.v4.acConfig.ucEncoderSel = 1; 1236926deccbSFrançois Tigeot 1237926deccbSFrançois Tigeot /* Select the PLL for the PHY 1238926deccbSFrançois Tigeot * DP PHY should be clocked from external src if there is 1239926deccbSFrançois Tigeot * one. 1240926deccbSFrançois Tigeot */ 1241926deccbSFrançois Tigeot /* On DCE5 DCPLL usually generates the DP ref clock */ 1242926deccbSFrançois Tigeot if (is_dp) { 1243926deccbSFrançois Tigeot if (rdev->clock.dp_extclk) 1244926deccbSFrançois Tigeot args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; 1245926deccbSFrançois Tigeot else 1246926deccbSFrançois Tigeot args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; 1247926deccbSFrançois Tigeot } else 1248926deccbSFrançois Tigeot args.v4.acConfig.ucRefClkSource = pll_id; 1249926deccbSFrançois Tigeot 1250926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1251926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1252926deccbSFrançois Tigeot args.v4.acConfig.ucTransmitterSel = 0; 1253926deccbSFrançois Tigeot break; 1254926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1255926deccbSFrançois Tigeot args.v4.acConfig.ucTransmitterSel = 1; 1256926deccbSFrançois Tigeot break; 1257926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1258926deccbSFrançois Tigeot args.v4.acConfig.ucTransmitterSel = 2; 1259926deccbSFrançois Tigeot break; 1260926deccbSFrançois Tigeot } 1261926deccbSFrançois Tigeot 1262926deccbSFrançois Tigeot if (is_dp) 1263926deccbSFrançois Tigeot args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */ 1264926deccbSFrançois Tigeot else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 1265926deccbSFrançois Tigeot if (dig->coherent_mode) 1266926deccbSFrançois Tigeot args.v4.acConfig.fCoherentMode = 1; 1267926deccbSFrançois Tigeot if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1268926deccbSFrançois Tigeot args.v4.acConfig.fDualLinkConnector = 1; 1269926deccbSFrançois Tigeot } 1270926deccbSFrançois Tigeot break; 1271926deccbSFrançois Tigeot case 5: 1272926deccbSFrançois Tigeot args.v5.ucAction = action; 1273926deccbSFrançois Tigeot if (is_dp) 1274926deccbSFrançois Tigeot args.v5.usSymClock = cpu_to_le16(dp_clock / 10); 1275926deccbSFrançois Tigeot else 1276926deccbSFrançois Tigeot args.v5.usSymClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1277926deccbSFrançois Tigeot 1278926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1279926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1280926deccbSFrançois Tigeot if (dig->linkb) 1281926deccbSFrançois Tigeot args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB; 1282926deccbSFrançois Tigeot else 1283926deccbSFrançois Tigeot args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA; 1284926deccbSFrançois Tigeot break; 1285926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1286926deccbSFrançois Tigeot if (dig->linkb) 1287926deccbSFrançois Tigeot args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD; 1288926deccbSFrançois Tigeot else 1289926deccbSFrançois Tigeot args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC; 1290926deccbSFrançois Tigeot break; 1291926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1292926deccbSFrançois Tigeot if (dig->linkb) 1293926deccbSFrançois Tigeot args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF; 1294926deccbSFrançois Tigeot else 1295926deccbSFrançois Tigeot args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE; 1296926deccbSFrançois Tigeot break; 129757e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 129857e252bfSMichael Neumann args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG; 129957e252bfSMichael Neumann break; 1300926deccbSFrançois Tigeot } 1301926deccbSFrançois Tigeot if (is_dp) 1302926deccbSFrançois Tigeot args.v5.ucLaneNum = dp_lane_count; 1303c6f73aabSFrançois Tigeot else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1304926deccbSFrançois Tigeot args.v5.ucLaneNum = 8; 1305926deccbSFrançois Tigeot else 1306926deccbSFrançois Tigeot args.v5.ucLaneNum = 4; 1307926deccbSFrançois Tigeot args.v5.ucConnObjId = connector_object_id; 1308926deccbSFrançois Tigeot args.v5.ucDigMode = atombios_get_encoder_mode(encoder); 1309926deccbSFrançois Tigeot 1310926deccbSFrançois Tigeot if (is_dp && rdev->clock.dp_extclk) 1311926deccbSFrançois Tigeot args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK; 1312926deccbSFrançois Tigeot else 1313926deccbSFrançois Tigeot args.v5.asConfig.ucPhyClkSrcId = pll_id; 1314926deccbSFrançois Tigeot 1315926deccbSFrançois Tigeot if (is_dp) 1316926deccbSFrançois Tigeot args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */ 1317926deccbSFrançois Tigeot else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 1318926deccbSFrançois Tigeot if (dig->coherent_mode) 1319926deccbSFrançois Tigeot args.v5.asConfig.ucCoherentMode = 1; 1320926deccbSFrançois Tigeot } 1321926deccbSFrançois Tigeot if (hpd_id == RADEON_HPD_NONE) 1322926deccbSFrançois Tigeot args.v5.asConfig.ucHPDSel = 0; 1323926deccbSFrançois Tigeot else 1324926deccbSFrançois Tigeot args.v5.asConfig.ucHPDSel = hpd_id + 1; 1325ee479021SImre Vadász args.v5.ucDigEncoderSel = 1 << dig_encoder; 1326926deccbSFrançois Tigeot args.v5.ucDPLaneSet = lane_set; 1327926deccbSFrançois Tigeot break; 1328926deccbSFrançois Tigeot default: 1329926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 1330926deccbSFrançois Tigeot break; 1331926deccbSFrançois Tigeot } 1332926deccbSFrançois Tigeot break; 1333926deccbSFrançois Tigeot default: 1334926deccbSFrançois Tigeot DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 1335926deccbSFrançois Tigeot break; 1336926deccbSFrançois Tigeot } 1337926deccbSFrançois Tigeot 1338926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1339926deccbSFrançois Tigeot } 1340926deccbSFrançois Tigeot 1341926deccbSFrançois Tigeot bool 1342926deccbSFrançois Tigeot atombios_set_edp_panel_power(struct drm_connector *connector, int action) 1343926deccbSFrançois Tigeot { 1344926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1345926deccbSFrançois Tigeot struct drm_device *dev = radeon_connector->base.dev; 1346926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1347926deccbSFrançois Tigeot union dig_transmitter_control args; 1348926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 1349926deccbSFrançois Tigeot uint8_t frev, crev; 1350926deccbSFrançois Tigeot 1351926deccbSFrançois Tigeot if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) 1352926deccbSFrançois Tigeot goto done; 1353926deccbSFrançois Tigeot 1354926deccbSFrançois Tigeot if (!ASIC_IS_DCE4(rdev)) 1355926deccbSFrançois Tigeot goto done; 1356926deccbSFrançois Tigeot 1357926deccbSFrançois Tigeot if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && 1358926deccbSFrançois Tigeot (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) 1359926deccbSFrançois Tigeot goto done; 1360926deccbSFrançois Tigeot 1361926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 1362926deccbSFrançois Tigeot goto done; 1363926deccbSFrançois Tigeot 1364926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 1365926deccbSFrançois Tigeot 1366926deccbSFrançois Tigeot args.v1.ucAction = action; 1367926deccbSFrançois Tigeot 1368926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1369926deccbSFrançois Tigeot 1370926deccbSFrançois Tigeot /* wait for the panel to power up */ 1371926deccbSFrançois Tigeot if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { 1372926deccbSFrançois Tigeot int i; 1373926deccbSFrançois Tigeot 1374926deccbSFrançois Tigeot for (i = 0; i < 300; i++) { 1375926deccbSFrançois Tigeot if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) 1376926deccbSFrançois Tigeot return true; 1377c4ef309bSzrj mdelay(1); 1378926deccbSFrançois Tigeot } 1379926deccbSFrançois Tigeot return false; 1380926deccbSFrançois Tigeot } 1381926deccbSFrançois Tigeot done: 1382926deccbSFrançois Tigeot return true; 1383926deccbSFrançois Tigeot } 1384926deccbSFrançois Tigeot 1385926deccbSFrançois Tigeot union external_encoder_control { 1386926deccbSFrançois Tigeot EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; 1387926deccbSFrançois Tigeot EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; 1388926deccbSFrançois Tigeot }; 1389926deccbSFrançois Tigeot 1390926deccbSFrançois Tigeot static void 1391926deccbSFrançois Tigeot atombios_external_encoder_setup(struct drm_encoder *encoder, 1392926deccbSFrançois Tigeot struct drm_encoder *ext_encoder, 1393926deccbSFrançois Tigeot int action) 1394926deccbSFrançois Tigeot { 1395926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1396926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1397926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1398926deccbSFrançois Tigeot struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); 1399926deccbSFrançois Tigeot union external_encoder_control args; 1400926deccbSFrançois Tigeot struct drm_connector *connector; 1401926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); 1402926deccbSFrançois Tigeot u8 frev, crev; 1403926deccbSFrançois Tigeot int dp_clock = 0; 1404926deccbSFrançois Tigeot int dp_lane_count = 0; 1405926deccbSFrançois Tigeot int connector_object_id = 0; 1406926deccbSFrançois Tigeot u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 1407926deccbSFrançois Tigeot 1408926deccbSFrançois Tigeot if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) 1409926deccbSFrançois Tigeot connector = radeon_get_connector_for_encoder_init(encoder); 1410926deccbSFrançois Tigeot else 1411926deccbSFrançois Tigeot connector = radeon_get_connector_for_encoder(encoder); 1412926deccbSFrançois Tigeot 1413926deccbSFrançois Tigeot if (connector) { 1414926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1415926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig_connector = 1416926deccbSFrançois Tigeot radeon_connector->con_priv; 1417926deccbSFrançois Tigeot 1418926deccbSFrançois Tigeot dp_clock = dig_connector->dp_clock; 1419926deccbSFrançois Tigeot dp_lane_count = dig_connector->dp_lane_count; 1420926deccbSFrançois Tigeot connector_object_id = 1421926deccbSFrançois Tigeot (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 1422926deccbSFrançois Tigeot } 1423926deccbSFrançois Tigeot 1424926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 1425926deccbSFrançois Tigeot 1426926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 1427926deccbSFrançois Tigeot return; 1428926deccbSFrançois Tigeot 1429926deccbSFrançois Tigeot switch (frev) { 1430926deccbSFrançois Tigeot case 1: 1431926deccbSFrançois Tigeot /* no params on frev 1 */ 1432926deccbSFrançois Tigeot break; 1433926deccbSFrançois Tigeot case 2: 1434926deccbSFrançois Tigeot switch (crev) { 1435926deccbSFrançois Tigeot case 1: 1436926deccbSFrançois Tigeot case 2: 1437926deccbSFrançois Tigeot args.v1.sDigEncoder.ucAction = action; 1438926deccbSFrançois Tigeot args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1439926deccbSFrançois Tigeot args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); 1440926deccbSFrançois Tigeot 1441926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) { 1442926deccbSFrançois Tigeot if (dp_clock == 270000) 1443926deccbSFrançois Tigeot args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 1444926deccbSFrançois Tigeot args.v1.sDigEncoder.ucLaneNum = dp_lane_count; 1445926deccbSFrançois Tigeot } else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1446926deccbSFrançois Tigeot args.v1.sDigEncoder.ucLaneNum = 8; 1447926deccbSFrançois Tigeot else 1448926deccbSFrançois Tigeot args.v1.sDigEncoder.ucLaneNum = 4; 1449926deccbSFrançois Tigeot break; 1450926deccbSFrançois Tigeot case 3: 1451926deccbSFrançois Tigeot args.v3.sExtEncoder.ucAction = action; 1452926deccbSFrançois Tigeot if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) 1453926deccbSFrançois Tigeot args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); 1454926deccbSFrançois Tigeot else 1455926deccbSFrançois Tigeot args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 1456926deccbSFrançois Tigeot args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); 1457926deccbSFrançois Tigeot 1458926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) { 1459926deccbSFrançois Tigeot if (dp_clock == 270000) 1460926deccbSFrançois Tigeot args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; 1461926deccbSFrançois Tigeot else if (dp_clock == 540000) 1462926deccbSFrançois Tigeot args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; 1463926deccbSFrançois Tigeot args.v3.sExtEncoder.ucLaneNum = dp_lane_count; 1464926deccbSFrançois Tigeot } else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) 1465926deccbSFrançois Tigeot args.v3.sExtEncoder.ucLaneNum = 8; 1466926deccbSFrançois Tigeot else 1467926deccbSFrançois Tigeot args.v3.sExtEncoder.ucLaneNum = 4; 1468926deccbSFrançois Tigeot switch (ext_enum) { 1469926deccbSFrançois Tigeot case GRAPH_OBJECT_ENUM_ID1: 1470926deccbSFrançois Tigeot args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; 1471926deccbSFrançois Tigeot break; 1472926deccbSFrançois Tigeot case GRAPH_OBJECT_ENUM_ID2: 1473926deccbSFrançois Tigeot args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; 1474926deccbSFrançois Tigeot break; 1475926deccbSFrançois Tigeot case GRAPH_OBJECT_ENUM_ID3: 1476926deccbSFrançois Tigeot args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; 1477926deccbSFrançois Tigeot break; 1478926deccbSFrançois Tigeot } 1479926deccbSFrançois Tigeot args.v3.sExtEncoder.ucBitPerColor = radeon_atom_get_bpc(encoder); 1480926deccbSFrançois Tigeot break; 1481926deccbSFrançois Tigeot default: 1482926deccbSFrançois Tigeot DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 1483926deccbSFrançois Tigeot return; 1484926deccbSFrançois Tigeot } 1485926deccbSFrançois Tigeot break; 1486926deccbSFrançois Tigeot default: 1487926deccbSFrançois Tigeot DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 1488926deccbSFrançois Tigeot return; 1489926deccbSFrançois Tigeot } 1490926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1491926deccbSFrançois Tigeot } 1492926deccbSFrançois Tigeot 1493926deccbSFrançois Tigeot static void 1494926deccbSFrançois Tigeot atombios_yuv_setup(struct drm_encoder *encoder, bool enable) 1495926deccbSFrançois Tigeot { 1496926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1497926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1498926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1499926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 1500926deccbSFrançois Tigeot ENABLE_YUV_PS_ALLOCATION args; 1501926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); 1502926deccbSFrançois Tigeot uint32_t temp, reg; 1503926deccbSFrançois Tigeot 1504926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 1505926deccbSFrançois Tigeot 1506926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 1507926deccbSFrançois Tigeot reg = R600_BIOS_3_SCRATCH; 1508926deccbSFrançois Tigeot else 1509926deccbSFrançois Tigeot reg = RADEON_BIOS_3_SCRATCH; 1510926deccbSFrançois Tigeot 1511926deccbSFrançois Tigeot /* XXX: fix up scratch reg handling */ 1512926deccbSFrançois Tigeot temp = RREG32(reg); 1513926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1514926deccbSFrançois Tigeot WREG32(reg, (ATOM_S3_TV1_ACTIVE | 1515926deccbSFrançois Tigeot (radeon_crtc->crtc_id << 18))); 1516926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1517926deccbSFrançois Tigeot WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); 1518926deccbSFrançois Tigeot else 1519926deccbSFrançois Tigeot WREG32(reg, 0); 1520926deccbSFrançois Tigeot 1521926deccbSFrançois Tigeot if (enable) 1522926deccbSFrançois Tigeot args.ucEnable = ATOM_ENABLE; 1523926deccbSFrançois Tigeot args.ucCRTC = radeon_crtc->crtc_id; 1524926deccbSFrançois Tigeot 1525926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1526926deccbSFrançois Tigeot 1527926deccbSFrançois Tigeot WREG32(reg, temp); 1528926deccbSFrançois Tigeot } 1529926deccbSFrançois Tigeot 1530926deccbSFrançois Tigeot static void 1531926deccbSFrançois Tigeot radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) 1532926deccbSFrançois Tigeot { 1533926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1534926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1535926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1536926deccbSFrançois Tigeot DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; 1537926deccbSFrançois Tigeot int index = 0; 1538926deccbSFrançois Tigeot 1539926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 1540926deccbSFrançois Tigeot 1541926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1542926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1543926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1544926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); 1545926deccbSFrançois Tigeot break; 1546926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1547926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI: 1548926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1549926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 1550926deccbSFrançois Tigeot break; 1551926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1552926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1553926deccbSFrançois Tigeot break; 1554926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1555926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 1556926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1557926deccbSFrançois Tigeot else 1558926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); 1559926deccbSFrançois Tigeot break; 1560926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1561926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1562926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1563926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 1564926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1565926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 1566926deccbSFrançois Tigeot else 1567926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 1568926deccbSFrançois Tigeot break; 1569926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1570926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1571926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1572926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 1573926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1574926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 1575926deccbSFrançois Tigeot else 1576926deccbSFrançois Tigeot index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 1577926deccbSFrançois Tigeot break; 1578926deccbSFrançois Tigeot default: 1579926deccbSFrançois Tigeot return; 1580926deccbSFrançois Tigeot } 1581926deccbSFrançois Tigeot 1582926deccbSFrançois Tigeot switch (mode) { 1583926deccbSFrançois Tigeot case DRM_MODE_DPMS_ON: 1584926deccbSFrançois Tigeot args.ucAction = ATOM_ENABLE; 1585926deccbSFrançois Tigeot /* workaround for DVOOutputControl on some RS690 systems */ 1586926deccbSFrançois Tigeot if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { 1587926deccbSFrançois Tigeot u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); 1588926deccbSFrançois Tigeot WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); 1589926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1590926deccbSFrançois Tigeot WREG32(RADEON_BIOS_3_SCRATCH, reg); 1591926deccbSFrançois Tigeot } else 1592926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1593926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 1594926deccbSFrançois Tigeot args.ucAction = ATOM_LCD_BLON; 1595926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1596926deccbSFrançois Tigeot } 1597926deccbSFrançois Tigeot break; 1598926deccbSFrançois Tigeot case DRM_MODE_DPMS_STANDBY: 1599926deccbSFrançois Tigeot case DRM_MODE_DPMS_SUSPEND: 1600926deccbSFrançois Tigeot case DRM_MODE_DPMS_OFF: 1601926deccbSFrançois Tigeot args.ucAction = ATOM_DISABLE; 1602926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1603926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 1604926deccbSFrançois Tigeot args.ucAction = ATOM_LCD_BLOFF; 1605926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1606926deccbSFrançois Tigeot } 1607926deccbSFrançois Tigeot break; 1608926deccbSFrançois Tigeot } 1609926deccbSFrançois Tigeot } 1610926deccbSFrançois Tigeot 1611926deccbSFrançois Tigeot static void 1612926deccbSFrançois Tigeot radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) 1613926deccbSFrançois Tigeot { 1614926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1615926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1616926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1617926deccbSFrançois Tigeot struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 1618926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 1619926deccbSFrançois Tigeot struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 1620926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = NULL; 1621926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = NULL; 1622c6f73aabSFrançois Tigeot bool travis_quirk = false; 1623926deccbSFrançois Tigeot 1624926deccbSFrançois Tigeot if (connector) { 1625926deccbSFrançois Tigeot radeon_connector = to_radeon_connector(connector); 1626926deccbSFrançois Tigeot radeon_dig_connector = radeon_connector->con_priv; 1627c6f73aabSFrançois Tigeot if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == 1628c6f73aabSFrançois Tigeot ENCODER_OBJECT_ID_TRAVIS) && 1629c6f73aabSFrançois Tigeot (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 1630c6f73aabSFrançois Tigeot !ASIC_IS_DCE5(rdev)) 1631c6f73aabSFrançois Tigeot travis_quirk = true; 1632926deccbSFrançois Tigeot } 1633926deccbSFrançois Tigeot 1634926deccbSFrançois Tigeot switch (mode) { 1635926deccbSFrançois Tigeot case DRM_MODE_DPMS_ON: 1636926deccbSFrançois Tigeot if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { 1637926deccbSFrançois Tigeot if (!connector) 1638926deccbSFrançois Tigeot dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; 1639926deccbSFrançois Tigeot else 1640926deccbSFrançois Tigeot dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); 1641926deccbSFrançois Tigeot 1642926deccbSFrançois Tigeot /* setup and enable the encoder */ 1643926deccbSFrançois Tigeot atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); 1644926deccbSFrançois Tigeot atombios_dig_encoder_setup(encoder, 1645926deccbSFrançois Tigeot ATOM_ENCODER_CMD_SETUP_PANEL_MODE, 1646926deccbSFrançois Tigeot dig->panel_mode); 1647926deccbSFrançois Tigeot if (ext_encoder) { 1648926deccbSFrançois Tigeot if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) 1649926deccbSFrançois Tigeot atombios_external_encoder_setup(encoder, ext_encoder, 1650926deccbSFrançois Tigeot EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); 1651926deccbSFrançois Tigeot } 1652926deccbSFrançois Tigeot } else if (ASIC_IS_DCE4(rdev)) { 1653926deccbSFrançois Tigeot /* setup and enable the encoder */ 1654926deccbSFrançois Tigeot atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); 1655926deccbSFrançois Tigeot } else { 1656926deccbSFrançois Tigeot /* setup and enable the encoder and transmitter */ 1657926deccbSFrançois Tigeot atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); 1658926deccbSFrançois Tigeot atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); 1659926deccbSFrançois Tigeot } 1660926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 1661926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 1662926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1663926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_ON); 1664926deccbSFrançois Tigeot radeon_dig_connector->edp_on = true; 1665926deccbSFrançois Tigeot } 1666c6f73aabSFrançois Tigeot } 1667c6f73aabSFrançois Tigeot /* enable the transmitter */ 1668c6f73aabSFrançois Tigeot atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 1669c6f73aabSFrançois Tigeot if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 1670c6f73aabSFrançois Tigeot /* DP_SET_POWER_D0 is set in radeon_dp_link_train */ 1671926deccbSFrançois Tigeot radeon_dp_link_train(encoder, connector); 1672926deccbSFrançois Tigeot if (ASIC_IS_DCE4(rdev)) 1673926deccbSFrançois Tigeot atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); 1674926deccbSFrançois Tigeot } 1675ee479021SImre Vadász if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 1676c6f73aabSFrançois Tigeot atombios_dig_transmitter_setup(encoder, 1677c6f73aabSFrançois Tigeot ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); 1678c6f73aabSFrançois Tigeot if (ext_encoder) 1679c6f73aabSFrançois Tigeot atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); 1680926deccbSFrançois Tigeot break; 1681926deccbSFrançois Tigeot case DRM_MODE_DPMS_STANDBY: 1682926deccbSFrançois Tigeot case DRM_MODE_DPMS_SUSPEND: 1683926deccbSFrançois Tigeot case DRM_MODE_DPMS_OFF: 1684c6f73aabSFrançois Tigeot if (ASIC_IS_DCE4(rdev)) { 1685c6f73aabSFrançois Tigeot if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) 1686c6f73aabSFrançois Tigeot atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); 1687c6f73aabSFrançois Tigeot } 1688c6f73aabSFrançois Tigeot if (ext_encoder) 1689c6f73aabSFrançois Tigeot atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); 1690c6f73aabSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 1691c6f73aabSFrançois Tigeot atombios_dig_transmitter_setup(encoder, 1692c6f73aabSFrançois Tigeot ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); 1693c6f73aabSFrançois Tigeot 1694c6f73aabSFrançois Tigeot if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && 1695c6f73aabSFrançois Tigeot connector && !travis_quirk) 1696c6f73aabSFrançois Tigeot radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); 1697c6f73aabSFrançois Tigeot if (ASIC_IS_DCE4(rdev)) { 1698926deccbSFrançois Tigeot /* disable the transmitter */ 1699c6f73aabSFrançois Tigeot atombios_dig_transmitter_setup(encoder, 1700c6f73aabSFrançois Tigeot ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 1701926deccbSFrançois Tigeot } else { 1702926deccbSFrançois Tigeot /* disable the encoder and transmitter */ 1703c6f73aabSFrançois Tigeot atombios_dig_transmitter_setup(encoder, 1704c6f73aabSFrançois Tigeot ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 1705926deccbSFrançois Tigeot atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); 1706926deccbSFrançois Tigeot } 1707926deccbSFrançois Tigeot if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { 1708c6f73aabSFrançois Tigeot if (travis_quirk) 1709c6f73aabSFrançois Tigeot radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); 1710926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 1711926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1712926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_OFF); 1713926deccbSFrançois Tigeot radeon_dig_connector->edp_on = false; 1714926deccbSFrançois Tigeot } 1715926deccbSFrançois Tigeot } 1716926deccbSFrançois Tigeot break; 1717926deccbSFrançois Tigeot } 1718926deccbSFrançois Tigeot } 1719926deccbSFrançois Tigeot 1720926deccbSFrançois Tigeot static void 1721926deccbSFrançois Tigeot radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) 1722926deccbSFrançois Tigeot { 1723926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1724926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1725926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1726926deccbSFrançois Tigeot 1727926deccbSFrançois Tigeot DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", 1728926deccbSFrançois Tigeot radeon_encoder->encoder_id, mode, radeon_encoder->devices, 1729926deccbSFrançois Tigeot radeon_encoder->active_device); 1730926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1731926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1732926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1733926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1734926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1735926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1736926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI: 1737926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1738926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1739926deccbSFrançois Tigeot radeon_atom_encoder_dpms_avivo(encoder, mode); 1740926deccbSFrançois Tigeot break; 1741926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1742926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1743926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 174457e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 1745926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1746926deccbSFrançois Tigeot radeon_atom_encoder_dpms_dig(encoder, mode); 1747926deccbSFrançois Tigeot break; 1748926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1749926deccbSFrançois Tigeot if (ASIC_IS_DCE5(rdev)) { 1750926deccbSFrançois Tigeot switch (mode) { 1751926deccbSFrançois Tigeot case DRM_MODE_DPMS_ON: 1752926deccbSFrançois Tigeot atombios_dvo_setup(encoder, ATOM_ENABLE); 1753926deccbSFrançois Tigeot break; 1754926deccbSFrançois Tigeot case DRM_MODE_DPMS_STANDBY: 1755926deccbSFrançois Tigeot case DRM_MODE_DPMS_SUSPEND: 1756926deccbSFrançois Tigeot case DRM_MODE_DPMS_OFF: 1757926deccbSFrançois Tigeot atombios_dvo_setup(encoder, ATOM_DISABLE); 1758926deccbSFrançois Tigeot break; 1759926deccbSFrançois Tigeot } 1760926deccbSFrançois Tigeot } else if (ASIC_IS_DCE3(rdev)) 1761926deccbSFrançois Tigeot radeon_atom_encoder_dpms_dig(encoder, mode); 1762926deccbSFrançois Tigeot else 1763926deccbSFrançois Tigeot radeon_atom_encoder_dpms_avivo(encoder, mode); 1764926deccbSFrançois Tigeot break; 1765926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1766926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1767926deccbSFrançois Tigeot if (ASIC_IS_DCE5(rdev)) { 1768926deccbSFrançois Tigeot switch (mode) { 1769926deccbSFrançois Tigeot case DRM_MODE_DPMS_ON: 1770926deccbSFrançois Tigeot atombios_dac_setup(encoder, ATOM_ENABLE); 1771926deccbSFrançois Tigeot break; 1772926deccbSFrançois Tigeot case DRM_MODE_DPMS_STANDBY: 1773926deccbSFrançois Tigeot case DRM_MODE_DPMS_SUSPEND: 1774926deccbSFrançois Tigeot case DRM_MODE_DPMS_OFF: 1775926deccbSFrançois Tigeot atombios_dac_setup(encoder, ATOM_DISABLE); 1776926deccbSFrançois Tigeot break; 1777926deccbSFrançois Tigeot } 1778926deccbSFrançois Tigeot } else 1779926deccbSFrançois Tigeot radeon_atom_encoder_dpms_avivo(encoder, mode); 1780926deccbSFrançois Tigeot break; 1781926deccbSFrançois Tigeot default: 1782926deccbSFrançois Tigeot return; 1783926deccbSFrançois Tigeot } 1784926deccbSFrançois Tigeot 1785926deccbSFrançois Tigeot radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); 1786926deccbSFrançois Tigeot 1787926deccbSFrançois Tigeot } 1788926deccbSFrançois Tigeot 1789926deccbSFrançois Tigeot union crtc_source_param { 1790926deccbSFrançois Tigeot SELECT_CRTC_SOURCE_PS_ALLOCATION v1; 1791926deccbSFrançois Tigeot SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; 1792926deccbSFrançois Tigeot }; 1793926deccbSFrançois Tigeot 1794926deccbSFrançois Tigeot static void 1795926deccbSFrançois Tigeot atombios_set_encoder_crtc_source(struct drm_encoder *encoder) 1796926deccbSFrançois Tigeot { 1797926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1798926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1799926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1800926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 1801926deccbSFrançois Tigeot union crtc_source_param args; 1802926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); 1803926deccbSFrançois Tigeot uint8_t frev, crev; 1804926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig; 1805926deccbSFrançois Tigeot 1806926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 1807926deccbSFrançois Tigeot 1808926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 1809926deccbSFrançois Tigeot return; 1810926deccbSFrançois Tigeot 1811926deccbSFrançois Tigeot switch (frev) { 1812926deccbSFrançois Tigeot case 1: 1813926deccbSFrançois Tigeot switch (crev) { 1814926deccbSFrançois Tigeot case 1: 1815926deccbSFrançois Tigeot default: 1816926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) 1817926deccbSFrançois Tigeot args.v1.ucCRTC = radeon_crtc->crtc_id; 1818926deccbSFrançois Tigeot else { 1819926deccbSFrançois Tigeot if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) { 1820926deccbSFrançois Tigeot args.v1.ucCRTC = radeon_crtc->crtc_id; 1821926deccbSFrançois Tigeot } else { 1822926deccbSFrançois Tigeot args.v1.ucCRTC = radeon_crtc->crtc_id << 2; 1823926deccbSFrançois Tigeot } 1824926deccbSFrançois Tigeot } 1825926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1826926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1827926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1828926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; 1829926deccbSFrançois Tigeot break; 1830926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1831926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1832926deccbSFrançois Tigeot if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) 1833926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; 1834926deccbSFrançois Tigeot else 1835926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; 1836926deccbSFrançois Tigeot break; 1837926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1838926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI: 1839926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1840926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; 1841926deccbSFrançois Tigeot break; 1842926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1843926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1844926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1845926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 1846926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1847926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 1848926deccbSFrançois Tigeot else 1849926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; 1850926deccbSFrançois Tigeot break; 1851926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1852926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1853926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1854926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 1855926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1856926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 1857926deccbSFrançois Tigeot else 1858926deccbSFrançois Tigeot args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; 1859926deccbSFrançois Tigeot break; 1860926deccbSFrançois Tigeot } 1861926deccbSFrançois Tigeot break; 1862926deccbSFrançois Tigeot case 2: 1863926deccbSFrançois Tigeot args.v2.ucCRTC = radeon_crtc->crtc_id; 1864926deccbSFrançois Tigeot if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) { 1865926deccbSFrançois Tigeot struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 1866926deccbSFrançois Tigeot 1867926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) 1868926deccbSFrançois Tigeot args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; 1869926deccbSFrançois Tigeot else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) 1870926deccbSFrançois Tigeot args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; 1871926deccbSFrançois Tigeot else 1872926deccbSFrançois Tigeot args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); 1873c6f73aabSFrançois Tigeot } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 1874c6f73aabSFrançois Tigeot args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; 1875c6f73aabSFrançois Tigeot } else { 1876926deccbSFrançois Tigeot args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); 1877c6f73aabSFrançois Tigeot } 1878926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1879926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1880926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1881926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 188257e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 1883926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1884926deccbSFrançois Tigeot dig = radeon_encoder->enc_priv; 1885926deccbSFrançois Tigeot switch (dig->dig_encoder) { 1886926deccbSFrançois Tigeot case 0: 1887926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; 1888926deccbSFrançois Tigeot break; 1889926deccbSFrançois Tigeot case 1: 1890926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; 1891926deccbSFrançois Tigeot break; 1892926deccbSFrançois Tigeot case 2: 1893926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; 1894926deccbSFrançois Tigeot break; 1895926deccbSFrançois Tigeot case 3: 1896926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; 1897926deccbSFrançois Tigeot break; 1898926deccbSFrançois Tigeot case 4: 1899926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; 1900926deccbSFrançois Tigeot break; 1901926deccbSFrançois Tigeot case 5: 1902926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; 1903926deccbSFrançois Tigeot break; 190457e252bfSMichael Neumann case 6: 190557e252bfSMichael Neumann args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID; 190657e252bfSMichael Neumann break; 1907926deccbSFrançois Tigeot } 1908926deccbSFrançois Tigeot break; 1909926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1910926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; 1911926deccbSFrançois Tigeot break; 1912926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1913926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1914926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1915926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1916926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1917926deccbSFrançois Tigeot else 1918926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; 1919926deccbSFrançois Tigeot break; 1920926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1921926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1922926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1923926deccbSFrançois Tigeot else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1924926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1925926deccbSFrançois Tigeot else 1926926deccbSFrançois Tigeot args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; 1927926deccbSFrançois Tigeot break; 1928926deccbSFrançois Tigeot } 1929926deccbSFrançois Tigeot break; 1930926deccbSFrançois Tigeot } 1931926deccbSFrançois Tigeot break; 1932926deccbSFrançois Tigeot default: 1933926deccbSFrançois Tigeot DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); 1934926deccbSFrançois Tigeot return; 1935926deccbSFrançois Tigeot } 1936926deccbSFrançois Tigeot 1937926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1938926deccbSFrançois Tigeot 1939926deccbSFrançois Tigeot /* update scratch regs with new routing */ 1940926deccbSFrançois Tigeot radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); 1941926deccbSFrançois Tigeot } 1942926deccbSFrançois Tigeot 1943926deccbSFrançois Tigeot static void 1944926deccbSFrançois Tigeot atombios_apply_encoder_quirks(struct drm_encoder *encoder, 1945926deccbSFrançois Tigeot struct drm_display_mode *mode) 1946926deccbSFrançois Tigeot { 1947926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1948926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1949926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1950926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 1951926deccbSFrançois Tigeot 1952926deccbSFrançois Tigeot /* Funky macbooks */ 1953c6f73aabSFrançois Tigeot if ((dev->pdev->device == 0x71C5) && 1954c6f73aabSFrançois Tigeot (dev->pdev->subsystem_vendor == 0x106b) && 1955c6f73aabSFrançois Tigeot (dev->pdev->subsystem_device == 0x0080)) { 1956926deccbSFrançois Tigeot if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { 1957926deccbSFrançois Tigeot uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); 1958926deccbSFrançois Tigeot 1959926deccbSFrançois Tigeot lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; 1960926deccbSFrançois Tigeot lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; 1961926deccbSFrançois Tigeot 1962926deccbSFrançois Tigeot WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); 1963926deccbSFrançois Tigeot } 1964926deccbSFrançois Tigeot } 1965926deccbSFrançois Tigeot 1966926deccbSFrançois Tigeot /* set scaler clears this on some chips */ 1967926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev) && 1968926deccbSFrançois Tigeot (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { 196957e252bfSMichael Neumann if (ASIC_IS_DCE8(rdev)) { 197057e252bfSMichael Neumann if (mode->flags & DRM_MODE_FLAG_INTERLACE) 197157e252bfSMichael Neumann WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 197257e252bfSMichael Neumann CIK_INTERLEAVE_EN); 197357e252bfSMichael Neumann else 197457e252bfSMichael Neumann WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 197557e252bfSMichael Neumann } else if (ASIC_IS_DCE4(rdev)) { 1976926deccbSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1977926deccbSFrançois Tigeot WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 1978926deccbSFrançois Tigeot EVERGREEN_INTERLEAVE_EN); 1979926deccbSFrançois Tigeot else 1980926deccbSFrançois Tigeot WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1981926deccbSFrançois Tigeot } else { 1982926deccbSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1983926deccbSFrançois Tigeot WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 1984926deccbSFrançois Tigeot AVIVO_D1MODE_INTERLEAVE_EN); 1985926deccbSFrançois Tigeot else 1986926deccbSFrançois Tigeot WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1987926deccbSFrançois Tigeot } 1988926deccbSFrançois Tigeot } 1989926deccbSFrançois Tigeot } 1990926deccbSFrançois Tigeot 1991ee479021SImre Vadász static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) 1992926deccbSFrançois Tigeot { 1993926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 1994926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1995926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 1996926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1997926deccbSFrançois Tigeot struct drm_encoder *test_encoder; 1998926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 1999926deccbSFrançois Tigeot uint32_t dig_enc_in_use = 0; 2000926deccbSFrançois Tigeot 2001926deccbSFrançois Tigeot if (ASIC_IS_DCE6(rdev)) { 2002926deccbSFrançois Tigeot /* DCE6 */ 2003926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 2004926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 2005926deccbSFrançois Tigeot if (dig->linkb) 2006ee479021SImre Vadász return 1; 2007926deccbSFrançois Tigeot else 2008ee479021SImre Vadász return 0; 2009926deccbSFrançois Tigeot break; 2010926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 2011926deccbSFrançois Tigeot if (dig->linkb) 2012ee479021SImre Vadász return 3; 2013926deccbSFrançois Tigeot else 2014ee479021SImre Vadász return 2; 2015926deccbSFrançois Tigeot break; 2016926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 2017926deccbSFrançois Tigeot if (dig->linkb) 2018ee479021SImre Vadász return 5; 2019926deccbSFrançois Tigeot else 2020ee479021SImre Vadász return 4; 2021926deccbSFrançois Tigeot break; 202257e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 2023ee479021SImre Vadász return 6; 202457e252bfSMichael Neumann break; 2025926deccbSFrançois Tigeot } 2026926deccbSFrançois Tigeot } else if (ASIC_IS_DCE4(rdev)) { 2027926deccbSFrançois Tigeot /* DCE4/5 */ 2028926deccbSFrançois Tigeot if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { 2029926deccbSFrançois Tigeot /* ontario follows DCE4 */ 2030926deccbSFrançois Tigeot if (rdev->family == CHIP_PALM) { 2031926deccbSFrançois Tigeot if (dig->linkb) 2032ee479021SImre Vadász return 1; 2033926deccbSFrançois Tigeot else 2034ee479021SImre Vadász return 0; 2035926deccbSFrançois Tigeot } else 2036926deccbSFrançois Tigeot /* llano follows DCE3.2 */ 2037ee479021SImre Vadász return radeon_crtc->crtc_id; 2038926deccbSFrançois Tigeot } else { 2039926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 2040926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 2041926deccbSFrançois Tigeot if (dig->linkb) 2042ee479021SImre Vadász return 1; 2043926deccbSFrançois Tigeot else 2044ee479021SImre Vadász return 0; 2045926deccbSFrançois Tigeot break; 2046926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 2047926deccbSFrançois Tigeot if (dig->linkb) 2048ee479021SImre Vadász return 3; 2049926deccbSFrançois Tigeot else 2050ee479021SImre Vadász return 2; 2051926deccbSFrançois Tigeot break; 2052926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 2053926deccbSFrançois Tigeot if (dig->linkb) 2054ee479021SImre Vadász return 5; 2055926deccbSFrançois Tigeot else 2056ee479021SImre Vadász return 4; 2057926deccbSFrançois Tigeot break; 2058926deccbSFrançois Tigeot } 2059926deccbSFrançois Tigeot } 2060926deccbSFrançois Tigeot } 2061926deccbSFrançois Tigeot 2062926deccbSFrançois Tigeot /* on DCE32 and encoder can driver any block so just crtc id */ 2063926deccbSFrançois Tigeot if (ASIC_IS_DCE32(rdev)) { 2064ee479021SImre Vadász return radeon_crtc->crtc_id; 2065926deccbSFrançois Tigeot } 2066926deccbSFrançois Tigeot 2067926deccbSFrançois Tigeot /* on DCE3 - LVTMA can only be driven by DIGB */ 2068926deccbSFrançois Tigeot list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 2069926deccbSFrançois Tigeot struct radeon_encoder *radeon_test_encoder; 2070926deccbSFrançois Tigeot 2071926deccbSFrançois Tigeot if (encoder == test_encoder) 2072926deccbSFrançois Tigeot continue; 2073926deccbSFrançois Tigeot 2074926deccbSFrançois Tigeot if (!radeon_encoder_is_digital(test_encoder)) 2075926deccbSFrançois Tigeot continue; 2076926deccbSFrançois Tigeot 2077926deccbSFrançois Tigeot radeon_test_encoder = to_radeon_encoder(test_encoder); 2078926deccbSFrançois Tigeot dig = radeon_test_encoder->enc_priv; 2079926deccbSFrançois Tigeot 2080926deccbSFrançois Tigeot if (dig->dig_encoder >= 0) 2081926deccbSFrançois Tigeot dig_enc_in_use |= (1 << dig->dig_encoder); 2082926deccbSFrançois Tigeot } 2083926deccbSFrançois Tigeot 2084926deccbSFrançois Tigeot if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { 2085926deccbSFrançois Tigeot if (dig_enc_in_use & 0x2) 2086926deccbSFrançois Tigeot DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); 2087926deccbSFrançois Tigeot return 1; 2088926deccbSFrançois Tigeot } 2089926deccbSFrançois Tigeot if (!(dig_enc_in_use & 1)) 2090926deccbSFrançois Tigeot return 0; 2091926deccbSFrançois Tigeot return 1; 2092926deccbSFrançois Tigeot } 2093926deccbSFrançois Tigeot 2094926deccbSFrançois Tigeot /* This only needs to be called once at startup */ 2095926deccbSFrançois Tigeot void 2096926deccbSFrançois Tigeot radeon_atom_encoder_init(struct radeon_device *rdev) 2097926deccbSFrançois Tigeot { 2098926deccbSFrançois Tigeot struct drm_device *dev = rdev->ddev; 2099926deccbSFrançois Tigeot struct drm_encoder *encoder; 2100926deccbSFrançois Tigeot 2101926deccbSFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 2102926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2103926deccbSFrançois Tigeot struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 2104926deccbSFrançois Tigeot 2105926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 2106926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 2107926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 2108926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 210957e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 2110926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 2111926deccbSFrançois Tigeot atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 2112926deccbSFrançois Tigeot break; 2113926deccbSFrançois Tigeot default: 2114926deccbSFrançois Tigeot break; 2115926deccbSFrançois Tigeot } 2116926deccbSFrançois Tigeot 2117926deccbSFrançois Tigeot if (ext_encoder && (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))) 2118926deccbSFrançois Tigeot atombios_external_encoder_setup(encoder, ext_encoder, 2119926deccbSFrançois Tigeot EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); 2120926deccbSFrançois Tigeot } 2121926deccbSFrançois Tigeot } 2122926deccbSFrançois Tigeot 2123926deccbSFrançois Tigeot static void 2124926deccbSFrançois Tigeot radeon_atom_encoder_mode_set(struct drm_encoder *encoder, 2125926deccbSFrançois Tigeot struct drm_display_mode *mode, 2126926deccbSFrançois Tigeot struct drm_display_mode *adjusted_mode) 2127926deccbSFrançois Tigeot { 2128926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 2129926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2130926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2131926deccbSFrançois Tigeot 2132926deccbSFrançois Tigeot radeon_encoder->pixel_clock = adjusted_mode->clock; 2133926deccbSFrançois Tigeot 2134926deccbSFrançois Tigeot /* need to call this here rather than in prepare() since we need some crtc info */ 2135926deccbSFrançois Tigeot radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 2136926deccbSFrançois Tigeot 2137926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { 2138926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) 2139926deccbSFrançois Tigeot atombios_yuv_setup(encoder, true); 2140926deccbSFrançois Tigeot else 2141926deccbSFrançois Tigeot atombios_yuv_setup(encoder, false); 2142926deccbSFrançois Tigeot } 2143926deccbSFrançois Tigeot 2144926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 2145926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 2146926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 2147926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 2148926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 2149926deccbSFrançois Tigeot atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); 2150926deccbSFrançois Tigeot break; 2151926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 2152926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 2153926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 215457e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 2155926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 2156926deccbSFrançois Tigeot /* handled in dpms */ 2157926deccbSFrançois Tigeot break; 2158926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI: 2159926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DVO1: 2160926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 2161926deccbSFrançois Tigeot atombios_dvo_setup(encoder, ATOM_ENABLE); 2162926deccbSFrançois Tigeot break; 2163926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 2164926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 2165926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 2166926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 2167926deccbSFrançois Tigeot atombios_dac_setup(encoder, ATOM_ENABLE); 2168926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { 2169926deccbSFrançois Tigeot if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 2170926deccbSFrançois Tigeot atombios_tv_setup(encoder, ATOM_ENABLE); 2171926deccbSFrançois Tigeot else 2172926deccbSFrançois Tigeot atombios_tv_setup(encoder, ATOM_DISABLE); 2173926deccbSFrançois Tigeot } 2174926deccbSFrançois Tigeot break; 2175926deccbSFrançois Tigeot } 2176926deccbSFrançois Tigeot 2177926deccbSFrançois Tigeot atombios_apply_encoder_quirks(encoder, adjusted_mode); 2178926deccbSFrançois Tigeot 2179ee479021SImre Vadász if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { 2180ee479021SImre Vadász if (rdev->asic->display.hdmi_enable) 2181ee479021SImre Vadász radeon_hdmi_enable(rdev, encoder, true); 2182ee479021SImre Vadász if (rdev->asic->display.hdmi_setmode) 2183ee479021SImre Vadász radeon_hdmi_setmode(rdev, encoder, adjusted_mode); 2184ee479021SImre Vadász } 2185926deccbSFrançois Tigeot } 2186926deccbSFrançois Tigeot 2187926deccbSFrançois Tigeot static bool 2188926deccbSFrançois Tigeot atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) 2189926deccbSFrançois Tigeot { 2190926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 2191926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2192926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2193926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 2194926deccbSFrançois Tigeot 2195926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | 2196926deccbSFrançois Tigeot ATOM_DEVICE_CV_SUPPORT | 2197926deccbSFrançois Tigeot ATOM_DEVICE_CRT_SUPPORT)) { 2198926deccbSFrançois Tigeot DAC_LOAD_DETECTION_PS_ALLOCATION args; 2199926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); 2200926deccbSFrançois Tigeot uint8_t frev, crev; 2201926deccbSFrançois Tigeot 2202926deccbSFrançois Tigeot memset(&args, 0, sizeof(args)); 2203926deccbSFrançois Tigeot 2204926deccbSFrançois Tigeot if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 2205926deccbSFrançois Tigeot return false; 2206926deccbSFrançois Tigeot 2207926deccbSFrançois Tigeot args.sDacload.ucMisc = 0; 2208926deccbSFrançois Tigeot 2209926deccbSFrançois Tigeot if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 2210926deccbSFrançois Tigeot (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) 2211926deccbSFrançois Tigeot args.sDacload.ucDacType = ATOM_DAC_A; 2212926deccbSFrançois Tigeot else 2213926deccbSFrançois Tigeot args.sDacload.ucDacType = ATOM_DAC_B; 2214926deccbSFrançois Tigeot 2215926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) 2216926deccbSFrançois Tigeot args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); 2217926deccbSFrançois Tigeot else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) 2218926deccbSFrançois Tigeot args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); 2219926deccbSFrançois Tigeot else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 2220926deccbSFrançois Tigeot args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); 2221926deccbSFrançois Tigeot if (crev >= 3) 2222926deccbSFrançois Tigeot args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 2223926deccbSFrançois Tigeot } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 2224926deccbSFrançois Tigeot args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); 2225926deccbSFrançois Tigeot if (crev >= 3) 2226926deccbSFrançois Tigeot args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 2227926deccbSFrançois Tigeot } 2228926deccbSFrançois Tigeot 2229926deccbSFrançois Tigeot atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 2230926deccbSFrançois Tigeot 2231926deccbSFrançois Tigeot return true; 2232926deccbSFrançois Tigeot } else 2233926deccbSFrançois Tigeot return false; 2234926deccbSFrançois Tigeot } 2235926deccbSFrançois Tigeot 2236926deccbSFrançois Tigeot static enum drm_connector_status 2237926deccbSFrançois Tigeot radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) 2238926deccbSFrançois Tigeot { 2239926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 2240926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2241926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2242926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 2243926deccbSFrançois Tigeot uint32_t bios_0_scratch; 2244926deccbSFrançois Tigeot 2245926deccbSFrançois Tigeot if (!atombios_dac_load_detect(encoder, connector)) { 2246926deccbSFrançois Tigeot DRM_DEBUG_KMS("detect returned false \n"); 2247926deccbSFrançois Tigeot return connector_status_unknown; 2248926deccbSFrançois Tigeot } 2249926deccbSFrançois Tigeot 2250926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 2251926deccbSFrançois Tigeot bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 2252926deccbSFrançois Tigeot else 2253926deccbSFrançois Tigeot bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); 2254926deccbSFrançois Tigeot 2255926deccbSFrançois Tigeot DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); 2256926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { 2257926deccbSFrançois Tigeot if (bios_0_scratch & ATOM_S0_CRT1_MASK) 2258926deccbSFrançois Tigeot return connector_status_connected; 2259926deccbSFrançois Tigeot } 2260926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { 2261926deccbSFrançois Tigeot if (bios_0_scratch & ATOM_S0_CRT2_MASK) 2262926deccbSFrançois Tigeot return connector_status_connected; 2263926deccbSFrançois Tigeot } 2264926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 2265926deccbSFrançois Tigeot if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) 2266926deccbSFrançois Tigeot return connector_status_connected; 2267926deccbSFrançois Tigeot } 2268926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 2269926deccbSFrançois Tigeot if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 2270926deccbSFrançois Tigeot return connector_status_connected; /* CTV */ 2271926deccbSFrançois Tigeot else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 2272926deccbSFrançois Tigeot return connector_status_connected; /* STV */ 2273926deccbSFrançois Tigeot } 2274926deccbSFrançois Tigeot return connector_status_disconnected; 2275926deccbSFrançois Tigeot } 2276926deccbSFrançois Tigeot 2277926deccbSFrançois Tigeot static enum drm_connector_status 2278926deccbSFrançois Tigeot radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) 2279926deccbSFrançois Tigeot { 2280926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 2281926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2282926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2283926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 2284926deccbSFrançois Tigeot struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 2285926deccbSFrançois Tigeot u32 bios_0_scratch; 2286926deccbSFrançois Tigeot 2287926deccbSFrançois Tigeot if (!ASIC_IS_DCE4(rdev)) 2288926deccbSFrançois Tigeot return connector_status_unknown; 2289926deccbSFrançois Tigeot 2290926deccbSFrançois Tigeot if (!ext_encoder) 2291926deccbSFrançois Tigeot return connector_status_unknown; 2292926deccbSFrançois Tigeot 2293926deccbSFrançois Tigeot if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) 2294926deccbSFrançois Tigeot return connector_status_unknown; 2295926deccbSFrançois Tigeot 2296926deccbSFrançois Tigeot /* load detect on the dp bridge */ 2297926deccbSFrançois Tigeot atombios_external_encoder_setup(encoder, ext_encoder, 2298926deccbSFrançois Tigeot EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); 2299926deccbSFrançois Tigeot 2300926deccbSFrançois Tigeot bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 2301926deccbSFrançois Tigeot 2302926deccbSFrançois Tigeot DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); 2303926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { 2304926deccbSFrançois Tigeot if (bios_0_scratch & ATOM_S0_CRT1_MASK) 2305926deccbSFrançois Tigeot return connector_status_connected; 2306926deccbSFrançois Tigeot } 2307926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { 2308926deccbSFrançois Tigeot if (bios_0_scratch & ATOM_S0_CRT2_MASK) 2309926deccbSFrançois Tigeot return connector_status_connected; 2310926deccbSFrançois Tigeot } 2311926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { 2312926deccbSFrançois Tigeot if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) 2313926deccbSFrançois Tigeot return connector_status_connected; 2314926deccbSFrançois Tigeot } 2315926deccbSFrançois Tigeot if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { 2316926deccbSFrançois Tigeot if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 2317926deccbSFrançois Tigeot return connector_status_connected; /* CTV */ 2318926deccbSFrançois Tigeot else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 2319926deccbSFrançois Tigeot return connector_status_connected; /* STV */ 2320926deccbSFrançois Tigeot } 2321926deccbSFrançois Tigeot return connector_status_disconnected; 2322926deccbSFrançois Tigeot } 2323926deccbSFrançois Tigeot 2324926deccbSFrançois Tigeot void 2325926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) 2326926deccbSFrançois Tigeot { 2327926deccbSFrançois Tigeot struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); 2328926deccbSFrançois Tigeot 2329926deccbSFrançois Tigeot if (ext_encoder) 2330926deccbSFrançois Tigeot /* ddc_setup on the dp bridge */ 2331926deccbSFrançois Tigeot atombios_external_encoder_setup(encoder, ext_encoder, 2332926deccbSFrançois Tigeot EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); 2333926deccbSFrançois Tigeot 2334926deccbSFrançois Tigeot } 2335926deccbSFrançois Tigeot 2336926deccbSFrançois Tigeot static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) 2337926deccbSFrançois Tigeot { 2338926deccbSFrançois Tigeot struct radeon_device *rdev = encoder->dev->dev_private; 2339926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2340926deccbSFrançois Tigeot struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 2341926deccbSFrançois Tigeot 2342926deccbSFrançois Tigeot if ((radeon_encoder->active_device & 2343926deccbSFrançois Tigeot (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || 2344926deccbSFrançois Tigeot (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 2345926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE)) { 2346926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 2347926deccbSFrançois Tigeot if (dig) { 2348ee479021SImre Vadász dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); 2349926deccbSFrançois Tigeot if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) { 2350926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 2351926deccbSFrançois Tigeot dig->afmt = rdev->mode_info.afmt[dig->dig_encoder]; 2352926deccbSFrançois Tigeot else 2353926deccbSFrançois Tigeot /* RS600/690/740 have only 1 afmt block */ 2354926deccbSFrançois Tigeot dig->afmt = rdev->mode_info.afmt[0]; 2355926deccbSFrançois Tigeot } 2356926deccbSFrançois Tigeot } 2357926deccbSFrançois Tigeot } 2358926deccbSFrançois Tigeot 2359926deccbSFrançois Tigeot radeon_atom_output_lock(encoder, true); 2360926deccbSFrançois Tigeot 2361926deccbSFrançois Tigeot if (connector) { 2362926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 2363926deccbSFrançois Tigeot 2364926deccbSFrançois Tigeot /* select the clock/data port if it uses a router */ 2365926deccbSFrançois Tigeot if (radeon_connector->router.cd_valid) 2366926deccbSFrançois Tigeot radeon_router_select_cd_port(radeon_connector); 2367926deccbSFrançois Tigeot 2368926deccbSFrançois Tigeot /* turn eDP panel on for mode set */ 2369926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) 2370926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 2371926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_ON); 2372926deccbSFrançois Tigeot } 2373926deccbSFrançois Tigeot 2374926deccbSFrançois Tigeot /* this is needed for the pll/ss setup to work correctly in some cases */ 2375926deccbSFrançois Tigeot atombios_set_encoder_crtc_source(encoder); 2376c6f73aabSFrançois Tigeot /* set up the FMT blocks */ 2377c6f73aabSFrançois Tigeot if (ASIC_IS_DCE8(rdev)) 2378c6f73aabSFrançois Tigeot dce8_program_fmt(encoder); 2379c6f73aabSFrançois Tigeot else if (ASIC_IS_DCE4(rdev)) 2380c6f73aabSFrançois Tigeot dce4_program_fmt(encoder); 2381c6f73aabSFrançois Tigeot else if (ASIC_IS_DCE3(rdev)) 2382c6f73aabSFrançois Tigeot dce3_program_fmt(encoder); 2383c6f73aabSFrançois Tigeot else if (ASIC_IS_AVIVO(rdev)) 2384c6f73aabSFrançois Tigeot avivo_program_fmt(encoder); 2385926deccbSFrançois Tigeot } 2386926deccbSFrançois Tigeot 2387926deccbSFrançois Tigeot static void radeon_atom_encoder_commit(struct drm_encoder *encoder) 2388926deccbSFrançois Tigeot { 2389926deccbSFrançois Tigeot /* need to call this here as we need the crtc set up */ 2390926deccbSFrançois Tigeot radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); 2391926deccbSFrançois Tigeot radeon_atom_output_lock(encoder, false); 2392926deccbSFrançois Tigeot } 2393926deccbSFrançois Tigeot 2394926deccbSFrançois Tigeot static void radeon_atom_encoder_disable(struct drm_encoder *encoder) 2395926deccbSFrançois Tigeot { 2396926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 2397926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2398926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2399926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig; 2400926deccbSFrançois Tigeot 2401926deccbSFrançois Tigeot /* check for pre-DCE3 cards with shared encoders; 2402926deccbSFrançois Tigeot * can't really use the links individually, so don't disable 2403926deccbSFrançois Tigeot * the encoder if it's in use by another connector 2404926deccbSFrançois Tigeot */ 2405926deccbSFrançois Tigeot if (!ASIC_IS_DCE3(rdev)) { 2406926deccbSFrançois Tigeot struct drm_encoder *other_encoder; 2407926deccbSFrançois Tigeot struct radeon_encoder *other_radeon_encoder; 2408926deccbSFrançois Tigeot 2409926deccbSFrançois Tigeot list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { 2410926deccbSFrançois Tigeot other_radeon_encoder = to_radeon_encoder(other_encoder); 2411926deccbSFrançois Tigeot if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && 2412926deccbSFrançois Tigeot drm_helper_encoder_in_use(other_encoder)) 2413926deccbSFrançois Tigeot goto disable_done; 2414926deccbSFrançois Tigeot } 2415926deccbSFrançois Tigeot } 2416926deccbSFrançois Tigeot 2417926deccbSFrançois Tigeot radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 2418926deccbSFrançois Tigeot 2419926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 2420926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 2421926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 2422926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 2423926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 2424926deccbSFrançois Tigeot atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); 2425926deccbSFrançois Tigeot break; 2426926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 2427926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 2428926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 242957e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 2430926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 2431926deccbSFrançois Tigeot /* handled in dpms */ 2432926deccbSFrançois Tigeot break; 2433926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI: 2434926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DVO1: 2435926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 2436926deccbSFrançois Tigeot atombios_dvo_setup(encoder, ATOM_DISABLE); 2437926deccbSFrançois Tigeot break; 2438926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 2439926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 2440926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 2441926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 2442926deccbSFrançois Tigeot atombios_dac_setup(encoder, ATOM_DISABLE); 2443926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 2444926deccbSFrançois Tigeot atombios_tv_setup(encoder, ATOM_DISABLE); 2445926deccbSFrançois Tigeot break; 2446926deccbSFrançois Tigeot } 2447926deccbSFrançois Tigeot 2448926deccbSFrançois Tigeot disable_done: 2449926deccbSFrançois Tigeot if (radeon_encoder_is_digital(encoder)) { 2450f43cf1b1SMichael Neumann if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { 2451f43cf1b1SMichael Neumann if (rdev->asic->display.hdmi_enable) 2452f43cf1b1SMichael Neumann radeon_hdmi_enable(rdev, encoder, false); 2453f43cf1b1SMichael Neumann } 2454926deccbSFrançois Tigeot dig = radeon_encoder->enc_priv; 2455926deccbSFrançois Tigeot dig->dig_encoder = -1; 2456926deccbSFrançois Tigeot } 2457926deccbSFrançois Tigeot radeon_encoder->active_device = 0; 2458926deccbSFrançois Tigeot } 2459926deccbSFrançois Tigeot 2460926deccbSFrançois Tigeot /* these are handled by the primary encoders */ 2461926deccbSFrançois Tigeot static void radeon_atom_ext_prepare(struct drm_encoder *encoder) 2462926deccbSFrançois Tigeot { 2463926deccbSFrançois Tigeot 2464926deccbSFrançois Tigeot } 2465926deccbSFrançois Tigeot 2466926deccbSFrançois Tigeot static void radeon_atom_ext_commit(struct drm_encoder *encoder) 2467926deccbSFrançois Tigeot { 2468926deccbSFrançois Tigeot 2469926deccbSFrançois Tigeot } 2470926deccbSFrançois Tigeot 2471926deccbSFrançois Tigeot static void 2472926deccbSFrançois Tigeot radeon_atom_ext_mode_set(struct drm_encoder *encoder, 2473926deccbSFrançois Tigeot struct drm_display_mode *mode, 2474926deccbSFrançois Tigeot struct drm_display_mode *adjusted_mode) 2475926deccbSFrançois Tigeot { 2476926deccbSFrançois Tigeot 2477926deccbSFrançois Tigeot } 2478926deccbSFrançois Tigeot 2479926deccbSFrançois Tigeot static void radeon_atom_ext_disable(struct drm_encoder *encoder) 2480926deccbSFrançois Tigeot { 2481926deccbSFrançois Tigeot 2482926deccbSFrançois Tigeot } 2483926deccbSFrançois Tigeot 2484926deccbSFrançois Tigeot static void 2485926deccbSFrançois Tigeot radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) 2486926deccbSFrançois Tigeot { 2487926deccbSFrançois Tigeot 2488926deccbSFrançois Tigeot } 2489926deccbSFrançois Tigeot 2490926deccbSFrançois Tigeot static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, 2491926deccbSFrançois Tigeot const struct drm_display_mode *mode, 2492926deccbSFrançois Tigeot struct drm_display_mode *adjusted_mode) 2493926deccbSFrançois Tigeot { 2494926deccbSFrançois Tigeot return true; 2495926deccbSFrançois Tigeot } 2496926deccbSFrançois Tigeot 2497926deccbSFrançois Tigeot static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { 2498926deccbSFrançois Tigeot .dpms = radeon_atom_ext_dpms, 2499926deccbSFrançois Tigeot .mode_fixup = radeon_atom_ext_mode_fixup, 2500926deccbSFrançois Tigeot .prepare = radeon_atom_ext_prepare, 2501926deccbSFrançois Tigeot .mode_set = radeon_atom_ext_mode_set, 2502926deccbSFrançois Tigeot .commit = radeon_atom_ext_commit, 2503926deccbSFrançois Tigeot .disable = radeon_atom_ext_disable, 2504926deccbSFrançois Tigeot /* no detect for TMDS/LVDS yet */ 2505926deccbSFrançois Tigeot }; 2506926deccbSFrançois Tigeot 2507926deccbSFrançois Tigeot static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { 2508926deccbSFrançois Tigeot .dpms = radeon_atom_encoder_dpms, 2509926deccbSFrançois Tigeot .mode_fixup = radeon_atom_mode_fixup, 2510926deccbSFrançois Tigeot .prepare = radeon_atom_encoder_prepare, 2511926deccbSFrançois Tigeot .mode_set = radeon_atom_encoder_mode_set, 2512926deccbSFrançois Tigeot .commit = radeon_atom_encoder_commit, 2513926deccbSFrançois Tigeot .disable = radeon_atom_encoder_disable, 2514926deccbSFrançois Tigeot .detect = radeon_atom_dig_detect, 2515926deccbSFrançois Tigeot }; 2516926deccbSFrançois Tigeot 2517926deccbSFrançois Tigeot static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { 2518926deccbSFrançois Tigeot .dpms = radeon_atom_encoder_dpms, 2519926deccbSFrançois Tigeot .mode_fixup = radeon_atom_mode_fixup, 2520926deccbSFrançois Tigeot .prepare = radeon_atom_encoder_prepare, 2521926deccbSFrançois Tigeot .mode_set = radeon_atom_encoder_mode_set, 2522926deccbSFrançois Tigeot .commit = radeon_atom_encoder_commit, 2523926deccbSFrançois Tigeot .detect = radeon_atom_dac_detect, 2524926deccbSFrançois Tigeot }; 2525926deccbSFrançois Tigeot 2526926deccbSFrançois Tigeot void radeon_enc_destroy(struct drm_encoder *encoder) 2527926deccbSFrançois Tigeot { 2528926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 2529926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 2530926deccbSFrançois Tigeot radeon_atom_backlight_exit(radeon_encoder); 2531c4ef309bSzrj kfree(radeon_encoder->enc_priv); 2532926deccbSFrançois Tigeot drm_encoder_cleanup(encoder); 2533c4ef309bSzrj kfree(radeon_encoder); 2534926deccbSFrançois Tigeot } 2535926deccbSFrançois Tigeot 2536926deccbSFrançois Tigeot static const struct drm_encoder_funcs radeon_atom_enc_funcs = { 2537926deccbSFrançois Tigeot .destroy = radeon_enc_destroy, 2538926deccbSFrançois Tigeot }; 2539926deccbSFrançois Tigeot 2540926deccbSFrançois Tigeot static struct radeon_encoder_atom_dac * 2541926deccbSFrançois Tigeot radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) 2542926deccbSFrançois Tigeot { 2543926deccbSFrançois Tigeot struct drm_device *dev = radeon_encoder->base.dev; 2544926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2545c4ef309bSzrj struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); 2546926deccbSFrançois Tigeot 2547926deccbSFrançois Tigeot if (!dac) 2548926deccbSFrançois Tigeot return NULL; 2549926deccbSFrançois Tigeot 2550926deccbSFrançois Tigeot dac->tv_std = radeon_atombios_get_tv_info(rdev); 2551926deccbSFrançois Tigeot return dac; 2552926deccbSFrançois Tigeot } 2553926deccbSFrançois Tigeot 2554926deccbSFrançois Tigeot static struct radeon_encoder_atom_dig * 2555926deccbSFrançois Tigeot radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) 2556926deccbSFrançois Tigeot { 2557926deccbSFrançois Tigeot int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 2558c4ef309bSzrj struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); 2559926deccbSFrançois Tigeot 2560926deccbSFrançois Tigeot if (!dig) 2561926deccbSFrançois Tigeot return NULL; 2562926deccbSFrançois Tigeot 2563926deccbSFrançois Tigeot /* coherent mode by default */ 2564926deccbSFrançois Tigeot dig->coherent_mode = true; 2565926deccbSFrançois Tigeot dig->dig_encoder = -1; 2566926deccbSFrançois Tigeot 2567926deccbSFrançois Tigeot if (encoder_enum == 2) 2568926deccbSFrançois Tigeot dig->linkb = true; 2569926deccbSFrançois Tigeot else 2570926deccbSFrançois Tigeot dig->linkb = false; 2571926deccbSFrançois Tigeot 2572926deccbSFrançois Tigeot return dig; 2573926deccbSFrançois Tigeot } 2574926deccbSFrançois Tigeot 2575926deccbSFrançois Tigeot void 2576926deccbSFrançois Tigeot radeon_add_atom_encoder(struct drm_device *dev, 2577926deccbSFrançois Tigeot uint32_t encoder_enum, 2578926deccbSFrançois Tigeot uint32_t supported_device, 2579926deccbSFrançois Tigeot u16 caps) 2580926deccbSFrançois Tigeot { 2581926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2582926deccbSFrançois Tigeot struct drm_encoder *encoder; 2583926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 2584926deccbSFrançois Tigeot 2585926deccbSFrançois Tigeot /* see if we already added it */ 2586926deccbSFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 2587926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 2588926deccbSFrançois Tigeot if (radeon_encoder->encoder_enum == encoder_enum) { 2589926deccbSFrançois Tigeot radeon_encoder->devices |= supported_device; 2590926deccbSFrançois Tigeot return; 2591926deccbSFrançois Tigeot } 2592926deccbSFrançois Tigeot 2593926deccbSFrançois Tigeot } 2594926deccbSFrançois Tigeot 2595926deccbSFrançois Tigeot /* add a new one */ 2596c4ef309bSzrj radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); 2597926deccbSFrançois Tigeot if (!radeon_encoder) 2598926deccbSFrançois Tigeot return; 2599926deccbSFrançois Tigeot 2600926deccbSFrançois Tigeot encoder = &radeon_encoder->base; 2601926deccbSFrançois Tigeot switch (rdev->num_crtc) { 2602926deccbSFrançois Tigeot case 1: 2603926deccbSFrançois Tigeot encoder->possible_crtcs = 0x1; 2604926deccbSFrançois Tigeot break; 2605926deccbSFrançois Tigeot case 2: 2606926deccbSFrançois Tigeot default: 2607926deccbSFrançois Tigeot encoder->possible_crtcs = 0x3; 2608926deccbSFrançois Tigeot break; 2609926deccbSFrançois Tigeot case 4: 2610926deccbSFrançois Tigeot encoder->possible_crtcs = 0xf; 2611926deccbSFrançois Tigeot break; 2612926deccbSFrançois Tigeot case 6: 2613926deccbSFrançois Tigeot encoder->possible_crtcs = 0x3f; 2614926deccbSFrançois Tigeot break; 2615926deccbSFrançois Tigeot } 2616926deccbSFrançois Tigeot 2617926deccbSFrançois Tigeot radeon_encoder->enc_priv = NULL; 2618926deccbSFrançois Tigeot 2619926deccbSFrançois Tigeot radeon_encoder->encoder_enum = encoder_enum; 2620926deccbSFrançois Tigeot radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; 2621926deccbSFrançois Tigeot radeon_encoder->devices = supported_device; 2622926deccbSFrançois Tigeot radeon_encoder->rmx_type = RMX_OFF; 2623926deccbSFrançois Tigeot radeon_encoder->underscan_type = UNDERSCAN_OFF; 2624926deccbSFrançois Tigeot radeon_encoder->is_ext_encoder = false; 2625926deccbSFrançois Tigeot radeon_encoder->caps = caps; 2626926deccbSFrançois Tigeot 2627926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 2628926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVDS: 2629926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 2630926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 2631926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 2632926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 2633926deccbSFrançois Tigeot radeon_encoder->rmx_type = RMX_FULL; 2634aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2635aee94f86SFrançois Tigeot DRM_MODE_ENCODER_LVDS, NULL); 2636926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 2637926deccbSFrançois Tigeot } else { 2638aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2639aee94f86SFrançois Tigeot DRM_MODE_ENCODER_TMDS, NULL); 2640926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 2641926deccbSFrançois Tigeot } 2642926deccbSFrançois Tigeot drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); 2643926deccbSFrançois Tigeot break; 2644926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC1: 2645aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2646aee94f86SFrançois Tigeot DRM_MODE_ENCODER_DAC, NULL); 2647926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); 2648926deccbSFrançois Tigeot drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); 2649926deccbSFrançois Tigeot break; 2650926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DAC2: 2651926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 2652926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 2653aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2654aee94f86SFrançois Tigeot DRM_MODE_ENCODER_TVDAC, NULL); 2655926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); 2656926deccbSFrançois Tigeot drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); 2657926deccbSFrançois Tigeot break; 2658926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DVO1: 2659926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 2660926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI: 2661926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 2662926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 2663926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 2664926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 266557e252bfSMichael Neumann case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: 2666926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 2667926deccbSFrançois Tigeot radeon_encoder->rmx_type = RMX_FULL; 2668aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2669aee94f86SFrançois Tigeot DRM_MODE_ENCODER_LVDS, NULL); 2670926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); 2671926deccbSFrançois Tigeot } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { 2672aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2673aee94f86SFrançois Tigeot DRM_MODE_ENCODER_DAC, NULL); 2674926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 2675926deccbSFrançois Tigeot } else { 2676aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2677aee94f86SFrançois Tigeot DRM_MODE_ENCODER_TMDS, NULL); 2678926deccbSFrançois Tigeot radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); 2679926deccbSFrançois Tigeot } 2680926deccbSFrançois Tigeot drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); 2681926deccbSFrançois Tigeot break; 2682926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_SI170B: 2683926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_CH7303: 2684926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: 2685926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: 2686926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_TITFP513: 2687926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_VT1623: 2688926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_HDMI_SI1930: 2689926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_TRAVIS: 2690926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_NUTMEG: 2691926deccbSFrançois Tigeot /* these are handled by the primary encoders */ 2692926deccbSFrançois Tigeot radeon_encoder->is_ext_encoder = true; 2693926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 2694aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2695aee94f86SFrançois Tigeot DRM_MODE_ENCODER_LVDS, NULL); 2696926deccbSFrançois Tigeot else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) 2697aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2698aee94f86SFrançois Tigeot DRM_MODE_ENCODER_DAC, NULL); 2699926deccbSFrançois Tigeot else 2700aee94f86SFrançois Tigeot drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, 2701aee94f86SFrançois Tigeot DRM_MODE_ENCODER_TMDS, NULL); 2702926deccbSFrançois Tigeot drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); 2703926deccbSFrançois Tigeot break; 2704926deccbSFrançois Tigeot } 2705926deccbSFrançois Tigeot } 2706