vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / ati / rage128_mode.cpp
bloba03478198a0aacdba3fce9c4004dbe95c567cba0
1 /*
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.
11 Authors:
12 Gerald Zajac 2009
16 #include "accelerant.h"
17 #include "rage128.h"
19 #include <unistd.h>
22 struct DisplayParams {
23 // CRTC registers
24 uint32 crtc_gen_cntl;
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;
29 uint32 crtc_pitch;
31 // DDA register
32 uint32 dda_config;
33 uint32 dda_on_off;
35 // Computed PLL values
36 int feedback_div;
37 int post_div;
39 // PLL registers
40 uint32 ppll_ref_div;
41 uint32 ppll_div_3;
46 static inline int
47 DivideWithRounding(int n, int d)
49 return (n + (d / 2)) / d; // compute n/d with rounding
53 static int
54 MinimumBits(uint32 value)
56 // Compute minimum number of bits required to contain a value (ie, log
57 // base 2 of value).
59 if (value == 0)
60 return 1;
62 int numBits = 0;
64 while (value != 0) {
65 value >>= 1;
66 numBits++;
69 return numBits;
73 static bool
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 };
81 uint32 format;
83 switch (mode.bitsPerPixel) {
84 case 8:
85 format = 2;
86 break;
87 case 15:
88 format = 3; // 555
89 break;
90 case 16:
91 format = 4; // 565
92 break;
93 case 32:
94 format = 6; // xRGB
95 break;
96 default:
97 TRACE("Unsupported color depth: %d bits/pixel\n", mode.bitsPerPixel);
98 return false;
101 params.crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN
102 | R128_CRTC_EN
103 | (format << 8));
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;
109 if (hSyncWidth <= 0)
110 hSyncWidth = 1;
111 if (hSyncWidth > 0x3f)
112 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;
123 if (vSyncWidth <= 0)
124 vSyncWidth = 1;
125 if (vSyncWidth > 0x1f)
126 vSyncWidth = 0x1f;
128 params.crtc_v_sync_strt_wid = ((mode.timing.v_sync_start - 1) & 0xfff)
129 | (vSyncWidth << 16)
130 | ((mode.timing.flags & B_POSITIVE_VSYNC) ? 0 : R128_CRTC_V_SYNC_POL);
132 params.crtc_pitch = mode.timing.h_display / 8;
134 return true;
138 static bool
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
172 + memSpec.casLatency
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);
179 return false;
182 params.dda_config = xClksPerTransferPrecise | (useablePrecision << 16)
183 | (memSpec.loopLatency << 20);
184 params.dda_on_off = (rOn << 16) | rOff;
186 return true;
190 static bool
191 CalculatePLLRegisters(const DisplayModeEx& mode, DisplayParams& params)
193 // Define PLL registers for requested video mode.
195 struct Divider {
196 int divider;
197 int bitValue;
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;
223 int bitValue = -1;
224 uint32 output_freq;
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,
230 pll.reference_freq);
231 params.post_div = postDividers[j].divider;
232 bitValue = postDividers[j].bitValue;
233 break;
237 if (bitValue < 0) {
238 TRACE("CalculatePLLRegisters(), acceptable divider not found\n");
239 return false;
242 params.ppll_ref_div = pll.reference_div;
243 params.ppll_div_3 = (params.feedback_div | (bitValue << 16));
245 return true;
249 static void
250 PLLWaitForReadUpdateComplete()
252 while (GetPLLReg(R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R)
256 static void
257 PLLWriteUpdate()
259 PLLWaitForReadUpdateComplete();
261 SetPLLReg(R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, R128_PPLL_ATOMIC_UPDATE_W);
265 static void
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);
328 PLLWriteUpdate();
330 PLLWaitForReadUpdateComplete();
331 SetPLLReg(R128_PPLL_DIV_3, params.ppll_div_3,
332 R128_PPLL_FB3_DIV_MASK | R128_PPLL_POST3_DIV_MASK);
333 PLLWriteUpdate();
335 PLLWaitForReadUpdateComplete();
336 SetPLLReg(R128_HTOTAL_CNTL, 0);
337 PLLWriteUpdate();
339 SetPLLReg(R128_PPLL_CNTL, 0, R128_PPLL_RESET
340 | R128_PPLL_SLEEP
341 | R128_PPLL_ATOMIC_UPDATE_EN
342 | R128_PPLL_VGA_ATOMIC_UPDATE_EN);
344 snooze(5000);
346 SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_PPLLCLK,
347 R128_VCLK_SRC_SEL_MASK);
352 status_t
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))
365 return B_BAD_VALUE;
367 if ( ! CalculatePLLRegisters(mode, params))
368 return B_BAD_VALUE;
370 if ( ! CalculateDDARegisters(mode, params))
371 return B_BAD_VALUE;
373 SetRegisters(params);
375 } else {
376 // Chip is connected to a laptop LCD monitor; or via a DVI interface.
378 uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel);
379 if (vesaMode == 0)
380 return B_BAD_VALUE;
382 if (ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE,
383 &vesaMode, sizeof(vesaMode)) != B_OK)
384 return B_ERROR;
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);
402 return B_OK;
407 void
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);
417 address &= ~0x07;
418 address += si.frameBufferOffset;
420 OUTREG(R128_CRTC_OFFSET, address);
421 return;
425 void
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)
433 return ;
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
440 while (count--) {
441 OUTREG(R128_PALETTE_DATA, ((colorData[0] << 16) // red
442 | (colorData[1] << 8) // green
443 | colorData[2])); // blue
444 colorData += 3;