1fc5a983dSmrg/*
2fc5a983dSmrg * Copyright (c) 2007-2008 NVIDIA, Corporation
3fc5a983dSmrg *
4fc5a983dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5fc5a983dSmrg * copy of this software and associated documentation files (the
6fc5a983dSmrg * "Software"), to deal in the Software without restriction, including
7fc5a983dSmrg * without limitation the rights to use, copy, modify, merge, publish,
8fc5a983dSmrg * distribute, sublicense, and/or sell copies of the Software, and to
9fc5a983dSmrg * permit persons to whom the Software is furnished to do so, subject to
10fc5a983dSmrg * the following conditions:
11fc5a983dSmrg *
12fc5a983dSmrg * The above copyright notice and this permission notice shall be included
13fc5a983dSmrg * in all copies or substantial portions of the Software.
14fc5a983dSmrg *
15fc5a983dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16fc5a983dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17fc5a983dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18fc5a983dSmrg * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19fc5a983dSmrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20fc5a983dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21fc5a983dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22fc5a983dSmrg */
23fc5a983dSmrg
24fc5a983dSmrg
25fc5a983dSmrg#ifdef HAVE_CONFIG_H
26fc5a983dSmrg#include "config.h"
27fc5a983dSmrg#endif
28fc5a983dSmrg
29fc5a983dSmrg#include <strings.h>
30fc5a983dSmrg
31fc5a983dSmrg#include "g80_type.h"
32fc5a983dSmrg#include "g80_display.h"
33fc5a983dSmrg#include "g80_output.h"
34fc5a983dSmrg
35fc5a983dSmrgstatic unsigned G80FindLoadVal(const unsigned char *table1)
36fc5a983dSmrg{
37fc5a983dSmrg    const unsigned char *p = table1;
38fc5a983dSmrg    int count;
39fc5a983dSmrg    const CARD32 def = 340;
40fc5a983dSmrg
41fc5a983dSmrg    for(p = table1; *(CARD16*)p != 0xb8ff && p < table1 + 64000; p += 2);
42fc5a983dSmrg    if(p == table1 + 64000)
43fc5a983dSmrg        return def;
44fc5a983dSmrg    p += 2;
45fc5a983dSmrg    if(*(CARD32*)p != 0x544942)
46fc5a983dSmrg        return def;
47fc5a983dSmrg    p += 4;
48fc5a983dSmrg    if(*(CARD16*)p != 0x100)
49fc5a983dSmrg        return def;
50fc5a983dSmrg    p += 2;
51fc5a983dSmrg    if(*p != 12)
52fc5a983dSmrg        return def;
53fc5a983dSmrg    p++;
54fc5a983dSmrg    if(*p != 6)
55fc5a983dSmrg        return def;
56fc5a983dSmrg    p++;
57fc5a983dSmrg    count = *p;
58fc5a983dSmrg    p += 2;
59fc5a983dSmrg    for(; *p != 'A' && count >= 0; count--, p += 6);
60fc5a983dSmrg    if(count == -1)
61fc5a983dSmrg        return def;
62fc5a983dSmrg    p += 4;
63fc5a983dSmrg    p = table1 + *(CARD16*)p;
64fc5a983dSmrg    p = table1 + *(CARD16*)p;
65fc5a983dSmrg    if(p[0] != 0x10 || p[1] != 4 || p[2] != 4 || p[3] != 2)
66fc5a983dSmrg        return def;
67fc5a983dSmrg    return *(CARD32*)(p + 4) & 0x3ff;
68fc5a983dSmrg}
69fc5a983dSmrg
70fc5a983dSmrgstatic Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
71fc5a983dSmrg{
72fc5a983dSmrg    unsigned char *table2, *table3;
73fc5a983dSmrg    unsigned char headerSize, entries, table3Entries, table3EntSize;
74fc5a983dSmrg    int i;
75fc5a983dSmrg    CARD16 a;
76fc5a983dSmrg    CARD32 b;
77fc5a983dSmrg
78fc5a983dSmrg    /* Clear the i2c map to invalid */
79fc5a983dSmrg    for(i = 0; i < G80_NUM_I2C_PORTS; i++)
80fc5a983dSmrg        pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
81fc5a983dSmrg
82fc5a983dSmrg    if(*(CARD16*)pNv->table1 != 0xaa55) goto fail;
83fc5a983dSmrg
84fc5a983dSmrg    a = *(CARD16*)(pNv->table1 + 0x36);
85fc5a983dSmrg    table2 = (unsigned char*)pNv->table1 + a;
86fc5a983dSmrg
87fc5a983dSmrg    if(table2[0] != 0x40) goto fail;
88fc5a983dSmrg
89fc5a983dSmrg    b = *(CARD32*)(table2 + 6);
90fc5a983dSmrg    if(b != 0x4edcbdcb) goto fail;
91fc5a983dSmrg
92fc5a983dSmrg    table3 = (unsigned char*)pNv->table1 + *(CARD16*)(table2 + 4);
93fc5a983dSmrg    table3Entries = table3[2];
94fc5a983dSmrg    table3EntSize = table3[3];
95fc5a983dSmrg    table3 += table3[1];
96fc5a983dSmrg
97fc5a983dSmrg    headerSize = table2[1];
98fc5a983dSmrg    entries = table2[2];
99fc5a983dSmrg
100fc5a983dSmrg    for(i = 0; i < entries; i++) {
101fc5a983dSmrg        int type, port, portType;
102fc5a983dSmrg        ORNum or;
103fc5a983dSmrg
104fc5a983dSmrg        b = *(CARD32*)&table2[headerSize + 8*i];
105fc5a983dSmrg        type = b & 0xf;
106fc5a983dSmrg        port = (b >> 4) & 0xf;
107fc5a983dSmrg        or = ffs((b >> 24) & 0xf) - 1;
108fc5a983dSmrg
10971ba42d0Smrg        if(b & 0x300000) {
110fc5a983dSmrg            /* Can't handle this type of output yet */
11171ba42d0Smrg            xf86DrvMsg(scrnIndex, X_INFO,
11271ba42d0Smrg                       "Ignoring unsupported external output type %d at output "
11371ba42d0Smrg                       "%d\n", type, or);
114fc5a983dSmrg            continue;
11571ba42d0Smrg        }
116fc5a983dSmrg
117fc5a983dSmrg        if(type == 0xe) break;
118fc5a983dSmrg
119fc5a983dSmrg        switch(type) {
120fc5a983dSmrg            case 0: /* CRT */
121fc5a983dSmrg                if(port >= table3Entries) {
122fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
123fc5a983dSmrg                               "VGA%d: invalid port %d\n", or, port);
124fc5a983dSmrg                    break;
125fc5a983dSmrg                }
126fc5a983dSmrg                b = *(CARD32*)&table3[table3EntSize * port];
127fc5a983dSmrg                port = b & 0xff;
128fc5a983dSmrg                portType = b >> 24;
129fc5a983dSmrg                if(portType != 5) {
130fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
131fc5a983dSmrg                               "VGA%d: invalid port type %d\n", or, portType);
132fc5a983dSmrg                    break;
133fc5a983dSmrg                }
134bd2f6fc9Smrg                if(port >= G80_NUM_I2C_PORTS) {
135bd2f6fc9Smrg                    xf86DrvMsg(scrnIndex, X_WARNING,
136bd2f6fc9Smrg                               "VGA%d: unrecognized port %d\n", or, port);
137bd2f6fc9Smrg                    break;
138bd2f6fc9Smrg                }
1392eed41b2Sapb                if(pNv->i2cMap[port].dac != (ORNum)-1) {
140fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
141fc5a983dSmrg                               "DDC routing table corrupt!  DAC %i -> %i for "
142fc5a983dSmrg                               "port %i\n", or, pNv->i2cMap[port].dac, port);
143fc5a983dSmrg                }
144fc5a983dSmrg                pNv->i2cMap[port].dac = or;
145fc5a983dSmrg                break;
146fc5a983dSmrg            case 1: /* TV */
14771ba42d0Smrg                xf86DrvMsg(scrnIndex, X_INFO,
14871ba42d0Smrg                           "Ignoring unsupported TV output %d\n", or);
149fc5a983dSmrg                break;
150fc5a983dSmrg
151fc5a983dSmrg            case 2: /* TMDS */
152fc5a983dSmrg                if(port >= table3Entries) {
153fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
154fc5a983dSmrg                               "DVI%d: invalid port %d\n", or, port);
155fc5a983dSmrg                    break;
156fc5a983dSmrg                }
157fc5a983dSmrg                b = *(CARD32*)&table3[table3EntSize * port];
158fc5a983dSmrg                port = b & 0xff;
159fc5a983dSmrg                portType = b >> 24;
160fc5a983dSmrg                if(portType != 5) {
161fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
162fc5a983dSmrg                               "DVI%d: invalid port type %d\n", or, portType);
163fc5a983dSmrg                    break;
164fc5a983dSmrg                }
165bd2f6fc9Smrg                if(port >= G80_NUM_I2C_PORTS) {
166bd2f6fc9Smrg                    xf86DrvMsg(scrnIndex, X_WARNING,
167bd2f6fc9Smrg                               "DVI%d: unrecognized port %d\n", or, port);
168bd2f6fc9Smrg                    break;
169bd2f6fc9Smrg                }
1702eed41b2Sapb                if(pNv->i2cMap[port].sor != (ORNum)-1)
171fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
172fc5a983dSmrg                               "DDC routing table corrupt!  SOR %i -> %i for "
173fc5a983dSmrg                               "port %i\n", or, pNv->i2cMap[port].sor, port);
174fc5a983dSmrg                pNv->i2cMap[port].sor = or;
175fc5a983dSmrg                break;
176fc5a983dSmrg
177fc5a983dSmrg            case 3: /* LVDS */
178fc5a983dSmrg                pNv->lvds.present = TRUE;
179fc5a983dSmrg                pNv->lvds.or = or;
180fc5a983dSmrg                pNv->lvds.i2cPort = -1;
181fc5a983dSmrg
182fc5a983dSmrg                if(port == 15) {
183fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_INFO, "LVDS has no I2C port\n");
184fc5a983dSmrg                    break;
185fc5a983dSmrg                }
186fc5a983dSmrg                if(port >= table3Entries) {
187fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
188fc5a983dSmrg                               "LVDS: invalid port %d\n", port);
189fc5a983dSmrg                    break;
190fc5a983dSmrg                }
191fc5a983dSmrg                b = *(CARD32*)&table3[table3EntSize * port];
192fc5a983dSmrg                port = b & 0xff;
193fc5a983dSmrg                portType = b >> 24;
194fc5a983dSmrg                if(portType != 5) {
195fc5a983dSmrg                    xf86DrvMsg(scrnIndex, X_WARNING,
196fc5a983dSmrg                               "LVDS: invalid port type %d\n", portType);
197fc5a983dSmrg                    break;
198fc5a983dSmrg                }
199bd2f6fc9Smrg                if(port >= G80_NUM_I2C_PORTS) {
200bd2f6fc9Smrg                    xf86DrvMsg(scrnIndex, X_WARNING,
201bd2f6fc9Smrg                               "LVDS: unrecognized port %d\n", port);
202bd2f6fc9Smrg                    break;
203bd2f6fc9Smrg                }
204fc5a983dSmrg                pNv->lvds.i2cPort = port;
205fc5a983dSmrg
206fc5a983dSmrg                break;
207fc5a983dSmrg
20871ba42d0Smrg            case 6: /* DisplayPort */
20971ba42d0Smrg                xf86DrvMsg(scrnIndex, X_INFO,
21071ba42d0Smrg                           "Ignoring unsupported DisplayPort output %d\n", or);
21171ba42d0Smrg                break;
21271ba42d0Smrg
213fc5a983dSmrg            default:
21471ba42d0Smrg                xf86DrvMsg(scrnIndex, X_INFO,
21571ba42d0Smrg                           "Ignoring unsupported output type %d at port %d\n",
21671ba42d0Smrg                           type, or);
217fc5a983dSmrg                break;
218fc5a983dSmrg        }
219fc5a983dSmrg    }
220fc5a983dSmrg
221fc5a983dSmrg    xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
222f3561b8bSmrg    if(pNv->lvds.present) {
223f3561b8bSmrg        if (pNv->lvds.i2cPort != -1)
224f3561b8bSmrg            xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> SOR%i (LVDS)\n", pNv->lvds.i2cPort, pNv->lvds.or);
225f3561b8bSmrg        else
226f3561b8bSmrg            xf86DrvMsg(scrnIndex, X_PROBED, "  [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
227f3561b8bSmrg    }
228fc5a983dSmrg    for(i = 0; i < G80_NUM_I2C_PORTS; i++) {
2292eed41b2Sapb        if(pNv->i2cMap[i].dac != (ORNum)-1)
230fc5a983dSmrg            xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
2312eed41b2Sapb        if(pNv->i2cMap[i].sor != (ORNum)-1)
232fc5a983dSmrg            xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
233fc5a983dSmrg    }
234fc5a983dSmrg
235fc5a983dSmrg    pNv->loadVal = G80FindLoadVal(pNv->table1);
236fc5a983dSmrg    xf86DrvMsg(scrnIndex, X_PROBED, "Load detection: %d\n", pNv->loadVal);
237fc5a983dSmrg
238fc5a983dSmrg    return TRUE;
239fc5a983dSmrg
240fc5a983dSmrgfail:
241fc5a983dSmrg    xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table.  "
242fc5a983dSmrg               "Mode setting will probably fail!\n");
243fc5a983dSmrg    return FALSE;
244fc5a983dSmrg}
245fc5a983dSmrg
246fc5a983dSmrgstatic CARD32 i2cAddr(const int port)
247fc5a983dSmrg{
248bd2f6fc9Smrg    const CARD32 addrs[G80_NUM_I2C_PORTS] = {
249bd2f6fc9Smrg        0xE138, 0xE150, 0xE168, 0xE180, 0xE254, 0xE274, 0xE764, 0xE780, 0xE79C,
250bd2f6fc9Smrg        0xE7B8
251bd2f6fc9Smrg    };
252bd2f6fc9Smrg    return addrs[port];
253fc5a983dSmrg}
254fc5a983dSmrg
255fc5a983dSmrgstatic void G80_I2CPutBits(I2CBusPtr b, int clock, int data)
256fc5a983dSmrg{
25784354367Smrg#ifdef XF86_SCRN_INTERFACE
25884354367Smrg    G80Ptr pNv = G80PTR(b->pScrn);
25984354367Smrg#else
260fc5a983dSmrg    G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
26184354367Smrg#endif
262fc5a983dSmrg    pNv->reg[i2cAddr(b->DriverPrivate.val)/4] = 4 | clock | data << 1;
263fc5a983dSmrg}
264fc5a983dSmrg
265fc5a983dSmrgstatic void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data)
266fc5a983dSmrg{
26784354367Smrg#ifdef XF86_SCRN_INTERFACE
26884354367Smrg    G80Ptr pNv = G80PTR(b->pScrn);
26984354367Smrg#else
270fc5a983dSmrg    G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
27184354367Smrg#endif
272fc5a983dSmrg    unsigned char val;
273fc5a983dSmrg
274fc5a983dSmrg    val = pNv->reg[i2cAddr(b->DriverPrivate.val)/4];
275fc5a983dSmrg    *clock = !!(val & 1);
276fc5a983dSmrg    *data = !!(val & 2);
277fc5a983dSmrg}
278fc5a983dSmrg
279fc5a983dSmrgstatic I2CBusPtr
280fc5a983dSmrgG80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port)
281fc5a983dSmrg{
282fc5a983dSmrg    I2CBusPtr i2c;
283fc5a983dSmrg
284fc5a983dSmrg    /* Allocate the I2C bus structure */
285fc5a983dSmrg    i2c = xf86CreateI2CBusRec();
286fc5a983dSmrg    if(!i2c) return NULL;
287fc5a983dSmrg
288fc5a983dSmrg    i2c->BusName = strdup(name);
289fc5a983dSmrg    i2c->scrnIndex = pScrn->scrnIndex;
29084354367Smrg#ifdef XF86_SCRN_INTERFACE
29184354367Smrg    i2c->pScrn = pScrn;
29284354367Smrg#endif
293fc5a983dSmrg    i2c->I2CPutBits = G80_I2CPutBits;
294fc5a983dSmrg    i2c->I2CGetBits = G80_I2CGetBits;
295fc5a983dSmrg    i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
296fc5a983dSmrg    i2c->StartTimeout = 550;
297fc5a983dSmrg    i2c->BitTimeout = 40;
298fc5a983dSmrg    i2c->ByteTimeout = 40;
299fc5a983dSmrg    i2c->AcknTimeout = 40;
300fc5a983dSmrg    i2c->DriverPrivate.val = port;
301fc5a983dSmrg
302fc5a983dSmrg    if(xf86I2CBusInit(i2c)) {
303fc5a983dSmrg        return i2c;
304fc5a983dSmrg    } else {
3056086d97eSmrg        free(i2c);
306fc5a983dSmrg        return NULL;
307fc5a983dSmrg    }
308fc5a983dSmrg}
309fc5a983dSmrg
310fc5a983dSmrgvoid
311fc5a983dSmrgG80OutputSetPClk(xf86OutputPtr output, int pclk)
312fc5a983dSmrg{
313fc5a983dSmrg    G80OutputPrivPtr pPriv = output->driver_private;
314fc5a983dSmrg    if(pPriv->set_pclk)
315fc5a983dSmrg        pPriv->set_pclk(output, pclk);
316fc5a983dSmrg}
317fc5a983dSmrg
318fc5a983dSmrgint
319fc5a983dSmrgG80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode)
320fc5a983dSmrg{
321fc5a983dSmrg    if(mode->Clock > 400000)
322fc5a983dSmrg        return MODE_CLOCK_HIGH;
323fc5a983dSmrg    if(mode->Clock < 25000)
324fc5a983dSmrg        return MODE_CLOCK_LOW;
325fc5a983dSmrg
326fc5a983dSmrg    return MODE_OK;
327fc5a983dSmrg}
328fc5a983dSmrg
329fc5a983dSmrgvoid
330fc5a983dSmrgG80OutputPrepare(xf86OutputPtr output)
331fc5a983dSmrg{
332fc5a983dSmrg}
333fc5a983dSmrg
334fc5a983dSmrgvoid
335fc5a983dSmrgG80OutputCommit(xf86OutputPtr output)
336fc5a983dSmrg{
337fc5a983dSmrg}
338fc5a983dSmrg
339fc5a983dSmrgstatic xf86MonPtr
340fc5a983dSmrgProbeDDC(I2CBusPtr i2c)
341fc5a983dSmrg{
342fc5a983dSmrg    ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
343fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
344fc5a983dSmrg    xf86MonPtr monInfo = NULL;
345fc5a983dSmrg    const int bus = i2c->DriverPrivate.val;
346fc5a983dSmrg    const CARD32 addr = i2cAddr(bus);
347fc5a983dSmrg
348fc5a983dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
349fc5a983dSmrg            "Probing for EDID on I2C bus %i...\n", bus);
350fc5a983dSmrg    pNv->reg[addr/4] = 7;
351fc5a983dSmrg    /* Should probably use xf86OutputGetEDID here */
352f3561b8bSmrg#ifdef EDID_COMPLETE_RAWDATA
35384354367Smrg    monInfo = xf86DoEEDID(XF86_SCRN_ARG(pScrn), i2c, TRUE);
354f3561b8bSmrg#else
35584354367Smrg    monInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), i2c);
356f3561b8bSmrg#endif
357fc5a983dSmrg    pNv->reg[addr/4] = 3;
358fc5a983dSmrg
359fc5a983dSmrg    if(monInfo) {
360fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
361fc5a983dSmrg                "DDC detected a %s:\n", monInfo->features.input_type ?
362fc5a983dSmrg                "DFP" : "CRT");
363fc5a983dSmrg        xf86PrintEDID(monInfo);
364fc5a983dSmrg    } else {
365fc5a983dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  ... none found\n");
366fc5a983dSmrg    }
367fc5a983dSmrg
368fc5a983dSmrg    return monInfo;
369fc5a983dSmrg}
370fc5a983dSmrg
371fc5a983dSmrg/*
372fc5a983dSmrg * Read an EDID from the i2c port.  Perform load detection on the DAC (if
373fc5a983dSmrg * present) to see if the display is connected via VGA.  Sets the cached status
374fc5a983dSmrg * of both outputs.  The status is marked dirty again in the BlockHandler.
375fc5a983dSmrg */
376fc5a983dSmrgvoid G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c)
377fc5a983dSmrg{
378fc5a983dSmrg    xf86MonPtr monInfo = ProbeDDC(i2c);
379fc5a983dSmrg    xf86OutputPtr connected = NULL;
380fc5a983dSmrg    Bool load = dac && G80DacLoadDetect(dac);
381fc5a983dSmrg
382fc5a983dSmrg    if(dac) {
383fc5a983dSmrg        G80OutputPrivPtr pPriv = dac->driver_private;
384fc5a983dSmrg
385fc5a983dSmrg        if(load) {
386fc5a983dSmrg            pPriv->cached_status = XF86OutputStatusConnected;
387fc5a983dSmrg            connected = dac;
388fc5a983dSmrg        } else {
389fc5a983dSmrg            pPriv->cached_status = XF86OutputStatusDisconnected;
390fc5a983dSmrg        }
391fc5a983dSmrg    }
392fc5a983dSmrg
393fc5a983dSmrg    if(sor) {
394fc5a983dSmrg        G80OutputPrivPtr pPriv = sor->driver_private;
395fc5a983dSmrg
396fc5a983dSmrg        if(monInfo && !load) {
397fc5a983dSmrg            pPriv->cached_status = XF86OutputStatusConnected;
398fc5a983dSmrg            connected = sor;
399fc5a983dSmrg        } else {
400fc5a983dSmrg            pPriv->cached_status = XF86OutputStatusDisconnected;
401fc5a983dSmrg        }
402fc5a983dSmrg    }
403fc5a983dSmrg
404fc5a983dSmrg    if(connected)
405fc5a983dSmrg        xf86OutputSetEDID(connected, monInfo);
406fc5a983dSmrg}
407fc5a983dSmrg
408fc5a983dSmrg/*
409fc5a983dSmrg * Reset the cached output status for all outputs.  Called from G80BlockHandler.
410fc5a983dSmrg */
411fc5a983dSmrgvoid
412fc5a983dSmrgG80OutputResetCachedStatus(ScrnInfoPtr pScrn)
413fc5a983dSmrg{
414fc5a983dSmrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
415fc5a983dSmrg    int i;
416fc5a983dSmrg
417fc5a983dSmrg    for(i = 0; i < xf86_config->num_output; i++) {
418fc5a983dSmrg        G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private;
419fc5a983dSmrg        pPriv->cached_status = XF86OutputStatusUnknown;
420fc5a983dSmrg    }
421fc5a983dSmrg}
422fc5a983dSmrg
423fc5a983dSmrgDisplayModePtr
424fc5a983dSmrgG80OutputGetDDCModes(xf86OutputPtr output)
425fc5a983dSmrg{
426fc5a983dSmrg    /* The EDID is read as part of the detect step */
427fc5a983dSmrg    output->funcs->detect(output);
428fc5a983dSmrg    return xf86OutputGetEDIDModes(output);
429fc5a983dSmrg}
430fc5a983dSmrg
431fc5a983dSmrgvoid
432fc5a983dSmrgG80OutputDestroy(xf86OutputPtr output)
433fc5a983dSmrg{
434fc5a983dSmrg    G80OutputPrivPtr pPriv = output->driver_private;
435fc5a983dSmrg
436fc5a983dSmrg    if(pPriv->partner)
437fc5a983dSmrg        ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL;
438fc5a983dSmrg    else
439fc5a983dSmrg        xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE);
440fc5a983dSmrg    pPriv->i2c = NULL;
441fc5a983dSmrg}
442fc5a983dSmrg
443fc5a983dSmrgBool
444fc5a983dSmrgG80CreateOutputs(ScrnInfoPtr pScrn)
445fc5a983dSmrg{
446fc5a983dSmrg    G80Ptr pNv = G80PTR(pScrn);
447fc5a983dSmrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
448fc5a983dSmrg    int i;
449fc5a983dSmrg
450fc5a983dSmrg    if(!G80ReadPortMapping(pScrn->scrnIndex, pNv))
451fc5a983dSmrg        return FALSE;
452fc5a983dSmrg
453fc5a983dSmrg    /* For each DDC port, create an output for the attached ORs */
454fc5a983dSmrg    for(i = 0; i < G80_NUM_I2C_PORTS; i++) {
455fc5a983dSmrg        xf86OutputPtr dac = NULL, sor = NULL;
456fc5a983dSmrg        I2CBusPtr i2c;
457fc5a983dSmrg        char i2cName[16];
458fc5a983dSmrg
4592eed41b2Sapb        if(pNv->i2cMap[i].dac == (ORNum)-1 && pNv->i2cMap[i].sor == (ORNum)-1)
460fc5a983dSmrg            /* No outputs on this port */
461fc5a983dSmrg            continue;
462fc5a983dSmrg
463fc5a983dSmrg        snprintf(i2cName, sizeof(i2cName), "I2C%i", i);
464fc5a983dSmrg        i2c = G80I2CInit(pScrn, i2cName, i);
465fc5a983dSmrg        if(!i2c) {
466fc5a983dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
467fc5a983dSmrg                       "Failed to initialize I2C for port %i.\n",
468fc5a983dSmrg                       i);
469fc5a983dSmrg            continue;
470fc5a983dSmrg        }
471fc5a983dSmrg
4722eed41b2Sapb        if(pNv->i2cMap[i].dac != (ORNum)-1)
473fc5a983dSmrg            dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac);
4742eed41b2Sapb        if(pNv->i2cMap[i].sor != (ORNum)-1)
475fc5a983dSmrg            sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS);
476fc5a983dSmrg
477fc5a983dSmrg        if(dac) {
478fc5a983dSmrg            G80OutputPrivPtr pPriv = dac->driver_private;
479fc5a983dSmrg
480fc5a983dSmrg            pPriv->partner = sor;
481fc5a983dSmrg            pPriv->i2c = i2c;
482fc5a983dSmrg            pPriv->scale = G80_SCALE_OFF;
483fc5a983dSmrg        }
484fc5a983dSmrg        if(sor) {
485fc5a983dSmrg            G80OutputPrivPtr pPriv = sor->driver_private;
486fc5a983dSmrg
487fc5a983dSmrg            pPriv->partner = dac;
488fc5a983dSmrg            pPriv->i2c = i2c;
489fc5a983dSmrg            pPriv->scale = G80_SCALE_ASPECT;
490fc5a983dSmrg        }
491fc5a983dSmrg    }
492fc5a983dSmrg
493fc5a983dSmrg    if(pNv->lvds.present) {
494fc5a983dSmrg        xf86OutputPtr lvds = G80CreateSor(pScrn, pNv->lvds.or, LVDS);
495fc5a983dSmrg
4966086d97eSmrg        if (lvds) {
4976086d97eSmrg            G80OutputPrivPtr pPriv = lvds->driver_private;
498fc5a983dSmrg
4996086d97eSmrg            pPriv->scale = G80_SCALE_ASPECT;
5006086d97eSmrg
5016086d97eSmrg            if(pNv->lvds.i2cPort != -1) {
5026086d97eSmrg                char i2cName[16];
503fc5a983dSmrg
5046086d97eSmrg                snprintf(i2cName, sizeof(i2cName), "I2C%i (LVDS)", pNv->lvds.i2cPort);
5056086d97eSmrg                pPriv->i2c = G80I2CInit(pScrn, i2cName, pNv->lvds.i2cPort);
5066086d97eSmrg                if(!pPriv->i2c) {
5076086d97eSmrg                    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5086086d97eSmrg                               "Failed to initialize I2C for port %i (LVDS)!\n",
5096086d97eSmrg                               pNv->lvds.i2cPort);
5106086d97eSmrg                }
511fc5a983dSmrg            }
512fc5a983dSmrg        }
513fc5a983dSmrg    }
514fc5a983dSmrg
515fc5a983dSmrg    /* For each output, set the crtc and clone masks */
516fc5a983dSmrg    for(i = 0; i < xf86_config->num_output; i++) {
517fc5a983dSmrg        xf86OutputPtr output = xf86_config->output[i];
518fc5a983dSmrg
519fc5a983dSmrg        /* Any output can connect to any head */
520fc5a983dSmrg        output->possible_crtcs = 0x3;
521fc5a983dSmrg        output->possible_clones = 0;
522fc5a983dSmrg    }
523fc5a983dSmrg
524fc5a983dSmrg    return TRUE;
525fc5a983dSmrg}
526