1/* 2 * Copyright (c) 2007 NVIDIA, Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included 13 * in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include "config.h" 26#endif 27 28#include "nv_include.h" 29 30static int 31NVDACPanelTweaks(NVPtr pNv, NVRegPtr state) 32{ 33 int tweak = 0; 34 35 if(pNv->usePanelTweak) { 36 tweak = pNv->PanelTweak; 37 } else { 38 /* begin flat panel hacks */ 39 /* This is unfortunate, but some chips need this register 40 tweaked or else you get artifacts where adjacent pixels are 41 swapped. There are no hard rules for what to set here so all 42 we can do is experiment and apply hacks. */ 43 44 if(((pNv->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) { 45#ifdef XSERVER_LIBPCIACCESS 46 if (((pNv->PciInfo->subvendor_id & 0xffff) == 0x1179) && 47 ((pNv->PciInfo->subdevice_id & 0xffff) == 0x0020)) 48#else 49 if (((pNv->PciInfo->subsysVendor & 0xffff) == 0x1179) && 50 ((pNv->PciInfo->subsysCard & 0xffff) == 0x0020)) 51#endif 52 { 53 54 /* Toshiba Tecra M2 */ 55 tweak = 1; 56 } else { 57 /* At least one NV34 laptop needs this workaround. */ 58 tweak = -1; 59 } 60 } 61 62 if((pNv->Chipset & 0xfff0) == 0x0310) { 63 tweak = 1; 64 } 65 /* end flat panel hacks */ 66 } 67 68 return tweak; 69} 70 71Bool 72NVDACInit(ScrnInfoPtr pScrn, DisplayModePtr mode) 73{ 74 int i; 75 int horizDisplay = (mode->CrtcHDisplay/8) - 1; 76 int horizStart = (mode->CrtcHSyncStart/8) - 1; 77 int horizEnd = (mode->CrtcHSyncEnd/8) - 1; 78 int horizTotal = (mode->CrtcHTotal/8) - 5; 79 int horizBlankStart = (mode->CrtcHDisplay/8) - 1; 80 int horizBlankEnd = (mode->CrtcHTotal/8) - 1; 81 int vertDisplay = mode->CrtcVDisplay - 1; 82 int vertStart = mode->CrtcVSyncStart - 1; 83 int vertEnd = mode->CrtcVSyncEnd - 1; 84 int vertTotal = mode->CrtcVTotal - 2; 85 int vertBlankStart = mode->CrtcVDisplay - 1; 86 int vertBlankEnd = mode->CrtcVTotal - 1; 87 88 NVPtr pNv = NVPTR(pScrn); 89 NVRegPtr nvReg = &pNv->ModeReg; 90 NVFBLayout *pLayout = &pNv->CurrentLayout; 91 vgaRegPtr pVga; 92 93 /* 94 * Initialize all of the generic VGA registers. Don't bother with 95 * VGA_FIX_SYNC_PULSES, given the relevant CRTC settings are overridden 96 * below. Ditto for the KGA workaround. 97 */ 98 if (!vgaHWInit(pScrn, mode)) 99 return(FALSE); 100 101 pVga = &VGAHWPTR(pScrn)->ModeReg; 102 103 /* 104 * Set all CRTC values. 105 */ 106 107 if(mode->Flags & V_INTERLACE) 108 vertTotal |= 1; 109 110 if(pNv->FlatPanel == 1) { 111 vertStart = vertTotal - 3; 112 vertEnd = vertTotal - 2; 113 vertBlankStart = vertStart; 114 horizStart = horizTotal - 5; 115 horizEnd = horizTotal - 2; 116 horizBlankEnd = horizTotal + 4; 117 if(pNv->Architecture == NV_ARCH_30) 118 horizTotal += 2; 119 } 120 121 pVga->CRTC[0x0] = NV_Set8Bits(horizTotal); 122 pVga->CRTC[0x1] = NV_Set8Bits(horizDisplay); 123 pVga->CRTC[0x2] = NV_Set8Bits(horizBlankStart); 124 pVga->CRTC[0x3] = NV_SetBitField(horizBlankEnd,4:0,4:0) 125 | NV_SetBit(7); 126 pVga->CRTC[0x4] = NV_Set8Bits(horizStart); 127 pVga->CRTC[0x5] = NV_SetBitField(horizBlankEnd,5:5,7:7) 128 | NV_SetBitField(horizEnd,4:0,4:0); 129 pVga->CRTC[0x6] = NV_SetBitField(vertTotal,7:0,7:0); 130 pVga->CRTC[0x7] = NV_SetBitField(vertTotal,8:8,0:0) 131 | NV_SetBitField(vertDisplay,8:8,1:1) 132 | NV_SetBitField(vertStart,8:8,2:2) 133 | NV_SetBitField(vertBlankStart,8:8,3:3) 134 | NV_SetBit(4) 135 | NV_SetBitField(vertTotal,9:9,5:5) 136 | NV_SetBitField(vertDisplay,9:9,6:6) 137 | NV_SetBitField(vertStart,9:9,7:7); 138 pVga->CRTC[0x9] = NV_SetBitField(vertBlankStart,9:9,5:5) 139 | NV_SetBit(6) 140 | ((mode->Flags & V_DBLSCAN) ? 0x80 : 0x00); 141 pVga->CRTC[0x10] = NV_Set8Bits(vertStart); 142 pVga->CRTC[0x11] = NV_SetBitField(vertEnd,3:0,3:0) | NV_SetBit(5); 143 pVga->CRTC[0x12] = NV_Set8Bits(vertDisplay); 144 pVga->CRTC[0x13] = ((pLayout->displayWidth/8)*(pLayout->bitsPerPixel/8)); 145 pVga->CRTC[0x15] = NV_Set8Bits(vertBlankStart); 146 pVga->CRTC[0x16] = NV_Set8Bits(vertBlankEnd); 147 148 pVga->Attribute[0x10] = 0x01; 149 150 if(pNv->Television) 151 pVga->Attribute[0x11] = 0x00; 152 153 nvReg->screen = NV_SetBitField(horizBlankEnd,6:6,4:4) 154 | NV_SetBitField(vertBlankStart,10:10,3:3) 155 | NV_SetBitField(vertStart,10:10,2:2) 156 | NV_SetBitField(vertDisplay,10:10,1:1) 157 | NV_SetBitField(vertTotal,10:10,0:0); 158 159 nvReg->horiz = NV_SetBitField(horizTotal,8:8,0:0) 160 | NV_SetBitField(horizDisplay,8:8,1:1) 161 | NV_SetBitField(horizBlankStart,8:8,2:2) 162 | NV_SetBitField(horizStart,8:8,3:3); 163 164 nvReg->extra = NV_SetBitField(vertTotal,11:11,0:0) 165 | NV_SetBitField(vertDisplay,11:11,2:2) 166 | NV_SetBitField(vertStart,11:11,4:4) 167 | NV_SetBitField(vertBlankStart,11:11,6:6); 168 169 if(mode->Flags & V_INTERLACE) { 170 horizTotal = (horizTotal >> 1) & ~1; 171 nvReg->interlace = NV_Set8Bits(horizTotal); 172 nvReg->horiz |= NV_SetBitField(horizTotal,8:8,4:4); 173 } else { 174 nvReg->interlace = 0xff; /* interlace off */ 175 } 176 177 178 /* 179 * Initialize DAC palette. 180 */ 181 if(pLayout->bitsPerPixel != 8 ) 182 { 183 for (i = 0; i < 256; i++) 184 { 185 pVga->DAC[i*3] = i; 186 pVga->DAC[(i*3)+1] = i; 187 pVga->DAC[(i*3)+2] = i; 188 } 189 } 190 191 /* 192 * Calculate the extended registers. 193 */ 194 195 if(pLayout->depth < 24) 196 i = pLayout->depth; 197 else i = 32; 198 199 if(pNv->Architecture >= NV_ARCH_10) 200 pNv->CURSOR = (U032 *)(pNv->FbStart + pNv->CursorStart); 201 202 NVCalcStateExt(pNv, 203 nvReg, 204 i, 205 pLayout->displayWidth, 206 mode->CrtcHDisplay, 207 pScrn->virtualY, 208 mode->Clock, 209 mode->Flags); 210 211 nvReg->scale = pNv->PRAMDAC[0x00000848/4] & 0xfff000ff; 212 if(pNv->FlatPanel == 1) { 213 nvReg->pixel |= (1 << 7); 214 if(!pNv->fpScaler || (pNv->fpWidth <= mode->HDisplay) 215 || (pNv->fpHeight <= mode->VDisplay)) 216 { 217 nvReg->scale |= (1 << 8) ; 218 } 219 nvReg->crtcSync = pNv->PRAMDAC[0x0828/4]; 220 nvReg->crtcSync += NVDACPanelTweaks(pNv, nvReg); 221 nvReg->crtcVSync = pNv->fpVTotal - 6; 222 } 223 224 nvReg->vpll = nvReg->pll; 225 nvReg->vpll2 = nvReg->pll; 226 nvReg->vpllB = nvReg->pllB; 227 nvReg->vpll2B = nvReg->pllB; 228 229 VGA_WR08(pNv->PCIO, 0x03D4, 0x1C); 230 nvReg->fifo = VGA_RD08(pNv->PCIO, 0x03D5) & ~(1<<5); 231 232 if(pNv->CRTCnumber) { 233 nvReg->head = pNv->PCRTC0[0x00000860/4] & ~0x00001000; 234 nvReg->head2 = pNv->PCRTC0[0x00002860/4] | 0x00001000; 235 nvReg->crtcOwner = 3; 236 nvReg->pllsel |= 0x20000800; 237 nvReg->vpll = pNv->PRAMDAC0[0x0508/4]; 238 if(pNv->twoStagePLL) 239 nvReg->vpllB = pNv->PRAMDAC0[0x0578/4]; 240 } else 241 if(pNv->twoHeads) { 242 nvReg->head = pNv->PCRTC0[0x00000860/4] | 0x00001000; 243 nvReg->head2 = pNv->PCRTC0[0x00002860/4] & ~0x00001000; 244 nvReg->crtcOwner = 0; 245 nvReg->vpll2 = pNv->PRAMDAC0[0x0520/4]; 246 if(pNv->twoStagePLL) 247 nvReg->vpll2B = pNv->PRAMDAC0[0x057C/4]; 248 } 249 250 nvReg->cursorConfig = 0x00000100; 251 if(mode->Flags & V_DBLSCAN) 252 nvReg->cursorConfig |= (1 << 4); 253 if(pNv->alphaCursor) { 254 if((pNv->Chipset & 0x0ff0) != 0x0110) 255 nvReg->cursorConfig |= 0x04011000; 256 else 257 nvReg->cursorConfig |= 0x14011000; 258 nvReg->general |= (1 << 29); 259 } else 260 nvReg->cursorConfig |= 0x02000000; 261 262 if(pNv->twoHeads) { 263 if((pNv->Chipset & 0x0ff0) == 0x0110) { 264 nvReg->dither = pNv->PRAMDAC[0x0528/4] & ~0x00010000; 265 if(pNv->FPDither) 266 nvReg->dither |= 0x00010000; 267 } else { 268 nvReg->dither = pNv->PRAMDAC[0x083C/4] & ~1; 269 if(pNv->FPDither) 270 nvReg->dither |= 1; 271 } 272 } 273 274 nvReg->timingH = 0; 275 nvReg->timingV = 0; 276 nvReg->displayV = mode->CrtcVDisplay; 277 278 return (TRUE); 279} 280 281void 282NVDACRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg, 283 Bool primary) 284{ 285 NVPtr pNv = NVPTR(pScrn); 286 int restore = VGA_SR_MODE; 287 288 if(primary) restore |= VGA_SR_CMAP | VGA_SR_FONTS; 289 NVLoadStateExt(pNv, nvReg); 290#if defined(__powerpc__) 291 restore &= ~VGA_SR_FONTS; 292#endif 293 vgaHWRestore(pScrn, vgaReg, restore); 294} 295 296/* 297 * NVDACSave 298 * 299 * This function saves the video state. 300 */ 301void 302NVDACSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg, 303 Bool saveFonts) 304{ 305 NVPtr pNv = NVPTR(pScrn); 306 307#if defined(__powerpc__) 308 saveFonts = FALSE; 309#endif 310 311 vgaHWSave(pScrn, vgaReg, VGA_SR_CMAP | VGA_SR_MODE | 312 (saveFonts? VGA_SR_FONTS : 0)); 313 NVUnloadStateExt(pNv, nvReg); 314 315 /* can't read this reliably on NV11 */ 316 if((pNv->Chipset & 0x0ff0) == 0x0110) 317 nvReg->crtcOwner = pNv->CRTCnumber; 318} 319 320#define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8))) 321#define MAKE_INDEX(in, w) (DEPTH_SHIFT(in, w) * 3) 322 323void 324NVDACLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, 325 VisualPtr pVisual ) 326{ 327 int i, index; 328 NVPtr pNv = NVPTR(pScrn); 329 vgaRegPtr pVga; 330 331 pVga = &VGAHWPTR(pScrn)->ModeReg; 332 333 switch(pNv->CurrentLayout.depth) { 334 case 15: 335 for(i = 0; i < numColors; i++) { 336 index = indices[i]; 337 pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red; 338 pVga->DAC[MAKE_INDEX(index, 5) + 1] = colors[index].green; 339 pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue; 340 } 341 break; 342 case 16: 343 for(i = 0; i < numColors; i++) { 344 index = indices[i]; 345 pVga->DAC[MAKE_INDEX(index, 6) + 1] = colors[index].green; 346 if(index < 32) { 347 pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red; 348 pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue; 349 } 350 } 351 break; 352 default: 353 for(i = 0; i < numColors; i++) { 354 index = indices[i]; 355 pVga->DAC[index*3] = colors[index].red; 356 pVga->DAC[(index*3)+1] = colors[index].green; 357 pVga->DAC[(index*3)+2] = colors[index].blue; 358 } 359 break; 360 } 361 vgaHWRestore(pScrn, pVga, VGA_SR_CMAP); 362} 363 364/* 365 * DDC1 support only requires DDC_SDA_MASK, 366 * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK 367 */ 368#define DDC_SDA_READ_MASK (1 << 3) 369#define DDC_SCL_READ_MASK (1 << 2) 370#define DDC_SDA_WRITE_MASK (1 << 4) 371#define DDC_SCL_WRITE_MASK (1 << 5) 372 373static void 374NV_I2CGetBits(I2CBusPtr b, int *clock, int *data) 375{ 376#ifdef XF86_SCRN_INTERFACE 377 NVPtr pNv = NVPTR(b->pScrn); 378#else 379 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]); 380#endif 381 unsigned char val; 382 383 /* Get the result. */ 384 VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase); 385 val = VGA_RD08(pNv->PCIO, 0x3d5); 386 387 *clock = (val & DDC_SCL_READ_MASK) != 0; 388 *data = (val & DDC_SDA_READ_MASK) != 0; 389} 390 391static void 392NV_I2CPutBits(I2CBusPtr b, int clock, int data) 393{ 394#ifdef XF86_SCRN_INTERFACE 395 NVPtr pNv = NVPTR(b->pScrn); 396#else 397 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]); 398#endif 399 unsigned char val; 400 401 VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1); 402 val = VGA_RD08(pNv->PCIO, 0x3d5) & 0xf0; 403 if (clock) 404 val |= DDC_SCL_WRITE_MASK; 405 else 406 val &= ~DDC_SCL_WRITE_MASK; 407 408 if (data) 409 val |= DDC_SDA_WRITE_MASK; 410 else 411 val &= ~DDC_SDA_WRITE_MASK; 412 413 VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1); 414 VGA_WR08(pNv->PCIO, 0x3d5, val | 0x1); 415} 416 417Bool 418NVDACi2cInit(ScrnInfoPtr pScrn) 419{ 420 NVPtr pNv = NVPTR(pScrn); 421 I2CBusPtr I2CPtr; 422 423 I2CPtr = xf86CreateI2CBusRec(); 424 if(!I2CPtr) return FALSE; 425 426 pNv->I2C = I2CPtr; 427 428 I2CPtr->BusName = "DDC"; 429 I2CPtr->scrnIndex = pScrn->scrnIndex; 430#ifdef XF86_SCRN_INTERFACE 431 I2CPtr->pScrn = pScrn; 432#endif 433 I2CPtr->I2CPutBits = NV_I2CPutBits; 434 I2CPtr->I2CGetBits = NV_I2CGetBits; 435 I2CPtr->AcknTimeout = 5; 436 437 if (!xf86I2CBusInit(I2CPtr)) { 438 return FALSE; 439 } 440 return TRUE; 441} 442