xref: /haiku/src/add-ons/accelerants/neomagic/engine/nm_crtc.c (revision aa94570a34695672df9b47adda2257f75d8da880)
1 /* CTRC functionality */
2 /* Author:
3    Rudolf Cornelissen 4/2003-1/2004
4 */
5 
6 #define MODULE_BIT 0x00040000
7 
8 #include "nm_std.h"
9 
10 /* Adjust passed parameters to a valid mode line */
11 //fixme: the order of the sync edges should also be checked,
12 //just like the sync signal's min. pulse length...
13 status_t nm_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 &= 0xfff8;
21 	*hs_s &= 0xfff8;
22 	*hs_e &= 0xfff8;
23 	*ht   &= 0xfff8;
24 
25 	/* confine to required number of bits, taking logic into account */
26 	if (*hd_e > ((0xff - 2) << 3)) *hd_e = ((0xff - 2) << 3);
27 	if (*hs_s > ((0xff - 1) << 3)) *hs_s = ((0xff - 1) << 3);
28 	if (*hs_e > ( 0xff      << 3)) *hs_e = ( 0xff      << 3);
29 	if (*ht   > ((0xff + 5) << 3)) *ht   = ((0xff + 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 	if (*hd_e > si->ps.max_crtc_width) *hd_e = si->ps.max_crtc_width;
35 
36 	/* if hor. total does not leave room for a sensible sync pulse, increase it! */
37 	if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
38 
39 	/* make sure sync pulse is not during display */
40 	if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
41 	if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
42 
43 	/* correct sync pulse if it is too long:
44 	 * there are only 5 bits available to save this in the card registers! */
45 	if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
46 
47 /*vertical*/
48 	/* confine to required number of bits, taking logic into account */
49 	if (si->ps.card_type < NM2200)
50 	{
51 		if (*vd_e > (0x3ff - 2)) *vd_e = (0x3ff - 2);
52 		if (*vs_s > (0x3ff - 1)) *vs_s = (0x3ff - 1);
53 		if (*vs_e >  0x3ff     ) *vs_e =  0x3ff     ;
54 		if (*vt   > (0x3ff + 2)) *vt   = (0x3ff + 2);
55 	}
56 	else
57 	{
58 		if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
59 		if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
60 		if (*vs_e >  0x7ff     ) *vs_e =  0x7ff     ;
61 		if (*vt   > (0x7ff + 2)) *vt   = (0x7ff + 2);
62 	}
63 
64 	/* confine to a reasonable height */
65 	if (*vd_e < 480) *vd_e = 480;
66 	if (*vd_e > si->ps.max_crtc_height) *vd_e = si->ps.max_crtc_height;
67 
68 	/*if vertical total does not leave room for a sync pulse, increase it!*/
69 	if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
70 
71 	/* make sure sync pulse is not during display */
72 	if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
73 	if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
74 
75 	/* correct sync pulse if it is too long:
76 	 * there are only 4 bits available to save this in the card registers! */
77 	if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
78 
79 	return B_OK;
80 }
81 
82 /* set a mode line */
83 status_t nm_crtc_set_timing(display_mode target, bool crt_only)
84 {
85 	uint8 temp;
86 
87 	uint32 htotal;		/*total horizontal total VCLKs*/
88 	uint32 hdisp_e;            /*end of horizontal display (begins at 0)*/
89 	uint32 hsync_s;            /*begin of horizontal sync pulse*/
90 	uint32 hsync_e;            /*end of horizontal sync pulse*/
91 	uint32 hblnk_s;            /*begin horizontal blanking*/
92 	uint32 hblnk_e;            /*end horizontal blanking*/
93 
94 	uint32 vtotal;		/*total vertical total scanlines*/
95 	uint32 vdisp_e;            /*end of vertical display*/
96 	uint32 vsync_s;            /*begin of vertical sync pulse*/
97 	uint32 vsync_e;            /*end of vertical sync pulse*/
98 	uint32 vblnk_s;            /*begin vertical blanking*/
99 	uint32 vblnk_e;            /*end vertical blanking*/
100 
101 	uint32 linecomp;	/*split screen and vdisp_e interrupt*/
102 
103 	LOG(4,("CRTC: setting timing\n"));
104 
105 	/* modify visible sceensize if needed */
106 	/* (note that MOVE_CURSOR checks for a panning/scrolling mode itself,
107 	 *  the display_mode as placed in si->dm may _not_ be modified!) */
108 	if (!(crt_only))
109 	{
110 		if (target.timing.h_display > si->ps.panel_width)
111 		{
112 			target.timing.h_display = si->ps.panel_width;
113 			LOG(4, ("CRTC: req. width > panel width: setting panning mode\n"));
114 		}
115 		if (target.timing.v_display > si->ps.panel_height)
116 		{
117 			target.timing.v_display = si->ps.panel_height;
118 			LOG(4, ("CRTC: req. height > panel height: setting scrolling mode\n"));
119 		}
120 	}
121 
122 	/* Modify parameters as required by standard VGA */
123 	htotal = ((target.timing.h_total >> 3) - 5);
124 	hdisp_e = ((target.timing.h_display >> 3) - 1);
125 	hblnk_s = hdisp_e;
126 	hblnk_e = (htotal + 0); /* this register differs from standard VGA! (says + 4) */
127 	hsync_s = (target.timing.h_sync_start >> 3);
128 	hsync_e = (target.timing.h_sync_end >> 3);
129 
130 	vtotal = target.timing.v_total - 2;
131 	vdisp_e = target.timing.v_display - 1;
132 	vblnk_s = vdisp_e;
133 	vblnk_e = (vtotal + 1);
134 	vsync_s = target.timing.v_sync_start;//-1;
135 	vsync_e = target.timing.v_sync_end;//-1;
136 
137 	/* prevent memory adress counter from being reset (linecomp may not occur) */
138 	linecomp = target.timing.v_display;
139 
140 	if (crt_only)
141 	{
142 		LOG(4,("CRTC: CRT only mode, setting full timing...\n"));
143 
144 		/* log the mode that will be set */
145 		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));
146 		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));
147 
148 		/* actually program the card! */
149 		/* unlock CRTC registers at index 0-7 */
150 		temp = (ISACRTCR(VSYNCE) & 0x7f);
151 		/* we need to wait a bit or the card will mess-up it's register values.. */
152 		snooze(10);
153 		ISACRTCW(VSYNCE, temp);
154 		/* horizontal standard VGA regs */
155 		ISACRTCW(HTOTAL, (htotal & 0xff));
156 		ISACRTCW(HDISPE, (hdisp_e & 0xff));
157 		ISACRTCW(HBLANKS, (hblnk_s & 0xff));
158 		/* also unlock vertical retrace registers in advance */
159 		ISACRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
160 		ISACRTCW(HSYNCS, (hsync_s & 0xff));
161 		ISACRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
162 
163 		/* vertical standard VGA regs */
164 		ISACRTCW(VTOTAL, (vtotal & 0xff));
165 		ISACRTCW(OVERFLOW,
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 		ISACRTCW(PRROWSCN, 0x00); /* not used */
173 		ISACRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
174 		ISACRTCW(VSYNCS, (vsync_s & 0xff));
175 		temp = (ISACRTCR(VSYNCE) & 0xf0);
176 		/* we need to wait a bit or the card will mess-up it's register values.. */
177 		snooze(10);
178 		ISACRTCW(VSYNCE, (temp | (vsync_e & 0x0f)));
179 		ISACRTCW(VDISPE, (vdisp_e & 0xff));
180 		ISACRTCW(VBLANKS, (vblnk_s & 0xff));
181 		ISACRTCW(VBLANKE, (vblnk_e & 0xff));
182 //linux:
183 //	regp->CRTC[23] = 0xC3;
184 		ISACRTCW(LINECOMP, (linecomp & 0xff));
185 
186 		/* horizontal - no extended regs available or needed on NeoMagic chips */
187 
188 		/* vertical - extended regs */
189 //fixme: checkout if b2 or 3 should be switched! (linux contains error here)
190 //fixme: linecomp should also have an extra bit... testable by setting linecomp
191 //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest
192 //for screenorig reset visible on upper half of the screen or not at all..
193 		if (si->ps.card_type >= NM2200)
194 			ISACRTCW(VEXT,
195 			(
196 			 	((vtotal & 0x400) >> (10 - 0)) |
197 				((vdisp_e & 0x400) >> (10 - 1)) |
198 				((vblnk_s & 0x400) >> (10 - 2)) |
199 				((vsync_s & 0x400) >> (10 - 3))/*|
200 				((linecomp&0x400)>>3)*/
201 			));
202 
203 		/* setup HSYNC & VSYNC polarity */
204 		LOG(2,("CRTC: sync polarity: "));
205 		temp = ISARB(MISCR);
206 		if (target.timing.flags & B_POSITIVE_HSYNC)
207 		{
208 			LOG(2,("H:pos "));
209 			temp &= ~0x40;
210 		}
211 		else
212 		{
213 			LOG(2,("H:neg "));
214 			temp |= 0x40;
215 		}
216 		if (target.timing.flags & B_POSITIVE_VSYNC)
217 		{
218 			LOG(2,("V:pos "));
219 			temp &= ~0x80;
220 		}
221 		else
222 		{
223 			LOG(2,("V:neg "));
224 			temp |= 0x80;
225 		}
226 		/* we need to wait a bit or the card will mess-up it's register values.. */
227 		snooze(10);
228 		ISAWB(MISCW, temp);
229 
230 		LOG(2,(", MISC reg readback: $%02x\n", ISARB(MISCR)));
231 	}
232 	else
233 	{
234 		LOG(4,("CRTC: internal flatpanel active, setting display region only\n"));
235 
236 		/* actually program the card! */
237 		/* unlock CRTC registers at index 0-7 */
238 		temp = (ISACRTCR(VSYNCE) & 0x7f);
239 		/* we need to wait a bit or the card will mess-up it's register values.. */
240 		snooze(10);
241 		ISACRTCW(VSYNCE, temp);
242 		/* horizontal standard VGA regs */
243 		ISACRTCW(HDISPE, (hdisp_e & 0xff));
244 
245 		/* vertical standard VGA regs */
246 		temp = (ISACRTCR(OVERFLOW) & ~0x52);
247 		/* we need to wait a bit or the card will mess-up it's register values.. */
248 		snooze(10);
249 		ISACRTCW(OVERFLOW,
250 		(
251 			temp |
252 			((vdisp_e & 0x100) >> (8 - 1)) |
253 			((vdisp_e & 0x200) >> (9 - 6)) |
254 			((linecomp & 0x100) >> (8 - 4))
255 		));
256 
257 		ISACRTCW(PRROWSCN, 0x00); /* not used */
258 
259 		temp = (ISACRTCR(MAXSCLIN) & ~0x40);
260 		/* we need to wait a bit or the card will mess-up it's register values.. */
261 		snooze(10);
262 		ISACRTCW(MAXSCLIN, (temp | ((linecomp & 0x200) >> (9 - 6))));
263 
264 		ISACRTCW(VDISPE, (vdisp_e & 0xff));
265 //linux:
266 //	regp->CRTC[23] = 0xC3;
267 		ISACRTCW(LINECOMP, (linecomp & 0xff));
268 
269 		/* horizontal - no extended regs available or needed on NeoMagic chips */
270 
271 		/* vertical - extended regs */
272 //fixme: linecomp should have an extra bit... testable by setting linecomp
273 //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest
274 //for screenorig reset visible on upper half of the screen or not at all..
275 		if (si->ps.card_type >= NM2200)
276 		{
277 			temp = (ISACRTCR(VEXT) & ~0x02);
278 			/* we need to wait a bit or the card will mess-up it's register values.. */
279 			snooze(10);
280 			ISACRTCW(VEXT,
281 			(
282 				temp |
283 				((vdisp_e & 0x400) >> (10 - 1))/*|
284 				((linecomp&0x400)>>3)*/
285 			));
286 		}
287 	}
288 
289 	return B_OK;
290 }
291 
292 status_t nm_crtc_depth(int mode)
293 {
294 	uint8 vid_delay = 0;
295 
296 	LOG(4,("CRTC: setting colordepth to be displayed\n"));
297 
298 	/* set VCLK scaling */
299 	switch(mode)
300 	{
301 	case BPP8:
302 		vid_delay = 0x01;
303 		break;
304 	case BPP15:
305 		vid_delay = 0x02;
306 		break;
307 	case BPP16:
308 		vid_delay = 0x03;
309 		break;
310 	case BPP24:
311 		vid_delay = 0x04;
312 		break;
313 	default:
314 		LOG(4,("CRTC: colordepth not supported, aborting!\n"));
315 		return B_ERROR;
316 		break;
317 	}
318 
319 	switch (si->ps.card_type)
320 	{
321 	case NM2070:
322 		vid_delay |= (ISAGRPHR(COLDEPTH) & 0xf0);
323 		break;
324 	default:
325 		vid_delay |= (ISAGRPHR(COLDEPTH) & 0x70);
326 		break;
327 	}
328 	/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
329 	snooze(10);
330 	ISAGRPHW(COLDEPTH, vid_delay);
331 
332 	snooze(10);
333 	LOG(4,("CRTC: colordepth register readback $%02x\n", (ISAGRPHR(COLDEPTH))));
334 
335 	return B_OK;
336 }
337 
338 status_t nm_crtc_dpms(bool display, bool h, bool v)
339 {
340 	uint8 temp;
341 
342 	LOG(4,("CRTC: setting DPMS: "));
343 
344 	/* start synchronous reset: required before turning screen off! */
345 	ISASEQW(RESET, 0x01);
346 
347 	/* turn screen off */
348 	temp = ISASEQR(CLKMODE);
349 	/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
350 	snooze(10);
351 
352 	if (display)
353 	{
354 		ISASEQW(CLKMODE, (temp & ~0x20));
355 
356 		/* end synchronous reset if display should be enabled */
357 		ISASEQW(RESET, 0x03);
358 
359 		LOG(4,("display on\n"));
360 	}
361 	else
362 	{
363 		ISASEQW(CLKMODE, (temp | 0x20));
364 
365 		LOG(4,("display off\n"));
366 	}
367 
368 //	LOG(4,("CRTC: setting DPMS (%d,%d,%d)\n", display,h,v));
369 
370 //	VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0xCF)|((!v)<<5))|((!h)<<4);
371 
372 	/* set some required fixed values for proper nm mode initialisation */
373 //	VGAW_I(CRTC,0x17,0xC3);
374 //	VGAW_I(CRTC,0x14,0x00);
375 
376 	return B_OK;
377 }
378 
379 status_t nm_crtc_dpms_fetch(bool * display, bool * h, bool * v)
380 {
381 	*display = !(ISASEQR(CLKMODE) & 0x20);
382 
383 //	*display=!((VGAR_I(SEQ,1)&0x20)>>5);
384 //	*h=!((VGAR_I(CRTCEXT,1)&0x10)>>4);
385 //	*v=!((VGAR_I(CRTCEXT,1)&0x20)>>5);
386 
387 	*h = *v = true;
388 
389 	LOG(4,("CTRC: fetched DPMS state:"));
390 	if (display) LOG(4,("display on\n"));
391 	else LOG(4,("display off\n"));
392 
393 	return B_OK;
394 }
395 
396 status_t nm_crtc_set_display_pitch()
397 {
398 	uint32 offset;
399 
400 	LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
401 
402 	/* figure out offset value hardware needs: same for all Neomagic cards */
403 	offset = si->fbc.bytes_per_row / 8;
404 
405 	LOG(2,("CRTC: offset register set to: $%04x\n", offset));
406 
407 	/* program the card */
408 	ISACRTCW(PITCHL, (offset & 0xff));
409 	//fixme: test for max supported pitch if possible,
410 	//not all bits below will be implemented.
411 	//NM2160: confirmed b0 and b1 in register below to exist and work.
412 	ISAGRPHW(CRTC_PITCHE, ((offset & 0xff00) >> 8));
413 
414 	return B_OK;
415 }
416 
417 status_t nm_crtc_set_display_start(uint32 startadd,uint8 bpp)
418 {
419 	uint8 val;
420 	uint32 timeout = 0;
421 
422 	LOG(2,("CRTC: relative startadd: $%06x\n",startadd));
423 	LOG(2,("CRTC: frameRAM: $%08x\n",si->framebuffer));
424 	LOG(2,("CRTC: framebuffer: $%08x\n",si->fbc.frame_buffer));
425 
426 	/* make sure we are in retrace, because otherwise distortions might occur
427 	 * during our reprogramming them (no double buffering) (verified on NM2160) */
428 
429 	/* we might have no retraces during setmode! So:
430 	 * wait 25mS max. for retrace to occur (refresh > 40Hz) */
431 	//fixme? move this function to the kernel driver... is much 'faster'.
432 	while ((!(ISARB(INSTAT1) & 0x08)) && (timeout < (25000/4)))
433 	{
434 		snooze(4);
435 		timeout++;
436 	}
437 
438 	/* the neomagic framebuffer startadress is given in 32bit words */
439 	startadd >>= 2;
440 
441 	/* set standard VGA registers */
442     ISACRTCW(FBSTADDH, ((startadd & 0x00FF00) >> 8));
443     ISACRTCW(FBSTADDL, (startadd & 0x0000FF));
444 
445 	/* set NM extended register */
446 	//fixme: NM2380 _must_ have one more bit (has >4Mb RAM)!!
447 	//this is testable via virtualscreen in 640x480x8 mode...
448 	//(b4 is >256Kb adresswrap bit, so that's already occupied)
449 	val = ISAGRPHR(FBSTADDE);
450 	/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
451 	snooze(10);
452 	if (si->ps.card_type < NM2200)
453 		ISAGRPHW(FBSTADDE,(((startadd >> 16) & 0x07) | (val & 0xf8)));
454 	else
455 		ISAGRPHW(FBSTADDE,(((startadd >> 16) & 0x0f) | (val & 0xf0)));
456 
457 	return B_OK;
458 }
459 
460 /* setup centering mode for current internal or simultaneous flatpanel mode */
461 status_t nm_crtc_center(display_mode target)
462 {
463 	uint8 vcent1, vcent2, vcent3, vcent4, vcent5;
464 	uint8 hcent1, hcent2, hcent3, hcent4, hcent5;
465 	uint8 ctrl2, ctrl3;
466 
467 	/* preset no centering */
468 	uint16 hoffset = 0;
469 	uint16 voffset = 0;
470 	vcent1 = vcent2 = vcent3 = vcent4 = vcent5 = 0x00;
471 	hcent1 = hcent2 = hcent3 = hcent4 = hcent5 = 0x00;
472 	ctrl2 = ctrl3 = 0x00;
473 
474 	/* calculate offsets for centering if prudent */
475 	if (target.timing.h_display < si->ps.panel_width)
476 	{
477 		hoffset = (si->ps.panel_width - target.timing.h_display);
478 		/* adjust for register contraints:
479 		 * horizontal center granularity is 16 pixels */
480 		hoffset = ((hoffset >> 4) - 1);
481 //fixme: what does this do?
482 		/* turn on horizontal centering? */
483 		ctrl3 = 0x10;
484 	}
485 
486 	if (target.timing.v_display < si->ps.panel_height)
487 	{
488 		voffset = (si->ps.panel_height - target.timing.v_display);
489 		/* adjust for register contraints:
490 		 * vertical center granularity is 2 pixels */
491 		voffset = ((voffset >> 1) - 2);
492 //fixme: what does this do?
493 		/* turn on vertical centering? */
494 		ctrl2 = 0x01;
495 	}
496 
497 	switch(target.timing.h_display)
498 	{
499 	case 640:
500 		hcent1 = hoffset;
501 		vcent3 = voffset;
502 		break;
503 	case 800:
504 		hcent2 = hoffset;
505 		switch(target.timing.v_display)
506 		{
507 		case 480:
508 			//Linux fixme: check this out...
509 			vcent3 = voffset;
510 			break;
511 		case 600:
512 			vcent4 = voffset;
513 			break;
514 		}
515 		break;
516 	case 1024:
517 		hcent5 = hoffset;
518 		vcent5 = voffset;
519 		break;
520 	case 1280:
521 		/* this mode equals the largest possible panel on the newest chip:
522 		 * so no centering needed here. */
523 		break;
524 	default:
525 		//fixme?: block non-standard modes? for now: not centered.
526 		break;
527 	}
528 
529 	/* now program the card's registers */
530 	ISAGRPHW(PANELVCENT1, vcent1);
531 	ISAGRPHW(PANELVCENT2, vcent2);
532 	ISAGRPHW(PANELVCENT3, vcent3);
533 	if (si->ps.card_type > NM2070)
534 	{
535 		ISAGRPHW(PANELVCENT4, vcent4);
536 		ISAGRPHW(PANELHCENT1, hcent1);
537 		ISAGRPHW(PANELHCENT2, hcent2);
538 		ISAGRPHW(PANELHCENT3, hcent3);
539 	}
540 	if (si->ps.card_type >= NM2160)
541 	{
542 		ISAGRPHW(PANELHCENT4, hcent4);
543 	}
544 	if (si->ps.card_type >= NM2200)
545 	{
546 		ISAGRPHW(PANELVCENT5, vcent5);
547 		ISAGRPHW(PANELHCENT5, hcent5);
548 	}
549 
550 	/* program panel control register 2: don't touch bit 3-5 */
551 	ctrl2 |= (ISAGRPHR(PANELCTRL2) & 0x38);
552 	/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
553 	snooze(10);
554 	ISAGRPHW(PANELCTRL2, ctrl2);
555 
556 	if (si->ps.card_type > NM2070)
557 	{
558 		/* program panel control register 3: don't touch bit 7-5 and bit 3-0 */
559 		ctrl3 |= (ISAGRPHR(PANELCTRL3) & 0xef);
560 		/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
561 		snooze(10);
562 		ISAGRPHW(PANELCTRL3, ctrl3);
563 	}
564 
565 	return B_OK;
566 }
567 
568 status_t nm_crtc_cursor_init()
569 {
570 	int i;
571 	uint32 * fb;
572 	/* cursor bitmap will be stored at the start of the framebuffer */
573 	uint32 curadd = 0, curreg;
574 
575 	/* set cursor bitmap adress on a 1kb boundary, and move the bits around
576 	 * so they get placed at the correct registerbits */
577 	//fixme: NM2380 must have an extra bit for > 4Mb???
578 	curreg = (((curadd >> 10) & 0x000f) << 8);
579 	curreg |= (((curadd >> 10) & 0x0ff0) >> 4);
580 
581 	if (si->ps.card_type < NM2200)
582 		CR1W(CURADDRESS, curreg);
583 	else
584 		CR1W(22CURADDRESS, curreg);
585 
586 	/*set cursor colour*/
587 	if (si->ps.card_type < NM2200)
588 	{
589 		/* background is black */
590 		CR1W(CURBGCOLOR, 0x00000000);
591 		/* foreground is white */
592 		CR1W(CURFGCOLOR, 0x00ffffff);
593 	}
594 	else
595 	{
596 		/* background is black */
597 		CR1W(22CURBGCOLOR, 0x00000000);
598 		/* foreground is white */
599 		CR1W(22CURFGCOLOR, 0x00ffffff);
600 	}
601 
602 	/*clear cursor*/
603 	fb = (uint32 *) si->framebuffer + curadd;
604 	for (i=0;i<(1024/4);i++)
605 	{
606 		fb[i]=0;
607 	}
608 
609 	/* activate hardware cursor */
610 	nm_crtc_cursor_show();
611 
612 	return B_OK;
613 }
614 
615 status_t nm_crtc_cursor_show()
616 {
617 	if (si->ps.card_type < NM2200)
618 	{
619 		CR1W(CURCTRL, 0x00000001);
620 	}
621 	else
622 	{
623 		CR1W(22CURCTRL, 0x00000001);
624 	}
625 	return B_OK;
626 }
627 
628 status_t nm_crtc_cursor_hide()
629 {
630 //linux fixme: using this kills PCI(?) access sometimes, so use ISA access as below...
631 /*
632 	if (si->ps.card_type < NM2200)
633 	{
634 		CR1W(CURCTRL, 0x00000000);
635 	}
636 	else
637 	{
638 		CR1W(22CURCTRL, 0x00000000);
639 	}
640 */
641 	/* disable cursor */
642 	ISAGRPHW(CURCTRL,0x00);
643 
644 	return B_OK;
645 }
646 
647 /*set up cursor shape*/
648 status_t nm_crtc_cursor_define(uint8* andMask,uint8* xorMask)
649 {
650 	uint8 y;
651 	uint8 * cursor;
652 
653 	/*get a pointer to the cursor*/
654 	cursor = (uint8*) si->framebuffer;
655 
656 	/*draw the cursor*/
657 	for(y=0;y<16;y++)
658 	{
659 		cursor[y*16+8]=~*andMask++;
660 		cursor[y*16+0]=*xorMask++;
661 		cursor[y*16+9]=~*andMask++;
662 		cursor[y*16+1]=*xorMask++;
663 	}
664 
665 	//test.. only valid for <NM2200!!
666 /*	{
667 		float pclk;
668 		uint8 n,m,x = 1;
669 		n = ISAGRPHR(PLLC_NL);
670 		m = ISAGRPHR(PLLC_M);
671 		LOG(4,("CRTC: PLLSEL $%02x\n", ISARB(MISCR)));
672 		LOG(4,("CRTC: PLLN $%02x\n", n));
673 		LOG(4,("CRTC: PLLM $%02x\n", m));
674 
675 		if (n & 0x80) x = 2;
676 		n &= 0x7f;
677 		pclk = ((si->ps.f_ref * (n + 1)) / ((m + 1) * x));
678 		LOG(2,("CRTC: Pixelclock is %fMHz\n", pclk));
679 		nm_general_output_select();
680 	}
681 */
682 	return B_OK;
683 }
684 
685 /*position the cursor*/
686 status_t nm_crtc_cursor_position(uint16 x ,uint16 y)
687 {
688 //NM2160 is ok without this, still verify the rest..:
689 	/* make sure we are not in retrace, because the register(s) might get copied
690 	 * during our reprogramming them (double buffering feature) */
691 /*	fixme!?
692 	while (ACCR(STATUS) & 0x08)
693 	{
694 		snooze(4);
695 	}
696 */
697 	if (si->ps.card_type < NM2200)
698 	{
699 		CR1W(CURX, (uint32)x);
700 		CR1W(CURY, (uint32)y);
701 	}
702 	else
703 	{
704 		CR1W(22CURX, (uint32)x);
705 		CR1W(22CURY, (uint32)y);
706 	}
707 
708 	return B_OK;
709 }
710