Xv: quick imple of NV04 overlay
[nouveau] / src / nv50_sor.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 #ifdef ENABLE_RANDR12
29
30 #define DPMS_SERVER
31 #include <X11/extensions/dpms.h>
32
33 #include "nv_include.h"
34 #include "nv50_type.h"
35 #include "nv50_display.h"
36 #include "nv50_output.h"
37
38 static void
39 NV50SorSetPClk(xf86OutputPtr output, int pclk)
40 {
41     NVPtr pNv = NVPTR(output->scrn);
42     NV50OutputPrivPtr pPriv = output->driver_private;
43     const int orOff = 0x800 * pPriv->or;
44
45     pNv->REGS[(0x00614300+orOff)/4] = (pclk > 165000) ? 0x101 : 0;
46 }
47
48 static void
49 NV50SorDPMSSet(xf86OutputPtr output, int mode)
50 {
51     NVPtr pNv = NVPTR(output->scrn);
52     NV50OutputPrivPtr pPriv = output->driver_private;
53     const int off = 0x800 * pPriv->or;
54     CARD32 tmp;
55
56     while(pNv->REGS[(0x0061C004+off)/4] & 0x80000000);
57
58     tmp = pNv->REGS[(0x0061C004+off)/4];
59     tmp |= 0x80000000;
60
61     if(mode == DPMSModeOn)
62         tmp |= 1;
63     else
64         tmp &= ~1;
65
66     pNv->REGS[(0x0061C004+off)/4] = tmp;
67 }
68
69 static void
70 NV50SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
71               DisplayModePtr adjusted_mode)
72 {
73     ScrnInfoPtr pScrn = output->scrn;
74     NV50OutputPrivPtr pPriv = output->driver_private;
75     const int sorOff = 0x40 * pPriv->or;
76
77     if(!adjusted_mode) {
78         /* Disconnect the SOR */
79         C(0x00000600 + sorOff, 0);
80         return;
81     }
82
83     // This wouldn't be necessary, but the server is stupid and calls
84     // NV50SorDPMSSet after the output is disconnected, even though the hardware
85     // turns it off automatically.
86     NV50SorDPMSSet(output, DPMSModeOn);
87
88     C(0x00000600 + sorOff,
89         (NV50CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) |
90         (adjusted_mode->Clock > 165000 ? 0x500 : 0x100) |
91         ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
92         ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0));
93 }
94
95 static xf86OutputStatus
96 NV50SorDetect(xf86OutputPtr output)
97 {
98
99     NV50OutputPrivPtr pPriv = output->driver_private;
100
101     /* Assume physical status isn't going to change before the BlockHandler */
102     if(pPriv->cached_status != XF86OutputStatusUnknown)
103         return pPriv->cached_status;
104
105     NV50OutputPartnersDetect(pPriv->partner, output, pPriv->i2c);
106     return pPriv->cached_status;
107 }
108
109 static void
110 NV50SorDestroy(xf86OutputPtr output)
111 {
112     NV50OutputDestroy(output);
113
114     xfree(output->driver_private);
115     output->driver_private = NULL;
116 }
117
118 static const xf86OutputFuncsRec NV50SorOutputFuncs = {
119     .dpms = NV50SorDPMSSet,
120     .save = NULL,
121     .restore = NULL,
122     .mode_valid = NV50OutputModeValid,
123     .mode_fixup = NV50OutputModeFixup,
124     .prepare = NV50OutputPrepare,
125     .commit = NV50OutputCommit,
126     .mode_set = NV50SorModeSet,
127     .detect = NV50SorDetect,
128     .get_modes = NV50OutputGetDDCModes,
129     .destroy = NV50SorDestroy,
130 };
131
132 xf86OutputPtr
133 NV50CreateSor(ScrnInfoPtr pScrn, ORNum or)
134 {
135     NV50OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
136     xf86OutputPtr output;
137     char orName[5];
138
139     if(!pPriv)
140         return FALSE;
141
142     snprintf(orName, 5, "DVI%i", or);
143     output = xf86OutputCreate(pScrn, &NV50SorOutputFuncs, orName);
144
145     pPriv->type = SOR;
146     pPriv->or = or;
147     pPriv->cached_status = XF86OutputStatusUnknown;
148     pPriv->set_pclk = NV50SorSetPClk;
149     output->driver_private = pPriv;
150     output->interlaceAllowed = TRUE;
151     output->doubleScanAllowed = TRUE;
152
153     return output;
154 }
155
156 #endif /* ENABLE_RANDR12 */