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