2 Haiku ATI video driver adapted from the X.org ATI driver.
4 Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
5 Precision Insight, Inc., Cedar Park, Texas, and
6 VA Linux Systems Inc., Fremont, California.
8 Copyright 2009 Haiku, Inc. All rights reserved.
9 Distributed under the terms of the MIT license.
16 #include "accelerant.h"
22 struct DisplayParams
{
25 uint32 crtc_h_total_disp
;
26 uint32 crtc_h_sync_strt_wid
;
27 uint32 crtc_v_total_disp
;
28 uint32 crtc_v_sync_strt_wid
;
35 // Computed PLL values
47 DivideWithRounding(int n
, int d
)
49 return (n
+ (d
/ 2)) / d
; // compute n/d with rounding
54 MinimumBits(uint32 value
)
56 // Compute minimum number of bits required to contain a value (ie, log
74 CalculateCrtcRegisters(const DisplayModeEx
& mode
, DisplayParams
& params
)
76 // Define CRTC registers for requested video mode.
77 // Return true if successful.
79 const uint8 hSyncFudge
[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
83 switch (mode
.bitsPerPixel
) {
97 TRACE("Unsupported color depth: %d bits/pixel\n", mode
.bitsPerPixel
);
101 params
.crtc_gen_cntl
= (R128_CRTC_EXT_DISP_EN
105 params
.crtc_h_total_disp
= (((mode
.timing
.h_total
/ 8) - 1) & 0xffff)
106 | (((mode
.timing
.h_display
/ 8) - 1) << 16);
108 int hSyncWidth
= (mode
.timing
.h_sync_end
- mode
.timing
.h_sync_start
) / 8;
111 if (hSyncWidth
> 0x3f)
114 int hSyncStart
= mode
.timing
.h_sync_start
- 8 + hSyncFudge
[format
- 1];
116 params
.crtc_h_sync_strt_wid
= (hSyncStart
& 0xfff) | (hSyncWidth
<< 16)
117 | ((mode
.timing
.flags
& B_POSITIVE_HSYNC
) ? 0 : R128_CRTC_H_SYNC_POL
);
119 params
.crtc_v_total_disp
= (((mode
.timing
.v_total
- 1) & 0xffff)
120 | ((mode
.timing
.v_display
- 1) << 16));
122 int vSyncWidth
= mode
.timing
.v_sync_end
- mode
.timing
.v_sync_start
;
125 if (vSyncWidth
> 0x1f)
128 params
.crtc_v_sync_strt_wid
= ((mode
.timing
.v_sync_start
- 1) & 0xfff)
130 | ((mode
.timing
.flags
& B_POSITIVE_VSYNC
) ? 0 : R128_CRTC_V_SYNC_POL
);
132 params
.crtc_pitch
= mode
.timing
.h_display
/ 8;
139 CalculateDDARegisters(const DisplayModeEx
& mode
, DisplayParams
& params
)
141 // Compute and write DDA registers for requested video mode.
142 // Return true if successful.
144 SharedInfo
& si
= *gInfo
.sharedInfo
;
145 R128_RAMSpec
& memSpec
= si
.r128MemSpec
;
146 R128_PLLParams
& pll
= si
.r128PLLParams
;
148 int displayFifoWidth
= 128;
149 int displayFifoDepth
= 32;
150 int xClkFreq
= pll
.xclk
;
152 int vClkFreq
= DivideWithRounding(pll
.reference_freq
* params
.feedback_div
,
153 pll
.reference_div
* params
.post_div
);
155 int bytesPerPixel
= (mode
.bitsPerPixel
+ 7) / 8;
157 int xClksPerTransfer
= DivideWithRounding(xClkFreq
* displayFifoWidth
,
158 vClkFreq
* bytesPerPixel
* 8);
160 int useablePrecision
= MinimumBits(xClksPerTransfer
) + 1;
162 int xClksPerTransferPrecise
= DivideWithRounding(
163 (xClkFreq
* displayFifoWidth
) << (11 - useablePrecision
),
164 vClkFreq
* bytesPerPixel
* 8);
166 int rOff
= xClksPerTransferPrecise
* (displayFifoDepth
- 4);
168 int rOn
= (4 * memSpec
.memBurstLen
169 + 3 * MAX(memSpec
.rasToCasDelay
- 2, 0)
170 + 2 * memSpec
.rasPercentage
171 + memSpec
.writeRecovery
173 + memSpec
.readToWriteDelay
174 + xClksPerTransfer
) << (11 - useablePrecision
);
176 if (rOn
+ memSpec
.loopLatency
>= rOff
) {
177 TRACE("Error: (rOn = %d) + (loopLatency = %d) >= (rOff = %d)\n",
178 rOn
, memSpec
.loopLatency
, rOff
);
182 params
.dda_config
= xClksPerTransferPrecise
| (useablePrecision
<< 16)
183 | (memSpec
.loopLatency
<< 20);
184 params
.dda_on_off
= (rOn
<< 16) | rOff
;
191 CalculatePLLRegisters(const DisplayModeEx
& mode
, DisplayParams
& params
)
193 // Define PLL registers for requested video mode.
200 // The following data is from RAGE 128 VR/RAGE 128 GL Register Reference
201 // Manual (Technical Reference Manual P/N RRG-G04100-C Rev. 0.04), page
202 // 3-17 (PLL_DIV_[3:0]).
204 const Divider postDividers
[] = {
205 { 1, 0 }, // VCLK_SRC
206 { 2, 1 }, // VCLK_SRC/2
207 { 4, 2 }, // VCLK_SRC/4
208 { 8, 3 }, // VCLK_SRC/8
209 { 3, 4 }, // VCLK_SRC/3
210 // bitValue = 5 is reserved
211 { 6, 6 }, // VCLK_SRC/6
212 { 12, 7 } // VCLK_SRC/12
215 R128_PLLParams
& pll
= gInfo
.sharedInfo
->r128PLLParams
;
216 uint32 freq
= mode
.timing
.pixel_clock
/ 10;
218 if (freq
> pll
.max_pll_freq
)
219 freq
= pll
.max_pll_freq
;
220 if (freq
* 12 < pll
.min_pll_freq
)
221 freq
= pll
.min_pll_freq
/ 12;
226 for (int j
= 0; j
< (int)B_COUNT_OF(postDividers
); j
++) {
227 output_freq
= postDividers
[j
].divider
* freq
;
228 if (output_freq
>= pll
.min_pll_freq
&& output_freq
<= pll
.max_pll_freq
) {
229 params
.feedback_div
= DivideWithRounding(pll
.reference_div
* output_freq
,
231 params
.post_div
= postDividers
[j
].divider
;
232 bitValue
= postDividers
[j
].bitValue
;
238 TRACE("CalculatePLLRegisters(), acceptable divider not found\n");
242 params
.ppll_ref_div
= pll
.reference_div
;
243 params
.ppll_div_3
= (params
.feedback_div
| (bitValue
<< 16));
250 PLLWaitForReadUpdateComplete()
252 while (GetPLLReg(R128_PPLL_REF_DIV
) & R128_PPLL_ATOMIC_UPDATE_R
)
259 PLLWaitForReadUpdateComplete();
261 SetPLLReg(R128_PPLL_REF_DIV
, R128_PPLL_ATOMIC_UPDATE_W
, R128_PPLL_ATOMIC_UPDATE_W
);
266 SetRegisters(DisplayParams
& params
)
268 // Write the common registers (most will be set to zero).
269 //-------------------------------------------------------
271 OUTREGM(R128_FP_GEN_CNTL
, R128_FP_BLANK_DIS
, R128_FP_BLANK_DIS
);
273 OUTREG(R128_OVR_CLR
, 0);
274 OUTREG(R128_OVR_WID_LEFT_RIGHT
, 0);
275 OUTREG(R128_OVR_WID_TOP_BOTTOM
, 0);
276 OUTREG(R128_OV0_SCALE_CNTL
, 0);
277 OUTREG(R128_MPP_TB_CONFIG
, 0);
278 OUTREG(R128_MPP_GP_CONFIG
, 0);
279 OUTREG(R128_SUBPIC_CNTL
, 0);
280 OUTREG(R128_VIPH_CONTROL
, 0);
281 OUTREG(R128_I2C_CNTL_1
, 0);
282 OUTREG(R128_GEN_INT_CNTL
, 0);
283 OUTREG(R128_CAP0_TRIG_CNTL
, 0);
284 OUTREG(R128_CAP1_TRIG_CNTL
, 0);
286 // If bursts are enabled, turn on discards and aborts.
288 uint32 busCntl
= INREG(R128_BUS_CNTL
);
289 if (busCntl
& (R128_BUS_WRT_BURST
| R128_BUS_READ_BURST
)) {
290 busCntl
|= R128_BUS_RD_DISCARD_EN
| R128_BUS_RD_ABORT_EN
;
291 OUTREG(R128_BUS_CNTL
, busCntl
);
294 // Write the DDA registers.
295 //-------------------------
297 OUTREG(R128_DDA_CONFIG
, params
.dda_config
);
298 OUTREG(R128_DDA_ON_OFF
, params
.dda_on_off
);
300 // Write the CRTC registers.
301 //--------------------------
303 OUTREG(R128_CRTC_GEN_CNTL
, params
.crtc_gen_cntl
);
305 OUTREGM(R128_DAC_CNTL
, R128_DAC_MASK_ALL
| R128_DAC_8BIT_EN
,
306 ~(R128_DAC_RANGE_CNTL
| R128_DAC_BLANKING
));
308 OUTREG(R128_CRTC_H_TOTAL_DISP
, params
.crtc_h_total_disp
);
309 OUTREG(R128_CRTC_H_SYNC_STRT_WID
, params
.crtc_h_sync_strt_wid
);
310 OUTREG(R128_CRTC_V_TOTAL_DISP
, params
.crtc_v_total_disp
);
311 OUTREG(R128_CRTC_V_SYNC_STRT_WID
, params
.crtc_v_sync_strt_wid
);
312 OUTREG(R128_CRTC_OFFSET
, 0);
313 OUTREG(R128_CRTC_OFFSET_CNTL
, 0);
314 OUTREG(R128_CRTC_PITCH
, params
.crtc_pitch
);
316 // Write the PLL registers.
317 //-------------------------
319 OUTREGM(R128_CLOCK_CNTL_INDEX
, R128_PLL_DIV_SEL
, R128_PLL_DIV_SEL
);
321 SetPLLReg(R128_VCLK_ECP_CNTL
, R128_VCLK_SRC_SEL_CPUCLK
, R128_VCLK_SRC_SEL_MASK
);
323 SetPLLReg(R128_PPLL_CNTL
, 0xffffffff,
324 R128_PPLL_RESET
| R128_PPLL_ATOMIC_UPDATE_EN
| R128_PPLL_VGA_ATOMIC_UPDATE_EN
);
326 PLLWaitForReadUpdateComplete();
327 SetPLLReg(R128_PPLL_REF_DIV
, params
.ppll_ref_div
, R128_PPLL_REF_DIV_MASK
);
330 PLLWaitForReadUpdateComplete();
331 SetPLLReg(R128_PPLL_DIV_3
, params
.ppll_div_3
,
332 R128_PPLL_FB3_DIV_MASK
| R128_PPLL_POST3_DIV_MASK
);
335 PLLWaitForReadUpdateComplete();
336 SetPLLReg(R128_HTOTAL_CNTL
, 0);
339 SetPLLReg(R128_PPLL_CNTL
, 0, R128_PPLL_RESET
341 | R128_PPLL_ATOMIC_UPDATE_EN
342 | R128_PPLL_VGA_ATOMIC_UPDATE_EN
);
346 SetPLLReg(R128_VCLK_ECP_CNTL
, R128_VCLK_SRC_SEL_PPLLCLK
,
347 R128_VCLK_SRC_SEL_MASK
);
353 Rage128_SetDisplayMode(const DisplayModeEx
& mode
)
355 // The code to actually configure the display.
356 // All the error checking must be done in ProposeDisplayMode(),
357 // and assume that the mode values we get here are acceptable.
359 DisplayParams params
; // where computed parameters are saved
361 if (gInfo
.sharedInfo
->displayType
== MT_VGA
) {
362 // Chip is connected to a monitor via a VGA connector.
364 if ( ! CalculateCrtcRegisters(mode
, params
))
367 if ( ! CalculatePLLRegisters(mode
, params
))
370 if ( ! CalculateDDARegisters(mode
, params
))
373 SetRegisters(params
);
376 // Chip is connected to a laptop LCD monitor; or via a DVI interface.
378 uint16 vesaMode
= GetVesaModeNumber(display_mode(mode
), mode
.bitsPerPixel
);
382 if (ioctl(gInfo
.deviceFileDesc
, ATI_SET_VESA_DISPLAY_MODE
,
383 &vesaMode
, sizeof(vesaMode
)) != B_OK
)
387 Rage128_AdjustFrame(mode
);
389 // Initialize the palette so that color depths > 8 bits/pixel will display
390 // the correct colors.
392 // Select primary monitor and enable 8-bit color.
393 OUTREGM(R128_DAC_CNTL
, R128_DAC_8BIT_EN
,
394 R128_DAC_PALETTE_ACC_CTL
| R128_DAC_8BIT_EN
);
395 OUTREG8(R128_PALETTE_INDEX
, 0); // set first color index
397 for (int i
= 0; i
< 256; i
++)
398 OUTREG(R128_PALETTE_DATA
, (i
<< 16) | (i
<< 8) | i
);
400 Rage128_EngineInit(mode
);
408 Rage128_AdjustFrame(const DisplayModeEx
& mode
)
410 // Adjust start address in frame buffer.
412 SharedInfo
& si
= *gInfo
.sharedInfo
;
414 int address
= (mode
.v_display_start
* mode
.virtual_width
415 + mode
.h_display_start
) * ((mode
.bitsPerPixel
+ 1) / 8);
418 address
+= si
.frameBufferOffset
;
420 OUTREG(R128_CRTC_OFFSET
, address
);
426 Rage128_SetIndexedColors(uint count
, uint8 first
, uint8
* colorData
, uint32 flags
)
428 // Set the indexed color palette for 8-bit color depth mode.
430 (void)flags
; // avoid compiler warning for unused arg
432 if (gInfo
.sharedInfo
->displayMode
.space
!= B_CMAP8
)
435 // Select primary monitor and enable 8-bit color.
436 OUTREGM(R128_DAC_CNTL
, R128_DAC_8BIT_EN
,
437 R128_DAC_PALETTE_ACC_CTL
| R128_DAC_8BIT_EN
);
438 OUTREG8(R128_PALETTE_INDEX
, first
); // set first color index
441 OUTREG(R128_PALETTE_DATA
, ((colorData
[0] << 16) // red
442 | (colorData
[1] << 8) // green
443 | colorData
[2])); // blue