Drop the NV*VGA defines and adjust users
[nouveau] / src / nv50_output.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 #include <string.h>
25
26 #include "nv_include.h"
27 #include "nv50_type.h"
28 #include "nv50_display.h"
29 #include "nv50_output.h"
30
31 #include <xf86DDC.h>
32
33 static Bool NV50ReadPortMapping(int scrnIndex, NVPtr pNv)
34 {
35          unsigned const char *VBIOS = (unsigned const char *)pNv->VBIOS.data;
36          unsigned char *table2;
37          unsigned char headerSize, entries;
38          int i;
39          CARD16 a;
40          CARD32 b;
41
42          if (!VBIOS)
43                 goto fail;
44
45          /* Clear the i2c map to invalid */
46          for (i = 0; i < 4; i++)
47                 pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
48
49         if (*(CARD16*)VBIOS != 0xaa55) goto fail;
50
51         a = *(CARD16*)(VBIOS + 0x36);
52         table2 = (unsigned char*)VBIOS + a;
53
54         if (table2[0] != 0x40) goto fail;
55
56         b = *(CARD32*)(table2 + 6);
57         if (b != 0x4edcbdcb) goto fail;
58
59         headerSize = table2[1];
60         entries = table2[2];
61
62         for(i = 0; i < entries; i++) {
63                 int type, port;
64                 ORNum or;
65
66                 b = *(CARD32*)&table2[headerSize + 8*i];
67                 type = b & 0xf;
68                 port = (b >> 4) & 0xf;
69                 or = ffs((b >> 24) & 0xf) - 1;
70
71                 if (type == 0xe)
72                         break;
73
74                 if(type < 4) {
75                         switch(type) {
76                                 case 0: /* CRT */
77                                         if(pNv->i2cMap[port].dac != -1) {
78                                                 xf86DrvMsg(scrnIndex, X_WARNING,
79                                                         "DDC routing table corrupt!  DAC %i -> %i "
80                                                         "for port %i\n",
81                                                         or, pNv->i2cMap[port].dac, port);
82                                         }
83                                         pNv->i2cMap[port].dac = or;
84                                         break;
85                                 case 1: /* TV */
86                                         break;
87                                 case 2: /* TMDS */
88                                         if(pNv->i2cMap[port].sor != -1)
89                                                 xf86DrvMsg(scrnIndex, X_WARNING,
90                                                         "DDC routing table corrupt!  SOR %i -> %i "
91                                                         "for port %i\n",
92                                                         or, pNv->i2cMap[port].sor, port);
93                                         pNv->i2cMap[port].sor = or;
94                                         break;
95                                 case 3: /* LVDS */
96                                         pNv->lvds.present = TRUE;
97                                         pNv->lvds.or = or;
98                                         break;
99                         }
100                 }
101         }
102
103         xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
104         if (pNv->lvds.present) {
105                 xf86DrvMsg(scrnIndex, X_PROBED,
106                         "  [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
107         }
108          for(i = 0; i < 4; i++) {
109                 if(pNv->i2cMap[i].dac != -1)
110                         xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
111                 if(pNv->i2cMap[i].sor != -1)
112                         xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
113         }
114
115         return TRUE;
116
117         fail:
118                 xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table.  "
119                         "Mode setting will probably fail!\n");
120                 return FALSE;
121 }
122
123 static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
124 {
125         NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
126         const int off = b->DriverPrivate.val * 0x18;
127
128         pNv->REGS[(0x0000E138+off)/4] = 4 | clock | data << 1;
129 }
130
131 static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
132 {
133         NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
134         const int off = b->DriverPrivate.val * 0x18;
135         unsigned char val;
136
137         val = pNv->REGS[(0x0000E138+off)/4];
138         *clock = !!(val & 1);
139         *data = !!(val & 2);
140 }
141
142 static I2CBusPtr
143 NV50I2CInit(ScrnInfoPtr pScrn, const char *name, const int port)
144 {
145         I2CBusPtr i2c;
146
147         /* Allocate the I2C bus structure */
148         i2c = xf86CreateI2CBusRec();
149         if(!i2c) return NULL;
150
151         i2c->BusName = strdup(name);
152         i2c->scrnIndex = pScrn->scrnIndex;
153         i2c->I2CPutBits = NV50_I2CPutBits;
154         i2c->I2CGetBits = NV50_I2CGetBits;
155         i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
156         i2c->StartTimeout = 550;
157         i2c->BitTimeout = 40;
158         i2c->ByteTimeout = 40;
159         i2c->AcknTimeout = 40;
160         i2c->DriverPrivate.val = port;
161
162         if(xf86I2CBusInit(i2c)) {
163                 return i2c;
164         } else {
165                 xfree(i2c);
166                 return NULL;
167         }
168 }
169
170 void
171 NV50OutputSetPClk(xf86OutputPtr output, int pclk)
172 {
173         NV50OutputPrivPtr nv_output = output->driver_private;
174
175         if (nv_output->set_pclk)
176                 nv_output->set_pclk(output, pclk);
177 }
178
179 int
180 NV50OutputModeValid(xf86OutputPtr output, DisplayModePtr mode)
181 {
182         if (mode->Clock > 400000)
183                 return MODE_CLOCK_HIGH;
184         if (mode->Clock < 25000)
185                 return MODE_CLOCK_LOW;
186
187         return MODE_OK;
188 }
189
190 void
191 NV50OutputPrepare(xf86OutputPtr output)
192 {
193 }
194
195 void
196 NV50OutputCommit(xf86OutputPtr output)
197 {
198 }
199
200 static xf86MonPtr
201 ProbeDDC(I2CBusPtr i2c)
202 {
203         ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
204         NVPtr pNv = NVPTR(pScrn);
205         xf86MonPtr monInfo = NULL;
206         const int bus = i2c->DriverPrivate.val, off = bus * 0x18;
207
208         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
209                 "Probing for EDID on I2C bus %i...\n", bus);
210         pNv->REGS[(0x0000E138+off)/4] = 7;
211         /* Should probably use xf86OutputGetEDID here */
212         monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
213         pNv->REGS[(0x0000E138+off)/4] = 3;
214
215         if(monInfo) {
216                 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
217                         "DDC detected a %s:\n", monInfo->features.input_type ?
218                         "DFP" : "CRT");
219                 xf86PrintEDID(monInfo);
220         } else {
221                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  ... none found\n");
222         }
223
224         return monInfo;
225 }
226
227 /*
228  * Read an EDID from the i2c port.  Perform load detection on the DAC (if
229  * present) to see if the display is connected via VGA.  Sets the cached status
230  * of both outputs.  The status is marked dirty again in the BlockHandler.
231  */
232 void NV50OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c)
233 {
234         xf86MonPtr monInfo = ProbeDDC(i2c);
235         xf86OutputPtr connected = NULL;
236         Bool load = dac && NV50DacLoadDetect(dac);
237
238         if(dac) {
239                 NV50OutputPrivPtr nv_output = dac->driver_private;
240
241                 if(load) {
242                         nv_output->cached_status = XF86OutputStatusConnected;
243                         connected = dac;
244                 } else {
245                         nv_output->cached_status = XF86OutputStatusDisconnected;
246                 }
247         }
248
249         if(sor) {
250                 NV50OutputPrivPtr nv_output = sor->driver_private;
251
252                 if(monInfo && !load) {
253                         nv_output->cached_status = XF86OutputStatusConnected;
254                         connected = sor;
255                 } else {
256                         nv_output->cached_status = XF86OutputStatusDisconnected;
257                 }
258         }
259
260         if(connected)
261                 xf86OutputSetEDID(connected, monInfo);
262 }
263
264 /*
265  * Reset the cached output status for all outputs.  Called from NV50BlockHandler.
266  */
267 void
268 NV50OutputResetCachedStatus(ScrnInfoPtr pScrn)
269 {
270         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
271         int i;
272
273         for(i = 0; i < xf86_config->num_output; i++) {
274                 NV50OutputPrivPtr nv_output = xf86_config->output[i]->driver_private;
275                 nv_output->cached_status = XF86OutputStatusUnknown;
276         }
277 }
278
279 DisplayModePtr
280 NV50OutputGetDDCModes(xf86OutputPtr output)
281 {
282         /* The EDID is read as part of the detect step */
283         output->funcs->detect(output);
284         return xf86OutputGetEDIDModes(output);
285 }
286
287 void
288 NV50OutputDestroy(xf86OutputPtr output)
289 {
290         NV50OutputPrivPtr nv_output = output->driver_private;
291
292         if(nv_output->partner)
293                 ((NV50OutputPrivPtr)nv_output->partner->driver_private)->partner = NULL;
294         else
295                 xf86DestroyI2CBusRec(nv_output->i2c, TRUE, TRUE);
296         nv_output->i2c = NULL;
297 }
298
299 Bool
300 NV50CreateOutputs(ScrnInfoPtr pScrn)
301 {
302         NVPtr pNv = NVPTR(pScrn);
303         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
304         int i;
305
306         if(!NV50ReadPortMapping(pScrn->scrnIndex, pNv))
307                 return FALSE;
308
309         /* For each DDC port, create an output for the attached ORs */
310         for (i = 0; i < 4; i++) {
311                 xf86OutputPtr dac = NULL, sor = NULL;
312                 I2CBusPtr i2c;
313                 char i2cName[16];
314
315                 if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1) {
316                         /* No outputs on this port */
317                         continue;
318                 }
319
320                 snprintf(i2cName, sizeof(i2cName), "I2C%i", i);
321                 i2c = NV50I2CInit(pScrn, i2cName, i);
322                 if (!i2c) {
323                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
324                                 "Failed to initialize I2C for port %i.\n",
325                                 i);
326                         continue;
327                 }
328
329                 if (pNv->i2cMap[i].dac != -1)
330                         dac = NV50CreateDac(pScrn, pNv->i2cMap[i].dac);
331                 if (pNv->i2cMap[i].sor != -1)
332                         sor = NV50CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS);
333
334                 if (dac) {
335                         NV50OutputPrivPtr nv_output = dac->driver_private;
336
337                         nv_output->partner = sor;
338                         nv_output->i2c = i2c;
339                         nv_output->scale = NV50_SCALE_OFF;
340                 }
341                 if (sor) {
342                         NV50OutputPrivPtr nv_output = sor->driver_private;
343
344                         nv_output->partner = dac;
345                         nv_output->i2c = i2c;
346                         nv_output->scale = NV50_SCALE_ASPECT;
347                 }
348         }
349
350         if (pNv->lvds.present) {
351                 xf86OutputPtr lvds = NV50CreateSor(pScrn, pNv->lvds.or, LVDS);
352                 NV50OutputPrivPtr nv_output = lvds->driver_private;
353
354                 nv_output->scale = NV50_SCALE_ASPECT;
355         }
356
357         /* For each output, set the crtc and clone masks */
358         for(i = 0; i < xf86_config->num_output; i++) {
359                 xf86OutputPtr output = xf86_config->output[i];
360
361                 /* Any output can connect to any head */
362                 output->possible_crtcs = 0x3;
363                 output->possible_clones = 0;
364         }
365
366         return TRUE;
367 }
368