There was some redundant arch checking code left, must have been missed after the...
[nouveau] / src / nv50_dac.c
1 /*
2  * Copyright (c) 2007 NVIDIA, Corporation
3  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <unistd.h>
29
30 #define DPMS_SERVER
31 #include <X11/extensions/dpms.h>
32
33 #include "nv_include.h"
34 #include "nv50_display.h"
35 #include "nv50_output.h"
36
37 static void
38 NV50DacSetPClk(xf86OutputPtr output, int pclk)
39 {
40     NVPtr pNv = NVPTR(output->scrn);
41     NV50OutputPrivPtr pPriv = output->driver_private;
42     const int orOff = 0x800 * pPriv->or;
43
44     pNv->REGS[(0x00614280+orOff)/4] = 0;
45 }
46
47 static void
48 NV50DacDPMSSet(xf86OutputPtr output, int mode)
49 {
50     NVPtr pNv = NVPTR(output->scrn);
51     NV50OutputPrivPtr pPriv = output->driver_private;
52     const int off = 0x800 * pPriv->or;
53     CARD32 tmp;
54
55     /*
56      * DPMSModeOn       everything on
57      * DPMSModeStandby  hsync disabled, vsync enabled
58      * DPMSModeSuspend  hsync enabled, vsync disabled
59      * DPMSModeOff      sync disabled
60      */
61     while(pNv->REGS[(0x0061A004+off)/4] & 0x80000000);
62
63     tmp = pNv->REGS[(0x0061A004+off)/4];
64     tmp &= ~0x7f;
65     tmp |= 0x80000000;
66
67     if(mode == DPMSModeStandby || mode == DPMSModeOff)
68         tmp |= 1;
69     if(mode == DPMSModeSuspend || mode == DPMSModeOff)
70         tmp |= 4;
71     if(mode != DPMSModeOn)
72         tmp |= 0x10;
73     if(mode == DPMSModeOff)
74         tmp |= 0x40;
75
76     pNv->REGS[(0x0061A004+off)/4] = tmp;
77 }
78
79 static void
80 NV50DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
81               DisplayModePtr adjusted_mode)
82 {
83     ScrnInfoPtr pScrn = output->scrn;
84     NV50OutputPrivPtr pPriv = output->driver_private;
85     const int dacOff = 0x80 * pPriv->or;
86
87     if(!adjusted_mode) {
88         C(0x00000400 + dacOff, 0);
89         return;
90     }
91
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);
96
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);
102 }
103
104 /*
105  * Perform DAC load detection to determine if there is a connected display.
106  */
107 static xf86OutputStatus
108 NV50DacDetect(xf86OutputPtr output)
109 {
110     NV50OutputPrivPtr pPriv = output->driver_private;
111
112     /* Assume physical status isn't going to change before the BlockHandler */
113     if(pPriv->cached_status != XF86OutputStatusUnknown)
114         return pPriv->cached_status;
115
116     NV50OutputPartnersDetect(output, pPriv->partner, pPriv->i2c);
117     return pPriv->cached_status;
118 }
119
120 Bool
121 NV50DacLoadDetect(xf86OutputPtr output)
122 {
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;
129
130     xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
131             pPriv->or);
132
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;
139     usleep(4500);
140     load = pNv->REGS[(0x0061A00C+dacOff)/4];
141     pNv->REGS[(0x0061A00C+dacOff)/4] = 0;
142     pNv->REGS[(0x0061A004+dacOff)/4] = 0x80000000 | tmp2;
143
144     // Use this DAC if all three channels show load.
145     if((load & 0x38000000) == 0x38000000) {
146         xf86ErrorF("found one!\n");
147         return TRUE;
148     }
149
150     xf86ErrorF("nothing.\n");
151     return FALSE;
152 }
153
154 static void
155 NV50DacDestroy(xf86OutputPtr output)
156 {
157     NV50OutputDestroy(output);
158
159     xfree(output->driver_private);
160     output->driver_private = NULL;
161 }
162
163 static const xf86OutputFuncsRec NV50DacOutputFuncs = {
164     .dpms = NV50DacDPMSSet,
165     .save = NULL,
166     .restore = NULL,
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,
175 };
176
177 xf86OutputPtr
178 NV50CreateDac(ScrnInfoPtr pScrn, ORNum or)
179 {
180     NV50OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
181     xf86OutputPtr output;
182     char orName[5];
183
184     if(!pPriv)
185         return FALSE;
186
187     snprintf(orName, 5, "VGA%i", or);
188     output = xf86OutputCreate(pScrn, &NV50DacOutputFuncs, orName);
189
190     pPriv->type = DAC;
191     pPriv->or = or;
192     pPriv->cached_status = XF86OutputStatusUnknown;
193     pPriv->set_pclk = NV50DacSetPClk;
194     output->driver_private = pPriv;
195     output->interlaceAllowed = TRUE;
196     output->doubleScanAllowed = TRUE;
197
198     return output;
199 }