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 void 99 Savage_GetPanelInfo() 100 { 101 SharedInfo& si = *gInfo.sharedInfo; 102 103 enum ACTIVE_DISPLAYS { // these are the bits in CR6B 104 ActiveCRT = 0x01, 105 ActiveLCD = 0x02, 106 ActiveTV = 0x04, 107 ActiveCRT2 = 0x20, 108 ActiveDUO = 0x80 109 }; 110 111 // Check LCD panel information. 112 113 uint8 cr6b = ReadCrtcReg(0x6b); 114 115 int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8; 116 int panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1; 117 118 // A Savage IX/MV in a Thinkpad T22 or SuperSavage in a Thinkpad T23 with 119 // a 1400x1050 display will return a width of 1408; thus, in this case, 120 // set the width to the correct value of 1400. 121 122 if (panelX == 1408) 123 panelX = 1400; 124 125 char* sTechnology; 126 127 if ((ReadSeqReg(0x39) & 0x03) == 0) 128 sTechnology = "TFT"; 129 else if ((ReadSeqReg(0x30) & 0x01) == 0) 130 sTechnology = "DSTN"; 131 else 132 sTechnology = "STN"; 133 134 TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology, 135 cr6b & ActiveLCD ? "and active" : "but not active"); 136 137 if (cr6b & ActiveLCD) { 138 TRACE("Limiting max video mode to %dx%d\n", panelX, panelY); 139 si.panelX = panelX; 140 si.panelY = panelY; 141 } else { 142 si.displayType = MT_CRT; 143 } 144 } 145 146 147 status_t 148 Savage_Init(void) 149 { 150 TRACE("Savage_Init()\n"); 151 152 SharedInfo& si = *gInfo.sharedInfo; 153 154 // MMIO should be automatically enabled for Savage chips; thus, use MMIO 155 // to enable VGA and turn color on. 156 157 WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01); 158 WriteMiscOutReg(ReadMiscOutReg() | 0x01); // turn color on 159 160 if (si.chipType >= S3_SAVAGE4) 161 WriteCrtcReg(0x40, 0x01, 0x01); 162 163 WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 164 WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F 165 WriteCrtcReg(0x39, 0xa0); // unlock sys regs CR40~CRFF 166 WriteSeqReg(0x08, 0x06); // unlock sequencer regs SR09~SRFF 167 168 WriteCrtcReg(0x40, 0x00, 0x01); 169 WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F 170 171 // Compute the amount of video memory and offscreen memory. 172 173 static const uint8 RamSavage3D[] = { 8, 4, 4, 2 }; 174 static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; 175 static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; 176 static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 }; 177 uint32 ramSizeMB = 0; // memory size in megabytes 178 179 uint8 cr36 = ReadCrtcReg(0x36); // get amount of video ram 180 181 switch (si.chipType) { 182 case S3_SAVAGE_3D: 183 ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ]; 184 break; 185 186 case S3_SAVAGE4: 187 // The Savage4 has one ugly special case to consider. On 188 // systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB 189 // when it really means 8MB. Why do it the same when you 190 // can do it different... 191 if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6)) 192 RamSavage4[1] = 8; 193 194 // FALL THROUGH 195 196 case S3_SAVAGE2000: 197 ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ]; 198 break; 199 200 case S3_SAVAGE_MX: 201 case S3_SUPERSAVAGE: 202 ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ]; 203 break; 204 205 case S3_PROSAVAGE: 206 case S3_PROSAVAGE_DDR: 207 case S3_TWISTER: 208 ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ]; 209 break; 210 211 default: 212 // How did we get here? 213 ramSizeMB = 0; 214 break; 215 } 216 217 uint32 usableMB = ramSizeMB; 218 219 220 // If a Savage MX chip has > 8 MB, clamp it at 8 MB since memory for the 221 // hardware cursor above 8 MB is unusable. 222 223 if (si.chipType == S3_SAVAGE_MX && ramSizeMB > 8) 224 usableMB = 8; 225 226 TRACE("Savage_Init() memory size: %d MB, usable memory: %d MB\n", ramSizeMB, usableMB); 227 228 if (usableMB <= 0) 229 return B_ERROR; 230 231 si.videoMemSize = usableMB * 1024 * 1024; 232 233 // Compute the Command Overflow Buffer (COB) location. 234 235 uint32 cobSize = 0x20000; // use 128kB for the COB 236 si.cobSizeIndex = 7; 237 238 // Note that the X.org developers stated that the command overflow buffer 239 // (COB) must END at a 4MB boundary which for all practical purposes means 240 // the very end of the video memory. 241 242 si.cobOffset = (si.videoMemSize - cobSize) & ~0x1ffff; // align cob to 128k 243 si.cursorOffset = (si.cobOffset - CURSOR_BYTES) & ~0xfff; // align to 4k boundary 244 si.frameBufferOffset = 0; 245 si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset; 246 247 TRACE("cobSizeIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobSizeIndex, cobSize, si.cobOffset); 248 TRACE("cursorOffset: 0x%x frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset); 249 250 // Reset graphics engine to avoid memory corruption. 251 252 WriteCrtcReg(0x66, 0x02, 0x02); // set reset flag 253 snooze(10000); 254 WriteCrtcReg(0x66, 0x00, 0x02); // clear reset flag 255 snooze(10000); 256 257 // Check for DVI/flat panel. 258 259 bool bDvi = false; 260 if (si.chipType == S3_SAVAGE4) { 261 WriteSeqReg(0x30, 0x00, 0x02); // clear bit 1 262 if (ReadSeqReg(0x30) & 0x02 /* 0x04 */) { 263 bDvi = true; 264 TRACE("Digital Flat Panel Detected\n"); 265 } 266 } 267 268 if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) { 269 si.displayType = MT_LCD; 270 Savage_GetPanelInfo(); 271 } 272 else if (bDvi) 273 si.displayType = MT_DFP; 274 else 275 si.displayType = MT_CRT; 276 277 TRACE("Display Type: %d\n", si.displayType); 278 279 // Detect current mclk. 280 281 WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs 282 283 uint8 m = ReadSeqReg(0x11) & 0x7f; 284 uint8 n = ReadSeqReg(0x10); 285 uint8 n1 = n & 0x1f; 286 uint8 n2 = (n >> 5) & 0x03; 287 si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100; 288 289 TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0); 290 291 // Set up the array of color spaces supported by the Savage chips. 292 293 si.colorSpaces[0] = B_CMAP8; 294 si.colorSpaces[1] = B_RGB16; 295 si.colorSpaces[2] = B_RGB32; 296 si.colorSpaceCount = 3; 297 298 si.bDisableHdwCursor = false; // allow use of hardware cursor 299 si.bDisableAccelDraw = false; // allow use of accelerated drawing functions 300 301 // Setup the mode list. 302 303 return CreateModeList(IsModeUsable, Savage_GetEdidInfo); 304 } 305 306 307 void 308 Savage_SetFunctionPointers(void) 309 { 310 // Setting the function pointers must be done prior to first ModeInit call 311 // or any accel activity. 312 313 switch (gInfo.sharedInfo->chipType) { 314 case S3_SAVAGE_3D: 315 case S3_SAVAGE_MX: 316 gInfo.WaitQueue = WaitQueue3D; 317 gInfo.WaitIdleEmpty = WaitIdleEmpty3D; 318 break; 319 320 case S3_SAVAGE4: 321 case S3_PROSAVAGE: 322 case S3_SUPERSAVAGE: 323 case S3_PROSAVAGE_DDR: 324 case S3_TWISTER: 325 gInfo.WaitQueue = WaitQueue4; 326 gInfo.WaitIdleEmpty = WaitIdleEmpty4; 327 break; 328 329 case S3_SAVAGE2000: 330 gInfo.WaitQueue = WaitQueue2K; 331 gInfo.WaitIdleEmpty = WaitIdleEmpty2K; 332 break; 333 } 334 335 gInfo.DPMSCapabilities = Savage_DPMSCapabilities; 336 gInfo.GetDPMSMode = Savage_GetDPMSMode; 337 gInfo.SetDPMSMode = Savage_SetDPMSMode; 338 339 gInfo.LoadCursorImage = Savage_LoadCursorImage; 340 gInfo.SetCursorPosition = Savage_SetCursorPosition; 341 gInfo.ShowCursor = Savage_ShowCursor; 342 343 gInfo.FillRectangle = Savage_FillRectangle; 344 gInfo.FillSpan = Savage_FillSpan; 345 gInfo.InvertRectangle = Savage_InvertRectangle; 346 gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit; 347 348 gInfo.AdjustFrame = Savage_AdjustFrame; 349 gInfo.ChipInit = Savage_Init; 350 gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams; 351 gInfo.SetDisplayMode = Savage_SetDisplayMode; 352 gInfo.SetIndexedColors = Savage_SetIndexedColors; 353 } 354 355