geode_ddc.c revision 04007eba
1/* Copyright (c) 2003-2007 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "xf86.h"
31#include "xf86Modes.h"
32#include "compiler.h"
33#include "geode.h"
34
35#ifdef XSERVER_LIBPCIACCESS
36#include <pciaccess.h>
37#endif
38
39/* GPIO Register defines from the CS5536 datasheet */
40
41#define GPIO_OUT        0x00
42#define GPIO_OUT_ENABLE 0x04
43#define GPIO_OUT_AUX1   0x10
44#define GPIO_IN_ENABLE  0x20
45#define GPIO_IN         0x30
46#define GPIO_IN_AUX1    0x34
47
48/* The DDC pins are defined to be on GPIO pins 3 and 4 */
49#define DDC_SCL_PIN  (1 << 3)
50#define DDC_SDA_PIN  (1 << 4)
51
52#define DDC_DATA_HIGH    DDC_SDA_PIN
53#define DDC_DATA_LOW     (DDC_SDA_PIN << 16)
54
55#define DDC_CLK_HIGH     DDC_SCL_PIN
56#define DDC_CLK_LOW      (DDC_SCL_PIN << 16)
57
58#define CS5536_ISA_DEVICE 0x20901022
59#define CS5535_ISA_DEVICE 0x002b100b
60
61static unsigned short
62geode_gpio_iobase(void)
63{
64#ifdef XSERVER_LIBPCIACCESS
65    struct pci_device *pci;
66
67    /* The CS5536 GPIO device is always in the same slot: 00:0f.0 */
68    /* The CS5535 device should be in same slot as well */
69
70    pci = pci_device_find_by_slot(0, 0, 0xF, 0x0);
71
72    if (pci == NULL)
73        return 0;
74
75    if (pci_device_probe(pci) != 0)
76        return 0;
77
78    /* The GPIO I/O address is in resource 1 */
79    return (unsigned short) pci->regions[1].base_addr;
80#else
81    PCITAG Tag;
82
83    Tag = pciFindFirst(CS5536_ISA_DEVICE, 0xFFFFFFFF);
84
85    if (Tag == PCI_NOT_FOUND) {
86        Tag = pciFindFirst(CS5535_ISA_DEVICE, 0xFFFFFFFF);
87
88        if (Tag == PCI_NOT_FOUND)
89            return 0;
90    }
91
92    /* The GPIO I/O address is in resource 1 */
93    return (unsigned short) (pciReadLong(Tag, 0x14) & ~1);
94#endif
95}
96
97static void
98geode_ddc_putbits(I2CBusPtr b, int scl, int sda)
99{
100    unsigned long iobase = (unsigned long) b->DriverPrivate.ptr;
101    unsigned long dat;
102
103    dat = scl ? DDC_CLK_HIGH : DDC_CLK_LOW;
104    dat |= sda ? DDC_DATA_HIGH : DDC_DATA_LOW;
105
106    outl(iobase + GPIO_OUT, dat);
107}
108
109static void
110geode_ddc_getbits(I2CBusPtr b, int *scl, int *sda)
111{
112    unsigned long iobase = (unsigned long) b->DriverPrivate.ptr;
113    unsigned long dat = inl(iobase + GPIO_IN);
114
115    *scl = (dat & DDC_CLK_HIGH) ? 1 : 0;
116    *sda = (dat & DDC_DATA_HIGH) ? 1 : 0;
117}
118
119Bool
120GeodeI2CInit(ScrnInfoPtr pScrni, I2CBusPtr * ptr, char *name)
121{
122    I2CBusPtr bus;
123    unsigned int ddciobase;
124
125    ddciobase = geode_gpio_iobase();
126
127    if (ddciobase == 0) {
128        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
129                   "Could not find the GPIO I/O base\n");
130        return FALSE;
131    }
132
133    /* The GPIO pins for DDC are multiplexed with a
134     * serial port.  If that serial port is enabled, then
135     * assume that there is no DDC on the board
136     */
137
138    if ((inl(ddciobase + GPIO_IN_AUX1) & DDC_CLK_HIGH) ||
139        (inl(ddciobase + GPIO_OUT_AUX1) & DDC_DATA_HIGH)) {
140        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
141                   "GPIO pins are in serial mode.  Assuming no DDC\n");
142        return FALSE;
143    }
144
145    outl(ddciobase + GPIO_OUT_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH);
146    outl(ddciobase + GPIO_IN_ENABLE, DDC_DATA_HIGH | DDC_CLK_HIGH);
147
148    bus = xf86CreateI2CBusRec();
149
150    if (!bus)
151        return FALSE;
152
153    bus->BusName = name;
154    bus->scrnIndex = pScrni->scrnIndex;
155
156    bus->I2CGetBits = geode_ddc_getbits;
157    bus->I2CPutBits = geode_ddc_putbits;
158    bus->DriverPrivate.ptr = (void *) (unsigned long) (ddciobase);
159
160    if (!xf86I2CBusInit(bus))
161        return FALSE;
162
163    *ptr = bus;
164    return TRUE;
165}
166
167static xf86MonPtr
168GeodeGetDDC(ScrnInfoPtr pScrni)
169{
170    xf86MonPtr mon = NULL;
171    I2CBusPtr bus;
172
173    if (!GeodeI2CInit(pScrni, &bus, "CS5536 DDC BUS"))
174        return NULL;
175
176    mon = xf86DoEDID_DDC2(DDC_CALL(pScrni), bus);
177
178#if (XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,0,0))
179    if (mon)
180        xf86DDCApplyQuirks(pScrni->scrnIndex, mon);
181#endif
182
183    xf86DestroyI2CBusRec(bus, FALSE, FALSE);
184
185    return mon;
186}
187
188void
189GeodeProbeDDC(ScrnInfoPtr pScrni, int index)
190{
191    ConfiguredMonitor = GeodeGetDDC(pScrni);
192}
193
194xf86MonPtr
195GeodeDoDDC(ScrnInfoPtr pScrni, int index)
196{
197    xf86MonPtr info = NULL;
198
199    info = GeodeGetDDC(pScrni);
200    xf86PrintEDID(info);
201    xf86SetDDCproperties(pScrni, info);
202    return info;
203}
204