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