2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
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.
18 #include "accelerant.h"
19 #include "i810_regs.h"
21 #include <create_display_modes.h> // common accelerant header file
26 // I810_CalcVCLK -- Determine closest clock frequency to the one requested.
27 #define MAX_VCO_FREQ 600.0
28 #define TARGET_MAX_N 30
31 #define CALC_VCLK(m,n,p) (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ
35 CalcVCLK(double freq
, uint16
& clkM
, uint16
& clkN
, uint16
& clkP
) {
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.
52 f_vco
= f_target
* (1 << p
);
57 m
= int(f_vco
/ (REF_FREQ
/ (double)n
) / (double)4.0 + 0.5);
60 f_out
= CALC_VCLK(m
, n
, p
);
61 f_err
= 1.0 - (f_target
/ f_out
);
62 if (fabs(f_err
) < errMax
) {
68 } while ((fabs(f_err
) >= errTarget
) && ((n
<= TARGET_MAX_N
)
69 || (fabs(errBest
) > errMax
)));
71 if (fabs(f_err
) < errTarget
) {
76 clkM
= (m_best
- 2) & 0x3FF;
77 clkN
= (n_best
- 2) & 0x3FF;
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
);
87 SetCrtcTimingValues(const DisplayModeEx
& mode
)
89 // Set the timing values for CRTC registers cr00 to cr18, and some extended
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
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));
118 crtc
[0x07] = (((vTotal
& 0x100) >> 8)
119 | ((vDisp_e
& 0x100) >> 7)
120 | ((vSync_s
& 0x100) >> 6)
121 | ((vBlank_s
& 0x100) >> 5)
123 | ((vTotal
& 0x200) >> 4)
124 | ((vDisp_e
& 0x200) >> 3)
125 | ((vSync_s
& 0x200) >> 2));
128 crtc
[0x09] = ((vBlank_s
& 0x200) >> 4) | 0x40;
135 crtc
[0x10] = vSync_s
;
136 crtc
[0x11] = (vSync_e
& 0x0f) | 0x20;
137 crtc
[0x12] = vDisp_e
;
140 crtc
[0x15] = vBlank_s
;
141 crtc
[0x16] = vBlank_e
;
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
);
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
);
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.
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
200 uint8 miscOutReg
= 0x08 | 0x01;
201 if (!(mode
.timing
.flags
& B_POSITIVE_HSYNC
))
203 if (!(mode
.timing
.flags
& B_POSITIVE_VSYNC
))
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
);
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
);
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
);
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
)
278 OUTREG8(DAC_MASK
, 0xff);
279 OUTREG8(DAC_W_INDEX
, first
); // initial color index
282 OUTREG8(DAC_DATA
, colorData
[0]); // red
283 OUTREG8(DAC_DATA
, colorData
[1]); // green
284 OUTREG8(DAC_DATA
, colorData
[2]); // blue