2 Haiku ATI video driver adapted from the X.org ATI driver.
4 Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
5 Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
7 Copyright 2009 Haiku, Inc. All rights reserved.
8 Distributed under the terms of the MIT license.
15 #include "accelerant.h"
23 static void SetClockRegisters(const DisplayModeEx
& mode
)
25 SharedInfo
& si
= *gInfo
.sharedInfo
;
26 M64_Params
& params
= si
.m64Params
;
30 bool extendedDiv
= false;
31 uint32 pixelClock
= mode
.timing
.pixel_clock
;
33 if (pixelClock
> params
.maxPixelClock
)
34 pixelClock
= params
.maxPixelClock
;
36 double q
= ((pixelClock
/ 10.0) * params
.refDivider
) / (2.0 * params
.refFreq
);
38 if (si
.chipType
>= MACH64_264VTB
) {
40 TRACE("SetClockRegisters(): Warning: q > 255\n");
44 } else if (q
> 127.5) {
50 } else if (q
> 63.75) {
54 } else if (q
> 42.5) {
57 } else if (q
> 31.875) {
61 } else if (q
> 21.25) {
64 } else if (q
>= 10.6666666667) {
69 TRACE("SetClockRegisters(): Warning: q < 10.66666667\n");
76 TRACE("SetClockRegisters(): Warning: q > 255\n");
88 TRACE("SetClockRegisters(): Warning: q < 16\n");
94 uint8 fbDiv
= uint8(q
* postDiv
);
96 // With some chips such as those with ID's 4750 & 475A, the display has
97 // ripples when using resolution 1440x900 at 60 Hz refresh rate.
98 // Decrementing fbDiv by 1 seems to fix this problem.
100 if (mode
.timing
.h_display
== 1440 && pixelClock
< 108000)
103 int clkNum
= params
.clockNumberToProgram
;
105 OUTREG8(CLOCK_CNTL
, clkNum
| CLOCK_STROBE
);
107 // Temporarily switch to accelerator mode.
108 uint32 crtc_gen_cntl
= INREG(CRTC_GEN_CNTL
);
109 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
110 OUTREG(CRTC_GEN_CNTL
, crtc_gen_cntl
| CRTC_EXT_DISP_EN
);
112 // Reset VCLK generator.
113 uint8 vclkCntl
= Mach64_GetPLLReg(PLL_VCLK_CNTL
);
114 Mach64_SetPLLReg(PLL_VCLK_CNTL
, vclkCntl
| PLL_VCLK_RESET
);
117 uint8 tmp
= Mach64_GetPLLReg(PLL_VCLK_POST_DIV
);
118 Mach64_SetPLLReg(PLL_VCLK_POST_DIV
,
119 (tmp
& ~(0x03 << (2 * clkNum
))) | (p
<< (2 * clkNum
)));
121 // Set feedback divider.
122 Mach64_SetPLLReg(PLL_VCLK0_FB_DIV
+ clkNum
, fbDiv
);
124 // Set extended post-divider.
125 if (si
.chipType
>= MACH64_264VTB
) {
126 tmp
= Mach64_GetPLLReg(PLL_XCLK_CNTL
);
128 Mach64_SetPLLReg(PLL_XCLK_CNTL
, tmp
| (0x10 << clkNum
));
130 Mach64_SetPLLReg(PLL_XCLK_CNTL
, tmp
& ~(0x10 << clkNum
));
133 // End VCLK generator reset.
134 Mach64_SetPLLReg(PLL_VCLK_CNTL
, vclkCntl
& ~PLL_VCLK_RESET
);
137 INREG8(DAC_W_INDEX
); // Clear DAC counter
139 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
140 OUTREG(CRTC_GEN_CNTL
, crtc_gen_cntl
); // Restore register
142 // Save parameters that will be used for computing the DSP parameters.
144 params
.vClkPostDivider
= postDiv
;
145 params
.vClkFeedbackDivider
= fbDiv
;
152 SetDSPRegisters(const DisplayModeEx
& mode
)
154 // Set up DSP register values for a VTB or later.
156 SharedInfo
& si
= *gInfo
.sharedInfo
;
157 M64_Params
& params
= si
.m64Params
;
159 #define Maximum_DSP_PRECISION 7
161 uint8 mClkFeedbackDivider
= Mach64_GetPLLReg(PLL_MCLK_FB_DIV
);
163 /* Compute a memory-to-screen bandwidth ratio */
164 uint32 multiplier
= uint32(mClkFeedbackDivider
) * params
.vClkPostDivider
;
165 uint32 divider
= uint32(params
.vClkFeedbackDivider
) * params
.xClkRefDivider
;
166 divider
*= ((mode
.bitsPerPixel
+ 1) / 4);
168 // Start by assuming a display FIFO width of 64 bits.
170 int vshift
= (6 - 2) - params
.xClkPostDivider
;
172 int RASMultiplier
= params
.xClkMaxRASDelay
;
175 // Determine dsp_precision first.
177 int tmp
= Mach64_Divide(multiplier
* params
.displayFIFODepth
, divider
, vshift
, -1);
180 for (dsp_precision
= -5; tmp
; dsp_precision
++)
182 if (dsp_precision
< 0)
184 else if (dsp_precision
> Maximum_DSP_PRECISION
)
185 dsp_precision
= Maximum_DSP_PRECISION
;
187 int xshift
= 6 - dsp_precision
;
190 int dsp_off
= Mach64_Divide(multiplier
* (params
.displayFIFODepth
- 1),
191 divider
, vshift
, -1) - Mach64_Divide(1, 1, vshift
- xshift
, 1);
193 int dsp_on
= Mach64_Divide(multiplier
, divider
, vshift
, 1);
194 tmp
= Mach64_Divide(RASMultiplier
, RASDivider
, xshift
, 1);
197 dsp_on
+= (tmp
* 2) +
198 Mach64_Divide(params
.xClkPageFaultDelay
, 1, xshift
, 1);
200 /* Calculate rounding factor and apply it to dsp_on */
201 tmp
= ((1 << (Maximum_DSP_PRECISION
- dsp_precision
)) - 1) >> 1;
202 dsp_on
= ((dsp_on
+ tmp
) / (tmp
+ 1)) * (tmp
+ 1);
204 if (dsp_on
>= ((dsp_off
/ (tmp
+ 1)) * (tmp
+ 1))) {
205 dsp_on
= dsp_off
- Mach64_Divide(multiplier
, divider
, vshift
, -1);
206 dsp_on
= (dsp_on
/ (tmp
+ 1)) * (tmp
+ 1);
209 int dsp_xclks
= Mach64_Divide(multiplier
, divider
, vshift
+ 5, 1);
211 // Build DSP register contents.
213 uint32 dsp_on_off
= SetBits(dsp_on
, DSP_ON
)
214 | SetBits(dsp_off
, DSP_OFF
);
215 uint32 dsp_config
= SetBits(dsp_precision
, DSP_PRECISION
)
216 | SetBits(dsp_xclks
, DSP_XCLKS_PER_QW
)
217 | SetBits(params
.displayLoopLatency
, DSP_LOOP_LATENCY
);
219 OUTREG(DSP_ON_OFF
, dsp_on_off
);
220 OUTREG(DSP_CONFIG
, dsp_config
);
225 SetCrtcRegisters(const DisplayModeEx
& mode
)
227 // Calculate the CRTC register values for requested video mode, and then set
228 // set the registers to the calculated values.
230 SharedInfo
& si
= *gInfo
.sharedInfo
;
232 uint32 crtc_h_total_disp
= ((mode
.timing
.h_total
/ 8) - 1)
233 | (((mode
.timing
.h_display
/ 8) - 1) << 16);
235 int hSyncWidth
= (mode
.timing
.h_sync_end
- mode
.timing
.h_sync_start
) / 8;
236 if (hSyncWidth
> 0x3f)
239 int hSyncStart
= mode
.timing
.h_sync_start
/ 8 - 1;
241 uint32 crtc_h_sync_strt_wid
= (hSyncWidth
<< 16)
242 | (hSyncStart
& 0xff) | ((hSyncStart
& 0x100) << 4)
243 | ((mode
.timing
.flags
& B_POSITIVE_HSYNC
) ? 0 : CRTC_H_SYNC_NEG
);
245 uint32 crtc_v_total_disp
= ((mode
.timing
.v_total
- 1)
246 | ((mode
.timing
.v_display
- 1) << 16));
248 int vSyncWidth
= mode
.timing
.v_sync_end
- mode
.timing
.v_sync_start
;
249 if (vSyncWidth
> 0x1f)
252 uint32 crtc_v_sync_strt_wid
= (mode
.timing
.v_sync_start
- 1)
254 | ((mode
.timing
.flags
& B_POSITIVE_VSYNC
) ? 0 : CRTC_V_SYNC_NEG
);
256 uint32 crtc_off_pitch
= SetBits(mode
.timing
.h_display
>> 3, CRTC_PITCH
);
258 uint32 crtc_gen_cntl
= INREG(CRTC_GEN_CNTL
) &
259 ~(CRTC_DBL_SCAN_EN
| CRTC_INTERLACE_EN
|
260 CRTC_HSYNC_DIS
| CRTC_VSYNC_DIS
| CRTC_CSYNC_EN
|
261 CRTC_PIX_BY_2_EN
| CRTC_VGA_XOVERSCAN
|
262 CRTC_PIX_WIDTH
| CRTC_BYTE_PIX_ORDER
|
263 CRTC_VGA_128KAP_PAGING
| CRTC_VFC_SYNC_TRISTATE
|
264 CRTC_LOCK_REGS
| // already off, but ...
265 CRTC_SYNC_TRISTATE
| CRTC_DISP_REQ_EN
|
266 CRTC_VGA_TEXT_132
| CRTC_CUR_B_TEST
);
268 crtc_gen_cntl
|= CRTC_EXT_DISP_EN
| CRTC_EN
| CRTC_VGA_LINEAR
| CRTC_CNT_EN
;
270 switch (mode
.bitsPerPixel
) {
272 crtc_gen_cntl
|= CRTC_PIX_WIDTH_8BPP
;
275 crtc_gen_cntl
|= CRTC_PIX_WIDTH_15BPP
;
278 crtc_gen_cntl
|= CRTC_PIX_WIDTH_16BPP
;
281 crtc_gen_cntl
|= CRTC_PIX_WIDTH_32BPP
;
284 TRACE("Undefined color depth, bitsPerPixel: %d\n", mode
.bitsPerPixel
);
288 // For now, set display FIFO low water mark as high as possible.
289 if (si
.chipType
< MACH64_264VTB
)
290 crtc_gen_cntl
|= CRTC_FIFO_LWM
;
293 // Write the CRTC registers.
294 //--------------------------
297 OUTREG(CRTC_GEN_CNTL
, crtc_gen_cntl
& ~(CRTC_EXT_DISP_EN
| CRTC_EN
));
299 OUTREG(CRTC_H_TOTAL_DISP
, crtc_h_total_disp
);
300 OUTREG(CRTC_H_SYNC_STRT_WID
, crtc_h_sync_strt_wid
);
301 OUTREG(CRTC_V_TOTAL_DISP
, crtc_v_total_disp
);
302 OUTREG(CRTC_V_SYNC_STRT_WID
, crtc_v_sync_strt_wid
);
304 OUTREG(CRTC_OFF_PITCH
, crtc_off_pitch
);
306 // Clear overscan registers.
308 OUTREG(OVR_WID_LEFT_RIGHT
, 0);
309 OUTREG(OVR_WID_TOP_BOTTOM
, 0);
311 // Finalise CRTC setup and turn on the screen.
312 OUTREG(CRTC_GEN_CNTL
, crtc_gen_cntl
);
320 Mach64_SetDisplayMode(const DisplayModeEx
& mode
)
322 // The code to actually configure the display.
323 // All the error checking must be done in ProposeDisplayMode(),
324 // and assume that the mode values we get here are acceptable.
326 SharedInfo
& si
= *gInfo
.sharedInfo
;
328 if (si
.displayType
== MT_VGA
) {
329 // Chip is connected to a monitor via a VGA connector.
331 SetCrtcRegisters(mode
);
332 SetClockRegisters(mode
);
334 if (si
.chipType
>= MACH64_264VTB
)
335 SetDSPRegisters(mode
);
338 // Chip is connected to a laptop LCD monitor; or via a DVI interface.
340 uint16 vesaMode
= GetVesaModeNumber(display_mode(mode
), mode
.bitsPerPixel
);
344 status_t status
= ioctl(gInfo
.deviceFileDesc
, ATI_SET_VESA_DISPLAY_MODE
,
345 &vesaMode
, sizeof(vesaMode
));
350 Mach64_AdjustFrame(mode
);
352 // Initialize the palette so that the various color depths will display
353 // the correct colors.
355 OUTREGM(DAC_CNTL
, DAC_8BIT_EN
, DAC_8BIT_EN
);
356 OUTREG8(DAC_MASK
, 0xff);
357 OUTREG8(DAC_W_INDEX
, 0); // initial color index
359 for (int i
= 0; i
< 256; i
++) {
360 OUTREG8(DAC_DATA
, i
);
361 OUTREG8(DAC_DATA
, i
);
362 OUTREG8(DAC_DATA
, i
);
365 Mach64_EngineInit(mode
);
373 Mach64_AdjustFrame(const DisplayModeEx
& mode
)
375 // Adjust start address in frame buffer.
377 SharedInfo
& si
= *gInfo
.sharedInfo
;
379 int address
= (mode
.v_display_start
* mode
.virtual_width
380 + mode
.h_display_start
) * ((mode
.bitsPerPixel
+ 1) / 8);
383 address
+= si
.frameBufferOffset
;
385 OUTREGM(CRTC_OFF_PITCH
, address
, 0xfffff);
391 Mach64_SetIndexedColors(uint count
, uint8 first
, uint8
* colorData
, uint32 flags
)
393 // Set the indexed color palette for 8-bit color depth mode.
395 (void)flags
; // avoid compiler warning for unused arg
397 if (gInfo
.sharedInfo
->displayMode
.space
!= B_CMAP8
)
400 OUTREG8(DAC_MASK
, 0xff);
401 OUTREG8(DAC_W_INDEX
, first
); // initial color index
404 OUTREG8(DAC_DATA
, colorData
[0]); // red
405 OUTREG8(DAC_DATA
, colorData
[1]); // green
406 OUTREG8(DAC_DATA
, colorData
[2]); // blue