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