1/*
2	Copyright 1999, Be Incorporated.   All Rights Reserved.
3	This file may be used under the terms of the Be Sample Code License.
4
5	Other authors:
6	Mark Watson,
7	Apsed,
8	Rudolf Cornelissen 11/2002-5/2006
9*/
10
11#define MODULE_BIT 0x00200000
12
13#include "acc_std.h"
14
15/*
16	Enable/Disable interrupts.  Just a wrapper around the
17	ioctl() to the kernel driver.
18*/
19static void interrupt_enable(bool flag)
20{
21	status_t result;
22	gx00_set_bool_state sbs;
23
24	if (si->ps.int_assigned)
25	{
26		/* set the magic number so the driver knows we're for real */
27		sbs.magic = GX00_PRIVATE_DATA_MAGIC;
28		sbs.do_it = flag;
29		/* contact driver and get a pointer to the registers and shared data */
30		result = ioctl(fd, GX00_RUN_INTERRUPTS, &sbs, sizeof(sbs));
31	}
32}
33
34/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
35status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
36{
37	/* BOUNDS WARNING:
38	 * It's impossible to deviate whatever small amount in a display_mode if the lower
39	 * and upper limits are the same!
40	 * Besides:
41	 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
42	 * returns B_BAD_VALUE!
43	 * Which means PROPOSEMODE should not return that on anything except on
44	 * deviations for:
45	 * display_mode.virtual_width;
46	 * display_mode.virtual_height;
47	 * display_mode.timing.h_display;
48	 * display_mode.timing.v_display;
49	 * So:
50	 * We don't use bounds here by making sure bounds and target are the same struct!
51	 * (See the call to PROPOSE_DISPLAY_MODE below) */
52	display_mode /*bounds,*/ target;
53
54	uint8 colour_depth1 = 32;
55	status_t result;
56	uint32 startadd,startadd_right;
57
58	/* Adjust mode to valid one and fail if invalid */
59	target /*= bounds*/ = *mode_to_set;
60	/* show the mode bits */
61	LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
62	LOG(1, ("SETMODE: requested target pixelclock %dkHz\n",  target.timing.pixel_clock));
63	LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
64										target.virtual_width, target.virtual_height));
65
66	/* See BOUNDS WARNING above... */
67	if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR)	return B_ERROR;
68
69	/* overlay engine, cursor and MOVE_DISPLAY need to know the status even when
70	 * in singlehead mode */
71	si->switched_crtcs = false;
72
73	/* disable interrupts using the kernel driver */
74	interrupt_enable(false);
75
76	/* then turn off screen(s) */
77	gx00_crtc_dpms(false, false, false);
78	if (si->ps.secondary_head)
79	{
80		g400_crtc2_dpms(false, false, false);
81	}
82	else
83	{
84		/* on singlehead cards with TVout program the MAVEN as well */
85		if (si->ps.tvout) gx00_maven_dpms(false, false, false);
86	}
87
88	/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
89	startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
90
91	/* calculate and set new mode bytes_per_row */
92	gx00_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
93
94	/*Perform the very long mode switch!*/
95	if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
96	{
97		uint8 colour_depth2 = colour_depth1;
98
99		/* init display mode for secondary head */
100		display_mode target2 = target;
101
102		LOG(1,("SETMODE: setting DUALHEAD mode\n"));
103
104		/* set the pixel clock PLL(s) */
105		LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
106		if (gx00_dac_set_pix_pll(target) == B_ERROR)
107			LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
108
109		/* we do not need to set the pixelclock here for a head that's in TVout mode */
110		if (!(target2.flags & TV_BITS))
111		{
112			LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
113			if (gx00_maven_set_vid_pll(target2) == B_ERROR)
114				LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n"));
115		}
116
117		/*set the colour depth for CRTC1 and the DAC */
118		switch(target.space)
119		{
120		case B_RGB16_LITTLE:
121			colour_depth1 = 16;
122			gx00_dac_mode(BPP16, 1.0);
123			gx00_crtc_depth(BPP16);
124			break;
125		case B_RGB32_LITTLE:
126			colour_depth1 = 32;
127			gx00_dac_mode(BPP32, 1.0);
128			gx00_crtc_depth(BPP32);
129			break;
130		}
131		/*set the colour depth for CRTC2 and the MAVEN */
132		switch(target2.space)
133		{
134		case B_RGB16_LITTLE:
135			colour_depth2 = 16;
136			gx00_maven_mode(BPP16, 1.0);
137			g400_crtc2_depth(BPP16);
138			break;
139		case B_RGB32_LITTLE:
140			colour_depth2 = 32;
141			gx00_maven_mode(BPP32DIR, 1.0);
142			g400_crtc2_depth(BPP32DIR);
143			break;
144		}
145
146		/* check if we are doing interlaced TVout mode */
147		si->interlaced_tv_mode = false;
148		if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
149			si->interlaced_tv_mode = true;
150
151		/*set the display(s) pitches*/
152		gx00_crtc_set_display_pitch ();
153		//fixme: seperate for real dualhead modes:
154		//we need a secondary si->fbc!
155		g400_crtc2_set_display_pitch ();
156
157		/*work out where the "right" screen starts*/
158		startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3));
159
160		/* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */
161		si->crtc_delay = 44;
162		if (colour_depth2 == 16) si->crtc_delay += 0;
163
164		/* set the outputs */
165		switch (si->ps.card_type)
166		{
167		case G400:
168		case G400MAX:
169			/* setup vertical timing adjust for crtc connected to the MAVEN:
170			 * assuming connected straight through. */
171			/* (extra "blanking" line for MAVEN hardware design fault) */
172			target2.timing.v_display++;
173
174			switch (target.flags & DUALHEAD_BITS)
175			{
176			case DUALHEAD_ON:
177			case DUALHEAD_CLONE:
178				gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
179				si->switched_crtcs = false;
180				break;
181			case DUALHEAD_SWITCH:
182				if (i2c_sec_tv_adapter() == B_OK)
183				{
184					/* Don't switch CRTC's because MAVEN YUV is impossible then,
185					 * and primary head output will be limited to 135Mhz pixelclock. */
186					LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
187					gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
188					si->switched_crtcs = true;
189				}
190				else
191				{
192					/* This limits the pixelclocks on both heads to 135Mhz,
193					 * but you can use overlay on the other output now. */
194					LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
195					gx00_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC);
196					si->switched_crtcs = false;
197					/* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */
198					si->crtc_delay = 17;
199					if (colour_depth1 == 16) si->crtc_delay += 4;
200					/* re-setup vertical timing adjust for crtc connected to the MAVEN:
201					 * cross connected. */
202					/* (extra "blanking" line for MAVEN hardware design fault) */
203					target.timing.v_display++;
204					target2.timing.v_display--;
205				}
206				break;
207			}
208			break;
209		case G450:
210		case G550:
211			if (!si->ps.primary_dvi)
212			/* output connector use is always 'straight-through' */
213			//fixme: re-evaluate when DVI is setup...
214			{
215				switch (target.flags & DUALHEAD_BITS)
216				{
217				case DUALHEAD_ON:
218				case DUALHEAD_CLONE:
219					gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
220					si->switched_crtcs = false;
221					break;
222				case DUALHEAD_SWITCH:
223					if (i2c_sec_tv_adapter() == B_OK)
224					{
225						/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
226						 * and primary head output will be limited to 235Mhz pixelclock. */
227						LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
228						gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
229						si->switched_crtcs = true;
230					}
231					else
232					{
233						/* This limits the pixelclocks on both heads to 235Mhz,
234						 * but you can use overlay on the other output now. */
235						LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
236						gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
237						si->switched_crtcs = false;
238					}
239					break;
240				}
241			}
242			else
243			/* output connector use is cross-linked if no TV cable connected! */
244			//fixme: re-evaluate when DVI is setup...
245			{
246				switch (target.flags & DUALHEAD_BITS)
247				{
248				case DUALHEAD_ON:
249				case DUALHEAD_CLONE:
250					if (i2c_sec_tv_adapter() == B_OK)
251					{
252						gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
253						si->switched_crtcs = false;
254					}
255					else
256					{
257						/* This limits the pixelclocks on both heads to 235Mhz,
258						 * but you can use overlay on the other output now. */
259						gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
260						si->switched_crtcs = false;
261					}
262					break;
263				case DUALHEAD_SWITCH:
264					if (i2c_sec_tv_adapter() == B_OK)
265					{
266						/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
267						 * and primary head output will be limited to 235Mhz pixelclock. */
268						LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
269						gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
270						si->switched_crtcs = true;
271					}
272					else
273					{
274						LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
275						gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
276						si->switched_crtcs = false;
277					}
278					break;
279				}
280			}
281			break;
282		default:
283			break;
284		}
285
286		if (si->switched_crtcs)
287		{
288				uint32 temp = startadd;
289				startadd = startadd_right;
290				startadd_right = temp;
291		}
292
293		/*Tell card what memory to display*/
294		switch (target.flags & DUALHEAD_BITS)
295		{
296		case DUALHEAD_ON:
297		case DUALHEAD_SWITCH:
298			gx00_crtc_set_display_start(startadd,colour_depth1);
299			g400_crtc2_set_display_start(startadd_right,colour_depth2);
300			break;
301		case DUALHEAD_CLONE:
302			gx00_crtc_set_display_start(startadd,colour_depth1);
303			g400_crtc2_set_display_start(startadd,colour_depth2);
304			break;
305		}
306
307		/* set the timing */
308		gx00_crtc_set_timing(target);
309		/* we do not need to setup CRTC2 here for a head that's in TVout mode */
310		if (!(target2.flags & TV_BITS))	result = g400_crtc2_set_timing(target2);
311
312		/* TVout support: setup CRTC2 and it's pixelclock */
313		if (si->ps.tvout && (target2.flags & TV_BITS)) maventv_init(target2);
314	}
315	else /* single head mode */
316	{
317		status_t status;
318		int colour_mode = BPP32;
319
320		switch(target.space)
321		{
322		case B_CMAP8:
323			colour_depth1 =  8;
324			colour_mode = BPP8;
325			break;
326		case B_RGB15_LITTLE:
327			colour_depth1 = 16;
328			colour_mode = BPP15;
329			break;
330		case B_RGB16_LITTLE:
331			colour_depth1 = 16;
332			colour_mode = BPP16;
333			break;
334		case B_RGB32_LITTLE:
335			colour_depth1 = 32;
336			colour_mode = BPP32;
337			break;
338		default:
339			LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
340			return B_ERROR;
341		}
342
343		/* set the pixel clock PLL */
344		if (si->ps.card_type >= G100)
345			//fixme: how about when TVout is enabled???
346			status = gx00_dac_set_pix_pll(target);
347		else
348		{
349			status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth1);
350		}
351		if (status==B_ERROR)
352			LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
353
354		/* set the colour depth for CRTC1 and the DAC */
355		gx00_dac_mode(colour_mode,1.0);
356		gx00_crtc_depth(colour_mode);
357
358		/* if we do TVout mode, its non-interlaced (as we are on <= G400MAX for sure) */
359		si->interlaced_tv_mode = false;
360
361		/* set the display pitch */
362		gx00_crtc_set_display_pitch();
363
364		/* tell the card what memory to display */
365		gx00_crtc_set_display_start(startadd,colour_depth1);
366
367		/* enable primary analog output */
368		switch (si->ps.card_type)
369		{
370		case G100:
371		case G200:
372		case G400:
373		case G400MAX:
374			if (!si->ps.secondary_head && si->ps.tvout && (target.flags & TV_BITS))
375				gx00_general_dac_select(DS_CRTC1MAVEN);
376			else
377				gx00_general_dac_select(DS_CRTC1DAC);
378			break;
379		case G450:
380		case G550:
381			gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
382			gx50_general_output_select();
383			break;
384		default:
385			break;
386		}
387
388		/* set the timing */
389		if (!si->ps.secondary_head && si->ps.tvout && (target.flags & TV_BITS))
390		{
391			/* calculate MAVEN-CRTC delay: only used during TVout */
392			si->crtc_delay = 17;
393			if (colour_depth1 == 16) si->crtc_delay += 4;
394			/* setup CRTC1 and it's pixelclock for TVout */
395			maventv_init(target);
396		}
397		else
398		{
399			gx00_maven_shutoff();
400			gx00_crtc_set_timing(target);
401		}
402	}
403
404	/* update driver's mode store */
405	si->dm = target;
406
407	/* set up acceleration for this mode */
408	gx00_acc_init();
409
410	/* restore screen(s) output state(s) */
411	SET_DPMS_MODE(si->dpms_flags);
412
413	/* clear line at bottom of screen if dualhead mode:
414	 * MAVEN hardware design fault 'fix'.
415	 * Note:
416	 * Not applicable for singlehead cards with a MAVEN, since it's only used
417	 * for TVout there. */
418	if ((target.flags & DUALHEAD_BITS) && (si->ps.card_type <= G400MAX))
419		gx00_maven_clrline();
420
421	LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
422
423	/* enable interrupts using the kernel driver */
424	interrupt_enable(true);
425
426	/* optimize memory-access if needed */
427	gx00_crtc_mem_priority(colour_depth1);
428
429	/* Tune RAM CAS-latency if needed. Must be done *here*! */
430	mga_set_cas_latency();
431
432	return B_OK;
433}
434
435/*
436	Set which pixel of the virtual frame buffer will show up in the
437	top left corner of the display device.  Used for page-flipping
438	games and virtual desktops.
439*/
440status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
441	uint8 colour_depth;
442	uint32 startadd,startadd_right;
443
444	LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
445
446	/* G400 CRTC1 handles multiples of 8 for 8bit, 4 for 16bit, 2 for 32 bit
447	   G400 CRTC2 handles multiples of 32 for 16-bit and 16 for 32-bit - must stoop to this in dualhead
448     */
449
450	/* reset lower bits, don't return an error! */
451	if (si->dm.flags & DUALHEAD_BITS)
452	{
453		switch(si->dm.space)
454		{
455		case B_RGB16_LITTLE:
456			colour_depth=16;
457			h_display_start &= ~0x1f;
458			break;
459		case B_RGB32_LITTLE:
460			colour_depth=32;
461			h_display_start &= ~0x0f;
462			break;
463		default:
464			LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space));
465			return B_ERROR;
466		}
467	}
468	else
469	{
470		switch(si->dm.space)
471		{
472		case B_CMAP8:
473			colour_depth=8;
474			h_display_start &= ~0x07;
475			break;
476		case B_RGB15_LITTLE: case B_RGB16_LITTLE:
477			colour_depth=16;
478			h_display_start &= ~0x03;
479			break;
480		case B_RGB32_LITTLE:
481			colour_depth=32;
482			h_display_start &= ~0x01;
483			break;
484		default:
485			return B_ERROR;
486		}
487	}
488
489	/* do not run past end of display */
490	switch (si->dm.flags & DUALHEAD_BITS)
491	{
492	case DUALHEAD_ON:
493	case DUALHEAD_SWITCH:
494		if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
495			return B_ERROR;
496		break;
497	default:
498		if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
499			return B_ERROR;
500		break;
501	}
502	if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
503		return B_ERROR;
504
505	/* everybody remember where we parked... */
506	si->dm.h_display_start = h_display_start;
507	si->dm.v_display_start = v_display_start;
508
509	/* actually set the registers */
510	//fixme: seperate both heads: we need a secondary si->fbc!
511	startadd = v_display_start * si->fbc.bytes_per_row;
512	startadd += h_display_start * (colour_depth >> 3);
513	startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
514	startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
515
516	/* account for switched CRTC's */
517	if (si->switched_crtcs)
518	{
519		uint32 temp = startadd;
520		startadd = startadd_right;
521		startadd_right = temp;
522	}
523
524	interrupt_enable(false);
525
526	switch (si->dm.flags&DUALHEAD_BITS)
527	{
528		case DUALHEAD_ON:
529		case DUALHEAD_SWITCH:
530			gx00_crtc_set_display_start(startadd,colour_depth);
531			g400_crtc2_set_display_start(startadd_right,colour_depth);
532			break;
533		case DUALHEAD_OFF:
534			gx00_crtc_set_display_start(startadd,colour_depth);
535			break;
536		case DUALHEAD_CLONE:
537			gx00_crtc_set_display_start(startadd,colour_depth);
538			g400_crtc2_set_display_start(startadd,colour_depth);
539			break;
540	}
541
542	interrupt_enable(true);
543	return B_OK;
544}
545
546/*
547	Set the indexed color palette.
548*/
549void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
550	int i;
551	uint8 *r,*g,*b;
552
553	/* Protect gamma correction when not in CMAP8 */
554	if (si->dm.space != B_CMAP8) return;
555
556	r=si->color_data;
557	g=r+256;
558	b=g+256;
559
560	i=first;
561	while (count--)
562	{
563		r[i]=*color_data++;
564		g[i]=*color_data++;
565		b[i]=*color_data++;
566		i++;
567	}
568	gx00_dac_palette(r,g,b);
569}
570
571/* Put the display into one of the Display Power Management modes. */
572status_t SET_DPMS_MODE(uint32 dpms_flags)
573{
574	interrupt_enable(false);
575
576	LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
577
578	/* note current DPMS state for our reference */
579	si->dpms_flags = dpms_flags;
580
581	if (si->dm.flags & DUALHEAD_BITS) /* dualhead */
582	{
583		switch(dpms_flags)
584		{
585		case B_DPMS_ON:	/* H: on, V: on */
586			gx00_crtc_dpms(true, true, true);
587			if (si->ps.secondary_head) g400_crtc2_dpms(true, true, true);
588			break;
589		case B_DPMS_STAND_BY:
590			if (si->settings.greensync)
591			{
592				/* blank screen, but keep sync running */
593				gx00_crtc_dpms(false, true, true);
594			}
595			else
596			{
597				gx00_crtc_dpms(false, false, true);
598			}
599			if (si->ps.secondary_head)
600			{
601				if ((si->dm.flags & TV_BITS) && (si->ps.card_type > G400MAX))
602				{
603					/* keep display enabled in TVout modes for G450 and G550! */
604					g400_crtc2_dpms(true, false, true);
605				}
606				else
607				{
608					g400_crtc2_dpms(false, false, true);
609				}
610			}
611			break;
612		case B_DPMS_SUSPEND:
613			if (si->settings.greensync)
614			{
615				/* blank screen, but keep sync running */
616				gx00_crtc_dpms(false, true, true);
617			}
618			else
619			{
620				gx00_crtc_dpms(false, true, false);
621			}
622			if (si->ps.secondary_head)
623			{
624				if ((si->dm.flags & TV_BITS) && (si->ps.card_type > G400MAX))
625				{
626					/* keep display enabled in TVout modes for G450 and G550! */
627					g400_crtc2_dpms(true, true, false);
628				}
629				else
630				{
631					g400_crtc2_dpms(false, true, false);
632				}
633			}
634			break;
635		case B_DPMS_OFF: /* H: off, V: off, display off */
636			if (si->settings.greensync)
637			{
638				/* blank screen, but keep sync running */
639				gx00_crtc_dpms(false, true, true);
640			}
641			else
642			{
643				gx00_crtc_dpms(false, false, false);
644			}
645			if (si->ps.secondary_head)
646			{
647				if ((si->dm.flags & TV_BITS) && (si->ps.card_type > G400MAX))
648				{
649					/* keep display enabled in TVout modes for G450 and G550! */
650					g400_crtc2_dpms(true, false, false);
651				}
652				else
653				{
654					g400_crtc2_dpms(false, false, false);
655				}
656			}
657			break;
658		default:
659			LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
660			interrupt_enable(true);
661			return B_ERROR;
662		}
663	}
664	else /* singlehead */
665	{
666		switch(dpms_flags)
667		{
668		case B_DPMS_ON:	/* H: on, V: on */
669			gx00_crtc_dpms(true, true, true);
670			/* on singlehead cards with TVout program the MAVEN as well */
671			if (si->dm.flags & TV_BITS) gx00_maven_dpms(true, true, true);
672			break;
673		case B_DPMS_STAND_BY:
674			if (si->settings.greensync)
675			{
676				/* blank screen, but keep sync running */
677				gx00_crtc_dpms(false, true, true);
678			}
679			else
680			{
681				gx00_crtc_dpms(false, false, true);
682			}
683			/* on singlehead cards with TVout program the MAVEN as well */
684			if (si->dm.flags & TV_BITS) gx00_maven_dpms(false, false, true);
685			break;
686		case B_DPMS_SUSPEND:
687			if (si->settings.greensync)
688			{
689				/* blank screen, but keep sync running */
690				gx00_crtc_dpms(false, true, true);
691			}
692			else
693			{
694				gx00_crtc_dpms(false, true, false);
695			}
696			/* on singlehead cards with TVout program the MAVEN as well */
697			if (si->dm.flags & TV_BITS) gx00_maven_dpms(false, true, false);
698			break;
699		case B_DPMS_OFF: /* H: off, V: off, display off */
700			if (si->settings.greensync)
701			{
702				/* blank screen, but keep sync running */
703				gx00_crtc_dpms(false, true, true);
704			}
705			else
706			{
707				gx00_crtc_dpms(false, false, false);
708			}
709			/* on singlehead cards with TVout program the MAVEN as well */
710			if (si->dm.flags & TV_BITS) gx00_maven_dpms(false, false, false);
711			break;
712		default:
713			LOG(8,("SET: Invalid DPMS settings (SH) 0x%08x\n", dpms_flags));
714			interrupt_enable(true);
715			return B_ERROR;
716		}
717	}
718	interrupt_enable(true);
719	return B_OK;
720}
721
722/* Report device DPMS capabilities. */
723uint32 DPMS_CAPABILITIES(void)
724{
725	if (si->settings.greensync)
726		/* we can blank the screen on CRTC1, G400 CRTC2 does not support intermediate
727		 * modes anyway. */
728		//fixme: G450/G550 support full DPMS on CRTC2...
729		return 	B_DPMS_ON | B_DPMS_OFF;
730	else
731		/* normally CRTC1 supports full DPMS (and on G450/G550 CRTC2 also).. */
732		return 	B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
733}
734
735/* Return the current DPMS mode. */
736uint32 DPMS_MODE(void)
737{
738	return si->dpms_flags;
739}
740