xref: /haiku/src/add-ons/accelerants/nvidia/engine/nv_crtc2.c (revision c567e07285203eb13751794705114a1ff5292f3e)
1 /* second CTRC functionality for GeForce cards */
2 /* Author:
3    Rudolf Cornelissen 11/2002-3/2004
4 */
5 
6 #define MODULE_BIT 0x00020000
7 
8 #include "nv_std.h"
9 
10 /*Adjust passed parameters to a valid mode line*/
11 status_t nv_crtc2_validate_timing(
12 	uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
13 	uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
14 )
15 {
16 /* horizontal */
17 	/* make all parameters multiples of 8 */
18 	*hd_e &= 0xfff8;
19 	*hs_s &= 0xfff8;
20 	*hs_e &= 0xfff8;
21 	*ht   &= 0xfff8;
22 
23 	/* confine to required number of bits, taking logic into account */
24 	if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3);
25 	if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
26 	if (*hs_e > ( 0x01ff      << 3)) *hs_e = ( 0x01ff      << 3);
27 	if (*ht   > ((0x01ff + 5) << 3)) *ht   = ((0x01ff + 5) << 3);
28 
29 	/* NOTE: keep horizontal timing at multiples of 8! */
30 	/* confine to a reasonable width */
31 	if (*hd_e < 640) *hd_e = 640;
32 	if (*hd_e > 2048) *hd_e = 2048;
33 
34 	/* if hor. total does not leave room for a sensible sync pulse, increase it! */
35 	if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
36 
37 	/* make sure sync pulse is not during display */
38 	if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
39 	if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
40 
41 	/* correct sync pulse if it is too long:
42 	 * there are only 5 bits available to save this in the card registers! */
43 	if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
44 
45 /*vertical*/
46 	/* confine to required number of bits, taking logic into account */
47 	//fixme if needed: on GeForce cards there are 12 instead of 11 bits...
48 	if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
49 	if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
50 	if (*vs_e >  0x7ff     ) *vs_e =  0x7ff     ;
51 	if (*vt   > (0x7ff + 2)) *vt   = (0x7ff + 2);
52 
53 	/* confine to a reasonable height */
54 	if (*vd_e < 480) *vd_e = 480;
55 	if (*vd_e > 1536) *vd_e = 1536;
56 
57 	/*if vertical total does not leave room for a sync pulse, increase it!*/
58 	if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
59 
60 	/* make sure sync pulse is not during display */
61 	if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
62 	if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
63 
64 	/* correct sync pulse if it is too long:
65 	 * there are only 4 bits available to save this in the card registers! */
66 	if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
67 
68 	return B_OK;
69 }
70 
71 /*set a mode line - inputs are in pixels*/
72 status_t nv_crtc2_set_timing(display_mode target)
73 {
74 	uint8 temp;
75 
76 	uint32 htotal;		/*total horizontal total VCLKs*/
77 	uint32 hdisp_e;            /*end of horizontal display (begins at 0)*/
78 	uint32 hsync_s;            /*begin of horizontal sync pulse*/
79 	uint32 hsync_e;            /*end of horizontal sync pulse*/
80 	uint32 hblnk_s;            /*begin horizontal blanking*/
81 	uint32 hblnk_e;            /*end horizontal blanking*/
82 
83 	uint32 vtotal;		/*total vertical total scanlines*/
84 	uint32 vdisp_e;            /*end of vertical display*/
85 	uint32 vsync_s;            /*begin of vertical sync pulse*/
86 	uint32 vsync_e;            /*end of vertical sync pulse*/
87 	uint32 vblnk_s;            /*begin vertical blanking*/
88 	uint32 vblnk_e;            /*end vertical blanking*/
89 
90 	uint32 linecomp;	/*split screen and vdisp_e interrupt*/
91 
92 	LOG(4,("CRTC2: setting timing\n"));
93 
94 	/* setup fixed modeline for flatpanel if connected and active */
95 	if (si->ps.tmds2_active)
96 	{
97 		LOG(2,("CRTC2: DFP active: tuning modeline\n"));
98 
99 		/* horizontal timing */
100 		target.timing.h_total = target.timing.h_display + 56;
101 		target.timing.h_sync_start = target.timing.h_total - 40;
102 		target.timing.h_sync_end = target.timing.h_total - 16;
103 
104 		/* vertical timing */
105 		target.timing.v_total = target.timing.v_display + 6;
106 		target.timing.v_sync_start = target.timing.v_total - 3;
107 		target.timing.v_sync_end = target.timing.v_total - 2;
108 	}
109 
110 	/* Modify parameters as required by standard VGA */
111 	htotal = ((target.timing.h_total >> 3) - 5);
112 	hdisp_e = ((target.timing.h_display >> 3) - 1);
113 	hblnk_s = hdisp_e;
114 	hblnk_e = (htotal + 4);//0;
115 	hsync_s = (target.timing.h_sync_start >> 3);
116 	hsync_e = (target.timing.h_sync_end >> 3);
117 
118 	vtotal = target.timing.v_total - 2;
119 	vdisp_e = target.timing.v_display - 1;
120 	vblnk_s = vdisp_e;
121 	vblnk_e = (vtotal + 1);
122 	vsync_s = target.timing.v_sync_start;//-1;
123 	vsync_e = target.timing.v_sync_end;//-1;
124 
125 	/* prevent memory adress counter from being reset (linecomp may not occur) */
126 	linecomp = target.timing.v_display;
127 
128 	/* enable access to CRTC2 */
129 	CRTC2W(OWNER, 0x03);
130 
131 	/* Note for laptop and DVI flatpanels:
132 	 * CRTC timing has a seperate set of registers from flatpanel timing.
133 	 * The flatpanel timing registers have scaling registers that are used to match
134 	 * these two modelines. */
135 	{
136 		LOG(4,("CRTC2: Setting full timing...\n"));
137 
138 		/* log the mode that will be set */
139 		LOG(2,("CRTC2:\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));
140 		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));
141 
142 		/* actually program the card! */
143 		/* unlock CRTC registers at index 0-7 */
144 		CRTC2W(VSYNCE, (CRTC2R(VSYNCE) & 0x7f));
145 		/* horizontal standard VGA regs */
146 		CRTC2W(HTOTAL, (htotal & 0xff));
147 		CRTC2W(HDISPE, (hdisp_e & 0xff));
148 		CRTC2W(HBLANKS, (hblnk_s & 0xff));
149 		/* also unlock vertical retrace registers in advance */
150 		CRTC2W(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
151 		CRTC2W(HSYNCS, (hsync_s & 0xff));
152 		CRTC2W(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
153 
154 		/* vertical standard VGA regs */
155 		CRTC2W(VTOTAL, (vtotal & 0xff));
156 		CRTC2W(OVERFLOW,
157 		(
158 			((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
159 			((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
160 			((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
161 			((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
162 		));
163 		CRTC2W(PRROWSCN, 0x00); /* not used */
164 		CRTC2W(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
165 		CRTC2W(VSYNCS, (vsync_s & 0xff));
166 		CRTC2W(VSYNCE, ((CRTC2R(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
167 		CRTC2W(VDISPE, (vdisp_e & 0xff));
168 		CRTC2W(VBLANKS, (vblnk_s & 0xff));
169 		CRTC2W(VBLANKE, (vblnk_e & 0xff));
170 		CRTC2W(LINECOMP, (linecomp & 0xff));
171 
172 		/* horizontal extended regs */
173 		//fixme: we reset bit4. is this correct??
174 		CRTC2W(HEB, (CRTC2R(HEB) & 0xe0) |
175 			(
176 		 	((htotal & 0x100) >> (8 - 0)) |
177 			((hdisp_e & 0x100) >> (8 - 1)) |
178 			((hblnk_s & 0x100) >> (8 - 2)) |
179 			((hsync_s & 0x100) >> (8 - 3))
180 			));
181 
182 		/* (mostly) vertical extended regs */
183 		CRTC2W(LSR,
184 			(
185 		 	((vtotal & 0x400) >> (10 - 0)) |
186 			((vdisp_e & 0x400) >> (10 - 1)) |
187 			((vsync_s & 0x400) >> (10 - 2)) |
188 			((vblnk_s & 0x400) >> (10 - 3)) |
189 			((hblnk_e & 0x040) >> (6 - 4))
190 			//fixme: we still miss one linecomp bit!?! is this it??
191 			//| ((linecomp & 0x400) >> 3)
192 			));
193 
194 		/* more vertical extended regs */
195 		CRTC2W(EXTRA,
196 			(
197 		 	((vtotal & 0x800) >> (11 - 0)) |
198 			((vdisp_e & 0x800) >> (11 - 2)) |
199 			((vsync_s & 0x800) >> (11 - 4)) |
200 			((vblnk_s & 0x800) >> (11 - 6))
201 			//fixme: do we miss another linecomp bit!?!
202 			));
203 
204 		/* setup 'large screen' mode */
205 		if (target.timing.h_display >= 1280)
206 			CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xfb));
207 		else
208 			CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x04));
209 
210 		/* setup HSYNC & VSYNC polarity */
211 		LOG(2,("CRTC2: sync polarity: "));
212 		temp = NV_REG8(NV8_MISCR);
213 		if (target.timing.flags & B_POSITIVE_HSYNC)
214 		{
215 			LOG(2,("H:pos "));
216 			temp &= ~0x40;
217 		}
218 		else
219 		{
220 			LOG(2,("H:neg "));
221 			temp |= 0x40;
222 		}
223 		if (target.timing.flags & B_POSITIVE_VSYNC)
224 		{
225 			LOG(2,("V:pos "));
226 			temp &= ~0x80;
227 		}
228 		else
229 		{
230 			LOG(2,("V:neg "));
231 			temp |= 0x80;
232 		}
233 		NV_REG8(NV8_MISCW) = temp;
234 
235 		LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR)));
236 	}
237 
238 	/* always disable interlaced operation */
239 	/* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */
240 	CRTC2W(INTERLACE, 0xff);
241 
242 	/* setup flatpanel if connected and active */
243 	if (si->ps.tmds2_active)
244 	{
245 		uint32 iscale_x, iscale_y;
246 
247 		//fixme: checkout upscaling and aspect!!!
248 		/* calculate needed inverse scaling factors in 20.12 format */
249 		iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.panel2_width);
250 		iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.panel2_height);
251 
252 		/* unblock flatpanel timing programming (or something like that..) */
253 		CRTC2W(FP_HTIMING, 0);
254 		CRTC2W(FP_VTIMING, 0);
255 
256 		/* nVidia cards support upscaling except on NV11 */
257 		if (si->ps.card_arch == NV11)
258 		{
259 			/* disable last fetched line limiting */
260 			DAC2W(FP_DEBUG2, 0x00000000);
261 			/* inform panel to scale if needed */
262 			if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12)))
263 			{
264 				LOG(2,("CRTC2: DFP needs to do scaling\n"));
265 				DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) | 0x00000100));
266 			}
267 			else
268 			{
269 				LOG(2,("CRTC2: no scaling for DFP needed\n"));
270 				DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff));
271 			}
272 		}
273 		else
274 		{
275 			LOG(2,("CRTC2: GPU scales for DFP if needed\n"));
276 
277 			/* GPU scaling is automatically setup by hardware */
278 //fixme: checkout non 4:3 aspect scaling.
279 //			DAC2W(FP_DEBUG3, (iscale_x & 0x00001fff) | ((iscale_y & 0x00001fff) << 16));
280 //			temp = (((iscale_x >> 1) & 0x00000fff) | (((iscale_y >> 1) & 0x00000fff) << 16));
281 //			DAC2W(FP_DEBUG1, (temp | (1 << 12) | (1 << 28)));
282 
283 			/* limit last fetched line if vertical scaling is done */
284 			if (iscale_y != (1 << 12))
285 				DAC2W(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16)));
286 //not needed apparantly:
287 //								((1 << 12) | ((target.timing.h_display - 1) <<  0)));
288 			else
289 				DAC2W(FP_DEBUG2, 0x00000000);
290 
291 			/* inform panel not to scale */
292 			DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff));
293 		}
294 
295 		/* do some logging.. */
296 		LOG(2,("CRTC2: FP_DEBUG0 reg readback: $%08x\n", DAC2R(FP_DEBUG0)));
297 		LOG(2,("CRTC2: FP_DEBUG1 reg readback: $%08x\n", DAC2R(FP_DEBUG1)));
298 		LOG(2,("CRTC2: FP_DEBUG2 reg readback: $%08x\n", DAC2R(FP_DEBUG2)));
299 		LOG(2,("CRTC2: FP_DEBUG3 reg readback: $%08x\n", DAC2R(FP_DEBUG3)));
300 		LOG(2,("CRTC2: FP_TG_CTRL reg readback: $%08x\n", DAC2R(FP_TG_CTRL)));
301 	}
302 
303 	return B_OK;
304 }
305 
306 status_t nv_crtc2_depth(int mode)
307 {
308 	uint8 viddelay = 0;
309 	uint32 genctrl = 0;
310 
311 	/* set VCLK scaling */
312 	switch(mode)
313 	{
314 	case BPP8:
315 		viddelay = 0x01;
316 		/* genctrl b4 & b5 reset: 'direct mode' */
317 		genctrl = 0x00101100;
318 		break;
319 	case BPP15:
320 		viddelay = 0x02;
321 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
322 		genctrl = 0x00100130;
323 		break;
324 	case BPP16:
325 		viddelay = 0x02;
326 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
327 		genctrl = 0x00101130;
328 		break;
329 	case BPP24:
330 		viddelay = 0x03;
331 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
332 		genctrl = 0x00100130;
333 		break;
334 	case BPP32:
335 		viddelay = 0x03;
336 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
337 		genctrl = 0x00101130;
338 		break;
339 	}
340 	/* enable access to CRTC2 */
341 	CRTC2W(OWNER, 0x03);
342 
343 	CRTC2W(PIXEL, ((CRTC2R(PIXEL) & 0xfc) | viddelay));
344 	DAC2W(GENCTRL, genctrl);
345 
346 	return B_OK;
347 }
348 
349 status_t nv_crtc2_dpms(bool display, bool h, bool v)
350 {
351 	uint8 temp;
352 
353 	LOG(4,("CRTC2: setting DPMS: "));
354 
355 	/* enable access to CRTC2 (and SEQUENCER2) */
356 	CRTC2W(OWNER, 0x03);
357 
358 	/* start synchronous reset: required before turning screen off! */
359 	SEQW(RESET, 0x01);
360 
361 	/* turn screen off */
362 	temp = SEQR(CLKMODE);
363 	if (display)
364 	{
365 		SEQW(CLKMODE, (temp & ~0x20));
366 
367 		/* end synchronous reset if display should be enabled */
368 		SEQW(RESET, 0x03);
369 
370 		LOG(4,("display on, "));
371 	}
372 	else
373 	{
374 		SEQW(CLKMODE, (temp | 0x20));
375 
376 		LOG(4,("display off, "));
377 	}
378 
379 	if (h)
380 	{
381 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0x7f));
382 		LOG(4,("hsync enabled, "));
383 	}
384 	else
385 	{
386 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x80));
387 		LOG(4,("hsync disabled, "));
388 	}
389 	if (v)
390 	{
391 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xbf));
392 		LOG(4,("vsync enabled\n"));
393 	}
394 	else
395 	{
396 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x40));
397 		LOG(4,("vsync disabled\n"));
398 	}
399 
400 	return B_OK;
401 }
402 
403 status_t nv_crtc2_dpms_fetch(bool *display, bool *h, bool *v)
404 {
405 	/* enable access to CRTC2 (and SEQUENCER2) */
406 	CRTC2W(OWNER, 0x03);
407 
408 	*display = !(SEQR(CLKMODE) & 0x20);
409 	*h = !(CRTC2R(REPAINT1) & 0x80);
410 	*v = !(CRTC2R(REPAINT1) & 0x40);
411 
412 	LOG(4,("CTRC2: fetched DPMS state:"));
413 	if (display) LOG(4,("display on, "));
414 	else LOG(4,("display off, "));
415 	if (h) LOG(4,("hsync enabled, "));
416 	else LOG(4,("hsync disabled, "));
417 	if (v) LOG(4,("vsync enabled\n"));
418 	else LOG(4,("vsync disabled\n"));
419 
420 	return B_OK;
421 }
422 
423 status_t nv_crtc2_set_display_pitch()
424 {
425 	uint32 offset;
426 
427 	LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
428 
429 	/* figure out offset value hardware needs */
430 	offset = si->fbc.bytes_per_row / 8;
431 
432 	LOG(2,("CRTC2: offset register set to: $%04x\n", offset));
433 
434 	/* enable access to CRTC2 */
435 	CRTC2W(OWNER, 0x03);
436 
437 	/* program the card */
438 	CRTC2W(PITCHL, (offset & 0x00ff));
439 	CRTC2W(REPAINT0, ((CRTC2R(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
440 
441 	return B_OK;
442 }
443 
444 status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp)
445 {
446 	uint32 timeout = 0;
447 
448 	LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp));
449 
450 	LOG(2,("CRTC2: startadd: $%08x\n", startadd));
451 	LOG(2,("CRTC2: frameRAM: $%08x\n", si->framebuffer));
452 	LOG(2,("CRTC2: framebuffer: $%08x\n", si->fbc.frame_buffer));
453 
454 	/* we might have no retraces during setmode! */
455 	/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
456 	while (((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display) &&
457 			(timeout < (25000/10)))
458 	{
459 		/* don't snooze much longer or retrace might get missed! */
460 		snooze(10);
461 		timeout++;
462 	}
463 
464 	/* enable access to CRTC2 */
465 	CRTC2W(OWNER, 0x03);
466 
467 	/* upto 4Gb RAM adressing: must be used on NV10 and later! */
468 	/* NOTE:
469 	 * While this register also exists on pre-NV10 cards, it will
470 	 * wrap-around at 16Mb boundaries!! */
471 
472 	/* 30bit adress in 32bit words */
473 	NV_REG32(NV32_NV10FB2STADD32) = (startadd & 0xfffffffc);
474 
475 	/* set byte adress: (b0 - 1) */
476 	ATB2W(HORPIXPAN, ((startadd & 0x00000003) << 1));
477 
478 	return B_OK;
479 }
480 
481 status_t nv_crtc2_cursor_init()
482 {
483 	int i;
484 	uint32 * fb;
485 	/* cursor bitmap will be stored at the start of the framebuffer */
486 	const uint32 curadd = 0;
487 
488 	/* enable access to CRTC2 */
489 	CRTC2W(OWNER, 0x03);
490 
491 	/* set cursor bitmap adress ... */
492 	if (si->ps.laptop)
493 	{
494 		/* must be used this way on pre-NV10 and on all 'Go' cards! */
495 
496 		/* cursorbitmap must start on 2Kbyte boundary: */
497 		/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
498 		CRTC2W(CURCTL0, ((curadd & 0x0001f800) >> 9));
499 		/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
500 		CRTC2W(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
501 		/* set adress bit24-31 */
502 		CRTC2W(CURCTL2, ((curadd & 0xff000000) >> 24));
503 	}
504 	else
505 	{
506 		/* upto 4Gb RAM adressing:
507 		 * can be used on NV10 and later (except for 'Go' cards)! */
508 		/* NOTE:
509 		 * This register does not exist on pre-NV10 and 'Go' cards. */
510 
511 		/* cursorbitmap must still start on 2Kbyte boundary: */
512 		NV_REG32(NV32_NV10CUR2ADD32) = (curadd & 0xfffff800);
513 	}
514 
515 	/* set cursor colour: not needed because of direct nature of cursor bitmap. */
516 
517 	/*clear cursor*/
518 	fb = (uint32 *) si->framebuffer + curadd;
519 	for (i=0;i<(2048/4);i++)
520 	{
521 		fb[i]=0;
522 	}
523 
524 	/* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */
525 	NV_REG32(NV32_2CURCONF) = 0x02000100;
526 
527 	/* activate hardware cursor */
528 	nv_crtc2_cursor_show();
529 
530 	return B_OK;
531 }
532 
533 status_t nv_crtc2_cursor_show()
534 {
535 	LOG(4,("CRTC2: enabling cursor\n"));
536 
537 	/* enable access to CRTC2 */
538 	CRTC2W(OWNER, 0x03);
539 
540 	/* b0 = 1 enables cursor */
541 	CRTC2W(CURCTL0, (CRTC2R(CURCTL0) | 0x01));
542 
543 	return B_OK;
544 }
545 
546 status_t nv_crtc2_cursor_hide()
547 {
548 	LOG(4,("CRTC2: disabling cursor\n"));
549 
550 	/* enable access to CRTC2 */
551 	CRTC2W(OWNER, 0x03);
552 
553 	/* b0 = 0 disables cursor */
554 	CRTC2W(CURCTL0, (CRTC2R(CURCTL0) & 0xfe));
555 
556 	return B_OK;
557 }
558 
559 /*set up cursor shape*/
560 status_t nv_crtc2_cursor_define(uint8* andMask,uint8* xorMask)
561 {
562 	int x, y;
563 	uint8 b;
564 	uint16 *cursor;
565 	uint16 pixel;
566 
567 	/* get a pointer to the cursor */
568 	cursor = (uint16*) si->framebuffer;
569 
570 	/* draw the cursor */
571 	/* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */
572 	for (y = 0; y < 16; y++)
573 	{
574 		b = 0x80;
575 		for (x = 0; x < 8; x++)
576 		{
577 			/* preset transparant */
578 			pixel = 0x0000;
579 			/* set white if requested */
580 			if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
581 			/* set black if requested */
582 			if ((!(*andMask & b)) &&   (*xorMask & b))  pixel = 0x8000;
583 			/* set invert if requested */
584 			if (  (*andMask & b)  &&   (*xorMask & b))  pixel = 0x7fff;
585 			/* place the pixel in the bitmap */
586 			cursor[x + (y * 32)] = pixel;
587 			b >>= 1;
588 		}
589 		xorMask++;
590 		andMask++;
591 		b = 0x80;
592 		for (; x < 16; x++)
593 		{
594 			/* preset transparant */
595 			pixel = 0x0000;
596 			/* set white if requested */
597 			if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
598 			/* set black if requested */
599 			if ((!(*andMask & b)) &&   (*xorMask & b))  pixel = 0x8000;
600 			/* set invert if requested */
601 			if (  (*andMask & b)  &&   (*xorMask & b))  pixel = 0x7fff;
602 			/* place the pixel in the bitmap */
603 			cursor[x + (y * 32)] = pixel;
604 			b >>= 1;
605 		}
606 		xorMask++;
607 		andMask++;
608 	}
609 
610 	return B_OK;
611 }
612 
613 /* position the cursor */
614 status_t nv_crtc2_cursor_position(uint16 x, uint16 y)
615 {
616 	uint16 yhigh;
617 
618 	/* make sure we are beyond the first line of the cursorbitmap being drawn during
619 	 * updating the position to prevent distortions: no double buffering feature */
620 	/* Note:
621 	 * we need to return as quick as possible or some apps will exhibit lagging.. */
622 
623 	/* read the old cursor Y position */
624 	yhigh = ((DAC2R(CURPOS) & 0x0fff0000) >> 16);
625 	/* make sure we will wait until we are below both the old and new Y position:
626 	 * visible cursorbitmap drawing needs to be done at least... */
627 	if (y > yhigh) yhigh = y;
628 
629 	if (yhigh < (si->dm.timing.v_display - 16))
630 	{
631 		/* we have vertical lines below old and new cursorposition to spare. So we
632 		 * update the cursor postion 'mid-screen', but below that area. */
633 		while (((uint16)(NV_REG32(NV32_RASTER2) & 0x000007ff)) < (yhigh + 16))
634 		{
635 			snooze(10);
636 		}
637 	}
638 	else
639 	{
640 		/* no room to spare, just wait for retrace (is relatively slow) */
641 		while ((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display)
642 		{
643 			/* don't snooze much longer or retrace might get missed! */
644 			snooze(10);
645 		}
646 	}
647 
648 	/* update cursorposition */
649 	DAC2W(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
650 
651 	return B_OK;
652 }
653