1 /* 2 Haiku S3 Savage driver adapted from the X.org Savage driver. 3 4 Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 5 Copyright (c) 2003-2006, X.Org Foundation 6 7 Copyright 2007-2008 Haiku, Inc. All rights reserved. 8 Distributed under the terms of the MIT license. 9 10 Authors: 11 Gerald Zajac 2006-2008 12 */ 13 14 15 #include "accel.h" 16 #include "savage.h" 17 18 19 20 static bool 21 Savage_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock) 22 { 23 // Get parameters for a color space which is supported by the Savage chips. 24 // Argument maxPixelClock is in KHz. 25 // Return true if the color space is supported; else return false. 26 27 switch (colorSpace) { 28 case B_RGB32: 29 bitsPerPixel = 32; 30 maxPixelClock = 220000; 31 break; 32 case B_RGB16: 33 bitsPerPixel = 16; 34 maxPixelClock = 250000; 35 break; 36 case B_CMAP8: 37 bitsPerPixel = 8; 38 maxPixelClock = 250000; 39 break; 40 default: 41 TRACE("Unsupported color space: 0x%X\n", colorSpace); 42 return false; 43 } 44 45 return true; 46 } 47 48 49 // Wait until "v" queue entries are free. 50 51 static void 52 WaitQueue3D(uint32 v) 53 { 54 uint32 slots = MAXFIFO - v; 55 while ((STATUS_WORD0 & 0x0000ffff) > slots); 56 } 57 58 59 static void 60 WaitQueue4(uint32 v) 61 { 62 uint32 slots = MAXFIFO - v; 63 while ((ALT_STATUS_WORD0 & 0x001fffff) > slots); 64 } 65 66 67 static void 68 WaitQueue2K(uint32 v) 69 { 70 uint32 slots = MAXFIFO - v; 71 while ((ALT_STATUS_WORD0 & 0x000fffff) > slots); 72 } 73 74 75 // Wait until GP is idle and queue is empty. 76 77 static void 78 WaitIdleEmpty3D() 79 { 80 while ((STATUS_WORD0 & 0x0008ffff) != 0x80000); 81 } 82 83 84 static void 85 WaitIdleEmpty4() 86 { 87 while ((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) ; 88 } 89 90 91 static void 92 WaitIdleEmpty2K() 93 { 94 while ((ALT_STATUS_WORD0 & 0x009fffff) != 0); 95 } 96 97 98 static bool 99 IsLCDWidthValid(int width) 100 { 101 // Search the array of valid LCD widths to find a width that matches the 102 // width by the caller, and return true if a match is found. 103 104 const int lcdWidths[] = { 640, 800, 1024, 1152, 1280, 1400, 1440, 1600, 1680 }; 105 106 for (int i = 0; i < NUM_ELEMENTS(lcdWidths); i++) { 107 if (lcdWidths[i] == width) 108 return true; 109 } 110 111 return false; // match not found 112 } 113 114 115 static void 116 Savage_GetPanelInfo() 117 { 118 SharedInfo& si = *gInfo.sharedInfo; 119 120 enum ACTIVE_DISPLAYS { // these are the bits in CR6B 121 ActiveCRT = 0x01, 122 ActiveLCD = 0x02, 123 ActiveTV = 0x04, 124 ActiveCRT2 = 0x20, 125 ActiveDUO = 0x80 126 }; 127 128 // Check LCD panel information. 129 130 uint8 cr6b = ReadCrtcReg(0x6b); 131 132 int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8; 133 int panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1; 134 135 if ( ! IsLCDWidthValid(panelX)) { 136 137 // Some chips such as the Savage IX/MV in a Thinkpad T-22 will return 138 // a width that is 8 pixels too wide probably because reg SR61 is set 139 // to a value +1 higher than it should be. Subtract 8 from the width, 140 // and check if that is a valid width. 141 142 panelX -= 8; 143 if ( ! IsLCDWidthValid(panelX)) { 144 TRACE("%dx%d LCD panel width invalid.\n", panelX + 8, panelY); 145 si.displayType = MT_CRT; 146 return; 147 } 148 } 149 150 char* sTechnology; 151 152 if ((ReadSeqReg(0x39) & 0x03) == 0) 153 sTechnology = "TFT"; 154 else if ((ReadSeqReg(0x30) & 0x01) == 0) 155 sTechnology = "DSTN"; 156 else 157 sTechnology = "STN"; 158 159 TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology, 160 cr6b & ActiveLCD ? "and active" : "but not active"); 161 162 if (cr6b & ActiveLCD) { 163 TRACE("Limiting max video mode to %dx%d\n", panelX, panelY); 164 si.panelX = panelX; 165 si.panelY = panelY; 166 } else { 167 si.displayType = MT_CRT; 168 } 169 } 170 171 172 status_t 173 Savage_Init(void) 174 { 175 TRACE("Savage_Init()\n"); 176 177 SharedInfo& si = *gInfo.sharedInfo; 178 179 // MMIO should be automatically enabled for Savage chips; thus, use MMIO 180 // to enable VGA and turn color on. 181 182 WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01); 183 WriteMiscOutReg(ReadMiscOutReg() | 0x01); // turn color on 184 185 if (si.chipType >= S3_SAVAGE4) 186 WriteCrtcReg(0x40, 0x01, 0x01); 187 188 WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 189 WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F 190 WriteCrtcReg(0x39, 0xa0); // unlock sys regs CR40~CRFF 191 WriteSeqReg(0x08, 0x06); // unlock sequencer regs SR09~SRFF 192 193 WriteCrtcReg(0x40, 0x00, 0x01); 194 WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F 195 196 // Compute the amount of video memory and offscreen memory. 197 198 static const uint8 RamSavage3D[] = { 8, 4, 4, 2 }; 199 static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; 200 static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; 201 static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 }; 202 int ramSizeMB = 0; // memory size in megabytes 203 204 uint8 cr36 = ReadCrtcReg(0x36); // get amount of video ram 205 206 switch (si.chipType) { 207 case S3_SAVAGE_3D: 208 ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ]; 209 break; 210 211 case S3_SAVAGE4: 212 // The Savage4 has one ugly special case to consider. On 213 // systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB 214 // when it really means 8MB. Why do it the same when you 215 // can do it different... 216 if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6)) 217 RamSavage4[1] = 8; 218 219 // FALL THROUGH 220 221 case S3_SAVAGE2000: 222 ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ]; 223 break; 224 225 case S3_SAVAGE_MX: 226 case S3_SUPERSAVAGE: 227 ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ]; 228 break; 229 230 case S3_PROSAVAGE: 231 case S3_PROSAVAGE_DDR: 232 case S3_TWISTER: 233 ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ]; 234 break; 235 236 default: 237 // How did we get here? 238 ramSizeMB = 0; 239 break; 240 } 241 242 TRACE("Savage_Init() memory size: %d MB\n", ramSizeMB); 243 244 if (ramSizeMB <= 0) 245 return B_ERROR; 246 247 si.videoMemSize = ramSizeMB * 1024 * 1024; 248 249 250 // Certain Savage4 and ProSavage chips can have coherency problems 251 // with respect to the Command Overflow Buffer (COB); thus, to avoid 252 // problems with these chips, set bDisableCOB to true. 253 254 si.bDisableCOB = false; 255 256 // Compute the Command Overflow Buffer (COB) location. 257 258 if ((S3_SAVAGE4_SERIES(si.chipType) || S3_SUPERSAVAGE == si.chipType) 259 && si.bDisableCOB) { 260 261 // The Savage4 and ProSavage have COB coherency bugs which render 262 // the buffer useless. 263 264 si.cobIndex = 0; 265 si.cobSize = 0; 266 si.bciThresholdHi = 32; 267 si.bciThresholdLo = 0; 268 } else { 269 // We use 128kB for the COB on all other chips. 270 si.cobSize = 0x20000; 271 if (S3_SAVAGE_3D_SERIES(si.chipType) || si.chipType == S3_SAVAGE2000) 272 si.cobIndex = 7; // rev.A savage4 apparently also uses 7 273 else 274 si.cobIndex = 2; 275 276 // Max command size: 2560 entries. 277 si.bciThresholdHi = si.cobSize / 4 + 32 - 2560; 278 si.bciThresholdLo = si.bciThresholdHi - 2560; 279 } 280 281 // Note that the X.org developers stated that the command overflow buffer 282 // (COB) must END at a 4MB boundary which for all practical purposes means 283 // the very end of the video memory. The cursor must be at the beginning 284 // of the video memory. It had been tried immediately preceding the COB, 285 // but the Savage MX chip screws up the cursor in that case. 286 287 si.cobOffset = (si.videoMemSize - si.cobSize) & ~0x1ffff; // align cob to 128k 288 si.cursorOffset = 0; 289 si.frameBufferOffset = si.cursorOffset + CURSOR_BYTES; 290 si.maxFrameBufferSize = si.cobOffset - si.frameBufferOffset; 291 292 TRACE("cobIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobIndex, si.cobSize, si.cobOffset); 293 TRACE("cursorOffset: 0x%x frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset); 294 295 // Reset graphics engine to avoid memory corruption. 296 297 WriteCrtcReg(0x66, 0x02, 0x02); // set reset flag 298 snooze(10000); 299 WriteCrtcReg(0x66, 0x00, 0x02); // clear reset flag 300 snooze(10000); 301 302 // Check for DVI/flat panel. 303 304 bool bDvi = false; 305 if (si.chipType == S3_SAVAGE4) { 306 WriteSeqReg(0x30, 0x00, 0x02); // clear bit 1 307 if (ReadSeqReg(0x30) & 0x02 /* 0x04 */) { 308 bDvi = true; 309 TRACE("Digital Flat Panel Detected\n"); 310 } 311 } 312 313 if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) { 314 si.displayType = MT_LCD; 315 Savage_GetPanelInfo(); 316 } 317 else if (bDvi) 318 si.displayType = MT_DFP; 319 else 320 si.displayType = MT_CRT; 321 322 TRACE("Display Type: %d\n", si.displayType); 323 324 // Detect current mclk. 325 326 WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs 327 328 uint8 m = ReadSeqReg(0x11) & 0x7f; 329 uint8 n = ReadSeqReg(0x10); 330 uint8 n1 = n & 0x1f; 331 uint8 n2 = (n >> 5) & 0x03; 332 si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100; 333 334 TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0); 335 336 // Set up the array of color spaces supported by the Savage chips. 337 338 si.colorSpaces[0] = B_CMAP8; 339 si.colorSpaces[1] = B_RGB16; 340 si.colorSpaces[2] = B_RGB32; 341 si.colorSpaceCount = 3; 342 343 // Get info about the display capabilities (EDID). 344 345 Savage_GetEdidInfo(); 346 347 // Setup the mode list. 348 349 return CreateModeList(IsModeUsable); 350 } 351 352 353 void 354 Savage_SetFunctionPointers(void) 355 { 356 // Setting the function pointers must be done prior to first ModeInit call 357 // or any accel activity. 358 359 switch (gInfo.sharedInfo->chipType) { 360 case S3_SAVAGE_3D: 361 case S3_SAVAGE_MX: 362 gInfo.WaitQueue = WaitQueue3D; 363 gInfo.WaitIdleEmpty = WaitIdleEmpty3D; 364 break; 365 366 case S3_SAVAGE4: 367 case S3_PROSAVAGE: 368 case S3_SUPERSAVAGE: 369 case S3_PROSAVAGE_DDR: 370 case S3_TWISTER: 371 gInfo.WaitQueue = WaitQueue4; 372 gInfo.WaitIdleEmpty = WaitIdleEmpty4; 373 break; 374 375 case S3_SAVAGE2000: 376 gInfo.WaitQueue = WaitQueue2K; 377 gInfo.WaitIdleEmpty = WaitIdleEmpty2K; 378 break; 379 } 380 381 gInfo.DPMSCapabilities = Savage_DPMSCapabilities; 382 gInfo.DPMSMode = Savage_DPMSMode; 383 gInfo.SetDPMSMode = Savage_SetDPMSMode; 384 385 gInfo.LoadCursorImage = Savage_LoadCursorImage; 386 gInfo.SetCursorPosition = Savage_SetCursorPosition; 387 gInfo.ShowCursor = Savage_ShowCursor; 388 389 gInfo.FillRectangle = Savage_FillRectangle; 390 gInfo.FillSpan = Savage_FillSpan; 391 gInfo.InvertRectangle = Savage_InvertRectangle; 392 gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit; 393 394 gInfo.AdjustFrame = Savage_AdjustFrame; 395 gInfo.ChipInit = Savage_Init; 396 gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams; 397 gInfo.SetDisplayMode = Savage_SetDisplayMode; 398 gInfo.SetIndexedColors = Savage_SetIndexedColors; 399 } 400 401