linux/drivers/video/nvidia/nv_setup.c
<<
>>
Prefs
   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 <adaplas@pol.net> 2005-03-11
  48 */
  49
  50#include <video/vga.h>
  51#include <linux/delay.h>
  52#include <linux/pci.h>
  53#include "nv_type.h"
  54#include "nv_local.h"
  55#include "nv_proto.h"
  56/*
  57 * Override VGA I/O routines.
  58 */
  59void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)
  60{
  61        VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
  62        VGA_WR08(par->PCIO, par->IOBase + 0x05, value);
  63}
  64u8 NVReadCrtc(struct nvidia_par *par, u8 index)
  65{
  66        VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
  67        return (VGA_RD08(par->PCIO, par->IOBase + 0x05));
  68}
  69void NVWriteGr(struct nvidia_par *par, u8 index, u8 value)
  70{
  71        VGA_WR08(par->PVIO, VGA_GFX_I, index);
  72        VGA_WR08(par->PVIO, VGA_GFX_D, value);
  73}
  74u8 NVReadGr(struct nvidia_par *par, u8 index)
  75{
  76        VGA_WR08(par->PVIO, VGA_GFX_I, index);
  77        return (VGA_RD08(par->PVIO, VGA_GFX_D));
  78}
  79void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)
  80{
  81        VGA_WR08(par->PVIO, VGA_SEQ_I, index);
  82        VGA_WR08(par->PVIO, VGA_SEQ_D, value);
  83}
  84u8 NVReadSeq(struct nvidia_par *par, u8 index)
  85{
  86        VGA_WR08(par->PVIO, VGA_SEQ_I, index);
  87        return (VGA_RD08(par->PVIO, VGA_SEQ_D));
  88}
  89void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)
  90{
  91        volatile u8 tmp;
  92
  93        tmp = 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}
 101u8 NVReadAttr(struct nvidia_par *par, u8 index)
 102{
 103        volatile u8 tmp;
 104
 105        tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
 106        if (par->paletteEnabled)
 107                index &= ~0x20;
 108        else
 109                index |= 0x20;
 110        VGA_WR08(par->PCIO, VGA_ATT_IW, index);
 111        return (VGA_RD08(par->PCIO, VGA_ATT_R));
 112}
 113void NVWriteMiscOut(struct nvidia_par *par, u8 value)
 114{
 115        VGA_WR08(par->PVIO, VGA_MIS_W, value);
 116}
 117u8 NVReadMiscOut(struct nvidia_par *par)
 118{
 119        return (VGA_RD08(par->PVIO, VGA_MIS_R));
 120}
 121#if 0
 122void NVEnablePalette(struct nvidia_par *par)
 123{
 124        volatile u8 tmp;
 125
 126        tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
 127        VGA_WR08(par->PCIO, VGA_ATT_IW, 0x00);
 128        par->paletteEnabled = 1;
 129}
 130void NVDisablePalette(struct nvidia_par *par)
 131{
 132        volatile u8 tmp;
 133
 134        tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
 135        VGA_WR08(par->PCIO, VGA_ATT_IW, 0x20);
 136        par->paletteEnabled = 0;
 137}
 138#endif  /*  0  */
 139void NVWriteDacMask(struct nvidia_par *par, u8 value)
 140{
 141        VGA_WR08(par->PDIO, VGA_PEL_MSK, value);
 142}
 143#if 0
 144u8 NVReadDacMask(struct nvidia_par *par)
 145{
 146        return (VGA_RD08(par->PDIO, VGA_PEL_MSK));
 147}
 148#endif  /*  0  */
 149void NVWriteDacReadAddr(struct nvidia_par *par, u8 value)
 150{
 151        VGA_WR08(par->PDIO, VGA_PEL_IR, value);
 152}
 153void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)
 154{
 155        VGA_WR08(par->PDIO, VGA_PEL_IW, value);
 156}
 157void NVWriteDacData(struct nvidia_par *par, u8 value)
 158{
 159        VGA_WR08(par->PDIO, VGA_PEL_D, value);
 160}
 161u8 NVReadDacData(struct nvidia_par *par)
 162{
 163        return (VGA_RD08(par->PDIO, VGA_PEL_D));
 164}
 165
 166static int NVIsConnected(struct nvidia_par *par, int output)
 167{
 168        volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
 169        u32 reg52C, reg608, dac0_reg608 = 0;
 170        int present;
 171
 172        if (output) {
 173            dac0_reg608 = NV_RD32(PRAMDAC, 0x0608);
 174            PRAMDAC += 0x800;
 175        }
 176
 177        reg52C = NV_RD32(PRAMDAC, 0x052C);
 178        reg608 = NV_RD32(PRAMDAC, 0x0608);
 179
 180        NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
 181
 182        NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
 183        msleep(1);
 184        NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
 185
 186        NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);
 187        NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |
 188                0x00001000);
 189
 190        msleep(1);
 191
 192        present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
 193
 194        if (present)
 195                printk("nvidiafb: CRTC%i analog found\n", output);
 196        else
 197                printk("nvidiafb: CRTC%i analog not found\n", output);
 198
 199        if (output)
 200            NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608);
 201
 202        NV_WR32(PRAMDAC, 0x052C, reg52C);
 203        NV_WR32(PRAMDAC, 0x0608, reg608);
 204
 205        return present;
 206}
 207
 208static void NVSelectHeadRegisters(struct nvidia_par *par, int head)
 209{
 210        if (head) {
 211                par->PCIO = par->PCIO0 + 0x2000;
 212                par->PCRTC = par->PCRTC0 + 0x800;
 213                par->PRAMDAC = par->PRAMDAC0 + 0x800;
 214                par->PDIO = par->PDIO0 + 0x2000;
 215        } else {
 216                par->PCIO = par->PCIO0;
 217                par->PCRTC = par->PCRTC0;
 218                par->PRAMDAC = par->PRAMDAC0;
 219                par->PDIO = par->PDIO0;
 220        }
 221}
 222
 223static void nv4GetConfig(struct nvidia_par *par)
 224{
 225        if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {
 226                par->RamAmountKBytes =
 227                    ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +
 228                    1024 * 2;
 229        } else {
 230                switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {
 231                case 0:
 232                        par->RamAmountKBytes = 1024 * 32;
 233                        break;
 234                case 1:
 235                        par->RamAmountKBytes = 1024 * 4;
 236                        break;
 237                case 2:
 238                        par->RamAmountKBytes = 1024 * 8;
 239                        break;
 240                case 3:
 241                default:
 242                        par->RamAmountKBytes = 1024 * 16;
 243                        break;
 244                }
 245        }
 246        par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?
 247            14318 : 13500;
 248        par->CURSOR = &par->PRAMIN[0x1E00];
 249        par->MinVClockFreqKHz = 12000;
 250        par->MaxVClockFreqKHz = 350000;
 251}
 252
 253static void nv10GetConfig(struct nvidia_par *par)
 254{
 255        struct pci_dev *dev;
 256        u32 implementation = par->Chipset & 0x0ff0;
 257
 258#ifdef __BIG_ENDIAN
 259        /* turn on big endian register access */
 260        if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {
 261                NV_WR32(par->PMC, 0x0004, 0x01000001);
 262                mb();
 263        }
 264#endif
 265
 266        dev = pci_get_bus_and_slot(0, 1);
 267        if ((par->Chipset & 0xffff) == 0x01a0) {
 268                u32 amt;
 269
 270                pci_read_config_dword(dev, 0x7c, &amt);
 271                par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
 272        } else if ((par->Chipset & 0xffff) == 0x01f0) {
 273                u32 amt;
 274
 275                pci_read_config_dword(dev, 0x84, &amt);
 276                par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
 277        } else {
 278                par->RamAmountKBytes =
 279                    (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
 280        }
 281        pci_dev_put(dev);
 282
 283        par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
 284            14318 : 13500;
 285
 286        if (par->twoHeads && (implementation != 0x0110)) {
 287                if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))
 288                        par->CrystalFreqKHz = 27000;
 289        }
 290
 291        par->CURSOR = NULL;     /* can't set this here */
 292        par->MinVClockFreqKHz = 12000;
 293        par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;
 294}
 295
 296int NVCommonSetup(struct fb_info *info)
 297{
 298        struct nvidia_par *par = info->par;
 299        struct fb_var_screeninfo *var;
 300        u16 implementation = par->Chipset & 0x0ff0;
 301        u8 *edidA = NULL, *edidB = NULL;
 302        struct fb_monspecs *monitorA, *monitorB;
 303        struct fb_monspecs *monA = NULL, *monB = NULL;
 304        int mobile = 0;
 305        int tvA = 0;
 306        int tvB = 0;
 307        int FlatPanel = -1;     /* really means the CRTC is slaved */
 308        int Television = 0;
 309        int err = 0;
 310
 311        var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
 312        monitorA = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
 313        monitorB = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
 314
 315        if (!var || !monitorA || !monitorB) {
 316                err = -ENOMEM;
 317                goto done;
 318        }
 319
 320        par->PRAMIN = par->REGS + (0x00710000 / 4);
 321        par->PCRTC0 = par->REGS + (0x00600000 / 4);
 322        par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
 323        par->PFB = par->REGS + (0x00100000 / 4);
 324        par->PFIFO = par->REGS + (0x00002000 / 4);
 325        par->PGRAPH = par->REGS + (0x00400000 / 4);
 326        par->PEXTDEV = par->REGS + (0x00101000 / 4);
 327        par->PTIMER = par->REGS + (0x00009000 / 4);
 328        par->PMC = par->REGS + (0x00000000 / 4);
 329        par->FIFO = par->REGS + (0x00800000 / 4);
 330
 331        /* 8 bit registers */
 332        par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;
 333        par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;
 334        par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;
 335
 336        par->twoHeads = (par->Architecture >= NV_ARCH_10) &&
 337            (implementation != 0x0100) &&
 338            (implementation != 0x0150) &&
 339            (implementation != 0x01A0) && (implementation != 0x0200);
 340
 341        par->fpScaler = (par->FpScale && par->twoHeads &&
 342                         (implementation != 0x0110));
 343
 344        par->twoStagePLL = (implementation == 0x0310) ||
 345            (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);
 346
 347        par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&
 348            (implementation != 0x0100);
 349
 350        par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);
 351
 352        /* look for known laptop chips */
 353        switch (par->Chipset & 0xffff) {
 354        case 0x0112:
 355        case 0x0174:
 356        case 0x0175:
 357        case 0x0176:
 358        case 0x0177:
 359        case 0x0179:
 360        case 0x017C:
 361        case 0x017D:
 362        case 0x0186:
 363        case 0x0187:
 364        case 0x018D:
 365        case 0x01D7:
 366        case 0x0228:
 367        case 0x0286:
 368        case 0x028C:
 369        case 0x0316:
 370        case 0x0317:
 371        case 0x031A:
 372        case 0x031B:
 373        case 0x031C:
 374        case 0x031D:
 375        case 0x031E:
 376        case 0x031F:
 377        case 0x0324:
 378        case 0x0325:
 379        case 0x0328:
 380        case 0x0329:
 381        case 0x032C:
 382        case 0x032D:
 383        case 0x0347:
 384        case 0x0348:
 385        case 0x0349:
 386        case 0x034B:
 387        case 0x034C:
 388        case 0x0160:
 389        case 0x0166:
 390        case 0x0169:
 391        case 0x016B:
 392        case 0x016C:
 393        case 0x016D:
 394        case 0x00C8:
 395        case 0x00CC:
 396        case 0x0144:
 397        case 0x0146:
 398        case 0x0147:
 399        case 0x0148:
 400        case 0x0098:
 401        case 0x0099:
 402                mobile = 1;
 403                break;
 404        default:
 405                break;
 406        }
 407
 408        if (par->Architecture == NV_ARCH_04)
 409                nv4GetConfig(par);
 410        else
 411                nv10GetConfig(par);
 412
 413        NVSelectHeadRegisters(par, 0);
 414
 415        NVLockUnlock(par, 0);
 416
 417        par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;
 418
 419        par->Television = 0;
 420
 421        nvidia_create_i2c_busses(par);
 422        if (!par->twoHeads) {
 423                par->CRTCnumber = 0;
 424                if (nvidia_probe_i2c_connector(info, 1, &edidA))
 425                        nvidia_probe_of_connector(info, 1, &edidA);
 426                if (edidA && !fb_parse_edid(edidA, var)) {
 427                        printk("nvidiafb: EDID found from BUS1\n");
 428                        monA = monitorA;
 429                        fb_edid_to_monspecs(edidA, monA);
 430                        FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
 431
 432                        /* NV4 doesn't support FlatPanels */
 433                        if ((par->Chipset & 0x0fff) <= 0x0020)
 434                                FlatPanel = 0;
 435                } else {
 436                        VGA_WR08(par->PCIO, 0x03D4, 0x28);
 437                        if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {
 438                                VGA_WR08(par->PCIO, 0x03D4, 0x33);
 439                                if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))
 440                                        Television = 1;
 441                                FlatPanel = 1;
 442                        } else {
 443                                FlatPanel = 0;
 444                        }
 445                        printk("nvidiafb: HW is currently programmed for %s\n",
 446                               FlatPanel ? (Television ? "TV" : "DFP") :
 447                               "CRT");
 448                }
 449
 450                if (par->FlatPanel == -1) {
 451                        par->FlatPanel = FlatPanel;
 452                        par->Television = Television;
 453                } else {
 454                        printk("nvidiafb: Forcing display type to %s as "
 455                               "specified\n", par->FlatPanel ? "DFP" : "CRT");
 456                }
 457        } else {
 458                u8 outputAfromCRTC, outputBfromCRTC;
 459                int CRTCnumber = -1;
 460                u8 slaved_on_A, slaved_on_B;
 461                int analog_on_A, analog_on_B;
 462                u32 oldhead;
 463                u8 cr44;
 464
 465                if (implementation != 0x0110) {
 466                        if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)
 467                                outputAfromCRTC = 1;
 468                        else
 469                                outputAfromCRTC = 0;
 470                        if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)
 471                                outputBfromCRTC = 1;
 472                        else
 473                                outputBfromCRTC = 0;
 474                        analog_on_A = NVIsConnected(par, 0);
 475                        analog_on_B = NVIsConnected(par, 1);
 476                } else {
 477                        outputAfromCRTC = 0;
 478                        outputBfromCRTC = 1;
 479                        analog_on_A = 0;
 480                        analog_on_B = 0;
 481                }
 482
 483                VGA_WR08(par->PCIO, 0x03D4, 0x44);
 484                cr44 = VGA_RD08(par->PCIO, 0x03D5);
 485
 486                VGA_WR08(par->PCIO, 0x03D5, 3);
 487                NVSelectHeadRegisters(par, 1);
 488                NVLockUnlock(par, 0);
 489
 490                VGA_WR08(par->PCIO, 0x03D4, 0x28);
 491                slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
 492                if (slaved_on_B) {
 493                        VGA_WR08(par->PCIO, 0x03D4, 0x33);
 494                        tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
 495                }
 496
 497                VGA_WR08(par->PCIO, 0x03D4, 0x44);
 498                VGA_WR08(par->PCIO, 0x03D5, 0);
 499                NVSelectHeadRegisters(par, 0);
 500                NVLockUnlock(par, 0);
 501
 502                VGA_WR08(par->PCIO, 0x03D4, 0x28);
 503                slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
 504                if (slaved_on_A) {
 505                        VGA_WR08(par->PCIO, 0x03D4, 0x33);
 506                        tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
 507                }
 508
 509                oldhead = NV_RD32(par->PCRTC0, 0x00000860);
 510                NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
 511
 512                if (nvidia_probe_i2c_connector(info, 1, &edidA))
 513                        nvidia_probe_of_connector(info, 1, &edidA);
 514                if (edidA && !fb_parse_edid(edidA, var)) {
 515                        printk("nvidiafb: EDID found from BUS1\n");
 516                        monA = monitorA;
 517                        fb_edid_to_monspecs(edidA, monA);
 518                }
 519
 520                if (nvidia_probe_i2c_connector(info, 2, &edidB))
 521                        nvidia_probe_of_connector(info, 2, &edidB);
 522                if (edidB && !fb_parse_edid(edidB, var)) {
 523                        printk("nvidiafb: EDID found from BUS2\n");
 524                        monB = monitorB;
 525                        fb_edid_to_monspecs(edidB, monB);
 526                }
 527
 528                if (slaved_on_A && !tvA) {
 529                        CRTCnumber = 0;
 530                        FlatPanel = 1;
 531                        printk("nvidiafb: CRTC 0 is currently programmed for "
 532                               "DFP\n");
 533                } else if (slaved_on_B && !tvB) {
 534                        CRTCnumber = 1;
 535                        FlatPanel = 1;
 536                        printk("nvidiafb: CRTC 1 is currently programmed "
 537                               "for DFP\n");
 538                } else if (analog_on_A) {
 539                        CRTCnumber = outputAfromCRTC;
 540                        FlatPanel = 0;
 541                        printk("nvidiafb: CRTC %i appears to have a "
 542                               "CRT attached\n", CRTCnumber);
 543                } else if (analog_on_B) {
 544                        CRTCnumber = outputBfromCRTC;
 545                        FlatPanel = 0;
 546                        printk("nvidiafb: CRTC %i appears to have a "
 547                               "CRT attached\n", CRTCnumber);
 548                } else if (slaved_on_A) {
 549                        CRTCnumber = 0;
 550                        FlatPanel = 1;
 551                        Television = 1;
 552                        printk("nvidiafb: CRTC 0 is currently programmed "
 553                               "for TV\n");
 554                } else if (slaved_on_B) {
 555                        CRTCnumber = 1;
 556                        FlatPanel = 1;
 557                        Television = 1;
 558                        printk("nvidiafb: CRTC 1 is currently programmed for "
 559                               "TV\n");
 560                } else if (monA) {
 561                        FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
 562                } else if (monB) {
 563                        FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;
 564                }
 565
 566                if (par->FlatPanel == -1) {
 567                        if (FlatPanel != -1) {
 568                                par->FlatPanel = FlatPanel;
 569                                par->Television = Television;
 570                        } else {
 571                                printk("nvidiafb: Unable to detect display "
 572                                       "type...\n");
 573                                if (mobile) {
 574                                        printk("...On a laptop, assuming "
 575                                               "DFP\n");
 576                                        par->FlatPanel = 1;
 577                                } else {
 578                                        printk("...Using default of CRT\n");
 579                                        par->FlatPanel = 0;
 580                                }
 581                        }
 582                } else {
 583                        printk("nvidiafb: Forcing display type to %s as "
 584                               "specified\n", par->FlatPanel ? "DFP" : "CRT");
 585                }
 586
 587                if (par->CRTCnumber == -1) {
 588                        if (CRTCnumber != -1)
 589                                par->CRTCnumber = CRTCnumber;
 590                        else {
 591                                printk("nvidiafb: Unable to detect which "
 592                                       "CRTCNumber...\n");
 593                                if (par->FlatPanel)
 594                                        par->CRTCnumber = 1;
 595                                else
 596                                        par->CRTCnumber = 0;
 597                                printk("...Defaulting to CRTCNumber %i\n",
 598                                       par->CRTCnumber);
 599                        }
 600                } else {
 601                        printk("nvidiafb: Forcing CRTCNumber %i as "
 602                               "specified\n", par->CRTCnumber);
 603                }
 604
 605                if (monA) {
 606                        if (((monA->input & FB_DISP_DDI) &&
 607                             par->FlatPanel) ||
 608                            ((!(monA->input & FB_DISP_DDI)) &&
 609                             !par->FlatPanel)) {
 610                                if (monB) {
 611                                        fb_destroy_modedb(monB->modedb);
 612                                        monB = NULL;
 613                                }
 614                        } else {
 615                                fb_destroy_modedb(monA->modedb);
 616                                monA = NULL;
 617                        }
 618                }
 619
 620                if (monB) {
 621                        if (((monB->input & FB_DISP_DDI) &&
 622                             !par->FlatPanel) ||
 623                            ((!(monB->input & FB_DISP_DDI)) &&
 624                             par->FlatPanel)) {
 625                                fb_destroy_modedb(monB->modedb);
 626                                monB = NULL;
 627                        } else
 628                                monA = monB;
 629                }
 630
 631                if (implementation == 0x0110)
 632                        cr44 = par->CRTCnumber * 0x3;
 633
 634                NV_WR32(par->PCRTC0, 0x00000860, oldhead);
 635
 636                VGA_WR08(par->PCIO, 0x03D4, 0x44);
 637                VGA_WR08(par->PCIO, 0x03D5, cr44);
 638                NVSelectHeadRegisters(par, par->CRTCnumber);
 639        }
 640
 641        printk("nvidiafb: Using %s on CRTC %i\n",
 642               par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",
 643               par->CRTCnumber);
 644
 645        if (par->FlatPanel && !par->Television) {
 646                par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;
 647                par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;
 648                par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;
 649
 650                printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight);
 651        }
 652
 653        if (monA)
 654                info->monspecs = *monA;
 655
 656        if (!par->FlatPanel || !par->twoHeads)
 657                par->FPDither = 0;
 658
 659        par->LVDS = 0;
 660        if (par->FlatPanel && par->twoHeads) {
 661                NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);
 662                if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)
 663                        par->LVDS = 1;
 664                printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");
 665        }
 666
 667        kfree(edidA);
 668        kfree(edidB);
 669done:
 670        kfree(var);
 671        kfree(monitorA);
 672        kfree(monitorB);
 673        return err;
 674}
 675