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.
33 #include <X11/extensions/dpms.h>
35 #include "nv_include.h"
36 #include "nv50_display.h"
37 #include "nv50_output.h"
40 NV50DacSetPClk(xf86OutputPtr output, int pclk)
42 NVPtr pNv = NVPTR(output->scrn);
43 NV50OutputPrivPtr pPriv = output->driver_private;
44 const int orOff = 0x800 * pPriv->or;
46 pNv->REGS[(0x00614280+orOff)/4] = 0;
50 NV50DacDPMSSet(xf86OutputPtr output, int mode)
52 NVPtr pNv = NVPTR(output->scrn);
53 NV50OutputPrivPtr pPriv = output->driver_private;
54 const int off = 0x800 * pPriv->or;
58 * DPMSModeOn everything on
59 * DPMSModeStandby hsync disabled, vsync enabled
60 * DPMSModeSuspend hsync enabled, vsync disabled
61 * DPMSModeOff sync disabled
63 while(pNv->REGS[(0x0061A004+off)/4] & 0x80000000);
65 tmp = pNv->REGS[(0x0061A004+off)/4];
69 if(mode == DPMSModeStandby || mode == DPMSModeOff)
71 if(mode == DPMSModeSuspend || mode == DPMSModeOff)
73 if(mode != DPMSModeOn)
75 if(mode == DPMSModeOff)
78 pNv->REGS[(0x0061A004+off)/4] = tmp;
82 NV50DacModeFixup(xf86OutputPtr output, DisplayModePtr mode,
83 DisplayModePtr adjusted_mode)
89 NV50DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
90 DisplayModePtr adjusted_mode)
92 ScrnInfoPtr pScrn = output->scrn;
93 NV50OutputPrivPtr pPriv = output->driver_private;
94 const int dacOff = 0x80 * pPriv->or;
97 NV50DisplayCommand(pScrn, 0x400 + dacOff, 0);
101 // This wouldn't be necessary, but the server is stupid and calls
102 // NV50DacDPMSSet after the output is disconnected, even though the hardware
103 // turns it off automatically.
104 NV50DacDPMSSet(output, DPMSModeOn);
106 NV50DisplayCommand(pScrn, 0x400 + dacOff,
107 (NV50CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40);
109 NV50DisplayCommand(pScrn, 0x404 + dacOff,
110 (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 |
111 (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0);
113 NV50CrtcSetScale(output->crtc, adjusted_mode, NV50_SCALE_OFF);
117 * Perform DAC load detection to determine if there is a connected display.
119 static xf86OutputStatus
120 NV50DacDetect(xf86OutputPtr output)
122 NV50OutputPrivPtr pPriv = output->driver_private;
124 /* Assume physical status isn't going to change before the BlockHandler */
125 if(pPriv->cached_status != XF86OutputStatusUnknown)
126 return pPriv->cached_status;
128 NV50OutputPartnersDetect(output, pPriv->partner, pPriv->i2c);
129 return pPriv->cached_status;
133 NV50DacLoadDetect(xf86OutputPtr output)
135 ScrnInfoPtr pScrn = output->scrn;
136 NVPtr pNv = NVPTR(pScrn);
137 NV50OutputPrivPtr pPriv = output->driver_private;
138 const int scrnIndex = pScrn->scrnIndex;
139 const int dacOff = 2048 * pPriv->or;
140 CARD32 load, tmp, tmp2;
142 xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
145 pNv->REGS[(0x0061A010+dacOff)/4] = 0x00000001;
146 tmp2 = pNv->REGS[(0x0061A004+dacOff)/4];
147 pNv->REGS[(0x0061A004+dacOff)/4] = 0x80150000;
148 while(pNv->REGS[(0x0061A004+dacOff)/4] & 0x80000000);
149 tmp = pNv->NVArch == 0x50 ? 420 : 340;
150 pNv->REGS[(0x0061A00C+dacOff)/4] = tmp | 0x100000;
152 load = pNv->REGS[(0x0061A00C+dacOff)/4];
153 pNv->REGS[(0x0061A00C+dacOff)/4] = 0;
154 pNv->REGS[(0x0061A004+dacOff)/4] = 0x80000000 | tmp2;
156 // Use this DAC if all three channels show load.
157 if((load & 0x38000000) == 0x38000000) {
158 xf86ErrorF("found one!\n");
162 xf86ErrorF("nothing.\n");
167 NV50DacDestroy(xf86OutputPtr output)
169 NV50OutputDestroy(output);
171 xfree(output->driver_private);
172 output->driver_private = NULL;
175 static const xf86OutputFuncsRec NV50DacOutputFuncs = {
176 .dpms = NV50DacDPMSSet,
179 .mode_valid = NV50OutputModeValid,
180 .mode_fixup = NV50DacModeFixup,
181 .prepare = NV50OutputPrepare,
182 .commit = NV50OutputCommit,
183 .mode_set = NV50DacModeSet,
184 .detect = NV50DacDetect,
185 .get_modes = NV50OutputGetDDCModes,
186 .destroy = NV50DacDestroy,
190 NV50CreateDac(ScrnInfoPtr pScrn, ORNum or)
192 NV50OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
193 xf86OutputPtr output;
199 snprintf(orName, 5, "VGA%i", or);
200 output = xf86OutputCreate(pScrn, &NV50DacOutputFuncs, orName);
204 pPriv->cached_status = XF86OutputStatusUnknown;
205 pPriv->set_pclk = NV50DacSetPClk;
206 output->driver_private = pPriv;
207 output->interlaceAllowed = TRUE;
208 output->doubleScanAllowed = TRUE;
213 #endif /* ENABLE_RANDR12 */