vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / intel_810 / i810_mode.cpp
bloba09fcb871ffadbd3df862548b620c7d6df0100b3
1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Gerald Zajac
7 */
9 /*!
10 Haiku Intel-810 video driver was adapted from the X.org intel driver which
11 has the following copyright.
13 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
14 All Rights Reserved.
18 #include "accelerant.h"
19 #include "i810_regs.h"
21 #include <create_display_modes.h> // common accelerant header file
22 #include <math.h>
23 #include <unistd.h>
26 // I810_CalcVCLK -- Determine closest clock frequency to the one requested.
27 #define MAX_VCO_FREQ 600.0
28 #define TARGET_MAX_N 30
29 #define REF_FREQ 24.0
31 #define CALC_VCLK(m,n,p) (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ
34 static void
35 CalcVCLK(double freq, uint16& clkM, uint16& clkN, uint16& clkP) {
36 int m, n, p;
37 double f_out, f_best;
38 double f_err;
39 double f_vco;
40 int m_best = 0, n_best = 0, p_best = 0;
41 double f_target = freq;
42 double errMax = 0.005;
43 double errTarget = 0.001;
44 double errBest = 999999.0;
46 p_best = p = int(log(MAX_VCO_FREQ / f_target) / log((double)2));
47 // Make sure p is within range.
48 if (p_best > 5) {
49 p_best = p = 5;
52 f_vco = f_target * (1 << p);
54 n = 2;
55 do {
56 n++;
57 m = int(f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5);
58 if (m < 3)
59 m = 3;
60 f_out = CALC_VCLK(m, n, p);
61 f_err = 1.0 - (f_target / f_out);
62 if (fabs(f_err) < errMax) {
63 m_best = m;
64 n_best = n;
65 f_best = f_out;
66 errBest = f_err;
68 } while ((fabs(f_err) >= errTarget) && ((n <= TARGET_MAX_N)
69 || (fabs(errBest) > errMax)));
71 if (fabs(f_err) < errTarget) {
72 m_best = m;
73 n_best = n;
76 clkM = (m_best - 2) & 0x3FF;
77 clkN = (n_best - 2) & 0x3FF;
78 clkP = (p_best << 4);
80 TRACE("Setting dot clock to %.1f MHz [ 0x%x 0x%x 0x%x ] [ %d %d %d ]\n",
81 CALC_VCLK(m_best, n_best, p_best),
82 clkM, clkN, clkP, m_best, n_best, p_best);
86 static void
87 SetCrtcTimingValues(const DisplayModeEx& mode)
89 // Set the timing values for CRTC registers cr00 to cr18, and some extended
90 // CRTC registers.
92 int hTotal = mode.timing.h_total / 8 - 5;
93 int hDisp_e = mode.timing.h_display / 8 - 1;
94 int hSync_s = mode.timing.h_sync_start / 8;
95 int hSync_e = mode.timing.h_sync_end / 8;
96 int hBlank_s = hDisp_e + 1; // start of horizontal blanking
97 int hBlank_e = hTotal; // end of horizontal blanking
99 int vTotal = mode.timing.v_total - 2;
100 int vDisp_e = mode.timing.v_display - 1;
101 int vSync_s = mode.timing.v_sync_start;
102 int vSync_e = mode.timing.v_sync_end;
103 int vBlank_s = vDisp_e; // start of vertical blanking
104 int vBlank_e = vTotal; // end of vertical blanking
106 uint16 offset = mode.bytesPerRow / 8;
108 // CRTC Controller values
110 uint8 crtc[25];
111 crtc[0x00] = hTotal;
112 crtc[0x01] = hDisp_e;
113 crtc[0x02] = hBlank_s;
114 crtc[0x03] = (hBlank_e & 0x1f) | 0x80;
115 crtc[0x04] = hSync_s;
116 crtc[0x05] = ((hSync_e & 0x1f) | ((hBlank_e & 0x20) << 2));
117 crtc[0x06] = vTotal;
118 crtc[0x07] = (((vTotal & 0x100) >> 8)
119 | ((vDisp_e & 0x100) >> 7)
120 | ((vSync_s & 0x100) >> 6)
121 | ((vBlank_s & 0x100) >> 5)
122 | 0x10
123 | ((vTotal & 0x200) >> 4)
124 | ((vDisp_e & 0x200) >> 3)
125 | ((vSync_s & 0x200) >> 2));
127 crtc[0x08] = 0x00;
128 crtc[0x09] = ((vBlank_s & 0x200) >> 4) | 0x40;
129 crtc[0x0a] = 0x00;
130 crtc[0x0b] = 0x00;
131 crtc[0x0c] = 0x00;
132 crtc[0x0d] = 0x00;
133 crtc[0x0e] = 0x00;
134 crtc[0x0f] = 0x00;
135 crtc[0x10] = vSync_s;
136 crtc[0x11] = (vSync_e & 0x0f) | 0x20;
137 crtc[0x12] = vDisp_e;
138 crtc[0x13] = offset;
139 crtc[0x14] = 0x00;
140 crtc[0x15] = vBlank_s;
141 crtc[0x16] = vBlank_e;
142 crtc[0x17] = 0xc3;
143 crtc[0x18] = 0xff;
145 // Set the standard CRTC vga regs; however, before setting them, unlock
146 // CRTC reg's 0-7 by clearing bit 7 of cr11
148 WriteCrtcReg(0x11, crtc[0x11] & ~0x80);
150 for (uint8 j = 0; j <= 0x18; j++)
151 WriteCrtcReg(j, crtc[j]);
153 // Set the extended CRTC reg's.
155 WriteCrtcReg(EXT_VERT_TOTAL, vTotal >> 8);
156 WriteCrtcReg(EXT_VERT_DISPLAY, vDisp_e >> 8);
157 WriteCrtcReg(EXT_VERT_SYNC_START, vSync_s >> 8);
158 WriteCrtcReg(EXT_VERT_BLANK_START, vBlank_s >> 8);
159 WriteCrtcReg(EXT_HORIZ_TOTAL, hTotal >> 8);
160 WriteCrtcReg(EXT_HORIZ_BLANK, (hBlank_e & 0x40) >> 6);
161 WriteCrtcReg(EXT_OFFSET, offset >> 8);
163 WriteCrtcReg(INTERLACE_CNTL, INTERLACE_DISABLE); // turn off interlace
165 // Enable high resolution mode.
166 WriteCrtcReg(IO_CTNL, ReadCrtcReg(IO_CTNL) | EXTENDED_CRTC_CNTL);
170 status_t
171 I810_SetDisplayMode(const DisplayModeEx& mode)
173 if (mode.bitsPerPixel != 8 && mode.bitsPerPixel != 16) {
174 // Only 8 & 16 bits/pixel are suppoted.
175 TRACE("Unsupported color depth: %d bpp\n", mode.bitsPerPixel);
176 return B_ERROR;
179 snooze(50000);
181 // Turn off DRAM refresh.
182 uint8 temp = INREG8(DRAM_ROW_CNTL_HI) & ~DRAM_REFRESH_RATE;
183 OUTREG8(DRAM_ROW_CNTL_HI, temp | DRAM_REFRESH_DISABLE);
185 snooze(1000); // wait 1 ms
187 // Calculate the VCLK that most closely matches the requested pixel clock,
188 // and then set the M, N, and P values.
190 uint16 m, n, p;
191 CalcVCLK(mode.timing.pixel_clock / 1000.0, m, n, p);
193 OUTREG16(VCLK2_VCO_M, m);
194 OUTREG16(VCLK2_VCO_N, n);
195 OUTREG8(VCLK2_VCO_DIV_SEL, p);
197 // Setup HSYNC & VSYNC polarity and select clock source 2 (0x08) for
198 // programmable PLL.
200 uint8 miscOutReg = 0x08 | 0x01;
201 if (!(mode.timing.flags & B_POSITIVE_HSYNC))
202 miscOutReg |= 0x40;
203 if (!(mode.timing.flags & B_POSITIVE_VSYNC))
204 miscOutReg |= 0x80;
206 OUTREG8(MISC_OUT_W, miscOutReg);
208 SetCrtcTimingValues(mode);
210 OUTREG32(MEM_MODE, INREG32(MEM_MODE) | 4);
212 // Set the address mapping to use the frame buffer memory mapped via the
213 // GTT table instead of the VGA buffer.
215 uint8 addrMapping = ReadGraphReg(ADDRESS_MAPPING);
216 addrMapping &= 0xE0; // preserve reserved bits 7:5
217 addrMapping |= (GTT_MEM_MAP_ENABLE | LINEAR_MODE_ENABLE);
218 WriteGraphReg(ADDRESS_MAPPING, addrMapping);
220 // Turn on DRAM refresh.
221 temp = INREG8(DRAM_ROW_CNTL_HI) & ~DRAM_REFRESH_RATE;
222 OUTREG8(DRAM_ROW_CNTL_HI, temp | DRAM_REFRESH_60HZ);
224 temp = INREG8(BITBLT_CNTL) & ~COLEXP_MODE;
225 temp |= (mode.bitsPerPixel == 8 ? COLEXP_8BPP : COLEXP_16BPP);
226 OUTREG8(BITBLT_CNTL, temp);
228 // Turn on 8 bit dac mode so that the indexed colors are displayed properly,
229 // and put display in high resolution mode.
231 uint32 temp32 = INREG32(PIXPIPE_CONFIG) & 0xF3E062FC;
232 temp32 |= (DAC_8_BIT | HIRES_MODE | NO_BLANK_DELAY |
233 (mode.bitsPerPixel == 8 ? DISPLAY_8BPP_MODE : DISPLAY_16BPP_MODE));
234 OUTREG32(PIXPIPE_CONFIG, temp32);
236 OUTREG16(EIR, 0);
238 temp32 = INREG32(FWATER_BLC);
239 temp32 &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK
240 | MM_BURST_LENGTH | MM_FIFO_WATERMARK);
241 temp32 |= I810_GetWatermark(mode);
242 OUTREG32(FWATER_BLC, temp32);
244 // Enable high resolution mode.
245 WriteCrtcReg(IO_CTNL, ReadCrtcReg(IO_CTNL) | EXTENDED_CRTC_CNTL);
247 I810_AdjustFrame(mode);
248 return B_OK;
252 void
253 I810_AdjustFrame(const DisplayModeEx& mode)
255 // Adjust start address in frame buffer.
257 uint32 address = ((mode.v_display_start * mode.virtual_width
258 + mode.h_display_start) * mode.bytesPerPixel) >> 2;
260 WriteCrtcReg(START_ADDR_LO, address & 0xff);
261 WriteCrtcReg(START_ADDR_HI, (address >> 8) & 0xff);
262 WriteCrtcReg(EXT_START_ADDR_HI, (address >> 22) & 0xff);
263 WriteCrtcReg(EXT_START_ADDR,
264 ((address >> 16) & 0x3f) | EXT_START_ADDR_ENABLE);
268 void
269 I810_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
271 // Set the indexed color palette for 8-bit color depth mode.
273 (void)flags; // avoid compiler warning for unused arg
275 if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
276 return ;
278 OUTREG8(DAC_MASK, 0xff);
279 OUTREG8(DAC_W_INDEX, first); // initial color index
281 while (count--) {
282 OUTREG8(DAC_DATA, colorData[0]); // red
283 OUTREG8(DAC_DATA, colorData[1]); // green
284 OUTREG8(DAC_DATA, colorData[2]); // blue
286 colorData += 3;