1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2007-8 Advanced Micro Devices, Inc. 3254885Sdumbbell * Copyright 2008 Red Hat Inc. 4254885Sdumbbell * 5254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 6254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 7254885Sdumbbell * to deal in the Software without restriction, including without limitation 8254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 10254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 11254885Sdumbbell * 12254885Sdumbbell * The above copyright notice and this permission notice shall be included in 13254885Sdumbbell * all copies or substantial portions of the Software. 14254885Sdumbbell * 15254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 22254885Sdumbbell * 23254885Sdumbbell * Authors: Dave Airlie 24254885Sdumbbell * Alex Deucher 25254885Sdumbbell */ 26254885Sdumbbell 27254885Sdumbbell#include <sys/cdefs.h> 28254885Sdumbbell__FBSDID("$FreeBSD$"); 29254885Sdumbbell 30254885Sdumbbell#include <dev/drm2/drmP.h> 31254885Sdumbbell#include <dev/drm2/drm_crtc_helper.h> 32254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h> 33254885Sdumbbell#include <dev/drm2/drm_fixed.h> 34254885Sdumbbell#include "radeon.h" 35254885Sdumbbell#include "atom.h" 36254885Sdumbbell 37254885Sdumbbellstatic void radeon_overscan_setup(struct drm_crtc *crtc, 38254885Sdumbbell struct drm_display_mode *mode) 39254885Sdumbbell{ 40254885Sdumbbell struct drm_device *dev = crtc->dev; 41254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 42254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 43254885Sdumbbell 44254885Sdumbbell WREG32(RADEON_OVR_CLR + radeon_crtc->crtc_offset, 0); 45254885Sdumbbell WREG32(RADEON_OVR_WID_LEFT_RIGHT + radeon_crtc->crtc_offset, 0); 46254885Sdumbbell WREG32(RADEON_OVR_WID_TOP_BOTTOM + radeon_crtc->crtc_offset, 0); 47254885Sdumbbell} 48254885Sdumbbell 49254885Sdumbbellstatic void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, 50254885Sdumbbell struct drm_display_mode *mode) 51254885Sdumbbell{ 52254885Sdumbbell struct drm_device *dev = crtc->dev; 53254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 54254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 55254885Sdumbbell int xres = mode->hdisplay; 56254885Sdumbbell int yres = mode->vdisplay; 57254885Sdumbbell bool hscale = true, vscale = true; 58254885Sdumbbell int hsync_wid; 59254885Sdumbbell int vsync_wid; 60254885Sdumbbell int hsync_start; 61254885Sdumbbell int blank_width; 62254885Sdumbbell u32 scale, inc, crtc_more_cntl; 63254885Sdumbbell u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active; 64254885Sdumbbell u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp; 65254885Sdumbbell u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp; 66254885Sdumbbell struct drm_display_mode *native_mode = &radeon_crtc->native_mode; 67254885Sdumbbell 68254885Sdumbbell fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) & 69254885Sdumbbell (RADEON_VERT_STRETCH_RESERVED | 70254885Sdumbbell RADEON_VERT_AUTO_RATIO_INC); 71254885Sdumbbell fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) & 72254885Sdumbbell (RADEON_HORZ_FP_LOOP_STRETCH | 73254885Sdumbbell RADEON_HORZ_AUTO_RATIO_INC); 74254885Sdumbbell 75254885Sdumbbell crtc_more_cntl = 0; 76254885Sdumbbell if ((rdev->family == CHIP_RS100) || 77254885Sdumbbell (rdev->family == CHIP_RS200)) { 78254885Sdumbbell /* This is to workaround the asic bug for RMX, some versions 79298955Spfg of BIOS doesn't have this register initialized correctly. */ 80254885Sdumbbell crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; 81254885Sdumbbell } 82254885Sdumbbell 83254885Sdumbbell 84254885Sdumbbell fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) 85254885Sdumbbell | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); 86254885Sdumbbell 87254885Sdumbbell hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; 88254885Sdumbbell if (!hsync_wid) 89254885Sdumbbell hsync_wid = 1; 90254885Sdumbbell hsync_start = mode->crtc_hsync_start - 8; 91254885Sdumbbell 92254885Sdumbbell fp_h_sync_strt_wid = ((hsync_start & 0x1fff) 93254885Sdumbbell | ((hsync_wid & 0x3f) << 16) 94254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_NHSYNC) 95254885Sdumbbell ? RADEON_CRTC_H_SYNC_POL 96254885Sdumbbell : 0)); 97254885Sdumbbell 98254885Sdumbbell fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) 99254885Sdumbbell | ((mode->crtc_vdisplay - 1) << 16)); 100254885Sdumbbell 101254885Sdumbbell vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; 102254885Sdumbbell if (!vsync_wid) 103254885Sdumbbell vsync_wid = 1; 104254885Sdumbbell 105254885Sdumbbell fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) 106254885Sdumbbell | ((vsync_wid & 0x1f) << 16) 107254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_NVSYNC) 108254885Sdumbbell ? RADEON_CRTC_V_SYNC_POL 109254885Sdumbbell : 0)); 110254885Sdumbbell 111254885Sdumbbell fp_horz_vert_active = 0; 112254885Sdumbbell 113254885Sdumbbell if (native_mode->hdisplay == 0 || 114254885Sdumbbell native_mode->vdisplay == 0) { 115254885Sdumbbell hscale = false; 116254885Sdumbbell vscale = false; 117254885Sdumbbell } else { 118254885Sdumbbell if (xres > native_mode->hdisplay) 119254885Sdumbbell xres = native_mode->hdisplay; 120254885Sdumbbell if (yres > native_mode->vdisplay) 121254885Sdumbbell yres = native_mode->vdisplay; 122254885Sdumbbell 123254885Sdumbbell if (xres == native_mode->hdisplay) 124254885Sdumbbell hscale = false; 125254885Sdumbbell if (yres == native_mode->vdisplay) 126254885Sdumbbell vscale = false; 127254885Sdumbbell } 128254885Sdumbbell 129254885Sdumbbell switch (radeon_crtc->rmx_type) { 130254885Sdumbbell case RMX_FULL: 131254885Sdumbbell case RMX_ASPECT: 132254885Sdumbbell if (!hscale) 133254885Sdumbbell fp_horz_stretch |= ((xres/8-1) << 16); 134254885Sdumbbell else { 135254885Sdumbbell inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; 136254885Sdumbbell scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) 137254885Sdumbbell / native_mode->hdisplay + 1; 138254885Sdumbbell fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | 139254885Sdumbbell RADEON_HORZ_STRETCH_BLEND | 140254885Sdumbbell RADEON_HORZ_STRETCH_ENABLE | 141254885Sdumbbell ((native_mode->hdisplay/8-1) << 16)); 142254885Sdumbbell } 143254885Sdumbbell 144254885Sdumbbell if (!vscale) 145254885Sdumbbell fp_vert_stretch |= ((yres-1) << 12); 146254885Sdumbbell else { 147254885Sdumbbell inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; 148254885Sdumbbell scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) 149254885Sdumbbell / native_mode->vdisplay + 1; 150254885Sdumbbell fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | 151254885Sdumbbell RADEON_VERT_STRETCH_ENABLE | 152254885Sdumbbell RADEON_VERT_STRETCH_BLEND | 153254885Sdumbbell ((native_mode->vdisplay-1) << 12)); 154254885Sdumbbell } 155254885Sdumbbell break; 156254885Sdumbbell case RMX_CENTER: 157254885Sdumbbell fp_horz_stretch |= ((xres/8-1) << 16); 158254885Sdumbbell fp_vert_stretch |= ((yres-1) << 12); 159254885Sdumbbell 160254885Sdumbbell crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN | 161254885Sdumbbell RADEON_CRTC_AUTO_VERT_CENTER_EN); 162254885Sdumbbell 163254885Sdumbbell blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8; 164254885Sdumbbell if (blank_width > 110) 165254885Sdumbbell blank_width = 110; 166254885Sdumbbell 167254885Sdumbbell fp_crtc_h_total_disp = (((blank_width) & 0x3ff) 168254885Sdumbbell | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); 169254885Sdumbbell 170254885Sdumbbell hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; 171254885Sdumbbell if (!hsync_wid) 172254885Sdumbbell hsync_wid = 1; 173254885Sdumbbell 174254885Sdumbbell fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff) 175254885Sdumbbell | ((hsync_wid & 0x3f) << 16) 176254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_NHSYNC) 177254885Sdumbbell ? RADEON_CRTC_H_SYNC_POL 178254885Sdumbbell : 0)); 179254885Sdumbbell 180254885Sdumbbell fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff) 181254885Sdumbbell | ((mode->crtc_vdisplay - 1) << 16)); 182254885Sdumbbell 183254885Sdumbbell vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; 184254885Sdumbbell if (!vsync_wid) 185254885Sdumbbell vsync_wid = 1; 186254885Sdumbbell 187254885Sdumbbell fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff) 188254885Sdumbbell | ((vsync_wid & 0x1f) << 16) 189254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_NVSYNC) 190254885Sdumbbell ? RADEON_CRTC_V_SYNC_POL 191254885Sdumbbell : 0))); 192254885Sdumbbell 193254885Sdumbbell fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) | 194254885Sdumbbell (((native_mode->hdisplay / 8) & 0x1ff) << 16)); 195254885Sdumbbell break; 196254885Sdumbbell case RMX_OFF: 197254885Sdumbbell default: 198254885Sdumbbell fp_horz_stretch |= ((xres/8-1) << 16); 199254885Sdumbbell fp_vert_stretch |= ((yres-1) << 12); 200254885Sdumbbell break; 201254885Sdumbbell } 202254885Sdumbbell 203254885Sdumbbell WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch); 204254885Sdumbbell WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch); 205254885Sdumbbell WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl); 206254885Sdumbbell WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active); 207254885Sdumbbell WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid); 208254885Sdumbbell WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid); 209254885Sdumbbell WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp); 210254885Sdumbbell WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); 211254885Sdumbbell} 212254885Sdumbbell 213254885Sdumbbellstatic void radeon_pll_wait_for_read_update_complete(struct drm_device *dev) 214254885Sdumbbell{ 215254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 216254885Sdumbbell int i = 0; 217254885Sdumbbell 218254885Sdumbbell /* FIXME: Certain revisions of R300 can't recover here. Not sure of 219254885Sdumbbell the cause yet, but this workaround will mask the problem for now. 220254885Sdumbbell Other chips usually will pass at the very first test, so the 221254885Sdumbbell workaround shouldn't have any effect on them. */ 222254885Sdumbbell for (i = 0; 223254885Sdumbbell (i < 10000 && 224254885Sdumbbell RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); 225254885Sdumbbell i++); 226254885Sdumbbell} 227254885Sdumbbell 228254885Sdumbbellstatic void radeon_pll_write_update(struct drm_device *dev) 229254885Sdumbbell{ 230254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 231254885Sdumbbell 232254885Sdumbbell while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); 233254885Sdumbbell 234254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_REF_DIV, 235254885Sdumbbell RADEON_PPLL_ATOMIC_UPDATE_W, 236254885Sdumbbell ~(RADEON_PPLL_ATOMIC_UPDATE_W)); 237254885Sdumbbell} 238254885Sdumbbell 239254885Sdumbbellstatic void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev) 240254885Sdumbbell{ 241254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 242254885Sdumbbell int i = 0; 243254885Sdumbbell 244254885Sdumbbell 245254885Sdumbbell /* FIXME: Certain revisions of R300 can't recover here. Not sure of 246254885Sdumbbell the cause yet, but this workaround will mask the problem for now. 247254885Sdumbbell Other chips usually will pass at the very first test, so the 248254885Sdumbbell workaround shouldn't have any effect on them. */ 249254885Sdumbbell for (i = 0; 250254885Sdumbbell (i < 10000 && 251254885Sdumbbell RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); 252254885Sdumbbell i++); 253254885Sdumbbell} 254254885Sdumbbell 255254885Sdumbbellstatic void radeon_pll2_write_update(struct drm_device *dev) 256254885Sdumbbell{ 257254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 258254885Sdumbbell 259254885Sdumbbell while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); 260254885Sdumbbell 261254885Sdumbbell WREG32_PLL_P(RADEON_P2PLL_REF_DIV, 262254885Sdumbbell RADEON_P2PLL_ATOMIC_UPDATE_W, 263254885Sdumbbell ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); 264254885Sdumbbell} 265254885Sdumbbell 266254885Sdumbbellstatic uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, 267254885Sdumbbell uint16_t fb_div) 268254885Sdumbbell{ 269254885Sdumbbell unsigned int vcoFreq; 270254885Sdumbbell 271254885Sdumbbell if (!ref_div) 272254885Sdumbbell return 1; 273254885Sdumbbell 274254885Sdumbbell vcoFreq = ((unsigned)ref_freq * fb_div) / ref_div; 275254885Sdumbbell 276254885Sdumbbell /* 277254885Sdumbbell * This is horribly crude: the VCO frequency range is divided into 278254885Sdumbbell * 3 parts, each part having a fixed PLL gain value. 279254885Sdumbbell */ 280254885Sdumbbell if (vcoFreq >= 30000) 281254885Sdumbbell /* 282254885Sdumbbell * [300..max] MHz : 7 283254885Sdumbbell */ 284254885Sdumbbell return 7; 285254885Sdumbbell else if (vcoFreq >= 18000) 286254885Sdumbbell /* 287254885Sdumbbell * [180..300) MHz : 4 288254885Sdumbbell */ 289254885Sdumbbell return 4; 290254885Sdumbbell else 291254885Sdumbbell /* 292254885Sdumbbell * [0..180) MHz : 1 293254885Sdumbbell */ 294254885Sdumbbell return 1; 295254885Sdumbbell} 296254885Sdumbbell 297254885Sdumbbellstatic void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) 298254885Sdumbbell{ 299254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 300254885Sdumbbell struct drm_device *dev = crtc->dev; 301254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 302254885Sdumbbell uint32_t crtc_ext_cntl = 0; 303254885Sdumbbell uint32_t mask; 304254885Sdumbbell 305254885Sdumbbell if (radeon_crtc->crtc_id) 306254885Sdumbbell mask = (RADEON_CRTC2_DISP_DIS | 307254885Sdumbbell RADEON_CRTC2_VSYNC_DIS | 308254885Sdumbbell RADEON_CRTC2_HSYNC_DIS | 309254885Sdumbbell RADEON_CRTC2_DISP_REQ_EN_B); 310254885Sdumbbell else 311254885Sdumbbell mask = (RADEON_CRTC_DISPLAY_DIS | 312254885Sdumbbell RADEON_CRTC_VSYNC_DIS | 313254885Sdumbbell RADEON_CRTC_HSYNC_DIS); 314254885Sdumbbell 315254885Sdumbbell /* 316254885Sdumbbell * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC. 317254885Sdumbbell * Therefore it is set in the DAC DMPS function. 318254885Sdumbbell * This is different for GPU's with a single CRTC but a primary and a 319254885Sdumbbell * TV DAC: here it controls the single CRTC no matter where it is 320254885Sdumbbell * routed. Therefore we set it here. 321254885Sdumbbell */ 322254885Sdumbbell if (rdev->flags & RADEON_SINGLE_CRTC) 323254885Sdumbbell crtc_ext_cntl = RADEON_CRTC_CRT_ON; 324254885Sdumbbell 325254885Sdumbbell switch (mode) { 326254885Sdumbbell case DRM_MODE_DPMS_ON: 327254885Sdumbbell radeon_crtc->enabled = true; 328254885Sdumbbell /* adjust pm to dpms changes BEFORE enabling crtcs */ 329254885Sdumbbell radeon_pm_compute_clocks(rdev); 330254885Sdumbbell if (radeon_crtc->crtc_id) 331254885Sdumbbell WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask)); 332254885Sdumbbell else { 333254885Sdumbbell WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | 334254885Sdumbbell RADEON_CRTC_DISP_REQ_EN_B)); 335254885Sdumbbell WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl)); 336254885Sdumbbell } 337254885Sdumbbell drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); 338254885Sdumbbell radeon_crtc_load_lut(crtc); 339254885Sdumbbell break; 340254885Sdumbbell case DRM_MODE_DPMS_STANDBY: 341254885Sdumbbell case DRM_MODE_DPMS_SUSPEND: 342254885Sdumbbell case DRM_MODE_DPMS_OFF: 343254885Sdumbbell drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); 344254885Sdumbbell if (radeon_crtc->crtc_id) 345254885Sdumbbell WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask)); 346254885Sdumbbell else { 347254885Sdumbbell WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | 348254885Sdumbbell RADEON_CRTC_DISP_REQ_EN_B)); 349254885Sdumbbell WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl)); 350254885Sdumbbell } 351254885Sdumbbell radeon_crtc->enabled = false; 352254885Sdumbbell /* adjust pm to dpms changes AFTER disabling crtcs */ 353254885Sdumbbell radeon_pm_compute_clocks(rdev); 354254885Sdumbbell break; 355254885Sdumbbell } 356254885Sdumbbell} 357254885Sdumbbell 358254885Sdumbbellint radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, 359254885Sdumbbell struct drm_framebuffer *old_fb) 360254885Sdumbbell{ 361254885Sdumbbell return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 362254885Sdumbbell} 363254885Sdumbbell 364254885Sdumbbellint radeon_crtc_set_base_atomic(struct drm_crtc *crtc, 365254885Sdumbbell struct drm_framebuffer *fb, 366254885Sdumbbell int x, int y, enum mode_set_atomic state) 367254885Sdumbbell{ 368254885Sdumbbell return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 369254885Sdumbbell} 370254885Sdumbbell 371254885Sdumbbellint radeon_crtc_do_set_base(struct drm_crtc *crtc, 372254885Sdumbbell struct drm_framebuffer *fb, 373254885Sdumbbell int x, int y, int atomic) 374254885Sdumbbell{ 375254885Sdumbbell struct drm_device *dev = crtc->dev; 376254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 377254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 378254885Sdumbbell struct radeon_framebuffer *radeon_fb; 379254885Sdumbbell struct drm_framebuffer *target_fb; 380254885Sdumbbell struct drm_gem_object *obj; 381254885Sdumbbell struct radeon_bo *rbo; 382254885Sdumbbell uint64_t base; 383254885Sdumbbell uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; 384254885Sdumbbell uint32_t crtc_pitch, pitch_pixels; 385254885Sdumbbell uint32_t tiling_flags; 386254885Sdumbbell int format; 387254885Sdumbbell uint32_t gen_cntl_reg, gen_cntl_val; 388254885Sdumbbell int r; 389254885Sdumbbell 390254885Sdumbbell DRM_DEBUG_KMS("\n"); 391254885Sdumbbell /* no fb bound */ 392254885Sdumbbell if (!atomic && !crtc->fb) { 393254885Sdumbbell DRM_DEBUG_KMS("No FB bound\n"); 394254885Sdumbbell return 0; 395254885Sdumbbell } 396254885Sdumbbell 397254885Sdumbbell if (atomic) { 398254885Sdumbbell radeon_fb = to_radeon_framebuffer(fb); 399254885Sdumbbell target_fb = fb; 400254885Sdumbbell } 401254885Sdumbbell else { 402254885Sdumbbell radeon_fb = to_radeon_framebuffer(crtc->fb); 403254885Sdumbbell target_fb = crtc->fb; 404254885Sdumbbell } 405254885Sdumbbell 406254885Sdumbbell switch (target_fb->bits_per_pixel) { 407254885Sdumbbell case 8: 408254885Sdumbbell format = 2; 409254885Sdumbbell break; 410254885Sdumbbell case 15: /* 555 */ 411254885Sdumbbell format = 3; 412254885Sdumbbell break; 413254885Sdumbbell case 16: /* 565 */ 414254885Sdumbbell format = 4; 415254885Sdumbbell break; 416254885Sdumbbell case 24: /* RGB */ 417254885Sdumbbell format = 5; 418254885Sdumbbell break; 419254885Sdumbbell case 32: /* xRGB */ 420254885Sdumbbell format = 6; 421254885Sdumbbell break; 422254885Sdumbbell default: 423254885Sdumbbell return false; 424254885Sdumbbell } 425254885Sdumbbell 426254885Sdumbbell /* Pin framebuffer & get tilling informations */ 427254885Sdumbbell obj = radeon_fb->obj; 428254885Sdumbbell rbo = gem_to_radeon_bo(obj); 429254885Sdumbbell r = radeon_bo_reserve(rbo, false); 430254885Sdumbbell if (unlikely(r != 0)) 431254885Sdumbbell return r; 432254885Sdumbbell /* Only 27 bit offset for legacy CRTC */ 433254885Sdumbbell r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, 1 << 27, 434254885Sdumbbell &base); 435254885Sdumbbell if (unlikely(r != 0)) { 436254885Sdumbbell radeon_bo_unreserve(rbo); 437254885Sdumbbell return -EINVAL; 438254885Sdumbbell } 439254885Sdumbbell radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 440254885Sdumbbell radeon_bo_unreserve(rbo); 441254885Sdumbbell if (tiling_flags & RADEON_TILING_MICRO) 442254885Sdumbbell DRM_ERROR("trying to scanout microtiled buffer\n"); 443254885Sdumbbell 444254885Sdumbbell /* if scanout was in GTT this really wouldn't work */ 445254885Sdumbbell /* crtc offset is from display base addr not FB location */ 446254885Sdumbbell radeon_crtc->legacy_display_base_addr = rdev->mc.vram_start; 447254885Sdumbbell 448254885Sdumbbell base -= radeon_crtc->legacy_display_base_addr; 449254885Sdumbbell 450254885Sdumbbell crtc_offset_cntl = 0; 451254885Sdumbbell 452254885Sdumbbell pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); 453254885Sdumbbell crtc_pitch = (((pitch_pixels * target_fb->bits_per_pixel) + 454254885Sdumbbell ((target_fb->bits_per_pixel * 8) - 1)) / 455254885Sdumbbell (target_fb->bits_per_pixel * 8)); 456254885Sdumbbell crtc_pitch |= crtc_pitch << 16; 457254885Sdumbbell 458254885Sdumbbell crtc_offset_cntl |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN; 459254885Sdumbbell if (tiling_flags & RADEON_TILING_MACRO) { 460254885Sdumbbell if (ASIC_IS_R300(rdev)) 461254885Sdumbbell crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | 462254885Sdumbbell R300_CRTC_MICRO_TILE_BUFFER_DIS | 463254885Sdumbbell R300_CRTC_MACRO_TILE_EN); 464254885Sdumbbell else 465254885Sdumbbell crtc_offset_cntl |= RADEON_CRTC_TILE_EN; 466254885Sdumbbell } else { 467254885Sdumbbell if (ASIC_IS_R300(rdev)) 468254885Sdumbbell crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | 469254885Sdumbbell R300_CRTC_MICRO_TILE_BUFFER_DIS | 470254885Sdumbbell R300_CRTC_MACRO_TILE_EN); 471254885Sdumbbell else 472254885Sdumbbell crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; 473254885Sdumbbell } 474254885Sdumbbell 475254885Sdumbbell if (tiling_flags & RADEON_TILING_MACRO) { 476254885Sdumbbell if (ASIC_IS_R300(rdev)) { 477254885Sdumbbell crtc_tile_x0_y0 = x | (y << 16); 478254885Sdumbbell base &= ~0x7ff; 479254885Sdumbbell } else { 480254885Sdumbbell int byteshift = target_fb->bits_per_pixel >> 4; 481254885Sdumbbell int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11; 482254885Sdumbbell base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); 483254885Sdumbbell crtc_offset_cntl |= (y % 16); 484254885Sdumbbell } 485254885Sdumbbell } else { 486254885Sdumbbell int offset = y * pitch_pixels + x; 487254885Sdumbbell switch (target_fb->bits_per_pixel) { 488254885Sdumbbell case 8: 489254885Sdumbbell offset *= 1; 490254885Sdumbbell break; 491254885Sdumbbell case 15: 492254885Sdumbbell case 16: 493254885Sdumbbell offset *= 2; 494254885Sdumbbell break; 495254885Sdumbbell case 24: 496254885Sdumbbell offset *= 3; 497254885Sdumbbell break; 498254885Sdumbbell case 32: 499254885Sdumbbell offset *= 4; 500254885Sdumbbell break; 501254885Sdumbbell default: 502254885Sdumbbell return false; 503254885Sdumbbell } 504254885Sdumbbell base += offset; 505254885Sdumbbell } 506254885Sdumbbell 507254885Sdumbbell base &= ~7; 508254885Sdumbbell 509254885Sdumbbell if (radeon_crtc->crtc_id == 1) 510254885Sdumbbell gen_cntl_reg = RADEON_CRTC2_GEN_CNTL; 511254885Sdumbbell else 512254885Sdumbbell gen_cntl_reg = RADEON_CRTC_GEN_CNTL; 513254885Sdumbbell 514254885Sdumbbell gen_cntl_val = RREG32(gen_cntl_reg); 515254885Sdumbbell gen_cntl_val &= ~(0xf << 8); 516254885Sdumbbell gen_cntl_val |= (format << 8); 517254885Sdumbbell gen_cntl_val &= ~RADEON_CRTC_VSTAT_MODE_MASK; 518254885Sdumbbell WREG32(gen_cntl_reg, gen_cntl_val); 519254885Sdumbbell 520254885Sdumbbell crtc_offset = (u32)base; 521254885Sdumbbell 522254885Sdumbbell WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr); 523254885Sdumbbell 524254885Sdumbbell if (ASIC_IS_R300(rdev)) { 525254885Sdumbbell if (radeon_crtc->crtc_id) 526254885Sdumbbell WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0); 527254885Sdumbbell else 528254885Sdumbbell WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0); 529254885Sdumbbell } 530254885Sdumbbell WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl); 531254885Sdumbbell WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); 532254885Sdumbbell WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); 533254885Sdumbbell 534254885Sdumbbell if (!atomic && fb && fb != crtc->fb) { 535254885Sdumbbell radeon_fb = to_radeon_framebuffer(fb); 536254885Sdumbbell rbo = gem_to_radeon_bo(radeon_fb->obj); 537254885Sdumbbell r = radeon_bo_reserve(rbo, false); 538254885Sdumbbell if (unlikely(r != 0)) 539254885Sdumbbell return r; 540254885Sdumbbell radeon_bo_unpin(rbo); 541254885Sdumbbell radeon_bo_unreserve(rbo); 542254885Sdumbbell } 543254885Sdumbbell 544254885Sdumbbell /* Bytes per pixel may have changed */ 545254885Sdumbbell radeon_bandwidth_update(rdev); 546254885Sdumbbell 547254885Sdumbbell return 0; 548254885Sdumbbell} 549254885Sdumbbell 550254885Sdumbbellstatic bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) 551254885Sdumbbell{ 552254885Sdumbbell struct drm_device *dev = crtc->dev; 553254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 554254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 555254885Sdumbbell struct drm_encoder *encoder; 556254885Sdumbbell int format; 557254885Sdumbbell int hsync_start; 558254885Sdumbbell int hsync_wid; 559254885Sdumbbell int vsync_wid; 560254885Sdumbbell uint32_t crtc_h_total_disp; 561254885Sdumbbell uint32_t crtc_h_sync_strt_wid; 562254885Sdumbbell uint32_t crtc_v_total_disp; 563254885Sdumbbell uint32_t crtc_v_sync_strt_wid; 564254885Sdumbbell bool is_tv = false; 565254885Sdumbbell 566254885Sdumbbell DRM_DEBUG_KMS("\n"); 567254885Sdumbbell list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 568254885Sdumbbell if (encoder->crtc == crtc) { 569254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 570254885Sdumbbell if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 571254885Sdumbbell is_tv = true; 572254885Sdumbbell DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id); 573254885Sdumbbell break; 574254885Sdumbbell } 575254885Sdumbbell } 576254885Sdumbbell } 577254885Sdumbbell 578254885Sdumbbell switch (crtc->fb->bits_per_pixel) { 579254885Sdumbbell case 8: 580254885Sdumbbell format = 2; 581254885Sdumbbell break; 582254885Sdumbbell case 15: /* 555 */ 583254885Sdumbbell format = 3; 584254885Sdumbbell break; 585254885Sdumbbell case 16: /* 565 */ 586254885Sdumbbell format = 4; 587254885Sdumbbell break; 588254885Sdumbbell case 24: /* RGB */ 589254885Sdumbbell format = 5; 590254885Sdumbbell break; 591254885Sdumbbell case 32: /* xRGB */ 592254885Sdumbbell format = 6; 593254885Sdumbbell break; 594254885Sdumbbell default: 595254885Sdumbbell return false; 596254885Sdumbbell } 597254885Sdumbbell 598254885Sdumbbell crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) 599254885Sdumbbell | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); 600254885Sdumbbell 601254885Sdumbbell hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; 602254885Sdumbbell if (!hsync_wid) 603254885Sdumbbell hsync_wid = 1; 604254885Sdumbbell hsync_start = mode->crtc_hsync_start - 8; 605254885Sdumbbell 606254885Sdumbbell crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) 607254885Sdumbbell | ((hsync_wid & 0x3f) << 16) 608254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_NHSYNC) 609254885Sdumbbell ? RADEON_CRTC_H_SYNC_POL 610254885Sdumbbell : 0)); 611254885Sdumbbell 612254885Sdumbbell /* This works for double scan mode. */ 613254885Sdumbbell crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) 614254885Sdumbbell | ((mode->crtc_vdisplay - 1) << 16)); 615254885Sdumbbell 616254885Sdumbbell vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; 617254885Sdumbbell if (!vsync_wid) 618254885Sdumbbell vsync_wid = 1; 619254885Sdumbbell 620254885Sdumbbell crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) 621254885Sdumbbell | ((vsync_wid & 0x1f) << 16) 622254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_NVSYNC) 623254885Sdumbbell ? RADEON_CRTC_V_SYNC_POL 624254885Sdumbbell : 0)); 625254885Sdumbbell 626254885Sdumbbell if (radeon_crtc->crtc_id) { 627254885Sdumbbell uint32_t crtc2_gen_cntl; 628254885Sdumbbell uint32_t disp2_merge_cntl; 629254885Sdumbbell 630254885Sdumbbell /* if TV DAC is enabled for another crtc and keep it enabled */ 631254885Sdumbbell crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0x00718080; 632254885Sdumbbell crtc2_gen_cntl |= ((format << 8) 633254885Sdumbbell | RADEON_CRTC2_VSYNC_DIS 634254885Sdumbbell | RADEON_CRTC2_HSYNC_DIS 635254885Sdumbbell | RADEON_CRTC2_DISP_DIS 636254885Sdumbbell | RADEON_CRTC2_DISP_REQ_EN_B 637254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) 638254885Sdumbbell ? RADEON_CRTC2_DBL_SCAN_EN 639254885Sdumbbell : 0) 640254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_CSYNC) 641254885Sdumbbell ? RADEON_CRTC2_CSYNC_EN 642254885Sdumbbell : 0) 643254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_INTERLACE) 644254885Sdumbbell ? RADEON_CRTC2_INTERLACE_EN 645254885Sdumbbell : 0)); 646254885Sdumbbell 647254885Sdumbbell /* rs4xx chips seem to like to have the crtc enabled when the timing is set */ 648254885Sdumbbell if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) 649254885Sdumbbell crtc2_gen_cntl |= RADEON_CRTC2_EN; 650254885Sdumbbell 651254885Sdumbbell disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 652254885Sdumbbell disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 653254885Sdumbbell 654254885Sdumbbell WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); 655254885Sdumbbell WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); 656254885Sdumbbell 657254885Sdumbbell WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid); 658254885Sdumbbell WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid); 659254885Sdumbbell } else { 660254885Sdumbbell uint32_t crtc_gen_cntl; 661254885Sdumbbell uint32_t crtc_ext_cntl; 662254885Sdumbbell uint32_t disp_merge_cntl; 663254885Sdumbbell 664254885Sdumbbell crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0x00718000; 665254885Sdumbbell crtc_gen_cntl |= (RADEON_CRTC_EXT_DISP_EN 666254885Sdumbbell | (format << 8) 667254885Sdumbbell | RADEON_CRTC_DISP_REQ_EN_B 668254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) 669254885Sdumbbell ? RADEON_CRTC_DBL_SCAN_EN 670254885Sdumbbell : 0) 671254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_CSYNC) 672254885Sdumbbell ? RADEON_CRTC_CSYNC_EN 673254885Sdumbbell : 0) 674254885Sdumbbell | ((mode->flags & DRM_MODE_FLAG_INTERLACE) 675254885Sdumbbell ? RADEON_CRTC_INTERLACE_EN 676254885Sdumbbell : 0)); 677254885Sdumbbell 678254885Sdumbbell /* rs4xx chips seem to like to have the crtc enabled when the timing is set */ 679254885Sdumbbell if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) 680254885Sdumbbell crtc_gen_cntl |= RADEON_CRTC_EN; 681254885Sdumbbell 682254885Sdumbbell crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); 683254885Sdumbbell crtc_ext_cntl |= (RADEON_XCRT_CNT_EN | 684254885Sdumbbell RADEON_CRTC_VSYNC_DIS | 685254885Sdumbbell RADEON_CRTC_HSYNC_DIS | 686254885Sdumbbell RADEON_CRTC_DISPLAY_DIS); 687254885Sdumbbell 688254885Sdumbbell disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 689254885Sdumbbell disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 690254885Sdumbbell 691254885Sdumbbell WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 692254885Sdumbbell WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); 693254885Sdumbbell WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); 694254885Sdumbbell } 695254885Sdumbbell 696254885Sdumbbell if (is_tv) 697254885Sdumbbell radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp, 698254885Sdumbbell &crtc_h_sync_strt_wid, &crtc_v_total_disp, 699254885Sdumbbell &crtc_v_sync_strt_wid); 700254885Sdumbbell 701254885Sdumbbell WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp); 702254885Sdumbbell WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid); 703254885Sdumbbell WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp); 704254885Sdumbbell WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid); 705254885Sdumbbell 706254885Sdumbbell return true; 707254885Sdumbbell} 708254885Sdumbbell 709254885Sdumbbellstatic void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 710254885Sdumbbell{ 711254885Sdumbbell struct drm_device *dev = crtc->dev; 712254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 713254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 714254885Sdumbbell struct drm_encoder *encoder; 715254885Sdumbbell uint32_t feedback_div = 0; 716254885Sdumbbell uint32_t frac_fb_div = 0; 717254885Sdumbbell uint32_t reference_div = 0; 718254885Sdumbbell uint32_t post_divider = 0; 719254885Sdumbbell uint32_t freq = 0; 720254885Sdumbbell uint8_t pll_gain; 721254885Sdumbbell bool use_bios_divs = false; 722254885Sdumbbell /* PLL registers */ 723254885Sdumbbell uint32_t pll_ref_div = 0; 724254885Sdumbbell uint32_t pll_fb_post_div = 0; 725254885Sdumbbell uint32_t htotal_cntl = 0; 726254885Sdumbbell bool is_tv = false; 727254885Sdumbbell struct radeon_pll *pll; 728254885Sdumbbell 729254885Sdumbbell struct { 730254885Sdumbbell int divider; 731254885Sdumbbell int bitvalue; 732254885Sdumbbell } *post_div, post_divs[] = { 733254885Sdumbbell /* From RAGE 128 VR/RAGE 128 GL Register 734254885Sdumbbell * Reference Manual (Technical Reference 735254885Sdumbbell * Manual P/N RRG-G04100-C Rev. 0.04), page 736254885Sdumbbell * 3-17 (PLL_DIV_[3:0]). 737254885Sdumbbell */ 738254885Sdumbbell { 1, 0 }, /* VCLK_SRC */ 739254885Sdumbbell { 2, 1 }, /* VCLK_SRC/2 */ 740254885Sdumbbell { 4, 2 }, /* VCLK_SRC/4 */ 741254885Sdumbbell { 8, 3 }, /* VCLK_SRC/8 */ 742254885Sdumbbell { 3, 4 }, /* VCLK_SRC/3 */ 743254885Sdumbbell { 16, 5 }, /* VCLK_SRC/16 */ 744254885Sdumbbell { 6, 6 }, /* VCLK_SRC/6 */ 745254885Sdumbbell { 12, 7 }, /* VCLK_SRC/12 */ 746254885Sdumbbell { 0, 0 } 747254885Sdumbbell }; 748254885Sdumbbell 749254885Sdumbbell if (radeon_crtc->crtc_id) 750254885Sdumbbell pll = &rdev->clock.p2pll; 751254885Sdumbbell else 752254885Sdumbbell pll = &rdev->clock.p1pll; 753254885Sdumbbell 754254885Sdumbbell pll->flags = RADEON_PLL_LEGACY; 755254885Sdumbbell 756254885Sdumbbell if (mode->clock > 200000) /* range limits??? */ 757254885Sdumbbell pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 758254885Sdumbbell else 759254885Sdumbbell pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 760254885Sdumbbell 761254885Sdumbbell list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 762254885Sdumbbell if (encoder->crtc == crtc) { 763254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 764254885Sdumbbell 765254885Sdumbbell if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 766254885Sdumbbell is_tv = true; 767254885Sdumbbell break; 768254885Sdumbbell } 769254885Sdumbbell 770254885Sdumbbell if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 771254885Sdumbbell pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 772254885Sdumbbell if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { 773254885Sdumbbell if (!rdev->is_atom_bios) { 774254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 775254885Sdumbbell struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; 776254885Sdumbbell if (lvds) { 777254885Sdumbbell if (lvds->use_bios_dividers) { 778254885Sdumbbell pll_ref_div = lvds->panel_ref_divider; 779254885Sdumbbell pll_fb_post_div = (lvds->panel_fb_divider | 780254885Sdumbbell (lvds->panel_post_divider << 16)); 781254885Sdumbbell htotal_cntl = 0; 782254885Sdumbbell use_bios_divs = true; 783254885Sdumbbell } 784254885Sdumbbell } 785254885Sdumbbell } 786254885Sdumbbell pll->flags |= RADEON_PLL_USE_REF_DIV; 787254885Sdumbbell } 788254885Sdumbbell } 789254885Sdumbbell } 790254885Sdumbbell 791254885Sdumbbell DRM_DEBUG_KMS("\n"); 792254885Sdumbbell 793254885Sdumbbell if (!use_bios_divs) { 794254885Sdumbbell radeon_compute_pll_legacy(pll, mode->clock, 795254885Sdumbbell &freq, &feedback_div, &frac_fb_div, 796254885Sdumbbell &reference_div, &post_divider); 797254885Sdumbbell 798254885Sdumbbell for (post_div = &post_divs[0]; post_div->divider; ++post_div) { 799254885Sdumbbell if (post_div->divider == post_divider) 800254885Sdumbbell break; 801254885Sdumbbell } 802254885Sdumbbell 803254885Sdumbbell if (!post_div->divider) 804254885Sdumbbell post_div = &post_divs[0]; 805254885Sdumbbell 806254885Sdumbbell DRM_DEBUG_KMS("dc=%u, fd=%d, rd=%d, pd=%d\n", 807254885Sdumbbell (unsigned)freq, 808254885Sdumbbell feedback_div, 809254885Sdumbbell reference_div, 810254885Sdumbbell post_divider); 811254885Sdumbbell 812254885Sdumbbell pll_ref_div = reference_div; 813254885Sdumbbell#if defined(__powerpc__) && (0) /* TODO */ 814254885Sdumbbell /* apparently programming this otherwise causes a hang??? */ 815254885Sdumbbell if (info->MacModel == RADEON_MAC_IBOOK) 816254885Sdumbbell pll_fb_post_div = 0x000600ad; 817254885Sdumbbell else 818254885Sdumbbell#endif 819254885Sdumbbell pll_fb_post_div = (feedback_div | (post_div->bitvalue << 16)); 820254885Sdumbbell 821254885Sdumbbell htotal_cntl = mode->htotal & 0x7; 822254885Sdumbbell 823254885Sdumbbell } 824254885Sdumbbell 825254885Sdumbbell pll_gain = radeon_compute_pll_gain(pll->reference_freq, 826254885Sdumbbell pll_ref_div & 0x3ff, 827254885Sdumbbell pll_fb_post_div & 0x7ff); 828254885Sdumbbell 829254885Sdumbbell if (radeon_crtc->crtc_id) { 830254885Sdumbbell uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) & 831254885Sdumbbell ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | 832254885Sdumbbell RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); 833254885Sdumbbell 834254885Sdumbbell if (is_tv) { 835254885Sdumbbell radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl, 836254885Sdumbbell &pll_ref_div, &pll_fb_post_div, 837254885Sdumbbell &pixclks_cntl); 838254885Sdumbbell } 839254885Sdumbbell 840254885Sdumbbell WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 841254885Sdumbbell RADEON_PIX2CLK_SRC_SEL_CPUCLK, 842254885Sdumbbell ~(RADEON_PIX2CLK_SRC_SEL_MASK)); 843254885Sdumbbell 844254885Sdumbbell WREG32_PLL_P(RADEON_P2PLL_CNTL, 845254885Sdumbbell RADEON_P2PLL_RESET 846254885Sdumbbell | RADEON_P2PLL_ATOMIC_UPDATE_EN 847254885Sdumbbell | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT), 848254885Sdumbbell ~(RADEON_P2PLL_RESET 849254885Sdumbbell | RADEON_P2PLL_ATOMIC_UPDATE_EN 850254885Sdumbbell | RADEON_P2PLL_PVG_MASK)); 851254885Sdumbbell 852254885Sdumbbell WREG32_PLL_P(RADEON_P2PLL_REF_DIV, 853254885Sdumbbell pll_ref_div, 854254885Sdumbbell ~RADEON_P2PLL_REF_DIV_MASK); 855254885Sdumbbell 856254885Sdumbbell WREG32_PLL_P(RADEON_P2PLL_DIV_0, 857254885Sdumbbell pll_fb_post_div, 858254885Sdumbbell ~RADEON_P2PLL_FB0_DIV_MASK); 859254885Sdumbbell 860254885Sdumbbell WREG32_PLL_P(RADEON_P2PLL_DIV_0, 861254885Sdumbbell pll_fb_post_div, 862254885Sdumbbell ~RADEON_P2PLL_POST0_DIV_MASK); 863254885Sdumbbell 864254885Sdumbbell radeon_pll2_write_update(dev); 865254885Sdumbbell radeon_pll2_wait_for_read_update_complete(dev); 866254885Sdumbbell 867254885Sdumbbell WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl); 868254885Sdumbbell 869254885Sdumbbell WREG32_PLL_P(RADEON_P2PLL_CNTL, 870254885Sdumbbell 0, 871254885Sdumbbell ~(RADEON_P2PLL_RESET 872254885Sdumbbell | RADEON_P2PLL_SLEEP 873254885Sdumbbell | RADEON_P2PLL_ATOMIC_UPDATE_EN)); 874254885Sdumbbell 875254885Sdumbbell DRM_DEBUG_KMS("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", 876254885Sdumbbell (unsigned)pll_ref_div, 877254885Sdumbbell (unsigned)pll_fb_post_div, 878254885Sdumbbell (unsigned)htotal_cntl, 879254885Sdumbbell RREG32_PLL(RADEON_P2PLL_CNTL)); 880254885Sdumbbell DRM_DEBUG_KMS("Wrote2: rd=%u, fd=%u, pd=%u\n", 881254885Sdumbbell (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, 882254885Sdumbbell (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK, 883254885Sdumbbell (unsigned)((pll_fb_post_div & 884254885Sdumbbell RADEON_P2PLL_POST0_DIV_MASK) >> 16)); 885254885Sdumbbell 886280183Sdumbbell mdelay(50); /* Let the clock to lock */ 887254885Sdumbbell 888254885Sdumbbell WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 889254885Sdumbbell RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, 890254885Sdumbbell ~(RADEON_PIX2CLK_SRC_SEL_MASK)); 891254885Sdumbbell 892254885Sdumbbell WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); 893254885Sdumbbell } else { 894254885Sdumbbell uint32_t pixclks_cntl; 895254885Sdumbbell 896254885Sdumbbell 897254885Sdumbbell if (is_tv) { 898254885Sdumbbell pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); 899254885Sdumbbell radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div, 900254885Sdumbbell &pll_fb_post_div, &pixclks_cntl); 901254885Sdumbbell } 902254885Sdumbbell 903254885Sdumbbell if (rdev->flags & RADEON_IS_MOBILITY) { 904254885Sdumbbell /* A temporal workaround for the occasional blanking on certain laptop panels. 905254885Sdumbbell This appears to related to the PLL divider registers (fail to lock?). 906254885Sdumbbell It occurs even when all dividers are the same with their old settings. 907254885Sdumbbell In this case we really don't need to fiddle with PLL registers. 908254885Sdumbbell By doing this we can avoid the blanking problem with some panels. 909254885Sdumbbell */ 910254885Sdumbbell if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && 911254885Sdumbbell (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) & 912254885Sdumbbell (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { 913254885Sdumbbell WREG32_P(RADEON_CLOCK_CNTL_INDEX, 914254885Sdumbbell RADEON_PLL_DIV_SEL, 915254885Sdumbbell ~(RADEON_PLL_DIV_SEL)); 916254885Sdumbbell r100_pll_errata_after_index(rdev); 917254885Sdumbbell return; 918254885Sdumbbell } 919254885Sdumbbell } 920254885Sdumbbell 921254885Sdumbbell WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, 922254885Sdumbbell RADEON_VCLK_SRC_SEL_CPUCLK, 923254885Sdumbbell ~(RADEON_VCLK_SRC_SEL_MASK)); 924254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_CNTL, 925254885Sdumbbell RADEON_PPLL_RESET 926254885Sdumbbell | RADEON_PPLL_ATOMIC_UPDATE_EN 927254885Sdumbbell | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN 928254885Sdumbbell | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT), 929254885Sdumbbell ~(RADEON_PPLL_RESET 930254885Sdumbbell | RADEON_PPLL_ATOMIC_UPDATE_EN 931254885Sdumbbell | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN 932254885Sdumbbell | RADEON_PPLL_PVG_MASK)); 933254885Sdumbbell 934254885Sdumbbell WREG32_P(RADEON_CLOCK_CNTL_INDEX, 935254885Sdumbbell RADEON_PLL_DIV_SEL, 936254885Sdumbbell ~(RADEON_PLL_DIV_SEL)); 937254885Sdumbbell r100_pll_errata_after_index(rdev); 938254885Sdumbbell 939254885Sdumbbell if (ASIC_IS_R300(rdev) || 940254885Sdumbbell (rdev->family == CHIP_RS300) || 941254885Sdumbbell (rdev->family == CHIP_RS400) || 942254885Sdumbbell (rdev->family == CHIP_RS480)) { 943254885Sdumbbell if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { 944254885Sdumbbell /* When restoring console mode, use saved PPLL_REF_DIV 945254885Sdumbbell * setting. 946254885Sdumbbell */ 947254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_REF_DIV, 948254885Sdumbbell pll_ref_div, 949254885Sdumbbell 0); 950254885Sdumbbell } else { 951254885Sdumbbell /* R300 uses ref_div_acc field as real ref divider */ 952254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_REF_DIV, 953254885Sdumbbell (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), 954254885Sdumbbell ~R300_PPLL_REF_DIV_ACC_MASK); 955254885Sdumbbell } 956254885Sdumbbell } else 957254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_REF_DIV, 958254885Sdumbbell pll_ref_div, 959254885Sdumbbell ~RADEON_PPLL_REF_DIV_MASK); 960254885Sdumbbell 961254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_DIV_3, 962254885Sdumbbell pll_fb_post_div, 963254885Sdumbbell ~RADEON_PPLL_FB3_DIV_MASK); 964254885Sdumbbell 965254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_DIV_3, 966254885Sdumbbell pll_fb_post_div, 967254885Sdumbbell ~RADEON_PPLL_POST3_DIV_MASK); 968254885Sdumbbell 969254885Sdumbbell radeon_pll_write_update(dev); 970254885Sdumbbell radeon_pll_wait_for_read_update_complete(dev); 971254885Sdumbbell 972254885Sdumbbell WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl); 973254885Sdumbbell 974254885Sdumbbell WREG32_PLL_P(RADEON_PPLL_CNTL, 975254885Sdumbbell 0, 976254885Sdumbbell ~(RADEON_PPLL_RESET 977254885Sdumbbell | RADEON_PPLL_SLEEP 978254885Sdumbbell | RADEON_PPLL_ATOMIC_UPDATE_EN 979254885Sdumbbell | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); 980254885Sdumbbell 981254885Sdumbbell DRM_DEBUG_KMS("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", 982254885Sdumbbell pll_ref_div, 983254885Sdumbbell pll_fb_post_div, 984254885Sdumbbell (unsigned)htotal_cntl, 985254885Sdumbbell RREG32_PLL(RADEON_PPLL_CNTL)); 986254885Sdumbbell DRM_DEBUG_KMS("Wrote: rd=%d, fd=%d, pd=%d\n", 987254885Sdumbbell pll_ref_div & RADEON_PPLL_REF_DIV_MASK, 988254885Sdumbbell pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK, 989254885Sdumbbell (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16); 990254885Sdumbbell 991280183Sdumbbell mdelay(50); /* Let the clock to lock */ 992254885Sdumbbell 993254885Sdumbbell WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, 994254885Sdumbbell RADEON_VCLK_SRC_SEL_PPLLCLK, 995254885Sdumbbell ~(RADEON_VCLK_SRC_SEL_MASK)); 996254885Sdumbbell 997254885Sdumbbell if (is_tv) 998254885Sdumbbell WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); 999254885Sdumbbell } 1000254885Sdumbbell} 1001254885Sdumbbell 1002254885Sdumbbellstatic bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, 1003254885Sdumbbell const struct drm_display_mode *mode, 1004254885Sdumbbell struct drm_display_mode *adjusted_mode) 1005254885Sdumbbell{ 1006254885Sdumbbell if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1007254885Sdumbbell return false; 1008254885Sdumbbell return true; 1009254885Sdumbbell} 1010254885Sdumbbell 1011254885Sdumbbellstatic int radeon_crtc_mode_set(struct drm_crtc *crtc, 1012254885Sdumbbell struct drm_display_mode *mode, 1013254885Sdumbbell struct drm_display_mode *adjusted_mode, 1014254885Sdumbbell int x, int y, struct drm_framebuffer *old_fb) 1015254885Sdumbbell{ 1016254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1017254885Sdumbbell 1018254885Sdumbbell /* TODO TV */ 1019254885Sdumbbell radeon_crtc_set_base(crtc, x, y, old_fb); 1020254885Sdumbbell radeon_set_crtc_timing(crtc, adjusted_mode); 1021254885Sdumbbell radeon_set_pll(crtc, adjusted_mode); 1022254885Sdumbbell radeon_overscan_setup(crtc, adjusted_mode); 1023254885Sdumbbell if (radeon_crtc->crtc_id == 0) { 1024254885Sdumbbell radeon_legacy_rmx_mode_set(crtc, adjusted_mode); 1025254885Sdumbbell } else { 1026254885Sdumbbell if (radeon_crtc->rmx_type != RMX_OFF) { 1027254885Sdumbbell /* FIXME: only first crtc has rmx what should we 1028254885Sdumbbell * do ? 1029254885Sdumbbell */ 1030254885Sdumbbell DRM_ERROR("Mode need scaling but only first crtc can do that.\n"); 1031254885Sdumbbell } 1032254885Sdumbbell } 1033254885Sdumbbell return 0; 1034254885Sdumbbell} 1035254885Sdumbbell 1036254885Sdumbbellstatic void radeon_crtc_prepare(struct drm_crtc *crtc) 1037254885Sdumbbell{ 1038254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1039254885Sdumbbell struct drm_device *dev = crtc->dev; 1040254885Sdumbbell struct drm_crtc *crtci; 1041254885Sdumbbell 1042254885Sdumbbell radeon_crtc->in_mode_set = true; 1043254885Sdumbbell /* 1044254885Sdumbbell * The hardware wedges sometimes if you reconfigure one CRTC 1045254885Sdumbbell * whilst another is running (see fdo bug #24611). 1046254885Sdumbbell */ 1047254885Sdumbbell list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) 1048254885Sdumbbell radeon_crtc_dpms(crtci, DRM_MODE_DPMS_OFF); 1049254885Sdumbbell} 1050254885Sdumbbell 1051254885Sdumbbellstatic void radeon_crtc_commit(struct drm_crtc *crtc) 1052254885Sdumbbell{ 1053254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1054254885Sdumbbell struct drm_device *dev = crtc->dev; 1055254885Sdumbbell struct drm_crtc *crtci; 1056254885Sdumbbell 1057254885Sdumbbell /* 1058254885Sdumbbell * Reenable the CRTCs that should be running. 1059254885Sdumbbell */ 1060254885Sdumbbell list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) { 1061254885Sdumbbell if (crtci->enabled) 1062254885Sdumbbell radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON); 1063254885Sdumbbell } 1064254885Sdumbbell radeon_crtc->in_mode_set = false; 1065254885Sdumbbell} 1066254885Sdumbbell 1067254885Sdumbbellstatic const struct drm_crtc_helper_funcs legacy_helper_funcs = { 1068254885Sdumbbell .dpms = radeon_crtc_dpms, 1069254885Sdumbbell .mode_fixup = radeon_crtc_mode_fixup, 1070254885Sdumbbell .mode_set = radeon_crtc_mode_set, 1071254885Sdumbbell .mode_set_base = radeon_crtc_set_base, 1072254885Sdumbbell .mode_set_base_atomic = radeon_crtc_set_base_atomic, 1073254885Sdumbbell .prepare = radeon_crtc_prepare, 1074254885Sdumbbell .commit = radeon_crtc_commit, 1075254885Sdumbbell .load_lut = radeon_crtc_load_lut, 1076254885Sdumbbell}; 1077254885Sdumbbell 1078254885Sdumbbell 1079254885Sdumbbellvoid radeon_legacy_init_crtc(struct drm_device *dev, 1080254885Sdumbbell struct radeon_crtc *radeon_crtc) 1081254885Sdumbbell{ 1082254885Sdumbbell if (radeon_crtc->crtc_id == 1) 1083254885Sdumbbell radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP; 1084254885Sdumbbell drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs); 1085254885Sdumbbell} 1086