2 Copyright 2010 Haiku, Inc. All rights reserved.
3 Distributed under the terms of the MIT license.
10 Some of the code in this source file was adapted from the X.org tdfx
11 video driver, and was covered by the following copyright and license.
12 --------------------------------------------------------------------------
14 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
17 Permission is hereby granted, free of charge, to any person obtaining a
18 copy of this software and associated documentation files (the
19 "Software"), to deal in the Software without restriction, including
20 without limitation the rights to use, copy, modify, merge, publish,
21 distribute, sub license, and/or sell copies of the Software, and to
22 permit persons to whom the Software is furnished to do so, subject to
23 the following conditions:
25 The above copyright notice and this permission notice (including the
26 next paragraph) shall be included in all copies or substantial portions
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
32 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
33 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
34 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
35 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 #include "accelerant.h"
45 // Functions to read/write PIO registers.
46 //=======================================
49 WritePIOReg(uint32 offset
, int16 index
, uint8 value
)
52 prInfo
.magic
= TDFX_PRIVATE_DATA_MAGIC
;
53 prInfo
.offset
= offset
;
57 status_t result
= ioctl(gInfo
.deviceFileDesc
, TDFX_SET_PIO_REG
,
58 &prInfo
, sizeof(prInfo
));
60 TRACE("WritePIOReg() failed, result = 0x%x\n", result
);
65 ReadPIOReg(uint32 offset
, int16 index
)
68 prInfo
.magic
= TDFX_PRIVATE_DATA_MAGIC
;
69 prInfo
.offset
= offset
;
72 status_t result
= ioctl(gInfo
.deviceFileDesc
, TDFX_GET_PIO_REG
,
73 &prInfo
, sizeof(prInfo
));
75 TRACE("ReadPIOReg() failed, result = 0x%x\n", result
);
82 WriteMiscOutReg(uint8 value
)
84 WritePIOReg(MISC_OUT_W
- 0x300, -1, value
);
89 WriteCrtcReg(uint8 index
, uint8 value
)
91 WritePIOReg(CRTC_INDEX
- 0x300, index
, value
);
98 return ReadPIOReg(MISC_OUT_R
- 0x300, -1);
103 ReadCrtcReg(uint8 index
)
105 return ReadPIOReg(CRTC_INDEX
- 0x300, index
);
110 TDFX_WaitForFifo(uint32 entries
)
112 // The FIFO has 32 slots. This routine waits until at least `entries'
113 // of these slots are empty.
115 while ((INREG32(STATUS
) & 0x1f) < entries
) ;
122 // Wait for the graphics engine to be completely idle.
125 OUTREG32(CMD_3D
, CMD_3D_NOP
);
130 i
= (INREG32(STATUS
) & STATUS_BUSY
) ? 0 : i
+ 1;
136 TDFX_CalcPLL(int freq
)
138 const int refFreq
= 14318;
139 int best_error
= freq
;
144 for (int n
= 1; n
< 256; n
++) {
145 int freqCur
= refFreq
* (n
+ 2);
146 if (freqCur
< freq
) {
147 freqCur
= freqCur
/ 3;
148 if (freq
- freqCur
< best_error
) {
149 best_error
= freq
- freqCur
;
156 for (int m
= 1; m
< 64; m
++) {
157 for (int k
= 0; k
< 4; k
++) {
158 freqCur
= refFreq
* (n
+ 2) / (m
+ 2) / (1 << k
);
159 if (abs(freqCur
- freq
) < best_error
) {
160 best_error
= abs(freqCur
- freq
);
169 return (best_n
<< 8) | (best_m
<< 2) | best_k
;
174 TDFX_GetColorSpaceParams(int colorSpace
, uint8
& bitsPerPixel
)
176 // Get parameters for a color space which is supported by the 3dfx chips.
177 // Return true if the color space is supported; else return false.
179 switch (colorSpace
) {
193 TRACE("Unsupported color space: 0x%X\n", colorSpace
);
202 TDFX_SetDisplayMode(const DisplayModeEx
& mode
)
204 // The code to actually configure the display.
205 // All the error checking must be done in ProposeDisplayMode(),
206 // and assume that the mode values we get here are acceptable.
208 SharedInfo
& si
= *gInfo
.sharedInfo
;
209 bool clock2X
= mode
.timing
.pixel_clock
> si
.maxPixelClock
/ 2;
211 // Initialize the timing values for CRTC registers cr00 to cr18. Note
212 // that the number following the letters 'cr' is a hexadecimal number.
213 // Argument crtc will contain registers cr00 to cr18; thus, it must
214 // contain at least 25 (0x19) elements.
216 // Normally the horizontal timing values are divided by 8; however,
217 // if the clock is above the 2X value, divide by 16 such that the values
220 int horzDiv
= clock2X
? 16 : 8;
222 int hTotal
= mode
.timing
.h_total
/ horzDiv
- 5;
223 int hDisp_e
= mode
.timing
.h_display
/ horzDiv
- 1;
224 int hSync_s
= mode
.timing
.h_sync_start
/ horzDiv
;
225 int hSync_e
= mode
.timing
.h_sync_end
/ horzDiv
;
226 int hBlank_s
= hDisp_e
+ 1; // start of horizontal blanking
227 int hBlank_e
= hTotal
+ 3; // end of horizontal blanking
229 int vTotal
= mode
.timing
.v_total
- 2;
230 int vDisp_e
= mode
.timing
.v_display
- 1;
231 int vSync_s
= mode
.timing
.v_sync_start
;
232 int vSync_e
= mode
.timing
.v_sync_end
;
233 int vBlank_s
= vDisp_e
+ 1; // start of vertical blanking
234 int vBlank_e
= vTotal
; // end of vertical blanking
236 // CRTC Controller values
241 crtc
[0x01] = hDisp_e
;
242 crtc
[0x02] = hBlank_s
;
243 crtc
[0x03] = (hBlank_e
& 0x1f) | 0x80;
244 crtc
[0x04] = hSync_s
;
245 crtc
[0x05] = ((hSync_e
& 0x1f) | ((hBlank_e
& 0x20) << 2));
247 crtc
[0x07] = (((vTotal
& 0x100) >> 8)
248 | ((vDisp_e
& 0x100) >> 7)
249 | ((vSync_s
& 0x100) >> 6)
250 | ((vBlank_s
& 0x100) >> 5)
252 | ((vTotal
& 0x200) >> 4)
253 | ((vDisp_e
& 0x200) >> 3)
254 | ((vSync_s
& 0x200) >> 2));
256 crtc
[0x09] = ((vBlank_s
& 0x200) >> 4) | 0x40;
263 crtc
[0x10] = vSync_s
;
264 crtc
[0x11] = (vSync_e
& 0x0f) | 0x20;
265 crtc
[0x12] = vDisp_e
;
266 crtc
[0x13] = hDisp_e
+ 1;
268 crtc
[0x15] = vBlank_s
;
269 crtc
[0x16] = vBlank_e
;
273 // Set up the extra CR reg's to handle the higher resolution modes.
275 uint8 cr1a
= (hTotal
& 0x100) >> 8
276 | (hDisp_e
& 0x100) >> 6
277 | (hBlank_s
& 0x100) >> 4
278 | (hBlank_e
& 0x40) >> 1
279 | (hSync_s
& 0x100) >> 2
280 | (hSync_e
& 0x20) << 2;
282 uint8 cr1b
= (vTotal
& 0x400) >> 10
283 | (vDisp_e
& 0x400) >> 8
284 | (vBlank_s
& 0x400) >> 6
285 | (vBlank_e
& 0x400) >> 4;
287 uint8 miscOutReg
= 0x0f | (mode
.timing
.v_display
< 400 ? 0xa0
288 : mode
.timing
.v_display
< 480 ? 0x60
289 : mode
.timing
.v_display
< 768 ? 0xe0 : 0x20);
291 uint32 vgaInit0
= VGA0_EXTENSIONS
293 | ENABLE_ALT_READBACK
297 uint32 videoConfig
= VIDEO_PROCESSOR_ENABLE
| DESKTOP_ENABLE
298 | (mode
.bytesPerPixel
- 1) << DESKTOP_PIXEL_FORMAT_SHIFT
299 | (mode
.bytesPerPixel
> 1 ? DESKTOP_CLUT_BYPASS
: 0);
301 uint32 dacMode
= INREG32(DAC_MODE
) & ~DAC_MODE_2X
;
304 dacMode
|= DAC_MODE_2X
;
305 videoConfig
|= VIDEO_2X_MODE_ENABLE
;
308 uint32 pllFreq
= TDFX_CalcPLL(mode
.timing
.pixel_clock
);
310 // Note that for the Banshee chip, the mode 1280x1024 at 60Hz refresh does
311 // not display properly using the computed PLL frequency; thus, set it to
312 // the value that is computed when set by VESA.
314 if (si
.chipType
== BANSHEE
&& pllFreq
== 45831
315 && mode
.timing
.h_display
== 1280 && mode
.timing
.v_display
== 1024)
318 uint32 screenSize
= mode
.timing
.h_display
| (mode
.timing
.v_display
<< 12);
320 // Now that the values for the registers have been computed, write the
321 // registers to set the mode.
322 //=====================================================================
325 OUTREG32(VIDEO_PROC_CONFIG
, 0);
326 OUTREG32(PLL_CTRL0
, pllFreq
);
328 WriteMiscOutReg(miscOutReg
);
330 for (uint8 j
= 0; j
< 25; j
++)
331 WriteCrtcReg(j
, crtc
[j
]);
333 WriteCrtcReg(0x1a, cr1a
);
334 WriteCrtcReg(0x1b, cr1b
);
337 OUTREG32(VGA_INIT0
, vgaInit0
);
338 OUTREG32(DAC_MODE
, dacMode
);
339 OUTREG32(VIDEO_DESKTOP_OVERLAY_STRIDE
, mode
.bytesPerRow
);
340 OUTREG32(HW_CURSOR_PAT_ADDR
, si
.cursorOffset
);
341 OUTREG32(VIDEO_SCREEN_SIZE
, screenSize
);
342 OUTREG32(VIDEO_DESKTOP_START_ADDR
, si
.frameBufferOffset
);
345 OUTREG32(CLIP0_MIN
, 0);
346 OUTREG32(CLIP0_MAX
, 0x0fff0fff);
347 OUTREG32(CLIP1_MIN
, 0);
348 OUTREG32(CLIP1_MAX
, 0x0fff0fff);
349 OUTREG32(VIDEO_PROC_CONFIG
, videoConfig
);
350 OUTREG32(SRC_BASE_ADDR
, si
.frameBufferOffset
);
351 OUTREG32(DST_BASE_ADDR
, si
.frameBufferOffset
);
355 TDFX_AdjustFrame(mode
);
362 TDFX_AdjustFrame(const DisplayModeEx
& mode
)
364 // Adjust start address in frame buffer.
366 SharedInfo
& si
= *gInfo
.sharedInfo
;
368 int address
= (mode
.v_display_start
* mode
.virtual_width
369 + mode
.h_display_start
) * mode
.bytesPerPixel
;
372 address
+= si
.frameBufferOffset
;
375 OUTREG32(VIDEO_DESKTOP_START_ADDR
, address
);
381 TDFX_SetIndexedColors(uint count
, uint8 first
, uint8
* colorData
, uint32 flags
)
383 // Set the indexed color palette for 8-bit color depth mode.
385 (void)flags
; // avoid compiler warning for unused arg
387 if (gInfo
.sharedInfo
->displayMode
.space
!= B_CMAP8
)
390 uint32 index
= first
;
393 uint32 color
= ((colorData
[0] << 16) | (colorData
[1] << 8) | colorData
[2]);
395 OUTREG32(DAC_ADDR
, index
++);
396 INREG32(DAC_ADDR
); // color not always set unless we read after write
397 OUTREG32(DAC_DATA
, color
);