1/* 2Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. 3Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. 4Copyright (C) 2008 Francisco Jerez. All Rights Reserved. 5 6Permission is hereby granted, free of charge, to any person obtaining a copy of 7this software and associated documentation files (the "Software"), to deal in 8the Software without restriction, including without limitation the rights to 9use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10of the Software, and to permit persons to whom the Software is furnished to do 11so, subject to the following conditions: 12 13The above copyright notice and this permission notice shall be included in all 14copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- 18NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the names of The XFree86 Project and 24Silicon Motion shall not be used in advertising or otherwise to promote the 25sale, use or other dealings in this Software without prior written 26authorization from The XFree86 Project or Silicon Motion. 27*/ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include "smi.h" 34#include "smi_crtc.h" 35#include "smilynx.h" 36 37static void 38SMILynx_OutputDPMS_crt(xf86OutputPtr output, int mode) 39{ 40 ScrnInfoPtr pScrn = output->scrn; 41 SMIPtr pSmi = SMIPTR(pScrn); 42 SMIRegPtr reg = pSmi->mode; 43 vgaHWPtr hwp = VGAHWPTR(pScrn); 44 45 ENTER(); 46 47 switch (mode) { 48 case DPMSModeOn: 49 reg->SR31 |= 0x02; /* Enable CRT display*/ 50 reg->SR22 = (reg->SR22 & ~0x30) | 0x00; /* Set DPMS state*/ 51 break; 52 case DPMSModeStandby: 53 reg->SR31 |= 0x02; /* Enable CRT display*/ 54 reg->SR22 = (reg->SR22 & ~0x30) | 0x10; /* Set DPMS state*/ 55 break; 56 case DPMSModeSuspend: 57 reg->SR31 |= 0x02; /* Enable CRT display*/ 58 reg->SR22 = (reg->SR22 & ~0x30) | 0x20; /* Set DPMS state*/ 59 break; 60 case DPMSModeOff: 61 reg->SR31 &= ~0x02; /* Disable CRT display*/ 62 reg->SR22 = (reg->SR22 & ~0x30) | 0x30; /* Set DPMS state*/ 63 break; 64 } 65 66 /* Wait for vertical retrace */ 67 68 while (hwp->readST01(hwp) & 0x8) ; 69 while (!(hwp->readST01(hwp) & 0x8)) ; 70 71 /* Write the registers */ 72 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, reg->SR22); 73 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, reg->SR31); 74 75 LEAVE(); 76 77} 78 79static void 80SMILynx_OutputDPMS_lcd(xf86OutputPtr output, int mode) 81{ 82 ScrnInfoPtr pScrn = output->scrn; 83 SMIPtr pSmi = SMIPTR(pScrn); 84 SMIRegPtr reg = pSmi->mode; 85 xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 86 87 ENTER(); 88 89 switch (mode) { 90 case DPMSModeOn: 91 if(pSmi->Dualhead && 92 output->crtc == crtcConf->crtc[1]){ 93 /* Virtual Refresh is enabled */ 94 95 reg->SR21 &= ~0x10; /* Enable LCD framebuffer read operation and DSTN dithering engine */ 96 }else{ 97 if(pSmi->lcd == 2){ 98 /* LCD is DSTN */ 99 100 reg->SR21 &= ~0x10; /* Enable LCD framebuffer read operation and DSTN dithering engine */ 101 reg->SR21 &= ~0x20; /* Enable LCD framebuffer write operation */ 102 } 103 } 104 105 reg->SR31 |= 0x01; /* Enable LCD display*/ 106 break; 107 case DPMSModeStandby: 108 case DPMSModeSuspend: 109 case DPMSModeOff: 110 reg->SR21 |= 0x30; /* Disable LCD framebuffer r/w operation */ 111 reg->SR31 &= ~0x01; /* Disable LCD display*/ 112 break; 113 } 114 115 /* Write the registers */ 116 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, reg->SR21); 117 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, reg->SR31); 118 119 LEAVE(); 120 121 122} 123 124static void 125SMILynx_OutputDPMS_bios(xf86OutputPtr output, int mode) 126{ 127#ifdef USE_INT10 128 ScrnInfoPtr pScrn = output->scrn; 129 SMIPtr pSmi = SMIPTR(pScrn); 130 131 ENTER(); 132 133 pSmi->pInt10->ax = 0x4F10; 134 switch (mode) { 135 case DPMSModeOn: 136 pSmi->pInt10->bx = 0x0001; 137 break; 138 case DPMSModeStandby: 139 pSmi->pInt10->bx = 0x0101; 140 break; 141 case DPMSModeSuspend: 142 pSmi->pInt10->bx = 0x0201; 143 break; 144 case DPMSModeOff: 145 pSmi->pInt10->bx = 0x0401; 146 break; 147 } 148 pSmi->pInt10->cx = 0x0000; 149 pSmi->pInt10->num = 0x10; 150 xf86ExecX86int10(pSmi->pInt10); 151#endif 152 LEAVE(); 153} 154 155 156static DisplayModePtr 157SMILynx_OutputGetModes_crt(xf86OutputPtr output) 158{ 159 ScrnInfoPtr pScrn = output->scrn; 160 SMIPtr pSmi = SMIPTR(pScrn); 161 xf86MonPtr pMon = NULL; 162 163 ENTER(); 164 165 if(xf86LoaderCheckSymbol("xf86PrintEDID")){ /* Ensure the DDC module is loaded*/ 166 /* Try VBE */ 167 if(pSmi->pVbe){ 168 pMon = vbeDoEDID(pSmi->pVbe, NULL); 169 if ( pMon != NULL && 170 (pMon->rawData[0] == 0x00) && 171 (pMon->rawData[1] == 0xFF) && 172 (pMon->rawData[2] == 0xFF) && 173 (pMon->rawData[3] == 0xFF) && 174 (pMon->rawData[4] == 0xFF) && 175 (pMon->rawData[5] == 0xFF) && 176 (pMon->rawData[6] == 0xFF) && 177 (pMon->rawData[7] == 0x00)) { 178 xf86OutputSetEDID(output,pMon); 179 LEAVE(xf86OutputGetEDIDModes(output)); 180 } 181 } 182 183 /* Try DDC2 */ 184 if(pSmi->I2C){ 185 pMon=xf86OutputGetEDID(output,pSmi->I2C); 186 if(pMon){ 187 xf86OutputSetEDID(output,pMon); 188 LEAVE(xf86OutputGetEDIDModes(output)); 189 } 190 } 191 192 /* Try DDC1 */ 193 pMon=SMILynx_ddc1(pScrn); 194 if(pMon){ 195 xf86OutputSetEDID(output,pMon); 196 LEAVE(xf86OutputGetEDIDModes(output)); 197 } 198 } 199 200 LEAVE(NULL); 201} 202 203static xf86OutputStatus 204SMILynx_OutputDetect_crt(xf86OutputPtr output) 205{ 206 SMIPtr pSmi = SMIPTR(output->scrn); 207 SMIRegPtr mode = pSmi->mode; 208 vgaHWPtr hwp = VGAHWPTR(output->scrn); 209 CARD8 SR7D; 210 Bool status; 211 212 ENTER(); 213 214 SR7D = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x7D); 215 216 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, mode->SR21 & ~0x88); /* Enable DAC and color palette RAM */ 217 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x7B, 0x40); /* "TV and RAMDAC Testing Power", Green component */ 218 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x7D, SR7D | 0x10); /* Enable monitor detect */ 219 220 /* Wait for vertical retrace */ 221 while (!(hwp->readST01(hwp) & 0x8)) ; 222 while (hwp->readST01(hwp) & 0x8) ; 223 224 status = VGAIN8(pSmi, 0x3C2) & 0x10; 225 226 /* Restore previous state */ 227 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, mode->SR21); 228 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x7D, SR7D); 229 230 if(status) 231 LEAVE(XF86OutputStatusConnected); 232 else 233 LEAVE(XF86OutputStatusDisconnected); 234} 235 236Bool 237SMILynx_OutputPreInit(ScrnInfoPtr pScrn) 238{ 239 SMIPtr pSmi = SMIPTR(pScrn); 240 xf86OutputPtr output; 241 xf86OutputFuncsPtr outputFuncs; 242 243 ENTER(); 244 245 if(pSmi->Chipset == SMI_COUGAR3DR){ 246 /* Output 0 is LCD */ 247 SMI_OutputFuncsInit_base(&outputFuncs); 248 249 if(pSmi->useBIOS) 250 outputFuncs->dpms = SMILynx_OutputDPMS_bios; 251 else 252 outputFuncs->dpms = SMILynx_OutputDPMS_lcd; 253 254 outputFuncs->get_modes = SMI_OutputGetModes_native; 255 outputFuncs->detect = SMI_OutputDetect_lcd; 256 257 if(! (output = xf86OutputCreate(pScrn,outputFuncs,"LVDS"))) 258 LEAVE(FALSE); 259 260 output->possible_crtcs = 1 << 0; 261 output->possible_clones = 0; 262 output->interlaceAllowed = FALSE; 263 output->doubleScanAllowed = FALSE; 264 }else{ 265 /* Output 0 is LCD */ 266 SMI_OutputFuncsInit_base(&outputFuncs); 267 268 if(pSmi->useBIOS) 269 outputFuncs->dpms = SMILynx_OutputDPMS_bios; 270 else 271 outputFuncs->dpms = SMILynx_OutputDPMS_lcd; 272 273 outputFuncs->get_modes = SMI_OutputGetModes_native; 274 outputFuncs->detect = SMI_OutputDetect_lcd; 275 276 if(! (output = xf86OutputCreate(pScrn,outputFuncs,"LVDS"))) 277 LEAVE(FALSE); 278 279 output->interlaceAllowed = FALSE; 280 output->doubleScanAllowed = FALSE; 281 output->possible_crtcs = (1 << 0) | (1 << 1); 282 output->possible_clones = 1 << 1; 283 284 if(pSmi->Dualhead){ 285 /* Output 1 is CRT */ 286 SMI_OutputFuncsInit_base(&outputFuncs); 287 outputFuncs->dpms = SMILynx_OutputDPMS_crt; 288 outputFuncs->get_modes = SMILynx_OutputGetModes_crt; 289 290 if(pSmi->Chipset == SMI_LYNX3DM) 291 outputFuncs->detect = SMILynx_OutputDetect_crt; 292 293 if(! (output = xf86OutputCreate(pScrn,outputFuncs,"VGA"))) 294 LEAVE(FALSE); 295 296 output->interlaceAllowed = FALSE; 297 output->doubleScanAllowed = FALSE; 298 299 output->possible_crtcs = 1 << 0; 300 output->possible_clones = 1 << 0; 301 } 302 } 303 304 LEAVE(TRUE); 305} 306 307