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