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.
27 #include <X11/extensions/dpms.h>
29 #include "nv_include.h"
30 #include "nv50_display.h"
31 #include "nv50_output.h"
34 NV50DacSetPClk(xf86OutputPtr output, int pclk)
36 NV50OutputWrite(output, 0x4280, 0);
40 NV50DacDPMSSet(xf86OutputPtr output, int mode)
45 * DPMSModeOn everything on
46 * DPMSModeStandby hsync disabled, vsync enabled
47 * DPMSModeSuspend hsync enabled, vsync disabled
48 * DPMSModeOff sync disabled
50 while(NV50OutputRead(output, 0xa004) & 0x80000000);
52 tmp = NV50OutputRead(output, 0xa004);
56 if(mode == DPMSModeStandby || mode == DPMSModeOff)
58 if(mode == DPMSModeSuspend || mode == DPMSModeOff)
60 if(mode != DPMSModeOn)
62 if(mode == DPMSModeOff)
65 NV50OutputWrite(output, 0xa004, tmp);
69 NV50DacModeFixup(xf86OutputPtr output, DisplayModePtr mode,
70 DisplayModePtr adjusted_mode)
76 NV50DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
77 DisplayModePtr adjusted_mode)
79 ScrnInfoPtr pScrn = output->scrn;
80 NV50OutputPrivPtr nv_output = output->driver_private;
81 const int dacOff = 0x80 * nv_output->or;
84 NV50DisplayCommand(pScrn, 0x400 + dacOff, 0);
88 // This wouldn't be necessary, but the server is stupid and calls
89 // NV50DacDPMSSet after the output is disconnected, even though the hardware
90 // turns it off automatically.
91 NV50DacDPMSSet(output, DPMSModeOn);
93 NV50DisplayCommand(pScrn, 0x400 + dacOff,
94 (NV50CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40);
96 NV50DisplayCommand(pScrn, 0x404 + dacOff,
97 (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 |
98 (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0);
100 NV50CrtcSetScale(output->crtc, adjusted_mode, NV50_SCALE_OFF);
104 * Perform DAC load detection to determine if there is a connected display.
106 static xf86OutputStatus
107 NV50DacDetect(xf86OutputPtr output)
109 NV50OutputPrivPtr nv_output = output->driver_private;
111 /* Assume physical status isn't going to change before the BlockHandler */
112 if(nv_output->cached_status != XF86OutputStatusUnknown)
113 return nv_output->cached_status;
115 NV50OutputPartnersDetect(output, nv_output->partner, nv_output->i2c);
116 return nv_output->cached_status;
120 NV50DacLoadDetect(xf86OutputPtr output)
122 ScrnInfoPtr pScrn = output->scrn;
123 NVPtr pNv = NVPTR(pScrn);
124 NV50OutputPrivPtr nv_output = output->driver_private;
125 const int scrnIndex = pScrn->scrnIndex;
127 CARD32 load, tmp, tmp2;
129 xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
132 NV50OutputWrite(output, 0xa010, 0x00000001);
133 tmp2 = NV50OutputRead(output, 0xa004);
135 NV50OutputWrite(output, 0xa004, 0x80150000);
136 while(NV50OutputRead(output, 0xa004) & 0x80000000);
137 tmp = (pNv->NVArch == 0x50) ? 420 : 340;
138 NV50OutputWrite(output, 0xa00c, tmp | 0x100000);
139 sigstate = xf86BlockSIGIO();
141 xf86UnblockSIGIO(sigstate);
142 load = NV50OutputRead(output, 0xa00c);
143 NV50OutputWrite(output, 0xa00c, 0);
144 NV50OutputWrite(output, 0xa004, 0x80000000 | tmp2);
146 // Use this DAC if all three channels show load.
147 if((load & 0x38000000) == 0x38000000) {
148 xf86ErrorF("found one!\n");
152 xf86ErrorF("nothing.\n");
157 NV50DacDestroy(xf86OutputPtr output)
159 NV50OutputDestroy(output);
161 xfree(output->driver_private);
162 output->driver_private = NULL;
165 static const xf86OutputFuncsRec NV50DacOutputFuncs = {
166 .dpms = NV50DacDPMSSet,
169 .mode_valid = NV50OutputModeValid,
170 .mode_fixup = NV50DacModeFixup,
171 .prepare = NV50OutputPrepare,
172 .commit = NV50OutputCommit,
173 .mode_set = NV50DacModeSet,
174 .detect = NV50DacDetect,
175 .get_modes = NV50OutputGetDDCModes,
176 .destroy = NV50DacDestroy,
180 NV50CreateDac(ScrnInfoPtr pScrn, ORNum or)
182 NV50OutputPrivPtr nv_output = xnfcalloc(sizeof(*nv_output), 1);
183 xf86OutputPtr output;
189 snprintf(orName, 5, "VGA%i", or);
190 output = xf86OutputCreate(pScrn, &NV50DacOutputFuncs, orName);
192 nv_output->type = DAC;
194 nv_output->cached_status = XF86OutputStatusUnknown;
195 nv_output->set_pclk = NV50DacSetPClk;
196 output->driver_private = nv_output;
197 output->interlaceAllowed = TRUE;
198 output->doubleScanAllowed = TRUE;