xref: /haiku/src/add-ons/accelerants/nvidia/SetDisplayMode.c (revision c0ebc619bfbcc5a5b916606f406d951267dd3456)
108705d96Sshatty 
208705d96Sshatty /*
308705d96Sshatty 	Copyright 1999, Be Incorporated.   All Rights Reserved.
408705d96Sshatty 	This file may be used under the terms of the Be Sample Code License.
508705d96Sshatty 
608705d96Sshatty 	Other authors:
708705d96Sshatty 	Mark Watson,
808705d96Sshatty 	Apsed,
9a658603aSRudolf Cornelissen 	Rudolf Cornelissen 11/2002-11/2005
1008705d96Sshatty */
1108705d96Sshatty 
1208705d96Sshatty #define MODULE_BIT 0x00200000
1308705d96Sshatty 
1408705d96Sshatty #include "acc_std.h"
1508705d96Sshatty 
1608705d96Sshatty /*
1708705d96Sshatty 	Enable/Disable interrupts.  Just a wrapper around the
1808705d96Sshatty 	ioctl() to the kernel driver.
1908705d96Sshatty */
20ce3fc95eSRudolf Cornelissen static void interrupt_enable(bool flag)
21ce3fc95eSRudolf Cornelissen {
22ce3fc95eSRudolf Cornelissen 	status_t result = B_OK;
2308705d96Sshatty 	nv_set_bool_state sbs;
2408705d96Sshatty 
25ce3fc95eSRudolf Cornelissen 	if (si->ps.int_assigned)
26ce3fc95eSRudolf Cornelissen 	{
2708705d96Sshatty 		/* set the magic number so the driver knows we're for real */
2808705d96Sshatty 		sbs.magic = NV_PRIVATE_DATA_MAGIC;
2908705d96Sshatty 		sbs.do_it = flag;
3008705d96Sshatty 		/* contact driver and get a pointer to the registers and shared data */
3108705d96Sshatty 		result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs));
3208705d96Sshatty 	}
33ce3fc95eSRudolf Cornelissen }
3408705d96Sshatty 
3508705d96Sshatty /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
3608705d96Sshatty status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
3708705d96Sshatty {
3808705d96Sshatty 	/* BOUNDS WARNING:
3908705d96Sshatty 	 * It's impossible to deviate whatever small amount in a display_mode if the lower
4008705d96Sshatty 	 * and upper limits are the same!
4108705d96Sshatty 	 * Besides:
4208705d96Sshatty 	 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
4308705d96Sshatty 	 * returns B_BAD_VALUE!
4408705d96Sshatty 	 * Which means PROPOSEMODE should not return that on anything except on
4508705d96Sshatty 	 * deviations for:
4608705d96Sshatty 	 * display_mode.virtual_width;
4708705d96Sshatty 	 * display_mode.virtual_height;
4808705d96Sshatty 	 * display_mode.timing.h_display;
4908705d96Sshatty 	 * display_mode.timing.v_display;
5008705d96Sshatty 	 * So:
5108705d96Sshatty 	 * We don't use bounds here by making sure bounds and target are the same struct!
5208705d96Sshatty 	 * (See the call to PROPOSE_DISPLAY_MODE below) */
5308705d96Sshatty 	display_mode /*bounds,*/ target;
5408705d96Sshatty 
5508705d96Sshatty 	uint8 colour_depth1 = 32;
5608705d96Sshatty 	uint32 startadd,startadd_right;
5730f76422SRudolf Cornelissen //	bool crt1, crt2, cross;
5808705d96Sshatty 
5908705d96Sshatty 	/* Adjust mode to valid one and fail if invalid */
6008705d96Sshatty 	target /*= bounds*/ = *mode_to_set;
6108705d96Sshatty 	/* show the mode bits */
6208705d96Sshatty 	LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
6308705d96Sshatty 	LOG(1, ("SETMODE: requested target pixelclock %dkHz\n",  target.timing.pixel_clock));
6408705d96Sshatty 	LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
6508705d96Sshatty 										target.virtual_width, target.virtual_height));
6608705d96Sshatty 
6708705d96Sshatty 	/* See BOUNDS WARNING above... */
6808705d96Sshatty 	if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR)	return B_ERROR;
6908705d96Sshatty 
70c9c0c72bSRudolf Cornelissen 	/* make sure a possible 3D add-on will block rendering and re-initialize itself.
71c9c0c72bSRudolf Cornelissen 	 * note: update in _this_ order only */
72c9c0c72bSRudolf Cornelissen 	/* SET_DISPLAY_MODE will reset this flag when it's done. */
7321545d00SRudolf Cornelissen 	si->engine.threeD.mode_changing = true;
7421545d00SRudolf Cornelissen 	/* every 3D add-on will reset this bit-flag when it's done. */
7521545d00SRudolf Cornelissen 	si->engine.threeD.newmode = 0xffffffff;
7621545d00SRudolf Cornelissen 	/* every 3D clone needs to reclaim a slot.
7721545d00SRudolf Cornelissen 	 * note: this also cleans up reserved channels for killed 3D clones.. */
7821545d00SRudolf Cornelissen 	si->engine.threeD.clones = 0x00000000;
79afb207acSRudolf Cornelissen 
8008705d96Sshatty 	/* disable interrupts using the kernel driver */
8108705d96Sshatty 	interrupt_enable(false);
8208705d96Sshatty 
830703480cSRudolf Cornelissen 	/* disable TVout if supported */
840703480cSRudolf Cornelissen 	if (si->ps.tvout) BT_stop_tvout();
850b36eea4SRudolf Cornelissen 
8620603b95SRudolf Cornelissen 	/* turn off screen(s) _after_ TVout is disabled (if applicable) */
870669fe20SRudolf Cornelissen 	head1_dpms(false, false, false);
880669fe20SRudolf Cornelissen 	if (si->ps.secondary_head) head2_dpms(false, false, false);
893aa21459SRudolf Cornelissen 	if (si->ps.tvout) BT_dpms(false);
9008705d96Sshatty 
9108705d96Sshatty 	/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
92f2777ca1SRudolf Cornelissen 	startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
9308705d96Sshatty 
9408705d96Sshatty 	/* calculate and set new mode bytes_per_row */
9505ed3229SRudolf Cornelissen 	nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
9608705d96Sshatty 
9708705d96Sshatty 	/*Perform the very long mode switch!*/
9808705d96Sshatty 	if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
9908705d96Sshatty 	{
10008705d96Sshatty 		uint8 colour_depth2 = colour_depth1;
10108705d96Sshatty 
10208705d96Sshatty 		/* init display mode for secondary head */
10308705d96Sshatty 		display_mode target2 = target;
10408705d96Sshatty 
10508705d96Sshatty 		LOG(1,("SETMODE: setting DUALHEAD mode\n"));
10608705d96Sshatty 
10708705d96Sshatty 		/* validate flags for secondary TVout */
108b2459715SRudolf Cornelissen 		//fixme: remove or block on autodetect fail. (is now shutoff)
109b2459715SRudolf Cornelissen 		if ((0) && (target2.flags & TV_BITS))
11008705d96Sshatty 		{
11108705d96Sshatty 			target.flags &= ~TV_BITS;//still needed for some routines...
11208705d96Sshatty 			target2.flags &= ~TV_BITS;
11308705d96Sshatty 			LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
11408705d96Sshatty 		}
11508705d96Sshatty 
11630f76422SRudolf Cornelissen 		/* detect which connectors have a CRT connected */
11730f76422SRudolf Cornelissen 		//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
11830f76422SRudolf Cornelissen 		//or make it work with digital panels connected as well.
11930f76422SRudolf Cornelissen //		crt1 = nv_dac_crt_connected();
12030f76422SRudolf Cornelissen //		crt2 = nv_dac2_crt_connected();
12130f76422SRudolf Cornelissen 		/* connect outputs 'straight-through' */
12230f76422SRudolf Cornelissen //		if (crt1)
12330f76422SRudolf Cornelissen //		{
12430f76422SRudolf Cornelissen 			/* connector1 is used as primary output */
12530f76422SRudolf Cornelissen //			cross = false;
12630f76422SRudolf Cornelissen //		}
12730f76422SRudolf Cornelissen //		else
12830f76422SRudolf Cornelissen //		{
12930f76422SRudolf Cornelissen //			if (crt2)
13030f76422SRudolf Cornelissen 				/* connector2 is used as primary output */
13130f76422SRudolf Cornelissen //				cross = true;
13230f76422SRudolf Cornelissen //			else
13330f76422SRudolf Cornelissen 				/* no CRT detected: assume connector1 is used as primary output */
13430f76422SRudolf Cornelissen //				cross = false;
13530f76422SRudolf Cornelissen //		}
13630f76422SRudolf Cornelissen 		/* set output connectors assignment if possible */
13730f76422SRudolf Cornelissen 		if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
13830f76422SRudolf Cornelissen 			/* invert output assignment in switch mode */
13906f4c439SRudolf Cornelissen 			nv_general_head_select(true);
14030f76422SRudolf Cornelissen 		else
14106f4c439SRudolf Cornelissen 			nv_general_head_select(false);
14230f76422SRudolf Cornelissen 
14308705d96Sshatty 		/* set the pixel clock PLL(s) */
14408705d96Sshatty 		LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
14530f76422SRudolf Cornelissen 		if (head1_set_pix_pll(target) == B_ERROR)
14608705d96Sshatty 			LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
14708705d96Sshatty 
14808705d96Sshatty 		LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
14930f76422SRudolf Cornelissen 		if (head2_set_pix_pll(target2) == B_ERROR)
150a3b9d212SRudolf Cornelissen 			LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
15108705d96Sshatty 
15208705d96Sshatty 		/*set the colour depth for CRTC1 and the DAC */
15308705d96Sshatty 		switch(target.space)
15408705d96Sshatty 		{
155bc5690abSRudolf Cornelissen 		case B_CMAP8:
156bc5690abSRudolf Cornelissen 			colour_depth1 =  8;
15730f76422SRudolf Cornelissen 			head1_mode(BPP8, 1.0);
1580669fe20SRudolf Cornelissen 			head1_depth(BPP8);
159bc5690abSRudolf Cornelissen 			break;
160bc5690abSRudolf Cornelissen 		case B_RGB15_LITTLE:
161bc5690abSRudolf Cornelissen 			colour_depth1 = 16;
16230f76422SRudolf Cornelissen 			head1_mode(BPP15, 1.0);
1630669fe20SRudolf Cornelissen 			head1_depth(BPP15);
164bc5690abSRudolf Cornelissen 			break;
16508705d96Sshatty 		case B_RGB16_LITTLE:
16608705d96Sshatty 			colour_depth1 = 16;
16730f76422SRudolf Cornelissen 			head1_mode(BPP16, 1.0);
1680669fe20SRudolf Cornelissen 			head1_depth(BPP16);
16908705d96Sshatty 			break;
17008705d96Sshatty 		case B_RGB32_LITTLE:
17108705d96Sshatty 			colour_depth1 = 32;
17230f76422SRudolf Cornelissen 			head1_mode(BPP32, 1.0);
1730669fe20SRudolf Cornelissen 			head1_depth(BPP32);
17408705d96Sshatty 			break;
17508705d96Sshatty 		}
176a3b9d212SRudolf Cornelissen 		/*set the colour depth for CRTC2 and DAC2 */
17708705d96Sshatty 		switch(target2.space)
17808705d96Sshatty 		{
179bc5690abSRudolf Cornelissen 		case B_CMAP8:
180bc5690abSRudolf Cornelissen 			colour_depth2 =  8;
18130f76422SRudolf Cornelissen 			head2_mode(BPP8, 1.0);
1820669fe20SRudolf Cornelissen 			head2_depth(BPP8);
183bc5690abSRudolf Cornelissen 			break;
184bc5690abSRudolf Cornelissen 		case B_RGB15_LITTLE:
185bc5690abSRudolf Cornelissen 			colour_depth2 = 16;
18630f76422SRudolf Cornelissen 			head2_mode(BPP15, 1.0);
1870669fe20SRudolf Cornelissen 			head2_depth(BPP15);
188bc5690abSRudolf Cornelissen 			break;
18908705d96Sshatty 		case B_RGB16_LITTLE:
19008705d96Sshatty 			colour_depth2 = 16;
19130f76422SRudolf Cornelissen 			head2_mode(BPP16, 1.0);
1920669fe20SRudolf Cornelissen 			head2_depth(BPP16);
19308705d96Sshatty 			break;
19408705d96Sshatty 		case B_RGB32_LITTLE:
19508705d96Sshatty 			colour_depth2 = 32;
19630f76422SRudolf Cornelissen 			head2_mode(BPP32, 1.0);
1970669fe20SRudolf Cornelissen 			head2_depth(BPP32);
19808705d96Sshatty 			break;
19908705d96Sshatty 		}
20008705d96Sshatty 
20108705d96Sshatty 		/* check if we are doing interlaced TVout mode */
202b2459715SRudolf Cornelissen 		//fixme: we don't support interlaced mode?
20308705d96Sshatty 		si->interlaced_tv_mode = false;
204*c0ebc619SRudolf Cornelissen 
20508705d96Sshatty 		/*set the display(s) pitches*/
2060669fe20SRudolf Cornelissen 		head1_set_display_pitch ();
20708705d96Sshatty 		//fixme: seperate for real dualhead modes:
20808705d96Sshatty 		//we need a secondary si->fbc!
2090669fe20SRudolf Cornelissen 		head2_set_display_pitch ();
21008705d96Sshatty 
21108705d96Sshatty 		/*work out where the "right" screen starts*/
21208705d96Sshatty 		startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
21308705d96Sshatty 
21408705d96Sshatty 		/* Tell card what memory to display */
21508705d96Sshatty 		switch (target.flags & DUALHEAD_BITS)
21608705d96Sshatty 		{
21708705d96Sshatty 		case DUALHEAD_ON:
21808705d96Sshatty 		case DUALHEAD_SWITCH:
2190669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth1);
2200669fe20SRudolf Cornelissen 			head2_set_display_start(startadd_right,colour_depth2);
22108705d96Sshatty 			break;
22208705d96Sshatty 		case DUALHEAD_CLONE:
2230669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth1);
2240669fe20SRudolf Cornelissen 			head2_set_display_start(startadd,colour_depth2);
22508705d96Sshatty 			break;
22608705d96Sshatty 		}
22708705d96Sshatty 
22808705d96Sshatty 		/* set the timing */
2290669fe20SRudolf Cornelissen 		head1_set_timing(target);
230*c0ebc619SRudolf Cornelissen 		head2_set_timing(target2);
23108705d96Sshatty 
232*c0ebc619SRudolf Cornelissen 		/* TVout support: program TVout encoder and modify CRTC timing */
233b2459715SRudolf Cornelissen 		if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2);
23408705d96Sshatty 	}
23508705d96Sshatty 	else /* single head mode */
23608705d96Sshatty 	{
23708705d96Sshatty 		int colour_mode = BPP32;
23808705d96Sshatty 
23930f76422SRudolf Cornelissen 		/* connect output */
24030f76422SRudolf Cornelissen 		if (si->ps.secondary_head)
24130f76422SRudolf Cornelissen 		{
24230f76422SRudolf Cornelissen 			/* detect which connectors have a CRT connected */
24330f76422SRudolf Cornelissen 			//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
24430f76422SRudolf Cornelissen 			//or make it work with digital panels connected as well.
24530f76422SRudolf Cornelissen //			crt1 = nv_dac_crt_connected();
24630f76422SRudolf Cornelissen //			crt2 = nv_dac2_crt_connected();
24730f76422SRudolf Cornelissen 			/* connect outputs 'straight-through' */
24830f76422SRudolf Cornelissen //			if (crt1)
24930f76422SRudolf Cornelissen //			{
25030f76422SRudolf Cornelissen 				/* connector1 is used as primary output */
25130f76422SRudolf Cornelissen //				cross = false;
25230f76422SRudolf Cornelissen //			}
25330f76422SRudolf Cornelissen //			else
25430f76422SRudolf Cornelissen //			{
25530f76422SRudolf Cornelissen //				if (crt2)
25630f76422SRudolf Cornelissen 					/* connector2 is used as primary output */
25730f76422SRudolf Cornelissen //					cross = true;
25830f76422SRudolf Cornelissen //				else
25930f76422SRudolf Cornelissen 					/* no CRT detected: assume connector1 is used as primary output */
26030f76422SRudolf Cornelissen //					cross = false;
26130f76422SRudolf Cornelissen //			}
26230f76422SRudolf Cornelissen 			/* set output connectors assignment if possible */
26306f4c439SRudolf Cornelissen 			nv_general_head_select(false);
26430f76422SRudolf Cornelissen 		}
26530f76422SRudolf Cornelissen 
26608705d96Sshatty 		switch(target.space)
26708705d96Sshatty 		{
26808705d96Sshatty 		case B_CMAP8:        colour_depth1 =  8; colour_mode = BPP8;  break;
26908705d96Sshatty 		case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
27008705d96Sshatty 		case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
27108705d96Sshatty 		case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
27208705d96Sshatty 		default:
27308705d96Sshatty 			LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
27408705d96Sshatty 			return B_ERROR;
27508705d96Sshatty 		}
27608705d96Sshatty 
27708705d96Sshatty 		/* set the pixel clock PLL */
278*c0ebc619SRudolf Cornelissen 		if (head1_set_pix_pll(target) == B_ERROR)
27908705d96Sshatty 			LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
28008705d96Sshatty 
28108705d96Sshatty 		/* set the colour depth for CRTC1 and the DAC */
28208705d96Sshatty 		/* first set the colordepth */
2830669fe20SRudolf Cornelissen 		head1_depth(colour_mode);
28408705d96Sshatty 		/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
28530f76422SRudolf Cornelissen 		head1_mode(colour_mode,1.0);
28608705d96Sshatty 
28708705d96Sshatty 		/* set the display pitch */
2880669fe20SRudolf Cornelissen 		head1_set_display_pitch();
28908705d96Sshatty 
29008705d96Sshatty 		/* tell the card what memory to display */
2910669fe20SRudolf Cornelissen 		head1_set_display_start(startadd,colour_depth1);
29208705d96Sshatty 
29308705d96Sshatty 		/* set the timing */
294*c0ebc619SRudolf Cornelissen 		head1_set_timing(target);
295b2459715SRudolf Cornelissen 
296*c0ebc619SRudolf Cornelissen 		/* TVout support: program TVout encoder and modify CRTC timing */
297b2459715SRudolf Cornelissen 		if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target);
29808705d96Sshatty 
29908705d96Sshatty 		//fixme: shut-off the videoPLL if it exists...
30008705d96Sshatty 	}
30108705d96Sshatty 
30208705d96Sshatty 	/* update driver's mode store */
30308705d96Sshatty 	si->dm = target;
30408705d96Sshatty 
3053c4c0505SRudolf Cornelissen 	/* update FIFO data fetching according to mode */
3063c4c0505SRudolf Cornelissen 	nv_crtc_update_fifo();
3073c4c0505SRudolf Cornelissen 
30808705d96Sshatty 	/* set up acceleration for this mode */
309dd43fd34SRudolf Cornelissen 	/* note:
3103c4c0505SRudolf Cornelissen 	 * Maybe later we can forget about non-DMA mode (depends on 3D acceleration
3113c4c0505SRudolf Cornelissen 	 * attempts). */
312dd446dd3SRudolf Cornelissen 	if (!si->settings.dma_acc)
313b4c44701Sshatty 		nv_acc_init();
314dd43fd34SRudolf Cornelissen 	else
315dd43fd34SRudolf Cornelissen 		nv_acc_init_dma();
316b4c44701Sshatty 	/* set up overlay unit for this mode */
317aa1e552fSshatty 	nv_bes_init();
31808705d96Sshatty 
31989d37d46SRudolf Cornelissen 	/* note freemem range */
32089d37d46SRudolf Cornelissen 	/* first free adress follows hardcursor and workspace */
32121545d00SRudolf Cornelissen 	si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height;
32221545d00SRudolf Cornelissen 	if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048;
32389d37d46SRudolf Cornelissen 	/* last free adress is end-of-ram minus max space needed for overlay bitmaps */
32489d37d46SRudolf Cornelissen 	//fixme possible:
32589d37d46SRudolf Cornelissen 	//if overlay buffers are allocated subtract buffersize from mem_high;
32689d37d46SRudolf Cornelissen 	//only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
32721545d00SRudolf Cornelissen 	si->engine.threeD.mem_high = si->ps.memory_size - 1;
328fee251bcSRudolf Cornelissen 	/* don't touch the DMA acceleration engine command buffer if it exists */
329fee251bcSRudolf Cornelissen 	/* note:
330fdd699c7SRudolf Cornelissen 	 * the buffer is 32kB in size. Keep some extra distance for safety (faulty apps). */
331fdd699c7SRudolf Cornelissen 	if (si->settings.dma_acc)
332fdd699c7SRudolf Cornelissen 	{
333fdd699c7SRudolf Cornelissen 		if (si->ps.card_arch < NV40A)
334fdd699c7SRudolf Cornelissen 		{
335fdd699c7SRudolf Cornelissen 			/* keeping 32kB distance from the DMA buffer */
33621545d00SRudolf Cornelissen 			si->engine.threeD.mem_high -= (64 * 1024);
337fdd699c7SRudolf Cornelissen 		}
338fdd699c7SRudolf Cornelissen 		else
339fdd699c7SRudolf Cornelissen 		{
340fdd699c7SRudolf Cornelissen 			/* 416kB distance is just OK: keeping another 64kB distance for safety;
341fdd699c7SRudolf Cornelissen 			 * confirmed for NV43. */
342fdd699c7SRudolf Cornelissen 			/* note:
343fdd699c7SRudolf Cornelissen 			 * if you get too close to the DMA command buffer on NV40 and NV43 at
344fdd699c7SRudolf Cornelissen 			 * least (both confirmed), the source DMA instance will mess-up for
345fdd699c7SRudolf Cornelissen 			 * at least engine cmd NV_IMAGE_BLIT and NV12_IMAGE_BLIT. */
34621545d00SRudolf Cornelissen 			si->engine.threeD.mem_high -= (512 * 1024);
347fdd699c7SRudolf Cornelissen 		}
348fdd699c7SRudolf Cornelissen 	}
34921545d00SRudolf Cornelissen 	si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */
35089d37d46SRudolf Cornelissen 
351bfecd0cdSRudolf Cornelissen 	/* restore screen(s) output state(s) */
352bfecd0cdSRudolf Cornelissen 	SET_DPMS_MODE(si->dpms_flags);
35308705d96Sshatty 
35408705d96Sshatty 	/* enable interrupts using the kernel driver */
35508705d96Sshatty 	interrupt_enable(true);
35608705d96Sshatty 
357c9c0c72bSRudolf Cornelissen 	/* make sure a possible 3D add-on will re-initialize itself by signalling ready */
35821545d00SRudolf Cornelissen 	si->engine.threeD.mode_changing = false;
359c9c0c72bSRudolf Cornelissen 
36008705d96Sshatty 	/* optimize memory-access if needed */
3610669fe20SRudolf Cornelissen //	head1_mem_priority(colour_depth1);
36208705d96Sshatty 
36308705d96Sshatty 	/* Tune RAM CAS-latency if needed. Must be done *here*! */
36408705d96Sshatty 	nv_set_cas_latency();
36508705d96Sshatty 
366bfecd0cdSRudolf Cornelissen 	LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
367bfecd0cdSRudolf Cornelissen 
36808705d96Sshatty 	return B_OK;
36908705d96Sshatty }
37008705d96Sshatty 
37108705d96Sshatty /*
37208705d96Sshatty 	Set which pixel of the virtual frame buffer will show up in the
37308705d96Sshatty 	top left corner of the display device.  Used for page-flipping
37408705d96Sshatty 	games and virtual desktops.
37508705d96Sshatty */
37608705d96Sshatty status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
37708705d96Sshatty 	uint8 colour_depth;
37808705d96Sshatty 	uint32 startadd,startadd_right;
37908705d96Sshatty 
38008705d96Sshatty 	LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
38108705d96Sshatty 
382255e5021SRudolf Cornelissen 	/* nVidia cards support pixelprecise panning on both heads in all modes:
383255e5021SRudolf Cornelissen 	 * No stepping granularity needed! */
384255e5021SRudolf Cornelissen 
385255e5021SRudolf Cornelissen 	/* determine bits used for the colordepth */
38608705d96Sshatty 	switch(si->dm.space)
38708705d96Sshatty 	{
38808705d96Sshatty 	case B_CMAP8:
38908705d96Sshatty 		colour_depth=8;
39008705d96Sshatty 		break;
391255e5021SRudolf Cornelissen 	case B_RGB15_LITTLE:
392255e5021SRudolf Cornelissen 	case B_RGB16_LITTLE:
39308705d96Sshatty 		colour_depth=16;
394255e5021SRudolf Cornelissen 		break;
395255e5021SRudolf Cornelissen 	case B_RGB24_LITTLE:
396255e5021SRudolf Cornelissen 		colour_depth=24;
39708705d96Sshatty 		break;
39808705d96Sshatty 	case B_RGB32_LITTLE:
39908705d96Sshatty 		colour_depth=32;
40008705d96Sshatty 		break;
40108705d96Sshatty 	default:
40208705d96Sshatty 		return B_ERROR;
40308705d96Sshatty 	}
40408705d96Sshatty 
40508705d96Sshatty 	/* do not run past end of display */
40608705d96Sshatty 	switch (si->dm.flags & DUALHEAD_BITS)
40708705d96Sshatty 	{
40808705d96Sshatty 	case DUALHEAD_ON:
40908705d96Sshatty 	case DUALHEAD_SWITCH:
41008705d96Sshatty 		if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
41108705d96Sshatty 			return B_ERROR;
41208705d96Sshatty 		break;
41308705d96Sshatty 	default:
41408705d96Sshatty 		if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
41508705d96Sshatty 			return B_ERROR;
41608705d96Sshatty 		break;
41708705d96Sshatty 	}
41808705d96Sshatty 	if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
41908705d96Sshatty 		return B_ERROR;
42008705d96Sshatty 
42108705d96Sshatty 	/* everybody remember where we parked... */
42208705d96Sshatty 	si->dm.h_display_start = h_display_start;
42308705d96Sshatty 	si->dm.v_display_start = v_display_start;
42408705d96Sshatty 
42508705d96Sshatty 	/* actually set the registers */
42608705d96Sshatty 	//fixme: seperate both heads: we need a secondary si->fbc!
42708705d96Sshatty 	startadd = v_display_start * si->fbc.bytes_per_row;
42808705d96Sshatty 	startadd += h_display_start * (colour_depth >> 3);
429f2777ca1SRudolf Cornelissen 	startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
43008705d96Sshatty 	startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
43108705d96Sshatty 
43208705d96Sshatty 	interrupt_enable(false);
43308705d96Sshatty 
43408705d96Sshatty 	switch (si->dm.flags & DUALHEAD_BITS)
43508705d96Sshatty 	{
43608705d96Sshatty 		case DUALHEAD_ON:
43708705d96Sshatty 		case DUALHEAD_SWITCH:
4380669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
4390669fe20SRudolf Cornelissen 			head2_set_display_start(startadd_right,colour_depth);
44008705d96Sshatty 			break;
44108705d96Sshatty 		case DUALHEAD_OFF:
4420669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
44308705d96Sshatty 			break;
44408705d96Sshatty 		case DUALHEAD_CLONE:
4450669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
4460669fe20SRudolf Cornelissen 			head2_set_display_start(startadd,colour_depth);
44708705d96Sshatty 			break;
44808705d96Sshatty 	}
44908705d96Sshatty 
45008705d96Sshatty 	interrupt_enable(true);
45108705d96Sshatty 	return B_OK;
45208705d96Sshatty }
45308705d96Sshatty 
454255e5021SRudolf Cornelissen /* Set the indexed color palette */
45508705d96Sshatty void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
45608705d96Sshatty 	int i;
45708705d96Sshatty 	uint8 *r,*g,*b;
45808705d96Sshatty 
45908705d96Sshatty 	/* Protect gamma correction when not in CMAP8 */
46008705d96Sshatty 	if (si->dm.space != B_CMAP8) return;
46108705d96Sshatty 
46208705d96Sshatty 	r=si->color_data;
46308705d96Sshatty 	g=r+256;
46408705d96Sshatty 	b=g+256;
46508705d96Sshatty 
46608705d96Sshatty 	i=first;
46708705d96Sshatty 	while (count--)
46808705d96Sshatty 	{
46908705d96Sshatty 		r[i]=*color_data++;
47008705d96Sshatty 		g[i]=*color_data++;
47108705d96Sshatty 		b[i]=*color_data++;
47208705d96Sshatty 		i++;
47308705d96Sshatty 	}
47430f76422SRudolf Cornelissen 	head1_palette(r,g,b);
47530f76422SRudolf Cornelissen 	if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
47608705d96Sshatty }
47708705d96Sshatty 
47808705d96Sshatty /* Put the display into one of the Display Power Management modes. */
479bfecd0cdSRudolf Cornelissen status_t SET_DPMS_MODE(uint32 dpms_flags)
480bfecd0cdSRudolf Cornelissen {
48120603b95SRudolf Cornelissen 	bool display, h1h, h1v, h2h, h2v;
48220603b95SRudolf Cornelissen 
48308705d96Sshatty 	interrupt_enable(false);
48408705d96Sshatty 
48508705d96Sshatty 	LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
48608705d96Sshatty 
487bfecd0cdSRudolf Cornelissen 	/* note current DPMS state for our reference */
488bfecd0cdSRudolf Cornelissen 	si->dpms_flags = dpms_flags;
489bfecd0cdSRudolf Cornelissen 
49020603b95SRudolf Cornelissen 	/* determine signals to send to head(s) */
49120603b95SRudolf Cornelissen 	display = h1h = h1v = h2h = h2v = true;
49208705d96Sshatty 	switch(dpms_flags)
49308705d96Sshatty 	{
49408705d96Sshatty 	case B_DPMS_ON:	/* H: on, V: on, display on */
49508705d96Sshatty 		break;
49608705d96Sshatty 	case B_DPMS_STAND_BY:
49720603b95SRudolf Cornelissen 		display = h1h = h2h = false;
49808705d96Sshatty 		break;
49908705d96Sshatty 	case B_DPMS_SUSPEND:
50020603b95SRudolf Cornelissen 		display = h1v = h2v = false;
50108705d96Sshatty 		break;
50208705d96Sshatty 	case B_DPMS_OFF: /* H: off, V: off, display off */
50320603b95SRudolf Cornelissen 		display = h1h = h1v = h2h = h2v = false;
50408705d96Sshatty 		break;
50508705d96Sshatty 	default:
50608705d96Sshatty 		LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
50708705d96Sshatty 		interrupt_enable(true);
50808705d96Sshatty 		return B_ERROR;
50908705d96Sshatty 	}
51020603b95SRudolf Cornelissen 
51120603b95SRudolf Cornelissen 	/* CRTC used for TVout needs specific DPMS programming */
51220603b95SRudolf Cornelissen 	if (si->dm.flags & TV_BITS)
51308705d96Sshatty 	{
514a658603aSRudolf Cornelissen 		if (si->dm.flags & TV_PRIMARY)
515a658603aSRudolf Cornelissen 		{
516a658603aSRudolf Cornelissen 			LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n"));
51720603b95SRudolf Cornelissen 
51820603b95SRudolf Cornelissen 			if (!(si->settings.vga_on_tv))
51908705d96Sshatty 			{
52020603b95SRudolf Cornelissen 				/* block VGA output on head displaying on TV */
52120603b95SRudolf Cornelissen 				/* Note:
52220603b95SRudolf Cornelissen 				 * this specific sync setting is required: Vsync is used to keep TVout
52320603b95SRudolf Cornelissen 				 * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs).
52420603b95SRudolf Cornelissen 				 * This leaves Hsync only for shutting off the VGA screen. */
52520603b95SRudolf Cornelissen 				h1h = false;
52620603b95SRudolf Cornelissen 				h1v = true;
52720603b95SRudolf Cornelissen 			}
52820603b95SRudolf Cornelissen 			else
52920603b95SRudolf Cornelissen 			{
53020603b95SRudolf Cornelissen 				/* when concurrent VGA is used alongside TVout on a head, DPMS is safest
53120603b95SRudolf Cornelissen 				 * applied this way: Vsync is needed for stopping TVout successfully when
53220603b95SRudolf Cornelissen 				 * a (new) modeswitch occurs.
53320603b95SRudolf Cornelissen 				 * (see routine BT_stop_tvout() in nv_brooktreetv.c) */
53420603b95SRudolf Cornelissen 				/* Note:
53520603b95SRudolf Cornelissen 				 * applying 'normal' DPMS here and forcing Vsync on in the above mentioned
53620603b95SRudolf Cornelissen 				 * routine seems to not always be enough: sometimes image generation will
53720603b95SRudolf Cornelissen 				 * not resume in that case. */
53820603b95SRudolf Cornelissen 				h1h = display;
53920603b95SRudolf Cornelissen 				h1v = true;
54008705d96Sshatty 			}
54108705d96Sshatty 		}
542a658603aSRudolf Cornelissen 		else
543a658603aSRudolf Cornelissen 		{
544a658603aSRudolf Cornelissen 			LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n"));
545a658603aSRudolf Cornelissen 
546a658603aSRudolf Cornelissen 			if (!(si->settings.vga_on_tv))
547a658603aSRudolf Cornelissen 			{
548a658603aSRudolf Cornelissen 				/* block VGA output on head displaying on TV */
549a658603aSRudolf Cornelissen 				/* Note:
550a658603aSRudolf Cornelissen 				 * this specific sync setting is required: Vsync is used to keep TVout
551a658603aSRudolf Cornelissen 				 * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs).
552a658603aSRudolf Cornelissen 				 * This leaves Hsync only for shutting off the VGA screen. */
553a658603aSRudolf Cornelissen 				h2h = false;
554a658603aSRudolf Cornelissen 				h2v = true;
555a658603aSRudolf Cornelissen 			}
556a658603aSRudolf Cornelissen 			else
557a658603aSRudolf Cornelissen 			{
558a658603aSRudolf Cornelissen 				/* when concurrent VGA is used alongside TVout on a head, DPMS is safest
559a658603aSRudolf Cornelissen 				 * applied this way: Vsync is needed for stopping TVout successfully when
560a658603aSRudolf Cornelissen 				 * a (new) modeswitch occurs.
561a658603aSRudolf Cornelissen 				 * (see routine BT_stop_tvout() in nv_brooktreetv.c) */
562a658603aSRudolf Cornelissen 				/* Note:
563a658603aSRudolf Cornelissen 				 * applying 'normal' DPMS here and forcing Vsync on in the above mentioned
564a658603aSRudolf Cornelissen 				 * routine seems to not always be enough: sometimes image generation will
565a658603aSRudolf Cornelissen 				 * not resume in that case. */
566a658603aSRudolf Cornelissen 				h2h = display;
567a658603aSRudolf Cornelissen 				h2v = true;
568a658603aSRudolf Cornelissen 			}
569a658603aSRudolf Cornelissen 		}
570a658603aSRudolf Cornelissen 	}
5713aa21459SRudolf Cornelissen 
57220603b95SRudolf Cornelissen 	/* issue actual DPMS commands as far as applicable */
57320603b95SRudolf Cornelissen 	head1_dpms(display, h1h, h1v);
57420603b95SRudolf Cornelissen 	if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS))
57520603b95SRudolf Cornelissen 		head2_dpms(display, h2h, h2v);
57620603b95SRudolf Cornelissen 	if (si->dm.flags & TV_BITS)
57720603b95SRudolf Cornelissen 		BT_dpms(display);
57820603b95SRudolf Cornelissen 
57908705d96Sshatty 	interrupt_enable(true);
58008705d96Sshatty 	return B_OK;
58108705d96Sshatty }
58208705d96Sshatty 
58308705d96Sshatty /* Report device DPMS capabilities */
58420603b95SRudolf Cornelissen uint32 DPMS_CAPABILITIES(void)
58520603b95SRudolf Cornelissen {
58608705d96Sshatty 	return 	(B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
58708705d96Sshatty }
58808705d96Sshatty 
58908705d96Sshatty /* Return the current DPMS mode */
590bfecd0cdSRudolf Cornelissen uint32 DPMS_MODE(void)
591bfecd0cdSRudolf Cornelissen {
592bfecd0cdSRudolf Cornelissen 	return si->dpms_flags;
59308705d96Sshatty }
594