r128_crtc.c revision a56d54ac
11.1Sjoerg/* 21.1Sjoerg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and 31.1Sjoerg * VA Linux Systems Inc., Fremont, California. 41.1Sjoerg * 51.1Sjoerg * All Rights Reserved. 61.1Sjoerg * 71.1Sjoerg * Permission is hereby granted, free of charge, to any person obtaining 81.1Sjoerg * a copy of this software and associated documentation files (the 91.1Sjoerg * "Software"), to deal in the Software without restriction, including 101.1Sjoerg * without limitation on the rights to use, copy, modify, merge, 111.1Sjoerg * publish, distribute, sublicense, and/or sell copies of the Software, 121.1Sjoerg * and to permit persons to whom the Software is furnished to do so, 131.1Sjoerg * subject to the following conditions: 141.1Sjoerg * 151.1Sjoerg * The above copyright notice and this permission notice (including the 161.1Sjoerg * next paragraph) shall be included in all copies or substantial 171.1Sjoerg * portions of the Software. 181.1Sjoerg * 191.1Sjoerg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 201.1Sjoerg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 211.1Sjoerg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 221.1Sjoerg * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 231.1Sjoerg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <string.h> 34#include <stdio.h> 35 36#include "xf86.h" 37#include "xf86Modes.h" 38 39#ifdef HAVE_XEXTPROTO_71 40#include "X11/extensions/dpmsconst.h" 41#else 42#define DPMS_SERVER 43#include "X11/extensions/dpms.h" 44#endif 45 46#include "r128.h" 47#include "r128_probe.h" 48#include "r128_reg.h" 49 50static void r128_crtc_load_lut(xf86CrtcPtr crtc); 51 52static void r128_crtc_dpms(xf86CrtcPtr crtc, int mode) 53{ 54 int mask; 55 ScrnInfoPtr pScrn = crtc->scrn; 56 R128InfoPtr info = R128PTR(pScrn); 57 unsigned char *R128MMIO = info->MMIO; 58 R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 59 60 /* XXX: The HSYNC and VSYNC bits for CRTC2 don't exist on the r128? */ 61 mask = r128_crtc->crtc_id ? R128_CRTC2_DISP_DIS : (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_VSYNC_DIS); 62 63 switch (mode) { 64 case DPMSModeOn: 65 if (r128_crtc->crtc_id) { 66 OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask); 67 } else { 68 OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask); 69 } 70 break; 71 case DPMSModeStandby: 72 if (r128_crtc->crtc_id) { 73 OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask); 74 } else { 75 OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS), ~mask); 76 } 77 break; 78 case DPMSModeSuspend: 79 if (r128_crtc->crtc_id) { 80 OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask); 81 } else { 82 OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS), ~mask); 83 } 84 break; 85 case DPMSModeOff: 86 if (r128_crtc->crtc_id) { 87 OUTREGP(R128_CRTC2_GEN_CNTL, mask, ~mask); 88 } else { 89 OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask); 90 } 91 break; 92 } 93 94 if (mode != DPMSModeOn) { 95 if (r128_crtc->crtc_id) { 96 OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_EN); 97 } else { 98 OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_EN); 99 } 100 } else { 101 if (r128_crtc->crtc_id) { 102 OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_EN, ~R128_CRTC2_EN); 103 } else { 104 OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_EN, ~R128_CRTC_EN); 105 } 106 } 107 108 if (mode != DPMSModeOff) 109 r128_crtc_load_lut(crtc); 110} 111 112void r128_crtc_load_lut(xf86CrtcPtr crtc) 113{ 114 ScrnInfoPtr pScrn = crtc->scrn; 115 R128InfoPtr info = R128PTR(pScrn); 116 unsigned char *R128MMIO = info->MMIO; 117 R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 118 int i; 119 120 if (!crtc->enabled) 121 return; 122 123 PAL_SELECT(r128_crtc->crtc_id); 124 125 for (i = 0; i < 256; i++) { 126 OUTPAL(i, r128_crtc->lut_r[i], r128_crtc->lut_g[i], r128_crtc->lut_b[i]); 127 } 128} 129 130static Bool r128_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode) 131{ 132 return TRUE; 133} 134 135static void r128_crtc_mode_prepare(xf86CrtcPtr crtc) 136{ 137 r128_crtc_dpms(crtc, DPMSModeOff); 138} 139 140static void r128_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y) 141{ 142 ScrnInfoPtr pScrn = crtc->scrn; 143 R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 144 R128InfoPtr info = R128PTR(pScrn); 145 double dot_clock = adjusted_mode->Clock / 1000.0; 146 147 if (r128_crtc->cursor_offset) r128_crtc_hide_cursor(crtc); 148 xf86PrintModeline(pScrn->scrnIndex, adjusted_mode); 149 R128InitCommonRegisters(&info->ModeReg, info); 150 151 switch (r128_crtc->crtc_id) { 152 case 0: 153 R128InitCrtcRegisters(crtc, &info->ModeReg, adjusted_mode); 154 R128InitCrtcBase(crtc, &info->ModeReg, x, y); 155 if (dot_clock) { 156 R128InitPLLRegisters(crtc, &info->ModeReg, &info->pll, dot_clock); 157 R128InitDDARegisters(crtc, &info->ModeReg, &info->pll, adjusted_mode); 158 } else { 159 info->ModeReg.ppll_ref_div = info->SavedReg.ppll_ref_div; 160 info->ModeReg.ppll_div_3 = info->SavedReg.ppll_div_3; 161 info->ModeReg.htotal_cntl = info->SavedReg.htotal_cntl; 162 info->ModeReg.dda_config = info->SavedReg.dda_config; 163 info->ModeReg.dda_on_off = info->SavedReg.dda_on_off; 164 } 165 break; 166 case 1: 167 R128InitCrtc2Registers(crtc, &info->ModeReg, adjusted_mode); 168 R128InitCrtc2Base(crtc, &info->ModeReg, x, y); 169 if (dot_clock) { 170 R128InitPLL2Registers(crtc, &info->ModeReg, &info->pll, dot_clock); 171 R128InitDDA2Registers(crtc, &info->ModeReg, &info->pll, adjusted_mode); 172 } 173 break; 174 } 175 176 R128RestoreCommonRegisters(pScrn, &info->ModeReg); 177 178 switch (r128_crtc->crtc_id) { 179 case 0: 180 R128RestoreDDARegisters(pScrn, &info->ModeReg); 181 R128RestoreCrtcRegisters(pScrn, &info->ModeReg); 182 R128RestorePLLRegisters(pScrn, &info->ModeReg); 183 break; 184 case 1: 185 R128RestoreDDA2Registers(pScrn, &info->ModeReg); 186 R128RestoreCrtc2Registers(pScrn, &info->ModeReg); 187 R128RestorePLL2Registers(pScrn, &info->ModeReg); 188 break; 189 } 190 191 if (r128_crtc->cursor_offset) r128_crtc_show_cursor(crtc); 192} 193 194static void r128_crtc_mode_commit(xf86CrtcPtr crtc) 195{ 196 r128_crtc_dpms(crtc, DPMSModeOn); 197} 198 199static void r128_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size) 200{ 201 R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 202 int i; 203 204 for (i = 0; i < 256; i++) { 205 r128_crtc->lut_r[i] = red[i] >> 8; 206 r128_crtc->lut_g[i] = green[i] >> 8; 207 r128_crtc->lut_b[i] = blue[i] >> 8; 208 } 209 210 r128_crtc_load_lut(crtc); 211} 212 213static Bool r128_crtc_lock(xf86CrtcPtr crtc) 214{ 215 ScrnInfoPtr pScrn = crtc->scrn; 216 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 217 R128InfoPtr info = R128PTR(pScrn); 218 219#ifdef HAVE_XAA_H 220 if (info->accel) info->accel->Sync(pScrn); 221#endif 222#ifdef USE_EXA 223 if (info->ExaDriver) exaWaitSync(pScreen); 224#endif 225 226 return FALSE; 227} 228 229static void r128_crtc_unlock(xf86CrtcPtr crtc) 230{ 231 ScrnInfoPtr pScrn = crtc->scrn; 232 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 233 R128InfoPtr info = R128PTR(pScrn); 234 235#ifdef HAVE_XAA_H 236 if (info->accel) info->accel->Sync(pScrn); 237#endif 238#ifdef USE_EXA 239 if (info->ExaDriver) exaWaitSync(pScreen); 240#endif 241} 242 243static void *r128_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 244{ 245 ScrnInfoPtr pScrn = crtc->scrn; 246 R128InfoPtr info = R128PTR(pScrn); 247 248 R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 249 unsigned long rotate_offset = 0; 250 unsigned long rotate_pitch; 251 int cpp = pScrn->bitsPerPixel / 8; 252 int align = 4096; 253 int size; 254 255 rotate_pitch = pScrn->displayWidth * cpp; 256 size = rotate_pitch * height; 257 rotate_offset = R128AllocateMemory(pScrn, &(r128_crtc->rotate_mem), size, align, TRUE); 258 259 /* If allocations failed or if there was no accel. */ 260 if (rotate_offset == 0) 261 return NULL; 262 263 return info->FB + rotate_offset; 264} 265 266static PixmapPtr r128_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 267{ 268 ScrnInfoPtr pScrn = crtc->scrn; 269 PixmapPtr rotate_pixmap; 270 unsigned long rotate_pitch; 271 int cpp = pScrn->bitsPerPixel / 8; 272 273 if (!data) data = r128_crtc_shadow_allocate(crtc, width, height); 274 275 rotate_pitch = pScrn->displayWidth * cpp; 276 rotate_pixmap = GetScratchPixmapHeader(xf86ScrnToScreen(pScrn), 277 width, height, 278 pScrn->depth, 279 pScrn->bitsPerPixel, 280 rotate_pitch, 281 data); 282 283 if (rotate_pixmap == NULL) { 284 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 285 "Couldn't allocate shadow memory for rotated CRTC\n"); 286 return NULL; 287 } 288 289 return rotate_pixmap; 290} 291 292static void r128_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 293{ 294 ScrnInfoPtr pScrn = crtc->scrn; 295 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 296 R128InfoPtr info = R128PTR(pScrn); 297 298 R128CrtcPrivatePtr r128_crtc = crtc->driver_private; 299 300 if (rotate_pixmap) FreeScratchPixmapHeader(rotate_pixmap); 301 302 if (data && r128_crtc->rotate_mem != NULL) { 303#ifdef USE_EXA 304 if (info->ExaDriver) 305 exaOffscreenFree(pScreen, (ExaOffscreenArea *) r128_crtc->rotate_mem); 306#endif 307#ifdef HAVE_XAA_H 308 if (info->accel) 309 xf86FreeOffscreenLinear((FBLinearPtr) r128_crtc->rotate_mem); 310#endif 311 r128_crtc->rotate_mem = NULL; 312 } 313} 314 315static const xf86CrtcFuncsRec r128_crtc_funcs = { 316 .dpms = r128_crtc_dpms, 317 .save = NULL, 318 .restore = NULL, 319 .mode_fixup = r128_crtc_mode_fixup, 320 .prepare = r128_crtc_mode_prepare, 321 .mode_set = r128_crtc_mode_set, 322 .commit = r128_crtc_mode_commit, 323 .gamma_set = r128_crtc_gamma_set, 324 .lock = r128_crtc_lock, 325 .unlock = r128_crtc_unlock, 326 .shadow_create = r128_crtc_shadow_create, 327 .shadow_allocate = r128_crtc_shadow_allocate, 328 .shadow_destroy = r128_crtc_shadow_destroy, 329 .set_cursor_colors = r128_crtc_set_cursor_colors, 330 .set_cursor_position = r128_crtc_set_cursor_position, 331 .show_cursor = r128_crtc_show_cursor, 332 .hide_cursor = r128_crtc_hide_cursor, 333 .load_cursor_image = r128_crtc_load_cursor_image, 334 .destroy = NULL, 335}; 336 337Bool R128AllocateControllers(ScrnInfoPtr pScrn) 338{ 339 R128EntPtr pR128Ent = R128EntPriv(pScrn); 340 341 if (pR128Ent->Controller[0]) 342 return TRUE; 343 344 pR128Ent->pCrtc[0] = xf86CrtcCreate(pScrn, &r128_crtc_funcs); 345 if (!pR128Ent->pCrtc[0]) 346 return FALSE; 347 348 pR128Ent->Controller[0] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1); 349 if (!pR128Ent->Controller[0]) 350 return FALSE; 351 352 pR128Ent->pCrtc[0]->driver_private = pR128Ent->Controller[0]; 353 pR128Ent->Controller[0]->crtc_id = 0; 354 355 if (!pR128Ent->HasCRTC2) 356 return TRUE; 357 358 pR128Ent->pCrtc[1] = xf86CrtcCreate(pScrn, &r128_crtc_funcs); 359 if (!pR128Ent->pCrtc[1]) 360 return FALSE; 361 362 pR128Ent->Controller[1] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1); 363 if (!pR128Ent->Controller[1]) { 364 free(pR128Ent->Controller[0]); 365 return FALSE; 366 } 367 368 pR128Ent->pCrtc[1]->driver_private = pR128Ent->Controller[1]; 369 pR128Ent->Controller[1]->crtc_id = 1; 370 371 return TRUE; 372} 373 374void R128Blank(ScrnInfoPtr pScrn) 375{ 376 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 377 xf86OutputPtr output; 378 xf86CrtcPtr crtc; 379 int o, c; 380 381 for (c = 0; c < xf86_config->num_crtc; c++) { 382 crtc = xf86_config->crtc[c]; 383 for (o = 0; o < xf86_config->num_output; o++) { 384 output = xf86_config->output[o]; 385 if (output->crtc != crtc) 386 continue; 387 388 output->funcs->dpms(output, DPMSModeOff); 389 } 390 crtc->funcs->dpms(crtc, DPMSModeOff); 391 } 392} 393 394void R128Unblank(ScrnInfoPtr pScrn) 395{ 396 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 397 xf86OutputPtr output; 398 xf86CrtcPtr crtc; 399 int o, c; 400 401 for (c = 0; c < xf86_config->num_crtc; c++) { 402 crtc = xf86_config->crtc[c]; 403 if (!crtc->enabled) 404 continue; 405 crtc->funcs->dpms(crtc, DPMSModeOn); 406 for (o = 0; o < xf86_config->num_output; o++) { 407 output = xf86_config->output[o]; 408 if (output->crtc != crtc) 409 continue; 410 411 output->funcs->dpms(output, DPMSModeOn); 412 } 413 } 414} 415