1/*
2 * Acceleration for the Creator and Creator3D framebuffer - DDC support.
3 *
4 * Copyright (C) 2000 David S. Miller (davem@redhat.com)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "ffb.h"
30
31#include "ffb_dac.h"
32
33#include "xf86.h"
34#include "xf86_OSproc.h"
35
36#include "xf86DDC.h"
37
38/* XXX This needs a lot more work.  Only an attempt at the PAC2 version
39 * XXX is below, and that is untested.  The BT498 manual is unclear about
40 * XXX several details and I must figure them out by trial and error.
41 */
42
43/* Wait for the next VSYNC. */
44static void
45WaitForVSYNC(ffb_dacPtr dac)
46{
47	unsigned int vsap = DACCFG_READ(dac, FFBDAC_CFG_VSAP);
48	unsigned int vcnt;
49
50	vcnt = DACCFG_READ(dac, FFBDAC_CFG_TGVC);
51	while (vcnt > vsap)
52		vcnt = DACCFG_READ(dac, FFBDAC_CFG_TGVC);
53	while (vcnt <= vsap)
54		vcnt = DACCFG_READ(dac, FFBDAC_CFG_TGVC);
55
56}
57
58/* The manual seems to imply this is needed, but it's really clumsy
59 * so we can test if it really is a requirement with this.
60 */
61#define MDATA_NEEDS_BLANK
62
63/* DDC1/DDC2 support */
64static unsigned int
65FFBDacDdc1Read(ScrnInfoPtr pScrn)
66{
67	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
68	ffb_dacPtr dac = pFfb->dac;
69	unsigned int val;
70#ifdef MDATA_NEEDS_BLANK
71	unsigned int uctrl;
72#endif
73
74#ifdef MDATA_NEEDS_BLANK
75	/* Force a blank of the screen. */
76	uctrl = DACCFG_READ(dac, FFBDAC_CFG_UCTRL);
77	DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL,
78			  (uctrl | FFBDAC_UCTRL_ABLANK));
79#endif
80
81	/* Tristate SCL pin. */
82	DACCFG_WRITE(dac, FFBDAC_CFG_MPDATA,
83			  FFBDAC_CFG_MPDATA_SCL);
84
85	/* Pause until VSYNC is hit. */
86	WaitForVSYNC(dac);
87
88	/* Read the sense line to see what the monitor is driving
89	 * it at.
90	 */
91	val = DACCFG_READ(dac, FFBDAC_CFG_MPSENSE);
92	val = (val & FFBDAC_CFG_MPSENSE_SCL) ? 1 : 0;
93
94	/* Stop tristating the SCL pin. */
95	DACCFG_WRITE(dac, FFBDAC_CFG_MPDATA, 0);
96
97#ifdef MDATA_NEEDS_BLANK
98	/* Restore UCTRL to unblank the screen. */
99	DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL, uctrl);
100#endif
101
102	/* Return the result and we're done. */
103	return val;
104}
105
106static void
107FFBI2CGetBits(I2CBusPtr b, int *clock, int *data)
108{
109	FFBPtr pFfb = GET_FFB_FROM_SCRN(xf86Screens[b->scrnIndex]);
110	ffb_dacPtr dac = pFfb->dac;
111	unsigned int val;
112#ifdef MDATA_NEEDS_BLANK
113	unsigned int uctrl;
114#endif
115
116#ifdef MDATA_NEEDS_BLANK
117	/* Force a blank of the screen. */
118	uctrl = DACCFG_READ(dac, FFBDAC_CFG_UCTRL);
119	DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL,
120			  (uctrl | FFBDAC_UCTRL_ABLANK));
121#endif
122
123	/* Tristate SCL+SDA pins. */
124	DACCFG_WRITE(dac, FFBDAC_CFG_MPDATA,
125		     (FFBDAC_CFG_MPDATA_SCL | FFBDAC_CFG_MPDATA_SDA));
126
127	/* Read the sense line to see what the monitor is driving
128	 * them at.
129	 */
130	val = DACCFG_READ(dac, FFBDAC_CFG_MPSENSE);
131	*clock = (val & FFBDAC_CFG_MPSENSE_SCL) ? 1 : 0;
132	*data  = (val & FFBDAC_CFG_MPSENSE_SDA) ? 1 : 0;
133
134	/* Stop tristating the SCL pin. */
135	DACCFG_WRITE(dac, FFBDAC_CFG_MPDATA, 0);
136
137#ifdef MDATA_NEEDS_BLANK
138	/* Restore UCTRL to unblank the screen. */
139	DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL, uctrl);
140#endif
141}
142
143static void
144FFBI2CPutBits(I2CBusPtr b, int clock, int data)
145{
146	FFBPtr pFfb = GET_FFB_FROM_SCRN(xf86Screens[b->scrnIndex]);
147	ffb_dacPtr dac = pFfb->dac;
148	unsigned int val;
149#ifdef MDATA_NEEDS_BLANK
150	unsigned int uctrl;
151#endif
152
153	val = 0;
154	if (clock)
155		val |= FFBDAC_CFG_MPDATA_SCL;
156	if (data)
157		val |= FFBDAC_CFG_MPDATA_SDA;
158
159#ifdef MDATA_NEEDS_BLANK
160	/* Force a blank of the screen. */
161	uctrl = DACCFG_READ(dac, FFBDAC_CFG_UCTRL);
162	DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL,
163			  (uctrl | FFBDAC_UCTRL_ABLANK));
164#endif
165
166	/* Tristate requested pins. */
167	DACCFG_WRITE(dac, FFBDAC_CFG_MPDATA, val);
168
169#ifdef MDATA_NEEDS_BLANK
170	/* Restore UCTRL to unblank the screen. */
171	DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL, uctrl);
172#endif
173}
174
175Bool
176FFBi2cInit(ScrnInfoPtr pScrn)
177{
178	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
179	I2CBusPtr I2CPtr;
180
181	I2CPtr = xf86CreateI2CBusRec();
182	if (!I2CPtr)
183		return FALSE;
184
185	pFfb->I2C = I2CPtr;
186
187	I2CPtr->BusName		= "DDC";
188	I2CPtr->scrnIndex	= pScrn->scrnIndex;
189	I2CPtr->I2CPutBits	= FFBI2CPutBits;
190	I2CPtr->I2CGetBits	= FFBI2CGetBits;
191	I2CPtr->AcknTimeout	= 5;
192
193	if (!xf86I2CBusInit(I2CPtr))
194		return FALSE;
195
196	return TRUE;
197}
198