| 1 | |
| 2 | |* *|
|
| 3 | |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
|
| 4 | |* *|
|
| 5 | |* NOTICE TO USER: The source code is copyrighted under U.S. and *|
|
| 6 | |* international laws. Users and possessors of this source code are *|
|
| 7 | |* hereby granted a nonexclusive, royalty-free copyright license to *|
|
| 8 | |* use this code in individual and commercial software. *|
|
| 9 | |* *|
|
| 10 | |* Any use of this source code must include, in the user documenta- *|
|
| 11 | |* tion and internal comments to the code, notices to the end user *|
|
| 12 | |* as follows: *|
|
| 13 | |* *|
|
| 14 | |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
|
| 15 | |* *|
|
| 16 | |* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
|
| 17 | |* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
|
| 18 | |* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
|
| 19 | |* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
|
| 20 | |* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
|
| 21 | |* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
|
| 22 | |* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
|
| 23 | |* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
|
| 24 | |* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
|
| 25 | |* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
|
| 26 | |* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
|
| 27 | |* *|
|
| 28 | |* U.S. Government End Users. This source code is a "commercial *|
|
| 29 | |* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
|
| 30 | |* consisting of "commercial computer software" and "commercial *|
|
| 31 | |* computer software documentation," as such terms are used in *|
|
| 32 | |* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
|
| 33 | |* ment only as a commercial end item. Consistent with 48 C.F.R. *|
|
| 34 | |* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
|
| 35 | |* all U.S. Government End Users acquire the source code with only *|
|
| 36 | |* those rights set forth herein. *|
|
| 37 | |* *|
|
| 38 | \**************************************************************************
|
| 39 |
|
| 40 | |
| 41 | * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
|
| 42 | * XFree86 'nv' driver, this source code is provided under MIT-style licensing
|
| 43 | * where the source code is provided "as is" without warranty of any kind.
|
| 44 | * The only usage restriction is for the copyright notices to be retained
|
| 45 | * whenever code is used.
|
| 46 | *
|
| 47 | * Antonino Daplas <[email protected]> 2005-03-11
|
| 48 |
|
| 49 |
|
| 50 | #include <video/vga.h>
|
| 51 | #include <linux/delay.h>
|
| 52 | #include <linux/pci.h>
|
| 53 | #include <linux/slab.h>
|
| 54 | #include "nv_type.h"
|
| 55 | #include "nv_local.h"
|
| 56 | #include "nv_proto.h"
|
| 57 | |
| 58 | * Override VGA I/O routines.
|
| 59 |
|
| 60 | void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)
|
| 61 | {
|
| 62 | VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
|
| 63 | VGA_WR08(par->PCIO, par->IOBase + 0x05, value);
|
| 64 | }
|
| 65 | u8 NVReadCrtc(struct nvidia_par *par, u8 index)
|
| 66 | {
|
| 67 | VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
|
| 68 | return (VGA_RD08(par->PCIO, par->IOBase + 0x05));
|
| 69 | }
|
| 70 | void NVWriteGr(struct nvidia_par *par, u8 index, u8 value)
|
| 71 | {
|
| 72 | VGA_WR08(par->PVIO, VGA_GFX_I, index);
|
| 73 | VGA_WR08(par->PVIO, VGA_GFX_D, value);
|
| 74 | }
|
| 75 | u8 NVReadGr(struct nvidia_par *par, u8 index)
|
| 76 | {
|
| 77 | VGA_WR08(par->PVIO, VGA_GFX_I, index);
|
| 78 | return (VGA_RD08(par->PVIO, VGA_GFX_D));
|
| 79 | }
|
| 80 | void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)
|
| 81 | {
|
| 82 | VGA_WR08(par->PVIO, VGA_SEQ_I, index);
|
| 83 | VGA_WR08(par->PVIO, VGA_SEQ_D, value);
|
| 84 | }
|
| 85 | u8 NVReadSeq(struct nvidia_par *par, u8 index)
|
| 86 | {
|
| 87 | VGA_WR08(par->PVIO, VGA_SEQ_I, index);
|
| 88 | return (VGA_RD08(par->PVIO, VGA_SEQ_D));
|
| 89 | }
|
| 90 | void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)
|
| 91 | {
|
| 92 |
|
| 93 | VGA_RD08(par->PCIO, par->IOBase + 0x0a);
|
| 94 | if (par->paletteEnabled)
|
| 95 | index &= ~0x20;
|
| 96 | else
|
| 97 | index |= 0x20;
|
| 98 | VGA_WR08(par->PCIO, VGA_ATT_IW, index);
|
| 99 | VGA_WR08(par->PCIO, VGA_ATT_W, value);
|
| 100 | }
|
| 101 | u8 NVReadAttr(struct nvidia_par *par, u8 index)
|
| 102 | {
|
| 103 | VGA_RD08(par->PCIO, par->IOBase + 0x0a);
|
| 104 | if (par->paletteEnabled)
|
| 105 | index &= ~0x20;
|
| 106 | else
|
| 107 | index |= 0x20;
|
| 108 | VGA_WR08(par->PCIO, VGA_ATT_IW, index);
|
| 109 | return (VGA_RD08(par->PCIO, VGA_ATT_R));
|
| 110 | }
|
| 111 | void NVWriteMiscOut(struct nvidia_par *par, u8 value)
|
| 112 | {
|
| 113 | VGA_WR08(par->PVIO, VGA_MIS_W, value);
|
| 114 | }
|
| 115 | u8 NVReadMiscOut(struct nvidia_par *par)
|
| 116 | {
|
| 117 | return (VGA_RD08(par->PVIO, VGA_MIS_R));
|
| 118 | }
|
| 119 | void NVWriteDacMask(struct nvidia_par *par, u8 value)
|
| 120 | {
|
| 121 | VGA_WR08(par->PDIO, VGA_PEL_MSK, value);
|
| 122 | }
|
| 123 | void NVWriteDacReadAddr(struct nvidia_par *par, u8 value)
|
| 124 | {
|
| 125 | VGA_WR08(par->PDIO, VGA_PEL_IR, value);
|
| 126 | }
|
| 127 | void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)
|
| 128 | {
|
| 129 | VGA_WR08(par->PDIO, VGA_PEL_IW, value);
|
| 130 | }
|
| 131 | void NVWriteDacData(struct nvidia_par *par, u8 value)
|
| 132 | {
|
| 133 | VGA_WR08(par->PDIO, VGA_PEL_D, value);
|
| 134 | }
|
| 135 | u8 NVReadDacData(struct nvidia_par *par)
|
| 136 | {
|
| 137 | return (VGA_RD08(par->PDIO, VGA_PEL_D));
|
| 138 | }
|
| 139 |
|
| 140 | static int NVIsConnected(struct nvidia_par *par, int output)
|
| 141 | {
|
| 142 | volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
|
| 143 | u32 reg52C, reg608, dac0_reg608 = 0;
|
| 144 | int present;
|
| 145 |
|
| 146 | if (output) {
|
| 147 | dac0_reg608 = NV_RD32(PRAMDAC, 0x0608);
|
| 148 | PRAMDAC += 0x800;
|
| 149 | }
|
| 150 |
|
| 151 | reg52C = NV_RD32(PRAMDAC, 0x052C);
|
| 152 | reg608 = NV_RD32(PRAMDAC, 0x0608);
|
| 153 |
|
| 154 | NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
|
| 155 |
|
| 156 | NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
|
| 157 | msleep(1);
|
| 158 | NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
|
| 159 |
|
| 160 | NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);
|
| 161 | NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |
|
| 162 | 0x00001000);
|
| 163 |
|
| 164 | msleep(1);
|
| 165 |
|
| 166 | present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
|
| 167 |
|
| 168 | if (present)
|
| 169 | printk("nvidiafb: CRTC%i analog found\n", output);
|
| 170 | else
|
| 171 | printk("nvidiafb: CRTC%i analog not found\n", output);
|
| 172 |
|
| 173 | if (output)
|
| 174 | NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608);
|
| 175 |
|
| 176 | NV_WR32(PRAMDAC, 0x052C, reg52C);
|
| 177 | NV_WR32(PRAMDAC, 0x0608, reg608);
|
| 178 |
|
| 179 | return present;
|
| 180 | }
|
| 181 |
|
| 182 | static void NVSelectHeadRegisters(struct nvidia_par *par, int head)
|
| 183 | {
|
| 184 | if (head) {
|
| 185 | par->PCIO = par->PCIO0 + 0x2000;
|
| 186 | par->PCRTC = par->PCRTC0 + 0x800;
|
| 187 | par->PRAMDAC = par->PRAMDAC0 + 0x800;
|
| 188 | par->PDIO = par->PDIO0 + 0x2000;
|
| 189 | } else {
|
| 190 | par->PCIO = par->PCIO0;
|
| 191 | par->PCRTC = par->PCRTC0;
|
| 192 | par->PRAMDAC = par->PRAMDAC0;
|
| 193 | par->PDIO = par->PDIO0;
|
| 194 | }
|
| 195 | }
|
| 196 |
|
| 197 | static void nv4GetConfig(struct nvidia_par *par)
|
| 198 | {
|
| 199 | if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {
|
| 200 | par->RamAmountKBytes =
|
| 201 | ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +
|
| 202 | 1024 * 2;
|
| 203 | } else {
|
| 204 | switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {
|
| 205 | case 0:
|
| 206 | par->RamAmountKBytes = 1024 * 32;
|
| 207 | break;
|
| 208 | case 1:
|
| 209 | par->RamAmountKBytes = 1024 * 4;
|
| 210 | break;
|
| 211 | case 2:
|
| 212 | par->RamAmountKBytes = 1024 * 8;
|
| 213 | break;
|
| 214 | case 3:
|
| 215 | default:
|
| 216 | par->RamAmountKBytes = 1024 * 16;
|
| 217 | break;
|
| 218 | }
|
| 219 | }
|
| 220 | par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?
|
| 221 | 14318 : 13500;
|
| 222 | par->CURSOR = &par->PRAMIN[0x1E00];
|
| 223 | par->MinVClockFreqKHz = 12000;
|
| 224 | par->MaxVClockFreqKHz = 350000;
|
| 225 | }
|
| 226 |
|
| 227 | static void nv10GetConfig(struct nvidia_par *par)
|
| 228 | {
|
| 229 | struct pci_dev *dev;
|
| 230 | u32 implementation = par->Chipset & 0x0ff0;
|
| 231 |
|
| 232 | #ifdef __BIG_ENDIAN
|
| 233 |
|
| 234 | if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {
|
| 235 | NV_WR32(par->PMC, 0x0004, 0x01000001);
|
| 236 | mb();
|
| 237 | }
|
| 238 | #endif
|
| 239 |
|
| 240 | dev = pci_get_domain_bus_and_slot(pci_domain_nr(par->pci_dev->bus),
|
| 241 | 0, 1);
|
| 242 | if ((par->Chipset & 0xffff) == 0x01a0) {
|
| 243 | u32 amt;
|
| 244 |
|
| 245 | pci_read_config_dword(dev, 0x7c, &amt);
|
| 246 | par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
|
| 247 | } else if ((par->Chipset & 0xffff) == 0x01f0) {
|
| 248 | u32 amt;
|
| 249 |
|
| 250 | pci_read_config_dword(dev, 0x84, &amt);
|
| 251 | par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
|
| 252 | } else {
|
| 253 | par->RamAmountKBytes =
|
| 254 | (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
|
| 255 | }
|
| 256 | pci_dev_put(dev);
|
| 257 |
|
| 258 | par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
|
| 259 | 14318 : 13500;
|
| 260 |
|
| 261 | if (par->twoHeads && (implementation != 0x0110)) {
|
| 262 | if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))
|
| 263 | par->CrystalFreqKHz = 27000;
|
| 264 | }
|
| 265 |
|
| 266 | par->CURSOR = NULL;
|
| 267 | par->MinVClockFreqKHz = 12000;
|
| 268 | par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;
|
| 269 | }
|
| 270 |
|
| 271 | int NVCommonSetup(struct fb_info *info)
|
| 272 | {
|
| 273 | struct nvidia_par *par = info->par;
|
| 274 | struct fb_var_screeninfo *var;
|
| 275 | u16 implementation = par->Chipset & 0x0ff0;
|
| 276 | u8 *edidA = NULL, *edidB = NULL;
|
| 277 | struct fb_monspecs *monitorA, *monitorB;
|
| 278 | struct fb_monspecs *monA = NULL, *monB = NULL;
|
| 279 | int mobile = 0;
|
| 280 | int tvA = 0;
|
| 281 | int tvB = 0;
|
| 282 | int FlatPanel = -1;
|
| 283 | int Television = 0;
|
| 284 | int err = 0;
|
| 285 |
|
| 286 | var = kzalloc_obj(struct fb_var_screeninfo);
|
| 287 | monitorA = kzalloc_obj(struct fb_monspecs);
|
| 288 | monitorB = kzalloc_obj(struct fb_monspecs);
|
| 289 |
|
| 290 | if (!var || !monitorA || !monitorB) {
|
| 291 | err = -ENOMEM;
|
| 292 | goto done;
|
| 293 | }
|
| 294 |
|
| 295 | par->PRAMIN = par->REGS + (0x00710000 / 4);
|
| 296 | par->PCRTC0 = par->REGS + (0x00600000 / 4);
|
| 297 | par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
|
| 298 | par->PFB = par->REGS + (0x00100000 / 4);
|
| 299 | par->PFIFO = par->REGS + (0x00002000 / 4);
|
| 300 | par->PGRAPH = par->REGS + (0x00400000 / 4);
|
| 301 | par->PEXTDEV = par->REGS + (0x00101000 / 4);
|
| 302 | par->PTIMER = par->REGS + (0x00009000 / 4);
|
| 303 | par->PMC = par->REGS + (0x00000000 / 4);
|
| 304 | par->FIFO = par->REGS + (0x00800000 / 4);
|
| 305 |
|
| 306 |
|
| 307 | par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;
|
| 308 | par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;
|
| 309 | par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;
|
| 310 |
|
| 311 | par->twoHeads = (par->Architecture >= NV_ARCH_10) &&
|
| 312 | (implementation != 0x0100) &&
|
| 313 | (implementation != 0x0150) &&
|
| 314 | (implementation != 0x01A0) && (implementation != 0x0200);
|
| 315 |
|
| 316 | par->fpScaler = (par->FpScale && par->twoHeads &&
|
| 317 | (implementation != 0x0110));
|
| 318 |
|
| 319 | par->twoStagePLL = (implementation == 0x0310) ||
|
| 320 | (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);
|
| 321 |
|
| 322 | par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&
|
| 323 | (implementation != 0x0100);
|
| 324 |
|
| 325 | par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);
|
| 326 |
|
| 327 |
|
| 328 | switch (par->Chipset & 0xffff) {
|
| 329 | case 0x0112:
|
| 330 | case 0x0174:
|
| 331 | case 0x0175:
|
| 332 | case 0x0176:
|
| 333 | case 0x0177:
|
| 334 | case 0x0179:
|
| 335 | case 0x017C:
|
| 336 | case 0x017D:
|
| 337 | case 0x0186:
|
| 338 | case 0x0187:
|
| 339 | case 0x018D:
|
| 340 | case 0x01D7:
|
| 341 | case 0x0228:
|
| 342 | case 0x0286:
|
| 343 | case 0x028C:
|
| 344 | case 0x0316:
|
| 345 | case 0x0317:
|
| 346 | case 0x031A:
|
| 347 | case 0x031B:
|
| 348 | case 0x031C:
|
| 349 | case 0x031D:
|
| 350 | case 0x031E:
|
| 351 | case 0x031F:
|
| 352 | case 0x0324:
|
| 353 | case 0x0325:
|
| 354 | case 0x0328:
|
| 355 | case 0x0329:
|
| 356 | case 0x032C:
|
| 357 | case 0x032D:
|
| 358 | case 0x0347:
|
| 359 | case 0x0348:
|
| 360 | case 0x0349:
|
| 361 | case 0x034B:
|
| 362 | case 0x034C:
|
| 363 | case 0x0160:
|
| 364 | case 0x0166:
|
| 365 | case 0x0169:
|
| 366 | case 0x016B:
|
| 367 | case 0x016C:
|
| 368 | case 0x016D:
|
| 369 | case 0x00C8:
|
| 370 | case 0x00CC:
|
| 371 | case 0x0144:
|
| 372 | case 0x0146:
|
| 373 | case 0x0147:
|
| 374 | case 0x0148:
|
| 375 | case 0x0098:
|
| 376 | case 0x0099:
|
| 377 | mobile = 1;
|
| 378 | break;
|
| 379 | default:
|
| 380 | break;
|
| 381 | }
|
| 382 |
|
| 383 | if (par->Architecture == NV_ARCH_04)
|
| 384 | nv4GetConfig(par);
|
| 385 | else
|
| 386 | nv10GetConfig(par);
|
| 387 |
|
| 388 | NVSelectHeadRegisters(par, 0);
|
| 389 |
|
| 390 | NVLockUnlock(par, 0);
|
| 391 |
|
| 392 | par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;
|
| 393 |
|
| 394 | par->Television = 0;
|
| 395 |
|
| 396 | nvidia_create_i2c_busses(par);
|
| 397 | if (!par->twoHeads) {
|
| 398 | par->CRTCnumber = 0;
|
| 399 | if (nvidia_probe_i2c_connector(info, 1, &edidA))
|
| 400 | nvidia_probe_of_connector(info, 1, &edidA);
|
| 401 | if (edidA && !fb_parse_edid(edidA, var)) {
|
| 402 | printk("nvidiafb: EDID found from BUS1\n");
|
| 403 | monA = monitorA;
|
| 404 | fb_edid_to_monspecs(edidA, monA);
|
| 405 | FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
|
| 406 |
|
| 407 |
|
| 408 | if ((par->Chipset & 0x0fff) <= 0x0020)
|
| 409 | FlatPanel = 0;
|
| 410 | } else {
|
| 411 | VGA_WR08(par->PCIO, 0x03D4, 0x28);
|
| 412 | if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {
|
| 413 | VGA_WR08(par->PCIO, 0x03D4, 0x33);
|
| 414 | if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))
|
| 415 | Television = 1;
|
| 416 | FlatPanel = 1;
|
| 417 | } else {
|
| 418 | FlatPanel = 0;
|
| 419 | }
|
| 420 | printk("nvidiafb: HW is currently programmed for %s\n",
|
| 421 | FlatPanel ? (Television ? "TV" : "DFP") :
|
| 422 | "CRT");
|
| 423 | }
|
| 424 |
|
| 425 | if (par->FlatPanel == -1) {
|
| 426 | par->FlatPanel = FlatPanel;
|
| 427 | par->Television = Television;
|
| 428 | } else {
|
| 429 | printk("nvidiafb: Forcing display type to %s as "
|
| 430 | "specified\n", par->FlatPanel ? "DFP" : "CRT");
|
| 431 | }
|
| 432 | } else {
|
| 433 | u8 outputAfromCRTC, outputBfromCRTC;
|
| 434 | int CRTCnumber = -1;
|
| 435 | u8 slaved_on_A, slaved_on_B;
|
| 436 | int analog_on_A, analog_on_B;
|
| 437 | u32 oldhead;
|
| 438 | u8 cr44;
|
| 439 |
|
| 440 | if (implementation != 0x0110) {
|
| 441 | if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)
|
| 442 | outputAfromCRTC = 1;
|
| 443 | else
|
| 444 | outputAfromCRTC = 0;
|
| 445 | if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)
|
| 446 | outputBfromCRTC = 1;
|
| 447 | else
|
| 448 | outputBfromCRTC = 0;
|
| 449 | analog_on_A = NVIsConnected(par, 0);
|
| 450 | analog_on_B = NVIsConnected(par, 1);
|
| 451 | } else {
|
| 452 | outputAfromCRTC = 0;
|
| 453 | outputBfromCRTC = 1;
|
| 454 | analog_on_A = 0;
|
| 455 | analog_on_B = 0;
|
| 456 | }
|
| 457 |
|
| 458 | VGA_WR08(par->PCIO, 0x03D4, 0x44);
|
| 459 | cr44 = VGA_RD08(par->PCIO, 0x03D5);
|
| 460 |
|
| 461 | VGA_WR08(par->PCIO, 0x03D5, 3);
|
| 462 | NVSelectHeadRegisters(par, 1);
|
| 463 | NVLockUnlock(par, 0);
|
| 464 |
|
| 465 | VGA_WR08(par->PCIO, 0x03D4, 0x28);
|
| 466 | slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
|
| 467 | if (slaved_on_B) {
|
| 468 | VGA_WR08(par->PCIO, 0x03D4, 0x33);
|
| 469 | tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
|
| 470 | }
|
| 471 |
|
| 472 | VGA_WR08(par->PCIO, 0x03D4, 0x44);
|
| 473 | VGA_WR08(par->PCIO, 0x03D5, 0);
|
| 474 | NVSelectHeadRegisters(par, 0);
|
| 475 | NVLockUnlock(par, 0);
|
| 476 |
|
| 477 | VGA_WR08(par->PCIO, 0x03D4, 0x28);
|
| 478 | slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
|
| 479 | if (slaved_on_A) {
|
| 480 | VGA_WR08(par->PCIO, 0x03D4, 0x33);
|
| 481 | tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
|
| 482 | }
|
| 483 |
|
| 484 | oldhead = NV_RD32(par->PCRTC0, 0x00000860);
|
| 485 | NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
|
| 486 |
|
| 487 | if (nvidia_probe_i2c_connector(info, 1, &edidA))
|
| 488 | nvidia_probe_of_connector(info, 1, &edidA);
|
| 489 | if (edidA && !fb_parse_edid(edidA, var)) {
|
| 490 | printk("nvidiafb: EDID found from BUS1\n");
|
| 491 | monA = monitorA;
|
| 492 | fb_edid_to_monspecs(edidA, monA);
|
| 493 | }
|
| 494 |
|
| 495 | if (nvidia_probe_i2c_connector(info, 2, &edidB))
|
| 496 | nvidia_probe_of_connector(info, 2, &edidB);
|
| 497 | if (edidB && !fb_parse_edid(edidB, var)) {
|
| 498 | printk("nvidiafb: EDID found from BUS2\n");
|
| 499 | monB = monitorB;
|
| 500 | fb_edid_to_monspecs(edidB, monB);
|
| 501 | }
|
| 502 |
|
| 503 | if (slaved_on_A && !tvA) {
|
| 504 | CRTCnumber = 0;
|
| 505 | FlatPanel = 1;
|
| 506 | printk("nvidiafb: CRTC 0 is currently programmed for "
|
| 507 | "DFP\n");
|
| 508 | } else if (slaved_on_B && !tvB) {
|
| 509 | CRTCnumber = 1;
|
| 510 | FlatPanel = 1;
|
| 511 | printk("nvidiafb: CRTC 1 is currently programmed "
|
| 512 | "for DFP\n");
|
| 513 | } else if (analog_on_A) {
|
| 514 | CRTCnumber = outputAfromCRTC;
|
| 515 | FlatPanel = 0;
|
| 516 | printk("nvidiafb: CRTC %i appears to have a "
|
| 517 | "CRT attached\n", CRTCnumber);
|
| 518 | } else if (analog_on_B) {
|
| 519 | CRTCnumber = outputBfromCRTC;
|
| 520 | FlatPanel = 0;
|
| 521 | printk("nvidiafb: CRTC %i appears to have a "
|
| 522 | "CRT attached\n", CRTCnumber);
|
| 523 | } else if (slaved_on_A) {
|
| 524 | CRTCnumber = 0;
|
| 525 | FlatPanel = 1;
|
| 526 | Television = 1;
|
| 527 | printk("nvidiafb: CRTC 0 is currently programmed "
|
| 528 | "for TV\n");
|
| 529 | } else if (slaved_on_B) {
|
| 530 | CRTCnumber = 1;
|
| 531 | FlatPanel = 1;
|
| 532 | Television = 1;
|
| 533 | printk("nvidiafb: CRTC 1 is currently programmed for "
|
| 534 | "TV\n");
|
| 535 | } else if (monA) {
|
| 536 | FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
|
| 537 | } else if (monB) {
|
| 538 | FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;
|
| 539 | }
|
| 540 |
|
| 541 | if (par->FlatPanel == -1) {
|
| 542 | if (FlatPanel != -1) {
|
| 543 | par->FlatPanel = FlatPanel;
|
| 544 | par->Television = Television;
|
| 545 | } else {
|
| 546 | printk("nvidiafb: Unable to detect display "
|
| 547 | "type...\n");
|
| 548 | if (mobile) {
|
| 549 | printk("...On a laptop, assuming "
|
| 550 | "DFP\n");
|
| 551 | par->FlatPanel = 1;
|
| 552 | } else {
|
| 553 | printk("...Using default of CRT\n");
|
| 554 | par->FlatPanel = 0;
|
| 555 | }
|
| 556 | }
|
| 557 | } else {
|
| 558 | printk("nvidiafb: Forcing display type to %s as "
|
| 559 | "specified\n", par->FlatPanel ? "DFP" : "CRT");
|
| 560 | }
|
| 561 |
|
| 562 | if (par->CRTCnumber == -1) {
|
| 563 | if (CRTCnumber != -1)
|
| 564 | par->CRTCnumber = CRTCnumber;
|
| 565 | else {
|
| 566 | printk("nvidiafb: Unable to detect which "
|
| 567 | "CRTCNumber...\n");
|
| 568 | if (par->FlatPanel)
|
| 569 | par->CRTCnumber = 1;
|
| 570 | else
|
| 571 | par->CRTCnumber = 0;
|
| 572 | printk("...Defaulting to CRTCNumber %i\n",
|
| 573 | par->CRTCnumber);
|
| 574 | }
|
| 575 | } else {
|
| 576 | printk("nvidiafb: Forcing CRTCNumber %i as "
|
| 577 | "specified\n", par->CRTCnumber);
|
| 578 | }
|
| 579 |
|
| 580 | if (monA) {
|
| 581 | if (((monA->input & FB_DISP_DDI) &&
|
| 582 | par->FlatPanel) ||
|
| 583 | ((!(monA->input & FB_DISP_DDI)) &&
|
| 584 | !par->FlatPanel)) {
|
| 585 | if (monB) {
|
| 586 | fb_destroy_modedb(monB->modedb);
|
| 587 | monB = NULL;
|
| 588 | }
|
| 589 | } else {
|
| 590 | fb_destroy_modedb(monA->modedb);
|
| 591 | monA = NULL;
|
| 592 | }
|
| 593 | }
|
| 594 |
|
| 595 | if (monB) {
|
| 596 | if (((monB->input & FB_DISP_DDI) &&
|
| 597 | !par->FlatPanel) ||
|
| 598 | ((!(monB->input & FB_DISP_DDI)) &&
|
| 599 | par->FlatPanel)) {
|
| 600 | fb_destroy_modedb(monB->modedb);
|
| 601 | monB = NULL;
|
| 602 | } else
|
| 603 | monA = monB;
|
| 604 | }
|
| 605 |
|
| 606 | if (implementation == 0x0110)
|
| 607 | cr44 = par->CRTCnumber * 0x3;
|
| 608 |
|
| 609 | NV_WR32(par->PCRTC0, 0x00000860, oldhead);
|
| 610 |
|
| 611 | VGA_WR08(par->PCIO, 0x03D4, 0x44);
|
| 612 | VGA_WR08(par->PCIO, 0x03D5, cr44);
|
| 613 | NVSelectHeadRegisters(par, par->CRTCnumber);
|
| 614 | }
|
| 615 |
|
| 616 | printk("nvidiafb: Using %s on CRTC %i\n",
|
| 617 | par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",
|
| 618 | par->CRTCnumber);
|
| 619 |
|
| 620 | if (par->FlatPanel && !par->Television) {
|
| 621 | par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;
|
| 622 | par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;
|
| 623 | par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;
|
| 624 |
|
| 625 | printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight);
|
| 626 | }
|
| 627 |
|
| 628 | if (monA)
|
| 629 | info->monspecs = *monA;
|
| 630 |
|
| 631 | if (!par->FlatPanel || !par->twoHeads)
|
| 632 | par->FPDither = 0;
|
| 633 |
|
| 634 | par->LVDS = 0;
|
| 635 | if (par->FlatPanel && par->twoHeads) {
|
| 636 | NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);
|
| 637 | if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)
|
| 638 | par->LVDS = 1;
|
| 639 | printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");
|
| 640 | }
|
| 641 |
|
| 642 | kfree(edidA);
|
| 643 | kfree(edidB);
|
| 644 | done:
|
| 645 | kfree(var);
|
| 646 | kfree(monitorA);
|
| 647 | kfree(monitorB);
|
| 648 | return err;
|
| 649 | }
|