xref: /haiku/src/add-ons/accelerants/matrox/engine/mga_crtc.c (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 /* CTRC functionality */
2 /* Authors:
3    Mark Watson 2/2000,
4    Apsed,
5    Rudolf Cornelissen 11/2002-2/2004
6 */
7 
8 #define MODULE_BIT 0x00040000
9 
10 #include "mga_std.h"
11 
12 /*Adjust passed parameters to a valid mode line*/
13 status_t gx00_crtc_validate_timing(
14 	uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
15 	uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
16 )
17 {
18 /* horizontal */
19 	/* make all parameters multiples of 8 */
20 	*hd_e &= 0x0ff8; /* 2048 is a valid value for this item! */
21 	*hs_s &= 0x0ff8;
22 	*hs_e &= 0x0ff8;
23 	*ht   &= 0x0ff8;
24 
25 	/* confine to required number of bits, taking logic into account */
26 	if (*hd_e > ((0x00ff + 1) << 3)) *hd_e = ((0x00ff + 1) << 3);
27 	if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
28 	if (*hs_e > ( 0x01ff      << 3)) *hs_e = ( 0x01ff      << 3);
29 	if (*ht   > ((0x01ff + 5) << 3)) *ht   = ((0x01ff + 5) << 3);
30 
31 	/* NOTE: keep horizontal timing at multiples of 8! */
32 	/* confine to a reasonable width */
33 	if (*hd_e < 640) *hd_e = 640;
34 	switch (si->ps.card_type)
35 	{
36 	case MIL1:
37 	case MYST: /* fixme MYST220 has MIL2 range.. */
38 		if (*hd_e > 1600) *hd_e = 1600;
39 		break;
40 	case MIL2:
41 	case G100:
42 	case G200:
43 		if (*hd_e > 1920) *hd_e = 1920;
44 		break;
45 	default: /* G400 and up */
46 		if (*hd_e > 2048) *hd_e = 2048;
47 		break;
48 	}
49 
50 	/* if hor. total does not leave room for a sensible sync pulse, increase it! */
51 	if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
52 
53 	/* make sure sync pulse is not during display */
54 	if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
55 	if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
56 
57 	/* correct sync pulse if it is too long:
58 	 * there are only 5 bits available to save this in the card registers! */
59 	if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
60 
61 /*vertical*/
62 	/* confine to required number of bits, taking logic into account */
63 	if (*vd_e >  0x7ff     ) *vd_e =  0x7ff     ; /* linecomp max value = 0x7ff! */
64 	if (*vs_s > (0xfff - 1)) *vs_s = (0xfff - 1);
65 	if (*vs_e >  0xfff     ) *vs_e =  0xfff     ;
66 	if (*vt   > (0xfff + 2)) *vt   = (0xfff + 2);
67 
68 	/* confine to a reasonable height */
69 	if (*vd_e < 480) *vd_e = 480;
70 	switch (si->ps.card_type)
71 	{
72 	case MIL1:
73 	case MYST: /* fixme MYST220 has MIL2 range.. */
74 		if (*vd_e > 1200) *vd_e = 1200;
75 		break;
76 	case MIL2:
77 	case G100:
78 	case G200:
79 		if (*vd_e > 1440) *vd_e = 1440;
80 		break;
81 	default: /* G400 and up */
82 		if (*vd_e > 1536) *vd_e = 1536;
83 		break;
84 	}
85 
86 	/*if vertical total does not leave room for a sync pulse, increase it!*/
87 	if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
88 
89 	/* make sure sync pulse is not during display */
90 	if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
91 	if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
92 
93 	/* correct sync pulse if it is too long:
94 	 * there are only 4 bits available to save this in the card registers! */
95 	if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
96 
97 	return B_OK;
98 }
99 
100 /* set a mode line - inputs are in pixels */
101 status_t gx00_crtc_set_timing(display_mode target)
102 {
103 	uint8 temp;
104 
105 	uint32 htotal;		/*total horizontal total VCLKs*/
106 	uint32 hdisp_e;            /*end of horizontal display (begins at 0)*/
107 	uint32 hsync_s;            /*begin of horizontal sync pulse*/
108 	uint32 hsync_e;            /*end of horizontal sync pulse*/
109 	uint32 hblnk_s;            /*begin horizontal blanking*/
110 	uint32 hblnk_e;            /*end horizontal blanking*/
111 
112 	uint32 vtotal;		/*total vertical total scanlines*/
113 	uint32 vdisp_e;            /*end of vertical display*/
114 	uint32 vsync_s;            /*begin of vertical sync pulse*/
115 	uint32 vsync_e;            /*end of vertical sync pulse*/
116 	uint32 vblnk_s;            /*begin vertical blanking*/
117 	uint32 vblnk_e;            /*end vertical blanking*/
118 
119 	uint32 linecomp;	/*split screen and vdisp_e interrupt*/
120 
121 	LOG(4,("CRTC: setting timing\n"));
122 
123 	/* Modify parameters as required by standard VGA */
124 	htotal = ((target.timing.h_total >> 3) - 5);
125 	hdisp_e = ((target.timing.h_display >> 3) - 1);
126 	hblnk_s = hdisp_e;
127 	hblnk_e = (htotal + 4);
128 	hsync_s = (target.timing.h_sync_start >> 3);
129 	hsync_e = (target.timing.h_sync_end >> 3);
130 
131 	vtotal = target.timing.v_total - 2;
132 	vdisp_e = target.timing.v_display - 1;
133 	vblnk_s = vdisp_e;
134 	vblnk_e = (vtotal + 1);
135 	vsync_s = target.timing.v_sync_start - 1; /* Matrox */
136 	vsync_e = target.timing.v_sync_end - 1; /* Matrox */
137 
138 	/* We use the Matrox linecomp INT function to detect the
139 	 * vertical retrace at the earliest possible moment.. */
140 	linecomp = target.timing.v_display;
141 
142 	/*log the mode I am setting*/
143 	LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
144 	LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
145 
146 	/*actually program the card! Note linecomp is programmed to vblnk_s for VBI*/
147 	/*horizontal - VGA regs*/
148 
149 	VGAW_I(CRTC, 0x00, (htotal & 0x0ff));
150 	VGAW_I(CRTC, 0x01, (hdisp_e & 0x0ff));
151 	VGAW_I(CRTC, 0x02, (hblnk_s & 0x0ff));
152 	/* b7 should be set for compatibility reasons */
153 	VGAW_I(CRTC, 0x03, ((hblnk_e & 0x01f) | 0x80));
154 	VGAW_I(CRTC, 0x04, (hsync_s & 0x0ff));
155 	VGAW_I(CRTC, 0x05, (hsync_e & 0x01f) | ((hblnk_e & 0x020) << 2));
156 
157 	/*vertical - VGA regs*/
158 	VGAW_I(CRTC, 0x06, (vtotal & 0x0ff));
159 	VGAW_I(CRTC, 0x07,
160 	(
161 		((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
162 		((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
163 		((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
164 		((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
165 	));
166 	VGAW_I(CRTC, 0x08, 0x00);
167 	VGAW_I(CRTC, 0x09, ((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)));
168 	VGAW_I(CRTC, 0x10, (vsync_s & 0x0ff));
169 	VGAW_I(CRTC, 0x11, (((VGAR_I(CRTC, 0x11)) & 0xf0) | (vsync_e & 0x00f)));
170 	VGAW_I(CRTC, 0x12, (vdisp_e & 0x0ff));
171 	VGAW_I(CRTC, 0x15, (vblnk_s & 0x0ff));
172 	VGAW_I(CRTC, 0x16, (vblnk_e & 0x0ff));
173 	VGAW_I(CRTC, 0x18, (linecomp & 0x0ff));
174 
175 	/* horizontal - extended regs */
176 	/* do not touch external sync reset inputs: used for TVout */
177 	VGAW_I(CRTCEXT, 1,
178 	(
179 		((htotal & 0x100) >> (8 - 0)) |
180 		((hblnk_s & 0x100) >> (8 - 1)) |
181 		((hsync_s & 0x100) >> (8 - 2)) |
182 		((hblnk_e & 0x040) >> (6 - 6)) |
183 		(VGAR_I(CRTCEXT, 1) & 0xb8)
184 	));
185 
186 	/*vertical - extended regs*/
187 	VGAW_I(CRTCEXT, 2,
188 	(
189 	 	((vtotal & 0xc00) >> (10 - 0)) |
190 		((vdisp_e & 0x400) >> (10 - 2)) |
191 		((vblnk_s & 0xc00) >> (10 - 3)) |
192 		((vsync_s & 0xc00) >> (10 - 5)) |
193 		((linecomp & 0x400) >> (10 - 7))
194 	));
195 
196 	/* setup HSYNC & VSYNC polarity */
197 	LOG(2,("CRTC: sync polarity: "));
198 	temp = VGAR(MISCR);
199 	if (target.timing.flags & B_POSITIVE_HSYNC)
200 	{
201 		LOG(2,("H:pos "));
202 		temp &= ~0x40;
203 	}
204 	else
205 	{
206 		LOG(2,("H:neg "));
207 		temp |= 0x40;
208 	}
209 	if (target.timing.flags & B_POSITIVE_VSYNC)
210 	{
211 		LOG(2,("V:pos "));
212 		temp &= ~0x80;
213 	}
214 	else
215 	{
216 		LOG(2,("V:neg "));
217 		temp |= 0x80;
218 	}
219 	VGAW(MISCW, temp);
220 
221 	LOG(2,(", MISC reg readback: $%02x\n", VGAR(MISCR)));
222 
223 	return B_OK;
224 }
225 
226 status_t gx00_crtc_depth(int mode)
227 {
228 	uint8 viddelay = 0; // in CRTCEXT3, reserved if >= G100
229 
230 	if (si->ps.card_type < G100) do { // apsed TODO in caller
231 		if (si->ps.memory_size <= 2) { viddelay = 1<<3; break;}
232 		if (si->ps.memory_size <= 4) { viddelay = 0<<3; break;}
233 		viddelay = 2<<3; // for 8 to 16Mb of memory
234 	} while (0);
235 
236 	/* setup green_sync if requested */
237 	if (si->settings.greensync)
238 	{
239 		/* enable sync_on_green: ctrl bit polarity was reversed for Gxxx cards! */
240 		if (si->ps.card_type <= MIL2)
241 			DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20));
242 		else
243 			DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20));
244 		/* select horizontal _and_ vertical sync */
245 		viddelay |= 0x40;
246 
247 		LOG(4,("CRTC: sync_on_green enabled\n"));
248 	}
249 	else
250 	{
251 		/* disable sync_on_green: ctrl bit polarity was reversed for Gxxx cards! */
252 		if (si->ps.card_type <= MIL2)
253 			DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20));
254 		else
255 			DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20));
256 
257 		LOG(4,("CRTC: sync_on_green disabled\n"));
258 	}
259 
260 	/*set VCLK scaling*/
261 	switch(mode)
262 	{
263 	case BPP8:
264 		VGAW_I(CRTCEXT,3,viddelay|0x80);
265 		break;
266 	case BPP15:case BPP16:
267 		VGAW_I(CRTCEXT,3,viddelay|0x81);
268 		break;
269 	case BPP24:
270 		VGAW_I(CRTCEXT,3,viddelay|0x82);
271 		break;
272 	case BPP32:case BPP32DIR:
273 		VGAW_I(CRTCEXT,3,viddelay|0x83);
274 		break;
275 	}
276 	return B_OK;
277 }
278 
279 status_t gx00_crtc_dpms(bool display, bool h, bool v) // MIL2
280 {
281 	LOG(4,("CRTC: setting DPMS: "));
282 
283 	if (display)
284 	{
285 		VGAW_I(SEQ,1, 0x00);
286 		LOG(4,("display on, "));
287 	}
288 	else
289 	{
290 		VGAW_I(SEQ,1, 0x20);
291 		LOG(4,("display off, "));
292 	}
293 	if (h)
294 	{
295 		VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) & 0xef));
296 		LOG(4,("hsync enabled, "));
297 	}
298 	else
299 	{
300 		VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) | 0x10));
301 		LOG(4,("hsync disabled, "));
302 	}
303 	if (v)
304 	{
305 		VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) & 0xdf));
306 		LOG(4,("vsync enabled\n"));
307 	}
308 	else
309 	{
310 		VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) | 0x20));
311 		LOG(4,("vsync disabled\n"));
312 	}
313 
314 	/* set some required fixed values for proper MGA mode initialisation */
315 	VGAW_I(CRTC,0x17,0xC3);
316 	VGAW_I(CRTC,0x14,0x00);
317 
318 	/* make sure CRTC1 sync is patched through on connector on G450/G550! */
319 	if (si->ps.card_type >= G450)
320 	{
321 		if (si->crossed_conns)
322 		{
323 			/* patch through HD15 hsync and vsync unmodified */
324 			DXIW(SYNCCTRL, (DXIR(SYNCCTRL) & 0x0f));
325 		}
326 		else
327 		{
328 			/* patch through DVI-A hsync and vsync unmodified */
329 			DXIW(SYNCCTRL, (DXIR(SYNCCTRL) & 0xf0));
330 		}
331 	}
332 
333 	return B_OK;
334 }
335 
336 status_t gx00_crtc_dpms_fetch(bool *display, bool *h, bool *v) // MIL2
337 {
338 	*display=!(VGAR_I(SEQ, 1) & 0x20);
339 	*h=!(VGAR_I(CRTCEXT, 1) & 0x10);
340 	*v=!(VGAR_I(CRTCEXT, 1) & 0x20);
341 
342 	LOG(4,("CTRC: fetched DPMS state: "));
343 	if (*display) LOG(4,("display on, "));
344 	else LOG(4,("display off, "));
345 	if (*h) LOG(4,("hsync enabled, "));
346 	else LOG(4,("hsync disabled, "));
347 	if (*v) LOG(4,("vsync enabled\n"));
348 	else LOG(4,("vsync disabled\n"));
349 
350 	return B_OK;
351 }
352 
353 status_t gx00_crtc_set_display_pitch()
354 {
355 	uint32 offset;
356 
357 	LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
358 
359 	/* figure out offset value hardware needs:
360 	 * same for MIL1-G550 cards assuming MIL1/2 uses the TVP3026 64-bits DAC etc. */
361 	offset = si->fbc.bytes_per_row / 16;
362 
363 	LOG(2,("CRTC: offset register: 0x%04x\n",offset));
364 
365 	/*program the card!*/
366 	VGAW_I(CRTC,0x13,(offset&0xFF));
367 	VGAW_I(CRTCEXT,0,(VGAR_I(CRTCEXT,0)&0xCF)|((offset&0x300)>>4));
368 	return B_OK;
369 }
370 
371 status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp)
372 {
373 	uint32 ext0;
374 
375 	LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp));
376 
377 	/* Matrox docs are false/incomplete, always program qword adress. */
378 	startadd >>= 3;
379 
380 	LOG(2,("CRTC: startadd: %x\n",startadd));
381 	LOG(2,("CRTC: frameRAM: %x\n",si->framebuffer));
382 	LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer));
383 
384 	/* make sure we are in retrace on MIL cards (if possible), because otherwise
385 	 * distortions might occur during our reprogramming them (no double buffering) */
386 	if (si->ps.card_type < G100)
387 	{
388 		/* we might have no retraces during setmode! */
389 		uint32 timeout = 0;
390 		/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
391 		while ((!(ACCR(STATUS) & 0x08)) && (timeout < (25000/4)))
392 		{
393 			snooze(4);
394 			timeout++;
395 		}
396 	}
397 
398 	/*set standard registers*/
399 	VGAW_I(CRTC,0xD,startadd&0xFF);
400 	VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8);
401 
402 	//calculate extra bits that are standard over Gx00 series
403 	ext0 = VGAR_I(CRTCEXT,0)&0xB0;
404 	ext0|= (startadd&0xF0000)>>16;
405 
406 	//if card is a G200 or G400 then do first extension bit
407 	if (si->ps.card_type>=G200)
408 		ext0|=(startadd&0x100000)>>14;
409 
410 	//if card is a G400 then do write to its extension register
411 	if (si->ps.card_type>=G400)
412 		VGAW_I(CRTCEXT,8,((startadd&0x200000)>>21));
413 
414 	//write the extension bits
415 	VGAW_I(CRTCEXT,0,ext0);
416 
417 	return B_OK;
418 }
419 
420 status_t gx00_crtc_mem_priority(uint8 colordepth)
421 {
422 	float tpixclk, tmclk, refresh, temp;
423 	uint8 mp, vc, hiprilvl, maxhipri, prioctl;
424 
425 	/* we can only do this if card pins is read OK *and* card is coldstarted! */
426 	if (si->settings.usebios || (si->ps.pins_status != B_OK))
427 	{
428 		LOG(4,("CRTC: Card not coldstarted, skipping memory priority level setup\n"));
429 		return B_OK;
430 	}
431 
432 	/* only on G200 the mem_priority register should be programmed with this formula */
433 	if (si->ps.card_type != G200)
434 	{
435 		LOG(4,("CRTC: Memory priority level setup not needed, skipping\n"));
436 		return B_OK;
437 	}
438 
439 	/* make sure the G200 is running at peak performance, so for instance high-res
440 	 * overlay distortions due to bandwidth limitations are minimal.
441 	 * Note please that later cards have plenty of bandwidth to cope by default.
442 	 * Note also that the formula needed is entirely cardtype-dependant! */
443 	LOG(4,("CRTC: Setting G200 memory priority level\n"));
444 
445 	/* set memory controller pipe depth, assuming no codec or Vin operating */
446 	switch ((si->ps.memrdbk_reg & 0x00c00000) >> 22)
447 	{
448 	case 0:
449 		mp = 52;
450 		break;
451 	case 1:
452 		mp = 41;
453 		break;
454 	case 2:
455 		mp = 32;
456 		break;
457 	default:
458 		mp = 52;
459 		LOG(8,("CRTC: Streamer flowcontrol violation in PINS, defaulting to %%00\n"));
460 		break;
461 	}
462 
463 	/* calculate number of videoclocks needed per 8 pixels */
464 	vc = (8 * colordepth) / 64;
465 
466 	/* calculate pixelclock period (nS) */
467 	tpixclk = 1000000 / si->dm.timing.pixel_clock;
468 
469 	/* calculate memoryclock period (nS) */
470 	if (si->ps.v3_option2_reg & 0x08)
471 	{
472 		tmclk = 1000.0 / si->ps.std_engine_clock;
473 	}
474 	else
475 	{
476 		if (si->ps.v3_clk_div & 0x02)
477 			tmclk = 3000.0 / si->ps.std_engine_clock;
478 		else
479 			tmclk = 2000.0 / si->ps.std_engine_clock;
480 	}
481 
482 	/* calculate refreshrate of current displaymode */
483 	refresh = ((si->dm.timing.pixel_clock * 1000) /
484 		((uint32)si->dm.timing.h_total * (uint32)si->dm.timing.v_total));
485 
486 	/* calculate high priority request level, but stay on the 'crtc-safe' side:
487 	 * hence 'formula + 1.0' instead of 'formula + 0.5' */
488 	temp = (((((mp * tmclk) + (11 * vc * tpixclk)) / tpixclk) - (vc - 1)) / (8 * vc)) + 1.0;
489 	if (temp > 7.0) temp = 7.0;
490 	if (temp < 0.0) temp = 0.0;
491 	hiprilvl = 7 - ((uint8) temp);
492 	/* limit non-crtc priority so crtc always stays 'just' OK */
493 	if (hiprilvl > 4) hiprilvl = 4;
494 	if ((si->dm.timing.v_display > 768) && (hiprilvl > 3)) hiprilvl = 3;
495 	if ((si->dm.timing.v_display > 864) && (hiprilvl > 2) && (refresh >= 76.0)) hiprilvl = 2;
496 	if ((si->dm.timing.v_display > 1024) && (hiprilvl > 2)) hiprilvl = 2;
497 
498 	/* calculate maximum high priority requests */
499 	temp = (vc * (tmclk / tpixclk)) + 0.5;
500 	if (temp > (float)hiprilvl) temp = (float)hiprilvl;
501 	if (temp < 0.0) temp = 0.0;
502 	maxhipri = ((uint8) temp);
503 
504 	/* program the card */
505 	prioctl = ((hiprilvl & 0x07) | ((maxhipri & 0x07) << 4));
506 	VGAW_I(CRTCEXT, 6, prioctl);
507 
508 	/* log results */
509 	LOG(4,("CRTC: Vclks/char is %d, pixClk period %02.2fnS, memClk period %02.2fnS\n",
510 		vc, tpixclk, tmclk));
511 	LOG(4,("CRTC: memory priority control register is set to $%02x\n", prioctl));
512 
513 	return B_OK;
514 }
515 
516 status_t gx00_crtc_cursor_init()
517 {
518 	int i;
519 
520 	if (si->ps.card_type >= G100)
521 	{
522 		uint32 * fb;
523 		/* cursor bitmap will be stored at the start of the framebuffer on >= G100 */
524 		const uint32 curadd = 0;
525 
526 		/* set cursor bitmap adress ... */
527 		DXIW(CURADDL,curadd >> 10);
528 		DXIW(CURADDH,curadd >> 18);
529 		/* ... and repeat that: G100 requires other programming order than later cards!?! */
530 		DXIW(CURADDL,curadd >> 10);
531 		DXIW(CURADDH,curadd >> 18);
532 
533 		/*set cursor colour*/
534 		DXIW(CURCOL0RED,0XFF);
535 		DXIW(CURCOL0GREEN,0xFF);
536 		DXIW(CURCOL0BLUE,0xFF);
537 		DXIW(CURCOL1RED,0);
538 		DXIW(CURCOL1GREEN,0);
539 		DXIW(CURCOL1BLUE,0);
540 		DXIW(CURCOL2RED,0);
541 		DXIW(CURCOL2GREEN,0);
542 		DXIW(CURCOL2BLUE,0);
543 
544 		/*clear cursor*/
545 		fb = (uint32 *) si->framebuffer + curadd;
546 		for (i=0;i<(1024/4);i++)
547 		{
548 			fb[i]=0;
549 		}
550 	}
551 	else
552 	/* <= G100 cards have serial cursor color registers,
553 	 * and dedicated cursor bitmap RAM (in TVP3026 DAC)
554 	 */
555 	{
556 		/* select first colorRAM adress */
557 		DACW(TVP_CUROVRWTADD,0x00);
558 		/* overscan/border color is black, order of colors set is R,G,B */
559 		DACW(TVP_CUROVRDATA,0xff);
560 		DACW(TVP_CUROVRDATA,0xff);
561 		DACW(TVP_CUROVRDATA,0xff);
562 		/* set sursor color 0 */
563 		DACW(TVP_CUROVRDATA,0xff);
564 		DACW(TVP_CUROVRDATA,0xff);
565 		DACW(TVP_CUROVRDATA,0xff);
566 		/* set sursor color 1 */
567 		DACW(TVP_CUROVRDATA,0x00);
568 		DACW(TVP_CUROVRDATA,0x00);
569 		DACW(TVP_CUROVRDATA,0x00);
570 		/* set sursor color 2 */
571 		DACW(TVP_CUROVRDATA,0x00);
572 		DACW(TVP_CUROVRDATA,0x00);
573 		DACW(TVP_CUROVRDATA,0x00);
574 
575 		/* select first cursor pattern DAC-internal RAM adress, and
576 		 * make sure indirect cursor control register is selected as active register */
577 		DXIW(CURCTRL,(DXIR(CURCTRL) & 0x73));
578 		DACW(PALWTADD,0x00);
579 		/* now clear it, auto-incrementing the adress */
580 		for(i=0;i<1024;i++)
581 		{
582 			DACW(TVP_CURRAMDATA,0x00);
583 		}
584 	}
585 
586 	/* activate hardware cursor */
587 	DXIW(CURCTRL,1);
588 
589 	return B_OK;
590 }
591 
592 status_t gx00_crtc_cursor_show()
593 {
594 	if ((si->ps.card_type < G100) && (si->dm.timing.h_total > 2048))
595 	{
596 		/* MIL1/2 DAC needs to be told if h_total for the active mode gets above 2048 */
597 		DXIW(CURCTRL, 0x11);
598 	}
599 	else
600 	{
601 		DXIW(CURCTRL, 0x01);
602 	}
603 
604 	return B_OK;
605 }
606 
607 status_t gx00_crtc_cursor_hide()
608 {
609 	DXIW(CURCTRL,0);
610 	return B_OK;
611 }
612 
613 /*set up cursor shape*/
614 status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
615 {
616 	int y;
617 
618 	if(si->ps.card_type >= G100)
619 	{
620 		uint8 * cursor;
621 
622 		/*get a pointer to the cursor*/
623 		cursor = (uint8*) si->framebuffer;
624 
625 		/*draw the cursor*/
626 		for(y=0;y<16;y++)
627 		{
628 			cursor[y*16+7]=~*andMask++;
629 			cursor[y*16+15]=*xorMask++;
630 			cursor[y*16+6]=~*andMask++;
631 			cursor[y*16+14]=*xorMask++;
632 		}
633 	}
634 	else
635 	/* <= G100 cards have dedicated cursor bitmap RAM (in TVP3026 DAC) */
636 	{
637 		uint8 curctrl;
638 
639 		/* disable the cursor to prevent distortions in screen output */
640 		curctrl = (DXIR(CURCTRL));
641 		DXIW(CURCTRL, (curctrl & 0xfc));
642 		/* select first cursor pattern DAC-internal RAM adress for plane 0 */
643 		DXIW(CURCTRL, (DXIR(CURCTRL) & ~0x0c));
644 		DACW(PALWTADD, 0x00);
645 		/* now fill it, partly auto-incrementing the adress */
646 		for(y = 0; y < 16; y++)
647 		{
648 			DACW(PALWTADD, (y * 8));
649 			DACW(TVP_CURRAMDATA, ~*andMask++);
650 			DACW(TVP_CURRAMDATA, ~*andMask++);
651 		}
652 		/* select first cursor pattern DAC-internal RAM adress for plane 1 */
653 		DXIW(CURCTRL, (DXIR(CURCTRL) | 0x08));
654 		DACW(PALWTADD, 0x00);
655 		/* now fill it, partly auto-incrementing the adress */
656 		for(y = 0; y < 16; y++)
657 		{
658 			DACW(PALWTADD, y*8);
659 			DACW(TVP_CURRAMDATA, *xorMask++);
660 			DACW(TVP_CURRAMDATA, *xorMask++);
661 		}
662 		/* delay restoring the cursor to prevent distortions in screen output */
663 		snooze(5);
664 		/* restore the cursor */
665 		DXIW(CURCTRL, curctrl);
666 	}
667 
668 	return B_OK;
669 }
670 
671 /*position the cursor*/
672 status_t gx00_crtc_cursor_position(uint16 x ,uint16 y)
673 {
674 	int i=64;
675 
676 	x+=i;
677 	y+=i;
678 
679 	/* make sure we are not in retrace, because the register(s) might get copied
680 	 * during our reprogramming them (double buffering feature) */
681 	while (ACCR(STATUS) & 0x08)
682 	{
683 		snooze(4);
684 	}
685 
686 	DACW(CURSPOSXL,x&0xFF);
687 	DACW(CURSPOSXH,x>>8);
688 	DACW(CURSPOSYL,y&0xFF);
689 	DACW(CURSPOSYH,y>>8);
690 
691 	return B_OK;
692 }
693