1 /*
2 Haiku ATI video driver adapted from the X.org ATI driver.
3
4 Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
5 Precision Insight, Inc., Cedar Park, Texas, and
6 VA Linux Systems Inc., Fremont, California.
7
8 Copyright 2009 Haiku, Inc. All rights reserved.
9 Distributed under the terms of the MIT license.
10
11 Authors:
12 Gerald Zajac 2009
13 */
14
15
16 #include "accelerant.h"
17 #include "rage128.h"
18
19 #include <unistd.h>
20
21
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;
30
31 // DDA register
32 uint32 dda_config;
33 uint32 dda_on_off;
34
35 // Computed PLL values
36 int feedback_div;
37 int post_div;
38
39 // PLL registers
40 uint32 ppll_ref_div;
41 uint32 ppll_div_3;
42 };
43
44
45
46 static inline int
DivideWithRounding(int n,int d)47 DivideWithRounding(int n, int d)
48 {
49 return (n + (d / 2)) / d; // compute n/d with rounding
50 }
51
52
53 static int
MinimumBits(uint32 value)54 MinimumBits(uint32 value)
55 {
56 // Compute minimum number of bits required to contain a value (ie, log
57 // base 2 of value).
58
59 if (value == 0)
60 return 1;
61
62 int numBits = 0;
63
64 while (value != 0) {
65 value >>= 1;
66 numBits++;
67 }
68
69 return numBits;
70 }
71
72
73 static bool
CalculateCrtcRegisters(const DisplayModeEx & mode,DisplayParams & params)74 CalculateCrtcRegisters(const DisplayModeEx& mode, DisplayParams& params)
75 {
76 // Define CRTC registers for requested video mode.
77 // Return true if successful.
78
79 const uint8 hSyncFudge[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
80
81 uint32 format;
82
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;
99 }
100
101 params.crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN
102 | R128_CRTC_EN
103 | (format << 8));
104
105 params.crtc_h_total_disp = (((mode.timing.h_total / 8) - 1) & 0xffff)
106 | (((mode.timing.h_display / 8) - 1) << 16);
107
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;
113
114 int hSyncStart = mode.timing.h_sync_start - 8 + hSyncFudge[format - 1];
115
116 params.crtc_h_sync_strt_wid = (hSyncStart & 0xfff) | (hSyncWidth << 16)
117 | ((mode.timing.flags & B_POSITIVE_HSYNC) ? 0 : R128_CRTC_H_SYNC_POL);
118
119 params.crtc_v_total_disp = (((mode.timing.v_total - 1) & 0xffff)
120 | ((mode.timing.v_display - 1) << 16));
121
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;
127
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);
131
132 params.crtc_pitch = mode.timing.h_display / 8;
133
134 return true;
135 }
136
137
138 static bool
CalculateDDARegisters(const DisplayModeEx & mode,DisplayParams & params)139 CalculateDDARegisters(const DisplayModeEx& mode, DisplayParams& params)
140 {
141 // Compute and write DDA registers for requested video mode.
142 // Return true if successful.
143
144 SharedInfo& si = *gInfo.sharedInfo;
145 R128_RAMSpec& memSpec = si.r128MemSpec;
146 R128_PLLParams& pll = si.r128PLLParams;
147
148 int displayFifoWidth = 128;
149 int displayFifoDepth = 32;
150 int xClkFreq = pll.xclk;
151
152 int vClkFreq = DivideWithRounding(pll.reference_freq * params.feedback_div,
153 pll.reference_div * params.post_div);
154
155 int bytesPerPixel = (mode.bitsPerPixel + 7) / 8;
156
157 int xClksPerTransfer = DivideWithRounding(xClkFreq * displayFifoWidth,
158 vClkFreq * bytesPerPixel * 8);
159
160 int useablePrecision = MinimumBits(xClksPerTransfer) + 1;
161
162 int xClksPerTransferPrecise = DivideWithRounding(
163 (xClkFreq * displayFifoWidth) << (11 - useablePrecision),
164 vClkFreq * bytesPerPixel * 8);
165
166 int rOff = xClksPerTransferPrecise * (displayFifoDepth - 4);
167
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);
175
176 if (rOn + memSpec.loopLatency >= rOff) {
177 TRACE("Error: (rOn = %d) + (loopLatency = %d) >= (rOff = %d)\n",
178 rOn, memSpec.loopLatency, rOff);
179 return false;
180 }
181
182 params.dda_config = xClksPerTransferPrecise | (useablePrecision << 16)
183 | (memSpec.loopLatency << 20);
184 params.dda_on_off = (rOn << 16) | rOff;
185
186 return true;
187 }
188
189
190 static bool
CalculatePLLRegisters(const DisplayModeEx & mode,DisplayParams & params)191 CalculatePLLRegisters(const DisplayModeEx& mode, DisplayParams& params)
192 {
193 // Define PLL registers for requested video mode.
194
195 struct Divider {
196 int divider;
197 int bitValue;
198 };
199
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]).
203
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
213 };
214
215 R128_PLLParams& pll = gInfo.sharedInfo->r128PLLParams;
216 uint32 freq = mode.timing.pixel_clock / 10;
217
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;
222
223 int bitValue = -1;
224 uint32 output_freq;
225
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;
234 }
235 }
236
237 if (bitValue < 0) {
238 TRACE("CalculatePLLRegisters(), acceptable divider not found\n");
239 return false;
240 }
241
242 params.ppll_ref_div = pll.reference_div;
243 params.ppll_div_3 = (params.feedback_div | (bitValue << 16));
244
245 return true;
246 }
247
248
249 static void
PLLWaitForReadUpdateComplete()250 PLLWaitForReadUpdateComplete()
251 {
252 while (GetPLLReg(R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R)
253 ;
254 }
255
256 static void
PLLWriteUpdate()257 PLLWriteUpdate()
258 {
259 PLLWaitForReadUpdateComplete();
260
261 SetPLLReg(R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, R128_PPLL_ATOMIC_UPDATE_W);
262 }
263
264
265 static void
SetRegisters(DisplayParams & params)266 SetRegisters(DisplayParams& params)
267 {
268 // Write the common registers (most will be set to zero).
269 //-------------------------------------------------------
270
271 OUTREGM(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, R128_FP_BLANK_DIS);
272
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);
285
286 // If bursts are enabled, turn on discards and aborts.
287
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);
292 }
293
294 // Write the DDA registers.
295 //-------------------------
296
297 OUTREG(R128_DDA_CONFIG, params.dda_config);
298 OUTREG(R128_DDA_ON_OFF, params.dda_on_off);
299
300 // Write the CRTC registers.
301 //--------------------------
302
303 OUTREG(R128_CRTC_GEN_CNTL, params.crtc_gen_cntl);
304
305 OUTREGM(R128_DAC_CNTL, R128_DAC_MASK_ALL | R128_DAC_8BIT_EN,
306 ~(R128_DAC_RANGE_CNTL | R128_DAC_BLANKING));
307
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);
315
316 // Write the PLL registers.
317 //-------------------------
318
319 OUTREGM(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, R128_PLL_DIV_SEL);
320
321 SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_CPUCLK, R128_VCLK_SRC_SEL_MASK);
322
323 SetPLLReg(R128_PPLL_CNTL, 0xffffffff,
324 R128_PPLL_RESET | R128_PPLL_ATOMIC_UPDATE_EN | R128_PPLL_VGA_ATOMIC_UPDATE_EN);
325
326 PLLWaitForReadUpdateComplete();
327 SetPLLReg(R128_PPLL_REF_DIV, params.ppll_ref_div, R128_PPLL_REF_DIV_MASK);
328 PLLWriteUpdate();
329
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();
334
335 PLLWaitForReadUpdateComplete();
336 SetPLLReg(R128_HTOTAL_CNTL, 0);
337 PLLWriteUpdate();
338
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);
343
344 snooze(5000);
345
346 SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_PPLLCLK,
347 R128_VCLK_SRC_SEL_MASK);
348 }
349
350
351
352 status_t
Rage128_SetDisplayMode(const DisplayModeEx & mode)353 Rage128_SetDisplayMode(const DisplayModeEx& mode)
354 {
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.
358
359 DisplayParams params; // where computed parameters are saved
360
361 if (gInfo.sharedInfo->displayType == MT_VGA) {
362 // Chip is connected to a monitor via a VGA connector.
363
364 if ( ! CalculateCrtcRegisters(mode, params))
365 return B_BAD_VALUE;
366
367 if ( ! CalculatePLLRegisters(mode, params))
368 return B_BAD_VALUE;
369
370 if ( ! CalculateDDARegisters(mode, params))
371 return B_BAD_VALUE;
372
373 SetRegisters(params);
374
375 } else {
376 // Chip is connected to a laptop LCD monitor; or via a DVI interface.
377
378 uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel);
379 if (vesaMode == 0)
380 return B_BAD_VALUE;
381
382 if (ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE,
383 &vesaMode, sizeof(vesaMode)) != B_OK)
384 return B_ERROR;
385 }
386
387 Rage128_AdjustFrame(mode);
388
389 // Initialize the palette so that color depths > 8 bits/pixel will display
390 // the correct colors.
391
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
396
397 for (int i = 0; i < 256; i++)
398 OUTREG(R128_PALETTE_DATA, (i << 16) | (i << 8) | i );
399
400 Rage128_EngineInit(mode);
401
402 return B_OK;
403 }
404
405
406
407 void
Rage128_AdjustFrame(const DisplayModeEx & mode)408 Rage128_AdjustFrame(const DisplayModeEx& mode)
409 {
410 // Adjust start address in frame buffer.
411
412 SharedInfo& si = *gInfo.sharedInfo;
413
414 int address = (mode.v_display_start * mode.virtual_width
415 + mode.h_display_start) * ((mode.bitsPerPixel + 1) / 8);
416
417 address &= ~0x07;
418 address += si.frameBufferOffset;
419
420 OUTREG(R128_CRTC_OFFSET, address);
421 return;
422 }
423
424
425 void
Rage128_SetIndexedColors(uint count,uint8 first,uint8 * colorData,uint32 flags)426 Rage128_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
427 {
428 // Set the indexed color palette for 8-bit color depth mode.
429
430 (void)flags; // avoid compiler warning for unused arg
431
432 if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
433 return ;
434
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
439
440 while (count--) {
441 OUTREG(R128_PALETTE_DATA, ((colorData[0] << 16) // red
442 | (colorData[1] << 8) // green
443 | colorData[2])); // blue
444 colorData += 3;
445 }
446 }
447