savage_cursor.c revision aa9e3350
1/* 2 * Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * Copyright (c) 2003-2006, X.Org Foundation 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Except as contained in this notice, the name of the copyright holder(s) 24 * and author(s) shall not be used in advertising or otherwise to promote 25 * the sale, use or other dealings in this Software without prior written 26 * authorization from the copyright holder(s) and author(s). 27 */ 28 29/** 30 * \file savage_cursor.c 31 * Hardware cursor support for S3 Savage driver. Taken with very few changes 32 * from the s3virge cursor file. 33 * 34 * \author S. Marineau (19/04/97) 35 * \author Amancio Hasty 36 * \author Jon Tombs 37 * \author Tim Roberts 38 */ 39 40#ifdef HAVE_CONFIG_H 41#include "config.h" 42#endif 43 44#include "savage_driver.h" 45 46static void SavageLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src); 47static void SavageSetCursorPosition(ScrnInfoPtr pScrn, int x, int y); 48static void SavageSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg); 49 50 51/* 52 * Read/write to the DAC via MMIO 53 */ 54 55#define inCRReg(reg) (VGAHWPTR(pScrn))->readCrtc( VGAHWPTR(pScrn), reg ) 56#define outCRReg(reg, val) (VGAHWPTR(pScrn))->writeCrtc( VGAHWPTR(pScrn), reg, val ) 57#define inSRReg(reg) (VGAHWPTR(pScrn))->readSeq( VGAHWPTR(pScrn), reg ) 58#define outSRReg(reg, val) (VGAHWPTR(pScrn))->writeSeq( VGAHWPTR(pScrn), reg, val ) 59#if 0 60#define inStatus1() (VGAHWPTR(pScrn))->readST01( VGAHWPTR(pScrn) ) 61#endif 62 63/* 64 * certain HW cursor operations seem 65 * to require a delay to prevent lockups. 66 */ 67#define waitHSync(n) { \ 68 int num = n; \ 69 while (num--) { \ 70 while (inStatus1() & 0x01){};\ 71 while (!(inStatus1() & 0x01)){};\ 72 } \ 73 } 74#define MAX_CURS 64 75 76/* 77 * Disable HW Cursor on stretched LCDs. We don't know how to 78 * detect if display is stretched. Therefore we cannot rescale 79 * the HW cursor position. 80 */ 81 82#if 0 83static Bool 84SavageUseHWCursor(ScreenPtr pScr, CursorPtr pCurs) 85{ 86 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScr); 87 SavagePtr psav = SAVPTR(pScrn); 88 89 if (psav->PanelX != pScrn->currentMode->HDisplay 90 || psav->PanelY != pScrn->currentMode->VDisplay) { 91 /* BIT 1 : CRT is active, BIT 2 : LCD is active */ 92 unsigned char cr6d = inCRReg( 0x6d ); 93 if (cr6d & 0x02) 94 return FALSE; 95 } 96 return TRUE; 97} 98#endif 99 100Bool 101SavageHWCursorInit(ScreenPtr pScreen) 102{ 103 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 104 SavagePtr psav = SAVPTR(pScrn); 105 xf86CursorInfoPtr infoPtr; 106 107 infoPtr = xf86CreateCursorInfoRec(); 108 if(!infoPtr) 109 return FALSE; 110 111 psav->CursorInfoRec = infoPtr; 112 113 infoPtr->MaxWidth = MAX_CURS; 114 infoPtr->MaxHeight = MAX_CURS; 115 infoPtr->Flags = HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 | 116 HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK | 117 HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | 118 HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | 119 HARDWARE_CURSOR_INVERT_MASK; 120#if 0 121 /* 122 * The /MX family is apparently unique among the Savages, in that 123 * the cursor color is always straight RGB. The rest of the Savages 124 * use palettized values at 8-bit when not clock doubled. 125 */ 126 127 if (((psav->Chipset != S3_SAVAGE4) 128 && (inSRReg(0x18) & 0x80) && (inSRReg(0x15) & 0x50)) 129 || S3_SAVAGE_MOBILE_SERIES(psav->Chipset)) 130 infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP; 131#endif 132 /* 133 * With streams engine the Cursor seems to be ALWAYS TrueColor 134 *except at least the Savage4 135 */ 136 if (psav->Chipset != S3_SAVAGE4) 137 infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP; 138 139 infoPtr->SetCursorColors = SavageSetCursorColors; 140 infoPtr->SetCursorPosition = SavageSetCursorPosition; 141 infoPtr->LoadCursorImage = SavageLoadCursorImage; 142 infoPtr->HideCursor = SavageHideCursor; 143 infoPtr->ShowCursor = SavageShowCursor; 144 infoPtr->UseHWCursor = NULL; 145#if 0 /*AGD: HW cursor seems to work fine even with expansion... */ 146 if ((S3_SAVAGE_MOBILE_SERIES(psav->Chipset) 147 || (S3_MOBILE_TWISTER_SERIES(psav->Chipset))) && !psav->CrtOnly) 148 infoPtr->UseHWCursor = SavageUseHWCursor; 149 else 150 infoPtr->UseHWCursor = NULL; 151#endif 152 if( !psav->CursorKByte ) 153 psav->CursorKByte = pScrn->videoRam - 4; 154 155 return xf86InitCursor(pScreen, infoPtr); 156} 157 158void 159SavageShowCursor(ScrnInfoPtr pScrn) 160{ 161 SavagePtr psav = SAVPTR(pScrn); 162 163 /* Turn cursor on. */ 164 if (psav->IsSecondary) { 165 SelectIGA2(); 166 outCRReg( 0x45, inCRReg(0x45) | 0x01 ); 167 SelectIGA1(); 168 } else { 169 outCRReg( 0x45, inCRReg(0x45) | 0x01 ); 170 } 171 SAVPTR(pScrn)->hwc_on = TRUE; 172} 173 174 175void 176SavageHideCursor(ScrnInfoPtr pScrn) 177{ 178 SavagePtr psav = SAVPTR(pScrn); 179 180 /* Turn cursor off. */ 181 182 if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) ) 183 { 184 waitHSync(5); 185 } 186 if (psav->IsSecondary) { 187 SelectIGA2(); 188 outCRReg( 0x45, inCRReg(0x45) & 0xfe ); /* cursor2 */ 189 SelectIGA1(); 190 } else { 191 outCRReg( 0x45, inCRReg(0x45) & 0xfe ); 192 } 193 SAVPTR(pScrn)->hwc_on = FALSE; 194} 195 196static void 197SavageLoadCursorImage( 198 ScrnInfoPtr pScrn, 199 unsigned char* src) 200{ 201 SavagePtr psav = SAVPTR(pScrn); 202 203 /* Set cursor location in frame buffer. */ 204 if (psav->IsSecondary) { 205 SelectIGA2(); 206 /* Set cursor location in frame buffer. */ 207 outCRReg( 0x4d, (0xff & psav->CursorKByte)); 208 outCRReg( 0x4c, (0xff00 & psav->CursorKByte) >> 8); 209 SelectIGA1(); 210 } else { 211 outCRReg( 0x4d, (0xff & (CARD32)psav->CursorKByte)); 212 outCRReg( 0x4c, (0xff00 & (CARD32)psav->CursorKByte) >> 8); 213 } 214 215 /* Upload the cursor image to the frame buffer. */ 216 memcpy(psav->FBBase + psav->CursorKByte * 1024, src, 1024); 217 218 if( S3_SAVAGE4_SERIES( psav->Chipset ) ) { 219 /* 220 * Bug in Savage4 Rev B requires us to do an MMIO read after 221 * loading the cursor. 222 */ 223 volatile unsigned int i = ALT_STATUS_WORD0; 224 (void)i++; /* Not to be optimised out */ 225 } 226} 227 228static void 229SavageSetCursorPosition( 230 ScrnInfoPtr pScrn, 231 int x, 232 int y) 233{ 234 SavagePtr psav = SAVPTR(pScrn); 235 unsigned char xoff, yoff, byte; 236 237 if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) ) 238 { 239 waitHSync(5); 240 } 241 /* adjust for frame buffer base address granularity */ 242 if (pScrn->bitsPerPixel == 8) 243 x += ((pScrn->frameX0) & 3); 244 else if (pScrn->bitsPerPixel == 16) 245 x += ((pScrn->frameX0) & 1); 246 else if (pScrn->bitsPerPixel == 32) 247 x += ((pScrn->frameX0+2) & 3) - 2; 248 249 /* 250 * Make these even when used. There is a bug/feature on at least 251 * some chipsets that causes a "shadow" of the cursor in interlaced 252 * mode. Making this even seems to have no visible effect, so just 253 * do it for the generic case. 254 */ 255 256 if (x < 0) { 257 xoff = ((-x) & 0xFE); 258 x = 0; 259 } else { 260 xoff = 0; 261 } 262 263 if (y < 0) { 264 yoff = ((-y) & 0xFE); 265 y = 0; 266 } else { 267 yoff = 0; 268 } 269 270 /* This is the recomended order to move the cursor */ 271 if (psav->IsSecondary) { 272 SelectIGA2(); 273 outCRReg( 0x46, (x & 0xff00)>>8 ); 274 outCRReg( 0x47, (x & 0xff) ); 275 outCRReg( 0x49, (y & 0xff) ); 276 outCRReg( 0x4e, xoff ); 277 outCRReg( 0x4f, yoff ); 278 outCRReg( 0x48, (y & 0xff00)>>8 ); 279 SelectIGA1(); 280 } else { 281 outCRReg( 0x46, (x & 0xff00)>>8 ); 282 outCRReg( 0x47, (x & 0xff) ); 283 outCRReg( 0x49, (y & 0xff) ); 284 outCRReg( 0x4e, xoff ); 285 outCRReg( 0x4f, yoff ); 286 outCRReg( 0x48, (y & 0xff00)>>8 ); 287 } 288 289 /* fix for HW cursor on crtc2 */ 290 byte = inCRReg( 0x46 ); 291 outCRReg( 0x46, byte ); 292 293} 294 295 296static void 297SavageSetCursorColors( 298 ScrnInfoPtr pScrn, 299 int bg, 300 int fg) 301{ 302 SavagePtr psav = SAVPTR(pScrn); 303 Bool bNeedExtra = FALSE; 304 305 /* Clock doubled modes need an extra cursor stack write. */ 306 307 bNeedExtra = 308 (psav->CursorInfoRec->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP); 309 310 /* With the streams engine on HW Cursor seems to be 24bpp ALWAYS */ 311 if( 1 312#if 0 313 || S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || 314 (pScrn->depth == 24) || 315 ((pScrn->depth == 8) && bNeedExtra) 316#endif 317 ) 318 { 319 /* Do it straight, full 24 bit color. */ 320 if (psav->IsSecondary) { 321 /* cursor 2 */ 322 /* Reset the cursor color stack pointer */ 323 SelectIGA2(); 324 inCRReg(0x45); 325 /* Write low, mid, high bytes - foreground */ 326 outCRReg(0x4a, fg); 327 outCRReg(0x4a, fg >> 8); 328 outCRReg(0x4a, fg >> 16); 329 /* Reset the cursor color stack pointer */ 330 inCRReg(0x45); 331 /* Write low, mid, high bytes - background */ 332 outCRReg(0x4b, bg); 333 outCRReg(0x4b, bg >> 8); 334 outCRReg(0x4b, bg >> 16); 335 SelectIGA1(); 336 } else { 337 /* Reset the cursor color stack pointer */ 338 inCRReg(0x45); 339 /* Write low, mid, high bytes - foreground */ 340 outCRReg(0x4a, fg); 341 outCRReg(0x4a, fg >> 8); 342 outCRReg(0x4a, fg >> 16); 343 /* Reset the cursor color stack pointer */ 344 inCRReg(0x45); 345 /* Write low, mid, high bytes - background */ 346 outCRReg(0x4b, bg); 347 outCRReg(0x4b, bg >> 8); 348 outCRReg(0x4b, bg >> 16); 349 } 350 return; 351 } 352#if 0 353 else if( (pScrn->depth == 15) || (pScrn->depth == 16) ) 354 { 355 if (pScrn->depth == 15) { 356 fg = ((fg & 0xf80000) >> 9) | 357 ((fg & 0xf800) >> 6) | 358 ((fg & 0xf8) >> 3); 359 bg = ((bg & 0xf80000) >> 9) | 360 ((bg & 0xf800) >> 6) | 361 ((bg & 0xf8) >> 3); 362 } else { 363 fg = ((fg & 0xf80000) >> 8) | 364 ((fg & 0xfc00) >> 5) | 365 ((fg & 0xf8) >> 3); 366 bg = ((bg & 0xf80000) >> 8) | 367 ((bg & 0xfc00) >> 5) | 368 ((bg & 0xf8) >> 3); 369 } 370 /* Reset the cursor color stack pointer */ 371 inCRReg( 0x45 ); 372 outCRReg( 0x4a, fg ); 373 outCRReg( 0x4a, fg>>8 ); 374 if( bNeedExtra ) 375 { 376 outCRReg( 0x4a, fg ); 377 outCRReg( 0x4a, fg>>8 ); 378 } 379 /* Reset the cursor color stack pointer */ 380 inCRReg( 0x45 ); 381 outCRReg( 0x4b, bg ); 382 outCRReg( 0x4b, bg>>8 ); 383 if( bNeedExtra ) 384 { 385 outCRReg( 0x4b, bg ); 386 outCRReg( 0x4b, bg>>8 ); 387 } 388 } 389 else if( pScrn->depth == 8 ) 390 { 391 /* Reset the cursor color stack pointer */ 392 inCRReg(0x45); 393 /* Write foreground */ 394 outCRReg(0x4a, fg); 395 outCRReg(0x4a, fg); 396 /* Reset the cursor color stack pointer */ 397 inCRReg(0x45); 398 /* Write background */ 399 outCRReg(0x4b, bg); 400 outCRReg(0x4b, bg); 401 } 402#endif 403} 404