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