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