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