1e3d74329Smrg/* 2e3d74329Smrg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and 3e3d74329Smrg * VA Linux Systems Inc., Fremont, California. 4e3d74329Smrg * 5e3d74329Smrg * All Rights Reserved. 6e3d74329Smrg * 7e3d74329Smrg * Permission is hereby granted, free of charge, to any person obtaining 8e3d74329Smrg * a copy of this software and associated documentation files (the 9e3d74329Smrg * "Software"), to deal in the Software without restriction, including 10e3d74329Smrg * without limitation on the rights to use, copy, modify, merge, 11e3d74329Smrg * publish, distribute, sublicense, and/or sell copies of the Software, 12e3d74329Smrg * and to permit persons to whom the Software is furnished to do so, 13e3d74329Smrg * subject to the following conditions: 14e3d74329Smrg * 15e3d74329Smrg * The above copyright notice and this permission notice (including the 16e3d74329Smrg * next paragraph) shall be included in all copies or substantial 17e3d74329Smrg * portions of the Software. 18e3d74329Smrg * 19e3d74329Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20e3d74329Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21e3d74329Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22e3d74329Smrg * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 23e3d74329Smrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24e3d74329Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25e3d74329Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26e3d74329Smrg * DEALINGS IN THE SOFTWARE. 27e3d74329Smrg */ 28e3d74329Smrg 29e3d74329Smrg#ifdef HAVE_CONFIG_H 30e3d74329Smrg#include "config.h" 31e3d74329Smrg#endif 32e3d74329Smrg 33e3d74329Smrg#include <string.h> 34e3d74329Smrg#include <stdio.h> 35e3d74329Smrg 36e3d74329Smrg#include "xf86.h" 37e3d74329Smrg#include "xf86Modes.h" 38a56d54acSmrg 39a56d54acSmrg#ifdef HAVE_XEXTPROTO_71 40e3d74329Smrg#include "X11/extensions/dpmsconst.h" 41a56d54acSmrg#else 42a56d54acSmrg#define DPMS_SERVER 43a56d54acSmrg#include "X11/extensions/dpms.h" 44a56d54acSmrg#endif 45e3d74329Smrg 46e3d74329Smrg#include "r128.h" 47e3d74329Smrg#include "r128_probe.h" 48e3d74329Smrg#include "r128_reg.h" 49e3d74329Smrg 50cd241713Smrg 51cd241713Smrg#ifndef MAX 52cd241713Smrg#define MAX(a,b) ((a)>(b)?(a):(b)) 53cd241713Smrg#endif 54cd241713Smrg 55cd241713Smrg 56cd241713Smrg/* Define CRTC registers for requested video mode. */ 57cd241713SmrgBool R128InitCrtcRegisters(xf86CrtcPtr crtc, R128SavePtr save, DisplayModePtr mode) 58cd241713Smrg{ 59cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 60cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 61cd241713Smrg xf86OutputPtr output = R128FirstOutput(crtc); 62cd241713Smrg R128OutputPrivatePtr r128_output = output->driver_private; 63cd241713Smrg 64cd241713Smrg int format; 65cd241713Smrg int hsync_start; 66cd241713Smrg int hsync_wid; 67cd241713Smrg int hsync_fudge; 68cd241713Smrg int vsync_wid; 69cd241713Smrg int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; 70cd241713Smrg int hsync_fudge_fp[] = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 }; 71cd241713Smrg// int hsync_fudge_fp_crt[] = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 }; 72cd241713Smrg 73cd241713Smrg switch (info->CurrentLayout.pixel_code) { 74cd241713Smrg case 4: format = 1; break; 75cd241713Smrg case 8: format = 2; break; 76cd241713Smrg case 15: format = 3; break; /* 555 */ 77cd241713Smrg case 16: format = 4; break; /* 565 */ 78cd241713Smrg case 24: format = 5; break; /* RGB */ 79cd241713Smrg case 32: format = 6; break; /* xRGB */ 80cd241713Smrg default: 81cd241713Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 82cd241713Smrg "Unsupported pixel depth (%d)\n", 83cd241713Smrg info->CurrentLayout.bitsPerPixel); 84cd241713Smrg return FALSE; 85cd241713Smrg } 86cd241713Smrg 87cd241713Smrg if (r128_output->MonType == MT_LCD || r128_output->MonType == MT_DFP) 88cd241713Smrg hsync_fudge = hsync_fudge_fp[format-1]; 89cd241713Smrg else 90cd241713Smrg hsync_fudge = hsync_fudge_default[format-1]; 91cd241713Smrg 92cd241713Smrg save->crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN 93cd241713Smrg | R128_CRTC_EN 94cd241713Smrg | (format << 8) 95cd241713Smrg | ((mode->Flags & V_DBLSCAN) 96cd241713Smrg ? R128_CRTC_DBL_SCAN_EN 97cd241713Smrg : 0) 98cd241713Smrg | ((mode->Flags & V_INTERLACE) 99cd241713Smrg ? R128_CRTC_INTERLACE_EN 100cd241713Smrg : 0) 101cd241713Smrg | ((mode->Flags & V_CSYNC) 102cd241713Smrg ? R128_CRTC_CSYNC_EN 103cd241713Smrg : 0)); 104cd241713Smrg 105cd241713Smrg if (r128_output->MonType == MT_LCD || r128_output->MonType == MT_DFP) 106cd241713Smrg save->crtc_gen_cntl &= ~(R128_CRTC_DBL_SCAN_EN | R128_CRTC_INTERLACE_EN); 107cd241713Smrg 108cd241713Smrg save->crtc_ext_cntl |= R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN; 109cd241713Smrg 110cd241713Smrg save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff) 111cd241713Smrg | (((mode->CrtcHDisplay / 8) - 1) << 16)); 112cd241713Smrg 113cd241713Smrg hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; 114cd241713Smrg if (!hsync_wid) hsync_wid = 1; 115cd241713Smrg if (hsync_wid > 0x3f) hsync_wid = 0x3f; 116cd241713Smrg 117cd241713Smrg hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; 118cd241713Smrg 119cd241713Smrg save->crtc_h_sync_strt_wid = ((hsync_start & 0xfff) 120cd241713Smrg | (hsync_wid << 16) 121cd241713Smrg | ((mode->Flags & V_NHSYNC) 122cd241713Smrg ? R128_CRTC_H_SYNC_POL 123cd241713Smrg : 0)); 124cd241713Smrg 125cd241713Smrg#if 1 126cd241713Smrg /* This works for double scan mode. */ 127cd241713Smrg save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) 128cd241713Smrg | ((mode->CrtcVDisplay - 1) << 16)); 129cd241713Smrg#else 130cd241713Smrg /* This is what cce/nbmode.c example code 131cd241713Smrg does -- is this correct? */ 132cd241713Smrg save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) 133cd241713Smrg | ((mode->CrtcVDisplay 134cd241713Smrg * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1) 135cd241713Smrg << 16)); 136cd241713Smrg#endif 137cd241713Smrg 138cd241713Smrg vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; 139cd241713Smrg if (!vsync_wid) vsync_wid = 1; 140cd241713Smrg if (vsync_wid > 0x1f) vsync_wid = 0x1f; 141cd241713Smrg 142cd241713Smrg save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) 143cd241713Smrg | (vsync_wid << 16) 144cd241713Smrg | ((mode->Flags & V_NVSYNC) 145cd241713Smrg ? R128_CRTC_V_SYNC_POL 146cd241713Smrg : 0)); 147cd241713Smrg save->crtc_pitch = info->CurrentLayout.displayWidth / 8; 148cd241713Smrg 149cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 150cd241713Smrg "Pitch = %d bytes (virtualX = %d, " 151cd241713Smrg "displayWidth = %d)\n", 152cd241713Smrg save->crtc_pitch, pScrn->virtualX, 153cd241713Smrg info->CurrentLayout.displayWidth)); 154cd241713Smrg 155cd241713Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 156cd241713Smrg /* Change the endianness of the aperture */ 157cd241713Smrg switch (info->CurrentLayout.pixel_code) { 158cd241713Smrg case 15: 159cd241713Smrg case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break; 160cd241713Smrg case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break; 161cd241713Smrg default: break; 162cd241713Smrg } 163cd241713Smrg#endif 164cd241713Smrg 165cd241713Smrg return TRUE; 166cd241713Smrg} 167cd241713Smrg 168cd241713Smrg/* Define CRTC2 registers for requested video mode. */ 169cd241713SmrgBool R128InitCrtc2Registers(xf86CrtcPtr crtc, R128SavePtr save, DisplayModePtr mode) 170cd241713Smrg{ 171cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 172cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 173cd241713Smrg 174cd241713Smrg int format; 175cd241713Smrg int hsync_start; 176cd241713Smrg int hsync_wid; 177cd241713Smrg int hsync_fudge; 178cd241713Smrg int vsync_wid; 179cd241713Smrg int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; 180cd241713Smrg 181cd241713Smrg switch (info->CurrentLayout.pixel_code) { 182cd241713Smrg case 4: format = 1; break; 183cd241713Smrg case 8: format = 2; break; 184cd241713Smrg case 15: format = 3; break; /* 555 */ 185cd241713Smrg case 16: format = 4; break; /* 565 */ 186cd241713Smrg case 24: format = 5; break; /* RGB */ 187cd241713Smrg case 32: format = 6; break; /* xRGB */ 188cd241713Smrg default: 189cd241713Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 190cd241713Smrg "Unsupported pixel depth (%d)\n", info->CurrentLayout.bitsPerPixel); 191cd241713Smrg return FALSE; 192cd241713Smrg } 193cd241713Smrg 194cd241713Smrg hsync_fudge = hsync_fudge_default[format-1]; 195cd241713Smrg 196cd241713Smrg save->crtc2_gen_cntl = (R128_CRTC2_EN 197cd241713Smrg | (format << 8) 198cd241713Smrg | ((mode->Flags & V_DBLSCAN) 199cd241713Smrg ? R128_CRTC2_DBL_SCAN_EN 200cd241713Smrg : 0)); 201cd241713Smrg/* 202cd241713Smrg save->crtc2_gen_cntl &= ~R128_CRTC_EXT_DISP_EN; 203cd241713Smrg save->crtc2_gen_cntl |= (1 << 21); 204cd241713Smrg*/ 205cd241713Smrg save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff) 206cd241713Smrg | (((mode->CrtcHDisplay / 8) - 1) << 16)); 207cd241713Smrg 208cd241713Smrg hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; 209cd241713Smrg if (!hsync_wid) hsync_wid = 1; 210cd241713Smrg if (hsync_wid > 0x3f) hsync_wid = 0x3f; 211cd241713Smrg 212cd241713Smrg hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; 213cd241713Smrg 214cd241713Smrg save->crtc2_h_sync_strt_wid = ((hsync_start & 0xfff) 215cd241713Smrg | (hsync_wid << 16) 216cd241713Smrg | ((mode->Flags & V_NHSYNC) 217cd241713Smrg ? R128_CRTC2_H_SYNC_POL 218cd241713Smrg : 0)); 219cd241713Smrg 220cd241713Smrg#if 1 221cd241713Smrg /* This works for double scan mode. */ 222cd241713Smrg save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) 223cd241713Smrg | ((mode->CrtcVDisplay - 1) << 16)); 224cd241713Smrg#else 225cd241713Smrg /* This is what cce/nbmode.c example code 226cd241713Smrg does -- is this correct? */ 227cd241713Smrg save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) 228cd241713Smrg | ((mode->CrtcVDisplay 229cd241713Smrg * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1) 230cd241713Smrg << 16)); 231cd241713Smrg#endif 232cd241713Smrg 233cd241713Smrg vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; 234cd241713Smrg if (!vsync_wid) vsync_wid = 1; 235cd241713Smrg if (vsync_wid > 0x1f) vsync_wid = 0x1f; 236cd241713Smrg 237cd241713Smrg save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) 238cd241713Smrg | (vsync_wid << 16) 239cd241713Smrg | ((mode->Flags & V_NVSYNC) 240cd241713Smrg ? R128_CRTC2_V_SYNC_POL 241cd241713Smrg : 0)); 242cd241713Smrg save->crtc2_pitch = info->CurrentLayout.displayWidth / 8; 243cd241713Smrg 244cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 245cd241713Smrg "Pitch = %d bytes (virtualX = %d, " 246cd241713Smrg "displayWidth = %d)\n", 247cd241713Smrg save->crtc2_pitch, pScrn->virtualX, 248cd241713Smrg info->CurrentLayout.displayWidth)); 249cd241713Smrg return TRUE; 250cd241713Smrg} 251cd241713Smrg 252cd241713Smrg/* Write CRTC registers. */ 253cd241713Smrgvoid R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) 254cd241713Smrg{ 255cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 256cd241713Smrg unsigned char *R128MMIO = info->MMIO; 257cd241713Smrg 258cd241713Smrg OUTREG(R128_CRTC_GEN_CNTL, restore->crtc_gen_cntl); 259cd241713Smrg 260cd241713Smrg OUTREGP(R128_CRTC_EXT_CNTL, restore->crtc_ext_cntl, 261cd241713Smrg R128_CRTC_VSYNC_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_DISPLAY_DIS); 262cd241713Smrg 263cd241713Smrg OUTREG(R128_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); 264cd241713Smrg OUTREG(R128_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); 265cd241713Smrg OUTREG(R128_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); 266cd241713Smrg OUTREG(R128_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); 267cd241713Smrg OUTREG(R128_CRTC_OFFSET, restore->crtc_offset); 268cd241713Smrg OUTREG(R128_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); 269cd241713Smrg OUTREG(R128_CRTC_PITCH, restore->crtc_pitch); 270cd241713Smrg} 271cd241713Smrg 272cd241713Smrg/* Write CRTC2 registers. */ 273cd241713Smrgvoid R128RestoreCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr restore) 274cd241713Smrg{ 275cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 276cd241713Smrg unsigned char *R128MMIO = info->MMIO; 277cd241713Smrg 278cd241713Smrg OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl, 279cd241713Smrg R128_CRTC2_DISP_DIS); 280cd241713Smrg 281cd241713Smrg OUTREG(R128_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); 282cd241713Smrg OUTREG(R128_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid); 283cd241713Smrg OUTREG(R128_CRTC2_V_TOTAL_DISP, restore->crtc2_v_total_disp); 284cd241713Smrg OUTREG(R128_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid); 285cd241713Smrg OUTREG(R128_CRTC2_OFFSET, restore->crtc2_offset); 286cd241713Smrg OUTREG(R128_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); 287cd241713Smrg OUTREG(R128_CRTC2_PITCH, restore->crtc2_pitch); 288cd241713Smrg} 289cd241713Smrg 290cd241713Smrgstatic Bool R128InitCrtcBase(xf86CrtcPtr crtc, R128SavePtr save, int x, int y) 291cd241713Smrg{ 292cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 293cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 294cd241713Smrg int offset = y * info->CurrentLayout.displayWidth + x; 295cd241713Smrg int Base = pScrn->fbOffset; 296cd241713Smrg 297cd241713Smrg switch (info->CurrentLayout.pixel_code) { 298cd241713Smrg case 15: 299cd241713Smrg case 16: offset *= 2; break; 300cd241713Smrg case 24: offset *= 3; break; 301cd241713Smrg case 32: offset *= 4; break; 302cd241713Smrg } 303cd241713Smrg Base += offset; 304cd241713Smrg 305cd241713Smrg if (crtc->rotatedData != NULL) 306cd241713Smrg Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB; 307cd241713Smrg 308cd241713Smrg Base &= ~7; /* 3 lower bits are always 0 */ 309cd241713Smrg if (info->CurrentLayout.pixel_code == 24) 310cd241713Smrg Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */ 311cd241713Smrg 312cd241713Smrg save->crtc_offset = Base; 313cd241713Smrg save->crtc_offset_cntl = 0; 314cd241713Smrg 315cd241713Smrg return TRUE; 316cd241713Smrg} 317cd241713Smrg 318cd241713Smrgstatic Bool R128InitCrtc2Base(xf86CrtcPtr crtc, R128SavePtr save, int x, int y) 319cd241713Smrg{ 320cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 321cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 322cd241713Smrg int offset = y * info->CurrentLayout.displayWidth + x; 323cd241713Smrg int Base = pScrn->fbOffset; 324cd241713Smrg 325cd241713Smrg switch (info->CurrentLayout.pixel_code) { 326cd241713Smrg case 15: 327cd241713Smrg case 16: offset *= 2; break; 328cd241713Smrg case 24: offset *= 3; break; 329cd241713Smrg case 32: offset *= 4; break; 330cd241713Smrg } 331cd241713Smrg Base += offset; 332cd241713Smrg 333cd241713Smrg if (crtc->rotatedData != NULL) 334cd241713Smrg Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB; 335cd241713Smrg 336cd241713Smrg Base &= ~7; /* 3 lower bits are always 0 */ 337cd241713Smrg if (info->CurrentLayout.pixel_code == 24) 338cd241713Smrg Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */ 339cd241713Smrg 340cd241713Smrg save->crtc2_offset = Base; 341cd241713Smrg save->crtc2_offset_cntl = 0; 342cd241713Smrg 343cd241713Smrg return TRUE; 344cd241713Smrg} 345cd241713Smrg 346cd241713Smrg/* Define PLL registers for requested video mode. */ 347cd241713Smrgstatic void R128InitPLLRegisters(xf86CrtcPtr crtc, R128SavePtr save, 348cd241713Smrg R128PLLPtr pll, double dot_clock) 349cd241713Smrg{ 350cd241713Smrg#if R128_DEBUG 351cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 352cd241713Smrg#endif 353cd241713Smrg unsigned long freq = dot_clock * 100; 354cd241713Smrg struct { 355cd241713Smrg int divider; 356cd241713Smrg int bitvalue; 357cd241713Smrg } *post_div, 358cd241713Smrg post_divs[] = { 359cd241713Smrg /* From RAGE 128 VR/RAGE 128 GL Register 360cd241713Smrg Reference Manual (Technical Reference 361cd241713Smrg Manual P/N RRG-G04100-C Rev. 0.04), page 362cd241713Smrg 3-17 (PLL_DIV_[3:0]). */ 363cd241713Smrg { 1, 0 }, /* VCLK_SRC */ 364cd241713Smrg { 2, 1 }, /* VCLK_SRC/2 */ 365cd241713Smrg { 4, 2 }, /* VCLK_SRC/4 */ 366cd241713Smrg { 8, 3 }, /* VCLK_SRC/8 */ 367cd241713Smrg 368cd241713Smrg { 3, 4 }, /* VCLK_SRC/3 */ 369cd241713Smrg /* bitvalue = 5 is reserved */ 370cd241713Smrg { 6, 6 }, /* VCLK_SRC/6 */ 371cd241713Smrg { 12, 7 }, /* VCLK_SRC/12 */ 372cd241713Smrg { 0, 0 } 373cd241713Smrg }; 374cd241713Smrg 375cd241713Smrg if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; 376cd241713Smrg if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; 377cd241713Smrg 378cd241713Smrg for (post_div = &post_divs[0]; post_div->divider; ++post_div) { 379cd241713Smrg save->pll_output_freq = post_div->divider * freq; 380cd241713Smrg if (save->pll_output_freq >= pll->min_pll_freq 381cd241713Smrg && save->pll_output_freq <= pll->max_pll_freq) break; 382cd241713Smrg } 383cd241713Smrg 384cd241713Smrg save->dot_clock_freq = freq; 385cd241713Smrg save->feedback_div = R128Div(pll->reference_div * save->pll_output_freq, 386cd241713Smrg pll->reference_freq); 387cd241713Smrg save->post_div = post_div->divider; 388cd241713Smrg 389cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 390cd241713Smrg "dc=%d, of=%d, fd=%d, pd=%d\n", 391cd241713Smrg save->dot_clock_freq, 392cd241713Smrg save->pll_output_freq, 393cd241713Smrg save->feedback_div, 394cd241713Smrg save->post_div)); 395cd241713Smrg 396cd241713Smrg save->ppll_ref_div = pll->reference_div; 397cd241713Smrg save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16)); 398cd241713Smrg save->htotal_cntl = 0; 399cd241713Smrg 400cd241713Smrg} 401cd241713Smrg 402cd241713Smrg/* Define PLL2 registers for requested video mode. */ 403cd241713Smrgvoid R128InitPLL2Registers(xf86CrtcPtr crtc, R128SavePtr save, 404cd241713Smrg R128PLLPtr pll, double dot_clock) 405cd241713Smrg{ 406cd241713Smrg#if R128_DEBUG 407cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 408cd241713Smrg#endif 409cd241713Smrg unsigned long freq = dot_clock * 100; 410cd241713Smrg struct { 411cd241713Smrg int divider; 412cd241713Smrg int bitvalue; 413cd241713Smrg } *post_div, 414cd241713Smrg post_divs[] = { 415cd241713Smrg /* From RAGE 128 VR/RAGE 128 GL Register 416cd241713Smrg Reference Manual (Technical Reference 417cd241713Smrg Manual P/N RRG-G04100-C Rev. 0.04), page 418cd241713Smrg 3-17 (PLL_DIV_[3:0]). */ 419cd241713Smrg { 1, 0 }, /* VCLK_SRC */ 420cd241713Smrg { 2, 1 }, /* VCLK_SRC/2 */ 421cd241713Smrg { 4, 2 }, /* VCLK_SRC/4 */ 422cd241713Smrg { 8, 3 }, /* VCLK_SRC/8 */ 423cd241713Smrg 424cd241713Smrg { 3, 4 }, /* VCLK_SRC/3 */ 425cd241713Smrg /* bitvalue = 5 is reserved */ 426cd241713Smrg { 6, 6 }, /* VCLK_SRC/6 */ 427cd241713Smrg { 12, 7 }, /* VCLK_SRC/12 */ 428cd241713Smrg { 0, 0 } 429cd241713Smrg }; 430cd241713Smrg 431cd241713Smrg if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; 432cd241713Smrg if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; 433cd241713Smrg 434cd241713Smrg for (post_div = &post_divs[0]; post_div->divider; ++post_div) { 435cd241713Smrg save->pll_output_freq_2 = post_div->divider * freq; 436cd241713Smrg if (save->pll_output_freq_2 >= pll->min_pll_freq 437cd241713Smrg && save->pll_output_freq_2 <= pll->max_pll_freq) break; 438cd241713Smrg } 439cd241713Smrg 440cd241713Smrg save->dot_clock_freq_2 = freq; 441cd241713Smrg save->feedback_div_2 = R128Div(pll->reference_div 442cd241713Smrg * save->pll_output_freq_2, 443cd241713Smrg pll->reference_freq); 444cd241713Smrg save->post_div_2 = post_div->divider; 445cd241713Smrg 446cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 447cd241713Smrg "dc=%d, of=%d, fd=%d, pd=%d\n", 448cd241713Smrg save->dot_clock_freq_2, 449cd241713Smrg save->pll_output_freq_2, 450cd241713Smrg save->feedback_div_2, 451cd241713Smrg save->post_div_2)); 452cd241713Smrg 453cd241713Smrg save->p2pll_ref_div = pll->reference_div; 454cd241713Smrg save->p2pll_div_0 = (save->feedback_div_2 | (post_div->bitvalue<<16)); 455cd241713Smrg save->htotal_cntl2 = 0; 456cd241713Smrg} 457cd241713Smrg 458cd241713Smrgstatic void R128PLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) 459cd241713Smrg{ 460cd241713Smrg while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R); 461cd241713Smrg} 462cd241713Smrg 463cd241713Smrgstatic void R128PLLWriteUpdate(ScrnInfoPtr pScrn) 464cd241713Smrg{ 465cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 466cd241713Smrg unsigned char *R128MMIO = info->MMIO; 467cd241713Smrg 468cd241713Smrg while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R); 469cd241713Smrg 470cd241713Smrg OUTPLLP(pScrn, R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, 471cd241713Smrg ~R128_PPLL_ATOMIC_UPDATE_W); 472cd241713Smrg 473cd241713Smrg} 474cd241713Smrg 475cd241713Smrgstatic void R128PLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn) 476cd241713Smrg{ 477cd241713Smrg while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R); 478cd241713Smrg} 479cd241713Smrg 480cd241713Smrgstatic void R128PLL2WriteUpdate(ScrnInfoPtr pScrn) 481cd241713Smrg{ 482cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 483cd241713Smrg unsigned char *R128MMIO = info->MMIO; 484cd241713Smrg 485cd241713Smrg while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R); 486cd241713Smrg 487cd241713Smrg OUTPLLP(pScrn, R128_P2PLL_REF_DIV, 488cd241713Smrg R128_P2PLL_ATOMIC_UPDATE_W, 489cd241713Smrg ~(R128_P2PLL_ATOMIC_UPDATE_W)); 490cd241713Smrg} 491cd241713Smrg 492cd241713Smrg/* Write PLL registers. */ 493cd241713Smrgvoid R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) 494cd241713Smrg{ 495cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 496cd241713Smrg unsigned char *R128MMIO = info->MMIO; 497cd241713Smrg 498cd241713Smrg 499cd241713Smrg OUTPLLP(pScrn, R128_VCLK_ECP_CNTL, 500cd241713Smrg R128_VCLK_SRC_SEL_CPUCLK, 501cd241713Smrg ~(R128_VCLK_SRC_SEL_MASK)); 502cd241713Smrg 503cd241713Smrg OUTPLLP(pScrn, 504cd241713Smrg R128_PPLL_CNTL, 505cd241713Smrg R128_PPLL_RESET 506cd241713Smrg | R128_PPLL_ATOMIC_UPDATE_EN 507cd241713Smrg | R128_PPLL_VGA_ATOMIC_UPDATE_EN, 508cd241713Smrg ~(R128_PPLL_RESET 509cd241713Smrg | R128_PPLL_ATOMIC_UPDATE_EN 510cd241713Smrg | R128_PPLL_VGA_ATOMIC_UPDATE_EN)); 511cd241713Smrg 512cd241713Smrg OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, ~(R128_PLL_DIV_SEL)); 513cd241713Smrg 514cd241713Smrg/* R128PLLWaitForReadUpdateComplete(pScrn);*/ 515cd241713Smrg OUTPLLP(pScrn, R128_PPLL_REF_DIV, 516cd241713Smrg restore->ppll_ref_div, ~R128_PPLL_REF_DIV_MASK); 517cd241713Smrg/* R128PLLWriteUpdate(pScrn); 518cd241713Smrg 519cd241713Smrg R128PLLWaitForReadUpdateComplete(pScrn);*/ 520cd241713Smrg OUTPLLP(pScrn, R128_PPLL_DIV_3, 521cd241713Smrg restore->ppll_div_3, ~R128_PPLL_FB3_DIV_MASK); 522cd241713Smrg/* R128PLLWriteUpdate(pScrn);*/ 523cd241713Smrg OUTPLLP(pScrn, R128_PPLL_DIV_3, 524cd241713Smrg restore->ppll_div_3, ~R128_PPLL_POST3_DIV_MASK); 525cd241713Smrg 526cd241713Smrg R128PLLWriteUpdate(pScrn); 527cd241713Smrg R128PLLWaitForReadUpdateComplete(pScrn); 528cd241713Smrg 529cd241713Smrg OUTPLLP(pScrn, R128_PPLL_DIV_0, 530cd241713Smrg restore->ppll_div_0, ~R128_PPLL_FB0_DIV_MASK); 531cd241713Smrg/* R128PLLWriteUpdate(pScrn);*/ 532cd241713Smrg OUTPLLP(pScrn, R128_PPLL_DIV_0, 533cd241713Smrg restore->ppll_div_0, ~R128_PPLL_POST0_DIV_MASK); 534cd241713Smrg 535cd241713Smrg R128PLLWriteUpdate(pScrn); 536cd241713Smrg R128PLLWaitForReadUpdateComplete(pScrn); 537cd241713Smrg 538cd241713Smrg OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl); 539cd241713Smrg/* R128PLLWriteUpdate(pScrn);*/ 540cd241713Smrg 541cd241713Smrg OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~(R128_PPLL_RESET 542cd241713Smrg | R128_PPLL_SLEEP 543cd241713Smrg | R128_PPLL_ATOMIC_UPDATE_EN 544cd241713Smrg | R128_PPLL_VGA_ATOMIC_UPDATE_EN)); 545cd241713Smrg 546cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 547cd241713Smrg "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", 548cd241713Smrg restore->ppll_ref_div, 549cd241713Smrg restore->ppll_div_3, 550cd241713Smrg restore->htotal_cntl, 551cd241713Smrg INPLL(pScrn, R128_PPLL_CNTL))); 552cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 553cd241713Smrg "Wrote: rd=%d, fd=%d, pd=%d\n", 554cd241713Smrg restore->ppll_ref_div & R128_PPLL_REF_DIV_MASK, 555cd241713Smrg restore->ppll_div_3 & R128_PPLL_FB3_DIV_MASK, 556cd241713Smrg (restore->ppll_div_3 & 557cd241713Smrg R128_PPLL_POST3_DIV_MASK) >> 16)); 558cd241713Smrg 559cd241713Smrg usleep(5000); /* let the clock lock */ 560cd241713Smrg 561cd241713Smrg OUTPLLP(pScrn, R128_VCLK_ECP_CNTL, 562cd241713Smrg R128_VCLK_SRC_SEL_PPLLCLK, 563cd241713Smrg ~(R128_VCLK_SRC_SEL_MASK)); 564cd241713Smrg 565cd241713Smrg} 566cd241713Smrg 567cd241713Smrg/* Write PLL2 registers. */ 568cd241713Smrgvoid R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore) 569cd241713Smrg{ 570cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 571cd241713Smrg unsigned char *R128MMIO = info->MMIO; 572cd241713Smrg 573cd241713Smrg OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL, 574cd241713Smrg R128_V2CLK_SRC_SEL_CPUCLK, 575cd241713Smrg ~R128_V2CLK_SRC_SEL_MASK); 576cd241713Smrg 577cd241713Smrg OUTPLLP(pScrn, 578cd241713Smrg R128_P2PLL_CNTL, 579cd241713Smrg R128_P2PLL_RESET 580cd241713Smrg | R128_P2PLL_ATOMIC_UPDATE_EN 581cd241713Smrg | R128_P2PLL_VGA_ATOMIC_UPDATE_EN, 582cd241713Smrg ~(R128_P2PLL_RESET 583cd241713Smrg | R128_P2PLL_ATOMIC_UPDATE_EN 584cd241713Smrg | R128_P2PLL_VGA_ATOMIC_UPDATE_EN)); 585cd241713Smrg 586cd241713Smrg#if 1 587cd241713Smrg OUTREGP(R128_CLOCK_CNTL_INDEX, 0, R128_PLL2_DIV_SEL_MASK); 588cd241713Smrg#endif 589cd241713Smrg 590cd241713Smrg /*R128PLL2WaitForReadUpdateComplete(pScrn);*/ 591cd241713Smrg 592cd241713Smrg OUTPLLP(pScrn, R128_P2PLL_REF_DIV, restore->p2pll_ref_div, ~R128_P2PLL_REF_DIV_MASK); 593cd241713Smrg 594cd241713Smrg/* R128PLL2WriteUpdate(pScrn); 595cd241713Smrg R128PLL2WaitForReadUpdateComplete(pScrn);*/ 596cd241713Smrg 597cd241713Smrg OUTPLLP(pScrn, R128_P2PLL_DIV_0, 598cd241713Smrg restore->p2pll_div_0, ~R128_P2PLL_FB0_DIV_MASK); 599cd241713Smrg 600cd241713Smrg/* R128PLL2WriteUpdate(pScrn); 601cd241713Smrg R128PLL2WaitForReadUpdateComplete(pScrn);*/ 602cd241713Smrg 603cd241713Smrg OUTPLLP(pScrn, R128_P2PLL_DIV_0, 604cd241713Smrg restore->p2pll_div_0, ~R128_P2PLL_POST0_DIV_MASK); 605cd241713Smrg 606cd241713Smrg R128PLL2WriteUpdate(pScrn); 607cd241713Smrg R128PLL2WaitForReadUpdateComplete(pScrn); 608cd241713Smrg 609cd241713Smrg OUTPLL(R128_HTOTAL2_CNTL, restore->htotal_cntl2); 610cd241713Smrg 611cd241713Smrg/* R128PLL2WriteUpdate(pScrn);*/ 612cd241713Smrg 613cd241713Smrg OUTPLLP(pScrn, R128_P2PLL_CNTL, 0, ~(R128_P2PLL_RESET 614cd241713Smrg | R128_P2PLL_SLEEP 615cd241713Smrg | R128_P2PLL_ATOMIC_UPDATE_EN 616cd241713Smrg | R128_P2PLL_VGA_ATOMIC_UPDATE_EN)); 617cd241713Smrg 618cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 619cd241713Smrg "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", 620cd241713Smrg restore->p2pll_ref_div, 621cd241713Smrg restore->p2pll_div_0, 622cd241713Smrg restore->htotal_cntl2, 623cd241713Smrg INPLL(pScrn, R128_P2PLL_CNTL))); 624cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 625cd241713Smrg "Wrote: rd=%d, fd=%d, pd=%d\n", 626cd241713Smrg restore->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK, 627cd241713Smrg restore->p2pll_div_0 & R128_P2PLL_FB0_DIV_MASK, 628cd241713Smrg (restore->p2pll_div_0 & 629cd241713Smrg R128_P2PLL_POST0_DIV_MASK) >>16)); 630cd241713Smrg 631cd241713Smrg usleep(5000); /* Let the clock to lock */ 632cd241713Smrg 633cd241713Smrg OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL, 634cd241713Smrg R128_V2CLK_SRC_SEL_P2PLLCLK, 635cd241713Smrg ~R128_V2CLK_SRC_SEL_MASK); 636cd241713Smrg 637cd241713Smrg} 638cd241713Smrg 639cd241713Smrg/* Define DDA registers for requested video mode. */ 640cd241713SmrgBool R128InitDDARegisters(xf86CrtcPtr crtc, R128SavePtr save, 641cd241713Smrg R128PLLPtr pll, DisplayModePtr mode) 642cd241713Smrg{ 643cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 644cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 645cd241713Smrg xf86OutputPtr output = R128FirstOutput(crtc); 646cd241713Smrg R128OutputPrivatePtr r128_output = output->driver_private; 647cd241713Smrg 648cd241713Smrg int DisplayFifoWidth = 128; 649cd241713Smrg int DisplayFifoDepth = 32; 650cd241713Smrg int XclkFreq; 651cd241713Smrg int VclkFreq; 652cd241713Smrg int XclksPerTransfer; 653cd241713Smrg int XclksPerTransferPrecise; 654cd241713Smrg int UseablePrecision; 655cd241713Smrg int Roff; 656cd241713Smrg int Ron; 657cd241713Smrg 658cd241713Smrg XclkFreq = pll->xclk; 659cd241713Smrg 660cd241713Smrg VclkFreq = R128Div(pll->reference_freq * save->feedback_div, 661cd241713Smrg pll->reference_div * save->post_div); 662cd241713Smrg 663cd241713Smrg if (info->isDFP && !info->isPro2 && r128_output->PanelXRes > 0) { 664cd241713Smrg if (r128_output->PanelXRes != mode->CrtcHDisplay) 665cd241713Smrg VclkFreq = (VclkFreq * mode->CrtcHDisplay) / r128_output->PanelXRes; 666cd241713Smrg } 667cd241713Smrg 668cd241713Smrg XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth, 669cd241713Smrg VclkFreq * (info->CurrentLayout.pixel_bytes * 8)); 670cd241713Smrg 671cd241713Smrg UseablePrecision = R128MinBits(XclksPerTransfer) + 1; 672cd241713Smrg 673cd241713Smrg XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth) 674cd241713Smrg << (11 - UseablePrecision), 675cd241713Smrg VclkFreq * (info->CurrentLayout.pixel_bytes * 8)); 676cd241713Smrg 677cd241713Smrg Roff = XclksPerTransferPrecise * (DisplayFifoDepth - 4); 678cd241713Smrg 679cd241713Smrg Ron = (4 * info->ram->MB 680cd241713Smrg + 3 * MAX(info->ram->Trcd - 2, 0) 681cd241713Smrg + 2 * info->ram->Trp 682cd241713Smrg + info->ram->Twr 683cd241713Smrg + info->ram->CL 684cd241713Smrg + info->ram->Tr2w 685cd241713Smrg + XclksPerTransfer) << (11 - UseablePrecision); 686cd241713Smrg 687cd241713Smrg if (Ron + info->ram->Rloop >= Roff) { 688cd241713Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 689cd241713Smrg "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n", 690cd241713Smrg Ron, info->ram->Rloop, Roff); 691cd241713Smrg return FALSE; 692cd241713Smrg } 693cd241713Smrg 694cd241713Smrg save->dda_config = (XclksPerTransferPrecise 695cd241713Smrg | (UseablePrecision << 16) 696cd241713Smrg | (info->ram->Rloop << 20)); 697cd241713Smrg 698cd241713Smrg save->dda_on_off = (Ron << 16) | Roff; 699cd241713Smrg 700cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 701cd241713Smrg "XclkFreq = %d; VclkFreq = %d; " 7028ce07328Smrg "per = %d, %d (usable = %d)\n", 703cd241713Smrg XclkFreq, 704cd241713Smrg VclkFreq, 705cd241713Smrg XclksPerTransfer, 706cd241713Smrg XclksPerTransferPrecise, 707cd241713Smrg UseablePrecision)); 708cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 709cd241713Smrg "Roff = %d, Ron = %d, Rloop = %d\n", 710cd241713Smrg Roff, Ron, info->ram->Rloop)); 711cd241713Smrg 712cd241713Smrg return TRUE; 713cd241713Smrg} 714cd241713Smrg 715cd241713Smrg/* Define DDA2 registers for requested video mode. */ 716cd241713SmrgBool R128InitDDA2Registers(xf86CrtcPtr crtc, R128SavePtr save, 717cd241713Smrg R128PLLPtr pll, DisplayModePtr mode) 718cd241713Smrg{ 719cd241713Smrg ScrnInfoPtr pScrn = crtc->scrn; 720cd241713Smrg R128InfoPtr info = R128PTR(pScrn); 721cd241713Smrg xf86OutputPtr output = R128FirstOutput(crtc); 722cd241713Smrg R128OutputPrivatePtr r128_output = output->driver_private; 723cd241713Smrg 724cd241713Smrg int DisplayFifoWidth = 128; 725cd241713Smrg int DisplayFifoDepth = 32; 726cd241713Smrg int XclkFreq; 727cd241713Smrg int VclkFreq; 728cd241713Smrg int XclksPerTransfer; 729cd241713Smrg int XclksPerTransferPrecise; 730cd241713Smrg int UseablePrecision; 731cd241713Smrg int Roff; 732cd241713Smrg int Ron; 733cd241713Smrg 734cd241713Smrg XclkFreq = pll->xclk; 735cd241713Smrg 736cd241713Smrg VclkFreq = R128Div(pll->reference_freq * save->feedback_div_2, 737cd241713Smrg pll->reference_div * save->post_div_2); 738cd241713Smrg 739cd241713Smrg if (info->isDFP && !info->isPro2 && r128_output->PanelXRes > 0) { 740cd241713Smrg if (r128_output->PanelXRes != mode->CrtcHDisplay) 741cd241713Smrg VclkFreq = (VclkFreq * mode->CrtcHDisplay) / r128_output->PanelXRes; 742cd241713Smrg } 743cd241713Smrg 744cd241713Smrg XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth, 745cd241713Smrg VclkFreq * (info->CurrentLayout.pixel_bytes * 8)); 746cd241713Smrg 747cd241713Smrg UseablePrecision = R128MinBits(XclksPerTransfer) + 1; 748cd241713Smrg 749cd241713Smrg XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth) 750cd241713Smrg << (11 - UseablePrecision), 751cd241713Smrg VclkFreq * (info->CurrentLayout.pixel_bytes * 8)); 752cd241713Smrg 753cd241713Smrg Roff = XclksPerTransferPrecise * (DisplayFifoDepth - 4); 754cd241713Smrg 755cd241713Smrg Ron = (4 * info->ram->MB 756cd241713Smrg + 3 * MAX(info->ram->Trcd - 2, 0) 757cd241713Smrg + 2 * info->ram->Trp 758cd241713Smrg + info->ram->Twr 759cd241713Smrg + info->ram->CL 760cd241713Smrg + info->ram->Tr2w 761cd241713Smrg + XclksPerTransfer) << (11 - UseablePrecision); 762cd241713Smrg 763cd241713Smrg 764cd241713Smrg if (Ron + info->ram->Rloop >= Roff) { 765cd241713Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 766cd241713Smrg "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n", 767cd241713Smrg Ron, info->ram->Rloop, Roff); 768cd241713Smrg return FALSE; 769cd241713Smrg } 770cd241713Smrg 771cd241713Smrg save->dda2_config = (XclksPerTransferPrecise 772cd241713Smrg | (UseablePrecision << 16) 773cd241713Smrg | (info->ram->Rloop << 20)); 774cd241713Smrg 775cd241713Smrg /*save->dda2_on_off = (Ron << 16) | Roff;*/ 776cd241713Smrg /* shift most be 18 otherwise there's corruption on crtc2 */ 777cd241713Smrg save->dda2_on_off = (Ron << 18) | Roff; 778cd241713Smrg 779cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 780cd241713Smrg "XclkFreq = %d; VclkFreq = %d; " 7818ce07328Smrg "per = %d, %d (usable = %d)\n", 782cd241713Smrg XclkFreq, 783cd241713Smrg VclkFreq, 784cd241713Smrg XclksPerTransfer, 785cd241713Smrg XclksPerTransferPrecise, 786cd241713Smrg UseablePrecision)); 787cd241713Smrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 788cd241713Smrg "Roff = %d, Ron = %d, Rloop = %d\n", 789cd241713Smrg Roff, Ron, info->ram->Rloop)); 790cd241713Smrg 791cd241713Smrg return TRUE; 792cd241713Smrg} 793cd241713Smrg 794e3d74329Smrgstatic void r128_crtc_load_lut(xf86CrtcPtr crtc); 795e3d74329Smrg 796e3d74329Smrgstatic void r128_crtc_dpms(xf86CrtcPtr crtc, int mode) 797e3d74329Smrg{ 798e3d74329Smrg int mask; 799e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 800e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 801e3d74329Smrg unsigned char *R128MMIO = info->MMIO; 802e3d74329Smrg R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 803e3d74329Smrg 804e3d74329Smrg /* XXX: The HSYNC and VSYNC bits for CRTC2 don't exist on the r128? */ 805e3d74329Smrg mask = r128_crtc->crtc_id ? R128_CRTC2_DISP_DIS : (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_VSYNC_DIS); 806e3d74329Smrg 807e3d74329Smrg switch (mode) { 808e3d74329Smrg case DPMSModeOn: 809e3d74329Smrg if (r128_crtc->crtc_id) { 810e3d74329Smrg OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask); 811e3d74329Smrg } else { 812e3d74329Smrg OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask); 813e3d74329Smrg } 814e3d74329Smrg break; 815e3d74329Smrg case DPMSModeStandby: 816e3d74329Smrg if (r128_crtc->crtc_id) { 817e3d74329Smrg OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask); 818e3d74329Smrg } else { 819e3d74329Smrg OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS), ~mask); 820e3d74329Smrg } 821e3d74329Smrg break; 822e3d74329Smrg case DPMSModeSuspend: 823e3d74329Smrg if (r128_crtc->crtc_id) { 824e3d74329Smrg OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask); 825e3d74329Smrg } else { 826e3d74329Smrg OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS), ~mask); 827e3d74329Smrg } 828e3d74329Smrg break; 829e3d74329Smrg case DPMSModeOff: 830e3d74329Smrg if (r128_crtc->crtc_id) { 831e3d74329Smrg OUTREGP(R128_CRTC2_GEN_CNTL, mask, ~mask); 832e3d74329Smrg } else { 833e3d74329Smrg OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask); 834e3d74329Smrg } 835e3d74329Smrg break; 836e3d74329Smrg } 837e3d74329Smrg 838e3d74329Smrg if (mode != DPMSModeOn) { 839e3d74329Smrg if (r128_crtc->crtc_id) { 840e3d74329Smrg OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_EN); 841e3d74329Smrg } else { 842e3d74329Smrg OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_EN); 843e3d74329Smrg } 844e3d74329Smrg } else { 845e3d74329Smrg if (r128_crtc->crtc_id) { 846e3d74329Smrg OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_EN, ~R128_CRTC2_EN); 847e3d74329Smrg } else { 848e3d74329Smrg OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_EN, ~R128_CRTC_EN); 849e3d74329Smrg } 850e3d74329Smrg } 851e3d74329Smrg 852e3d74329Smrg if (mode != DPMSModeOff) 853e3d74329Smrg r128_crtc_load_lut(crtc); 854e3d74329Smrg} 855e3d74329Smrg 856e3d74329Smrgvoid r128_crtc_load_lut(xf86CrtcPtr crtc) 857e3d74329Smrg{ 858e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 859e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 860e3d74329Smrg unsigned char *R128MMIO = info->MMIO; 861e3d74329Smrg R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 862e3d74329Smrg int i; 863e3d74329Smrg 864e3d74329Smrg if (!crtc->enabled) 865e3d74329Smrg return; 866e3d74329Smrg 867e3d74329Smrg PAL_SELECT(r128_crtc->crtc_id); 868e3d74329Smrg 869e3d74329Smrg for (i = 0; i < 256; i++) { 870e3d74329Smrg OUTPAL(i, r128_crtc->lut_r[i], r128_crtc->lut_g[i], r128_crtc->lut_b[i]); 871e3d74329Smrg } 872e3d74329Smrg} 873e3d74329Smrg 874e3d74329Smrgstatic Bool r128_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode) 875e3d74329Smrg{ 876e3d74329Smrg return TRUE; 877e3d74329Smrg} 878e3d74329Smrg 879e3d74329Smrgstatic void r128_crtc_mode_prepare(xf86CrtcPtr crtc) 880e3d74329Smrg{ 881e3d74329Smrg r128_crtc_dpms(crtc, DPMSModeOff); 882e3d74329Smrg} 883e3d74329Smrg 884e3d74329Smrgstatic void r128_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y) 885e3d74329Smrg{ 886e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 887e3d74329Smrg R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 888e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 889e3d74329Smrg double dot_clock = adjusted_mode->Clock / 1000.0; 890e3d74329Smrg 891e3d74329Smrg if (r128_crtc->cursor_offset) r128_crtc_hide_cursor(crtc); 892e3d74329Smrg xf86PrintModeline(pScrn->scrnIndex, adjusted_mode); 893e3d74329Smrg R128InitCommonRegisters(&info->ModeReg, info); 894e3d74329Smrg 895e3d74329Smrg switch (r128_crtc->crtc_id) { 896e3d74329Smrg case 0: 897e3d74329Smrg R128InitCrtcRegisters(crtc, &info->ModeReg, adjusted_mode); 898e3d74329Smrg R128InitCrtcBase(crtc, &info->ModeReg, x, y); 899e3d74329Smrg if (dot_clock) { 900e3d74329Smrg R128InitPLLRegisters(crtc, &info->ModeReg, &info->pll, dot_clock); 901e3d74329Smrg R128InitDDARegisters(crtc, &info->ModeReg, &info->pll, adjusted_mode); 902e3d74329Smrg } else { 903e3d74329Smrg info->ModeReg.ppll_ref_div = info->SavedReg.ppll_ref_div; 904e3d74329Smrg info->ModeReg.ppll_div_3 = info->SavedReg.ppll_div_3; 905e3d74329Smrg info->ModeReg.htotal_cntl = info->SavedReg.htotal_cntl; 906e3d74329Smrg info->ModeReg.dda_config = info->SavedReg.dda_config; 907e3d74329Smrg info->ModeReg.dda_on_off = info->SavedReg.dda_on_off; 908e3d74329Smrg } 909e3d74329Smrg break; 910e3d74329Smrg case 1: 911e3d74329Smrg R128InitCrtc2Registers(crtc, &info->ModeReg, adjusted_mode); 912e3d74329Smrg R128InitCrtc2Base(crtc, &info->ModeReg, x, y); 913e3d74329Smrg if (dot_clock) { 914e3d74329Smrg R128InitPLL2Registers(crtc, &info->ModeReg, &info->pll, dot_clock); 915e3d74329Smrg R128InitDDA2Registers(crtc, &info->ModeReg, &info->pll, adjusted_mode); 916e3d74329Smrg } 917e3d74329Smrg break; 918e3d74329Smrg } 919e3d74329Smrg 920e3d74329Smrg R128RestoreCommonRegisters(pScrn, &info->ModeReg); 921e3d74329Smrg 922e3d74329Smrg switch (r128_crtc->crtc_id) { 923e3d74329Smrg case 0: 924e3d74329Smrg R128RestoreDDARegisters(pScrn, &info->ModeReg); 925e3d74329Smrg R128RestoreCrtcRegisters(pScrn, &info->ModeReg); 926e3d74329Smrg R128RestorePLLRegisters(pScrn, &info->ModeReg); 927e3d74329Smrg break; 928e3d74329Smrg case 1: 929e3d74329Smrg R128RestoreDDA2Registers(pScrn, &info->ModeReg); 930e3d74329Smrg R128RestoreCrtc2Registers(pScrn, &info->ModeReg); 931e3d74329Smrg R128RestorePLL2Registers(pScrn, &info->ModeReg); 932e3d74329Smrg break; 933e3d74329Smrg } 934e3d74329Smrg 935e3d74329Smrg if (r128_crtc->cursor_offset) r128_crtc_show_cursor(crtc); 936e3d74329Smrg} 937e3d74329Smrg 938e3d74329Smrgstatic void r128_crtc_mode_commit(xf86CrtcPtr crtc) 939e3d74329Smrg{ 940e3d74329Smrg r128_crtc_dpms(crtc, DPMSModeOn); 941e3d74329Smrg} 942e3d74329Smrg 943e3d74329Smrgstatic void r128_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size) 944e3d74329Smrg{ 945e3d74329Smrg R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 946e3d74329Smrg int i; 947e3d74329Smrg 948e3d74329Smrg for (i = 0; i < 256; i++) { 949e3d74329Smrg r128_crtc->lut_r[i] = red[i] >> 8; 950e3d74329Smrg r128_crtc->lut_g[i] = green[i] >> 8; 951e3d74329Smrg r128_crtc->lut_b[i] = blue[i] >> 8; 952e3d74329Smrg } 953e3d74329Smrg 954e3d74329Smrg r128_crtc_load_lut(crtc); 955e3d74329Smrg} 956e3d74329Smrg 957e3d74329Smrgstatic Bool r128_crtc_lock(xf86CrtcPtr crtc) 958e3d74329Smrg{ 959e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 960e3d74329Smrg ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 961e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 962e3d74329Smrg 963e3d74329Smrg#ifdef HAVE_XAA_H 964e3d74329Smrg if (info->accel) info->accel->Sync(pScrn); 965e3d74329Smrg#endif 966e3d74329Smrg#ifdef USE_EXA 967e3d74329Smrg if (info->ExaDriver) exaWaitSync(pScreen); 968e3d74329Smrg#endif 969e3d74329Smrg 970e3d74329Smrg return FALSE; 971e3d74329Smrg} 972e3d74329Smrg 973e3d74329Smrgstatic void r128_crtc_unlock(xf86CrtcPtr crtc) 974e3d74329Smrg{ 975e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 976e3d74329Smrg ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 977e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 978e3d74329Smrg 979e3d74329Smrg#ifdef HAVE_XAA_H 980e3d74329Smrg if (info->accel) info->accel->Sync(pScrn); 981e3d74329Smrg#endif 982e3d74329Smrg#ifdef USE_EXA 983e3d74329Smrg if (info->ExaDriver) exaWaitSync(pScreen); 984e3d74329Smrg#endif 985e3d74329Smrg} 986e3d74329Smrg 987e3d74329Smrgstatic void *r128_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 988e3d74329Smrg{ 989e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 990e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 991e3d74329Smrg 992e3d74329Smrg R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 993e3d74329Smrg unsigned long rotate_offset = 0; 994e3d74329Smrg unsigned long rotate_pitch; 995e3d74329Smrg int cpp = pScrn->bitsPerPixel / 8; 996e3d74329Smrg int align = 4096; 997e3d74329Smrg int size; 998e3d74329Smrg 999e3d74329Smrg rotate_pitch = pScrn->displayWidth * cpp; 1000e3d74329Smrg size = rotate_pitch * height; 1001e3d74329Smrg rotate_offset = R128AllocateMemory(pScrn, &(r128_crtc->rotate_mem), size, align, TRUE); 1002e3d74329Smrg 1003e3d74329Smrg /* If allocations failed or if there was no accel. */ 1004e3d74329Smrg if (rotate_offset == 0) 1005e3d74329Smrg return NULL; 1006e3d74329Smrg 1007e3d74329Smrg return info->FB + rotate_offset; 1008e3d74329Smrg} 1009e3d74329Smrg 1010e3d74329Smrgstatic PixmapPtr r128_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1011e3d74329Smrg{ 1012e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 1013e3d74329Smrg PixmapPtr rotate_pixmap; 1014e3d74329Smrg unsigned long rotate_pitch; 1015e3d74329Smrg int cpp = pScrn->bitsPerPixel / 8; 1016e3d74329Smrg 1017e3d74329Smrg if (!data) data = r128_crtc_shadow_allocate(crtc, width, height); 1018e3d74329Smrg 1019e3d74329Smrg rotate_pitch = pScrn->displayWidth * cpp; 1020e3d74329Smrg rotate_pixmap = GetScratchPixmapHeader(xf86ScrnToScreen(pScrn), 1021e3d74329Smrg width, height, 1022e3d74329Smrg pScrn->depth, 1023e3d74329Smrg pScrn->bitsPerPixel, 1024e3d74329Smrg rotate_pitch, 1025e3d74329Smrg data); 1026e3d74329Smrg 1027e3d74329Smrg if (rotate_pixmap == NULL) { 1028e3d74329Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1029e3d74329Smrg "Couldn't allocate shadow memory for rotated CRTC\n"); 1030e3d74329Smrg return NULL; 1031e3d74329Smrg } 1032e3d74329Smrg 1033e3d74329Smrg return rotate_pixmap; 1034e3d74329Smrg} 1035e3d74329Smrg 1036e3d74329Smrgstatic void r128_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1037e3d74329Smrg{ 1038e3d74329Smrg ScrnInfoPtr pScrn = crtc->scrn; 1039e3d74329Smrg ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 1040e3d74329Smrg R128InfoPtr info = R128PTR(pScrn); 1041e3d74329Smrg 1042e3d74329Smrg R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 1043e3d74329Smrg 1044e3d74329Smrg if (rotate_pixmap) FreeScratchPixmapHeader(rotate_pixmap); 1045e3d74329Smrg 1046e3d74329Smrg if (data && r128_crtc->rotate_mem != NULL) { 1047e3d74329Smrg#ifdef USE_EXA 1048e3d74329Smrg if (info->ExaDriver) 1049e3d74329Smrg exaOffscreenFree(pScreen, (ExaOffscreenArea *) r128_crtc->rotate_mem); 1050e3d74329Smrg#endif 1051e3d74329Smrg#ifdef HAVE_XAA_H 1052e3d74329Smrg if (info->accel) 1053e3d74329Smrg xf86FreeOffscreenLinear((FBLinearPtr) r128_crtc->rotate_mem); 1054e3d74329Smrg#endif 1055e3d74329Smrg r128_crtc->rotate_mem = NULL; 1056e3d74329Smrg } 1057e3d74329Smrg} 1058e3d74329Smrg 1059e3d74329Smrgstatic const xf86CrtcFuncsRec r128_crtc_funcs = { 1060e3d74329Smrg .dpms = r128_crtc_dpms, 1061e3d74329Smrg .save = NULL, 1062e3d74329Smrg .restore = NULL, 1063e3d74329Smrg .mode_fixup = r128_crtc_mode_fixup, 1064e3d74329Smrg .prepare = r128_crtc_mode_prepare, 1065e3d74329Smrg .mode_set = r128_crtc_mode_set, 1066e3d74329Smrg .commit = r128_crtc_mode_commit, 1067e3d74329Smrg .gamma_set = r128_crtc_gamma_set, 1068e3d74329Smrg .lock = r128_crtc_lock, 1069e3d74329Smrg .unlock = r128_crtc_unlock, 1070e3d74329Smrg .shadow_create = r128_crtc_shadow_create, 1071e3d74329Smrg .shadow_allocate = r128_crtc_shadow_allocate, 1072e3d74329Smrg .shadow_destroy = r128_crtc_shadow_destroy, 1073e3d74329Smrg .set_cursor_colors = r128_crtc_set_cursor_colors, 1074e3d74329Smrg .set_cursor_position = r128_crtc_set_cursor_position, 1075e3d74329Smrg .show_cursor = r128_crtc_show_cursor, 1076e3d74329Smrg .hide_cursor = r128_crtc_hide_cursor, 1077e3d74329Smrg .load_cursor_image = r128_crtc_load_cursor_image, 1078e3d74329Smrg .destroy = NULL, 1079e3d74329Smrg}; 1080e3d74329Smrg 1081e3d74329SmrgBool R128AllocateControllers(ScrnInfoPtr pScrn) 1082e3d74329Smrg{ 1083e3d74329Smrg R128EntPtr pR128Ent = R128EntPriv(pScrn); 1084e3d74329Smrg 1085e3d74329Smrg if (pR128Ent->Controller[0]) 1086e3d74329Smrg return TRUE; 1087e3d74329Smrg 1088e3d74329Smrg pR128Ent->pCrtc[0] = xf86CrtcCreate(pScrn, &r128_crtc_funcs); 1089e3d74329Smrg if (!pR128Ent->pCrtc[0]) 1090e3d74329Smrg return FALSE; 1091e3d74329Smrg 1092e3d74329Smrg pR128Ent->Controller[0] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1); 1093e3d74329Smrg if (!pR128Ent->Controller[0]) 1094e3d74329Smrg return FALSE; 1095e3d74329Smrg 1096e3d74329Smrg pR128Ent->pCrtc[0]->driver_private = pR128Ent->Controller[0]; 1097e3d74329Smrg pR128Ent->Controller[0]->crtc_id = 0; 1098e3d74329Smrg 1099e3d74329Smrg if (!pR128Ent->HasCRTC2) 1100e3d74329Smrg return TRUE; 1101e3d74329Smrg 1102e3d74329Smrg pR128Ent->pCrtc[1] = xf86CrtcCreate(pScrn, &r128_crtc_funcs); 1103e3d74329Smrg if (!pR128Ent->pCrtc[1]) 1104e3d74329Smrg return FALSE; 1105e3d74329Smrg 1106e3d74329Smrg pR128Ent->Controller[1] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1); 1107e3d74329Smrg if (!pR128Ent->Controller[1]) { 1108e3d74329Smrg free(pR128Ent->Controller[0]); 1109e3d74329Smrg return FALSE; 1110e3d74329Smrg } 1111e3d74329Smrg 1112e3d74329Smrg pR128Ent->pCrtc[1]->driver_private = pR128Ent->Controller[1]; 1113e3d74329Smrg pR128Ent->Controller[1]->crtc_id = 1; 1114e3d74329Smrg 1115e3d74329Smrg return TRUE; 1116e3d74329Smrg} 1117e3d74329Smrg 1118e3d74329Smrgvoid R128Blank(ScrnInfoPtr pScrn) 1119e3d74329Smrg{ 1120e3d74329Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1121e3d74329Smrg xf86OutputPtr output; 1122e3d74329Smrg xf86CrtcPtr crtc; 1123e3d74329Smrg int o, c; 1124e3d74329Smrg 1125e3d74329Smrg for (c = 0; c < xf86_config->num_crtc; c++) { 1126e3d74329Smrg crtc = xf86_config->crtc[c]; 1127e3d74329Smrg for (o = 0; o < xf86_config->num_output; o++) { 1128e3d74329Smrg output = xf86_config->output[o]; 1129e3d74329Smrg if (output->crtc != crtc) 1130e3d74329Smrg continue; 1131e3d74329Smrg 1132e3d74329Smrg output->funcs->dpms(output, DPMSModeOff); 1133e3d74329Smrg } 1134e3d74329Smrg crtc->funcs->dpms(crtc, DPMSModeOff); 1135e3d74329Smrg } 1136e3d74329Smrg} 1137e3d74329Smrg 1138e3d74329Smrgvoid R128Unblank(ScrnInfoPtr pScrn) 1139e3d74329Smrg{ 1140e3d74329Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1141e3d74329Smrg xf86OutputPtr output; 1142e3d74329Smrg xf86CrtcPtr crtc; 1143e3d74329Smrg int o, c; 1144e3d74329Smrg 1145e3d74329Smrg for (c = 0; c < xf86_config->num_crtc; c++) { 1146e3d74329Smrg crtc = xf86_config->crtc[c]; 1147e3d74329Smrg if (!crtc->enabled) 1148e3d74329Smrg continue; 1149e3d74329Smrg crtc->funcs->dpms(crtc, DPMSModeOn); 1150e3d74329Smrg for (o = 0; o < xf86_config->num_output; o++) { 1151e3d74329Smrg output = xf86_config->output[o]; 1152e3d74329Smrg if (output->crtc != crtc) 1153e3d74329Smrg continue; 1154e3d74329Smrg 1155e3d74329Smrg output->funcs->dpms(output, DPMSModeOn); 1156e3d74329Smrg } 1157e3d74329Smrg } 1158e3d74329Smrg} 1159