2 * Copyright (c) 2007 NVIDIA, Corporation
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:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
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.
31 #include <X11/extensions/dpms.h>
33 #include "nv_include.h"
34 #include "nv50_display.h"
35 #include "nv50_output.h"
38 NV50DacSetPClk(xf86OutputPtr output, int pclk)
40 NVPtr pNv = NVPTR(output->scrn);
41 NV50OutputPrivPtr pPriv = output->driver_private;
42 const int orOff = 0x800 * pPriv->or;
44 pNv->REGS[(0x00614280+orOff)/4] = 0;
48 NV50DacDPMSSet(xf86OutputPtr output, int mode)
50 NVPtr pNv = NVPTR(output->scrn);
51 NV50OutputPrivPtr pPriv = output->driver_private;
52 const int off = 0x800 * pPriv->or;
56 * DPMSModeOn everything on
57 * DPMSModeStandby hsync disabled, vsync enabled
58 * DPMSModeSuspend hsync enabled, vsync disabled
59 * DPMSModeOff sync disabled
61 while(pNv->REGS[(0x0061A004+off)/4] & 0x80000000);
63 tmp = pNv->REGS[(0x0061A004+off)/4];
67 if(mode == DPMSModeStandby || mode == DPMSModeOff)
69 if(mode == DPMSModeSuspend || mode == DPMSModeOff)
71 if(mode != DPMSModeOn)
73 if(mode == DPMSModeOff)
76 pNv->REGS[(0x0061A004+off)/4] = tmp;
80 NV50DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
81 DisplayModePtr adjusted_mode)
83 ScrnInfoPtr pScrn = output->scrn;
84 NV50OutputPrivPtr pPriv = output->driver_private;
85 const int dacOff = 0x80 * pPriv->or;
88 C(0x00000400 + dacOff, 0);
92 // This wouldn't be necessary, but the server is stupid and calls
93 // NV50DacDPMSSet after the output is disconnected, even though the hardware
94 // turns it off automatically.
95 NV50DacDPMSSet(output, DPMSModeOn);
97 C(0x00000400 + dacOff,
98 (NV50CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40);
99 C(0x00000404 + dacOff,
100 (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 |
101 (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0);
105 * Perform DAC load detection to determine if there is a connected display.
107 static xf86OutputStatus
108 NV50DacDetect(xf86OutputPtr output)
110 NV50OutputPrivPtr pPriv = output->driver_private;
112 /* Assume physical status isn't going to change before the BlockHandler */
113 if(pPriv->cached_status != XF86OutputStatusUnknown)
114 return pPriv->cached_status;
116 NV50OutputPartnersDetect(output, pPriv->partner, pPriv->i2c);
117 return pPriv->cached_status;
121 NV50DacLoadDetect(xf86OutputPtr output)
123 ScrnInfoPtr pScrn = output->scrn;
124 NVPtr pNv = NVPTR(pScrn);
125 NV50OutputPrivPtr pPriv = output->driver_private;
126 const int scrnIndex = pScrn->scrnIndex;
127 const int dacOff = 2048 * pPriv->or;
128 CARD32 load, tmp, tmp2;
130 xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
133 pNv->REGS[(0x0061A010+dacOff)/4] = 0x00000001;
134 tmp2 = pNv->REGS[(0x0061A004+dacOff)/4];
135 pNv->REGS[(0x0061A004+dacOff)/4] = 0x80150000;
136 while(pNv->REGS[(0x0061A004+dacOff)/4] & 0x80000000);
137 tmp = pNv->NVArch == 0x50 ? 420 : 340;
138 pNv->REGS[(0x0061A00C+dacOff)/4] = tmp | 0x100000;
140 load = pNv->REGS[(0x0061A00C+dacOff)/4];
141 pNv->REGS[(0x0061A00C+dacOff)/4] = 0;
142 pNv->REGS[(0x0061A004+dacOff)/4] = 0x80000000 | tmp2;
144 // Use this DAC if all three channels show load.
145 if((load & 0x38000000) == 0x38000000) {
146 xf86ErrorF("found one!\n");
150 xf86ErrorF("nothing.\n");
155 NV50DacDestroy(xf86OutputPtr output)
157 NV50OutputDestroy(output);
159 xfree(output->driver_private);
160 output->driver_private = NULL;
163 static const xf86OutputFuncsRec NV50DacOutputFuncs = {
164 .dpms = NV50DacDPMSSet,
167 .mode_valid = NV50OutputModeValid,
168 .mode_fixup = NV50OutputModeFixup,
169 .prepare = NV50OutputPrepare,
170 .commit = NV50OutputCommit,
171 .mode_set = NV50DacModeSet,
172 .detect = NV50DacDetect,
173 .get_modes = NV50OutputGetDDCModes,
174 .destroy = NV50DacDestroy,
178 NV50CreateDac(ScrnInfoPtr pScrn, ORNum or)
180 NV50OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
181 xf86OutputPtr output;
187 snprintf(orName, 5, "VGA%i", or);
188 output = xf86OutputCreate(pScrn, &NV50DacOutputFuncs, orName);
192 pPriv->cached_status = XF86OutputStatusUnknown;
193 pPriv->set_pclk = NV50DacSetPClk;
194 output->driver_private = pPriv;
195 output->interlaceAllowed = TRUE;
196 output->doubleScanAllowed = TRUE;