xref: /haiku/src/add-ons/accelerants/nvidia/SetDisplayMode.c (revision 0b36eea44d38ed94c99d31d13ae066b45b476846)
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,
9b2459715SRudolf Cornelissen 	Rudolf Cornelissen 11/2002-10/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 */
2008705d96Sshatty static void interrupt_enable(bool flag) {
2108705d96Sshatty 	status_t result;
2208705d96Sshatty 	nv_set_bool_state sbs;
2308705d96Sshatty 
2408705d96Sshatty 	/* set the magic number so the driver knows we're for real */
2508705d96Sshatty 	sbs.magic = NV_PRIVATE_DATA_MAGIC;
2608705d96Sshatty 	sbs.do_it = flag;
2708705d96Sshatty 	/* contact driver and get a pointer to the registers and shared data */
2808705d96Sshatty 	result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs));
2908705d96Sshatty }
3008705d96Sshatty 
3108705d96Sshatty /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
3208705d96Sshatty status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
3308705d96Sshatty {
3408705d96Sshatty 	/* BOUNDS WARNING:
3508705d96Sshatty 	 * It's impossible to deviate whatever small amount in a display_mode if the lower
3608705d96Sshatty 	 * and upper limits are the same!
3708705d96Sshatty 	 * Besides:
3808705d96Sshatty 	 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
3908705d96Sshatty 	 * returns B_BAD_VALUE!
4008705d96Sshatty 	 * Which means PROPOSEMODE should not return that on anything except on
4108705d96Sshatty 	 * deviations for:
4208705d96Sshatty 	 * display_mode.virtual_width;
4308705d96Sshatty 	 * display_mode.virtual_height;
4408705d96Sshatty 	 * display_mode.timing.h_display;
4508705d96Sshatty 	 * display_mode.timing.v_display;
4608705d96Sshatty 	 * So:
4708705d96Sshatty 	 * We don't use bounds here by making sure bounds and target are the same struct!
4808705d96Sshatty 	 * (See the call to PROPOSE_DISPLAY_MODE below) */
4908705d96Sshatty 	display_mode /*bounds,*/ target;
5008705d96Sshatty 
5108705d96Sshatty 	uint8 colour_depth1 = 32;
5208705d96Sshatty 	status_t result;
5308705d96Sshatty 	uint32 startadd,startadd_right;
5408705d96Sshatty 	bool display, h, v;
5530f76422SRudolf Cornelissen //	bool crt1, crt2, cross;
5608705d96Sshatty 
5708705d96Sshatty 	/* Adjust mode to valid one and fail if invalid */
5808705d96Sshatty 	target /*= bounds*/ = *mode_to_set;
5908705d96Sshatty 	/* show the mode bits */
6008705d96Sshatty 	LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
6108705d96Sshatty 	LOG(1, ("SETMODE: requested target pixelclock %dkHz\n",  target.timing.pixel_clock));
6208705d96Sshatty 	LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
6308705d96Sshatty 										target.virtual_width, target.virtual_height));
6408705d96Sshatty 
6508705d96Sshatty 	/* See BOUNDS WARNING above... */
6608705d96Sshatty 	if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR)	return B_ERROR;
6708705d96Sshatty 
6808705d96Sshatty 	/* if not dualhead capable card clear dualhead flags */
6908705d96Sshatty 	if (!(target.flags & DUALHEAD_CAPABLE))
7008705d96Sshatty 	{
7108705d96Sshatty 		target.flags &= ~DUALHEAD_BITS;
7208705d96Sshatty 	}
7308705d96Sshatty 	/* if not TVout capable card clear TVout flags */
7408705d96Sshatty 	if (!(target.flags & TV_CAPABLE))
7508705d96Sshatty 	{
7608705d96Sshatty 		target.flags &= ~TV_BITS;
7708705d96Sshatty 	}
7808705d96Sshatty 	LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
7908705d96Sshatty 
80c9c0c72bSRudolf Cornelissen 	/* make sure a possible 3D add-on will block rendering and re-initialize itself.
81c9c0c72bSRudolf Cornelissen 	 * note: update in _this_ order only */
82c9c0c72bSRudolf Cornelissen 	/* SET_DISPLAY_MODE will reset this flag when it's done. */
8321545d00SRudolf Cornelissen 	si->engine.threeD.mode_changing = true;
8421545d00SRudolf Cornelissen 	/* every 3D add-on will reset this bit-flag when it's done. */
8521545d00SRudolf Cornelissen 	si->engine.threeD.newmode = 0xffffffff;
8621545d00SRudolf Cornelissen 	/* every 3D clone needs to reclaim a slot.
8721545d00SRudolf Cornelissen 	 * note: this also cleans up reserved channels for killed 3D clones.. */
8821545d00SRudolf Cornelissen 	si->engine.threeD.clones = 0x00000000;
89afb207acSRudolf Cornelissen 
9008705d96Sshatty 	/* disable interrupts using the kernel driver */
9108705d96Sshatty 	interrupt_enable(false);
9208705d96Sshatty 
93*0b36eea4SRudolf Cornelissen 	/* disable TVout (set GPU CRTC to master mode) */
94*0b36eea4SRudolf Cornelissen 	//fixme: testing on singlehead cards only for now...
95*0b36eea4SRudolf Cornelissen //tmp disabled:
96*0b36eea4SRudolf Cornelissen //	if (!(si->ps.secondary_head)) BT_stop_tvout();
97*0b36eea4SRudolf Cornelissen 
9808705d96Sshatty 	/* find current DPMS state, then turn off screen(s) */
990669fe20SRudolf Cornelissen 	head1_dpms_fetch(&display, &h, &v);
1000669fe20SRudolf Cornelissen 	head1_dpms(false, false, false);
1010669fe20SRudolf Cornelissen 	if (si->ps.secondary_head) head2_dpms(false, false, false);
10208705d96Sshatty 
10308705d96Sshatty 	/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
104f2777ca1SRudolf Cornelissen 	startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
10508705d96Sshatty 
10608705d96Sshatty 	/* calculate and set new mode bytes_per_row */
10705ed3229SRudolf Cornelissen 	nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
10808705d96Sshatty 
10908705d96Sshatty 	/*Perform the very long mode switch!*/
11008705d96Sshatty 	if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
11108705d96Sshatty 	{
11208705d96Sshatty 		uint8 colour_depth2 = colour_depth1;
11308705d96Sshatty 
11408705d96Sshatty 		/* init display mode for secondary head */
11508705d96Sshatty 		display_mode target2 = target;
11608705d96Sshatty 
11708705d96Sshatty 		LOG(1,("SETMODE: setting DUALHEAD mode\n"));
11808705d96Sshatty 
11908705d96Sshatty 		/* validate flags for secondary TVout */
120b2459715SRudolf Cornelissen 		//fixme: remove or block on autodetect fail. (is now shutoff)
121b2459715SRudolf Cornelissen 		if ((0) && (target2.flags & TV_BITS))
12208705d96Sshatty 		{
12308705d96Sshatty 			target.flags &= ~TV_BITS;//still needed for some routines...
12408705d96Sshatty 			target2.flags &= ~TV_BITS;
12508705d96Sshatty 			LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
12608705d96Sshatty 		}
12708705d96Sshatty 
12830f76422SRudolf Cornelissen 		/* detect which connectors have a CRT connected */
12930f76422SRudolf Cornelissen 		//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
13030f76422SRudolf Cornelissen 		//or make it work with digital panels connected as well.
13130f76422SRudolf Cornelissen //		crt1 = nv_dac_crt_connected();
13230f76422SRudolf Cornelissen //		crt2 = nv_dac2_crt_connected();
13330f76422SRudolf Cornelissen 		/* connect outputs 'straight-through' */
13430f76422SRudolf Cornelissen //		if (crt1)
13530f76422SRudolf Cornelissen //		{
13630f76422SRudolf Cornelissen 			/* connector1 is used as primary output */
13730f76422SRudolf Cornelissen //			cross = false;
13830f76422SRudolf Cornelissen //		}
13930f76422SRudolf Cornelissen //		else
14030f76422SRudolf Cornelissen //		{
14130f76422SRudolf Cornelissen //			if (crt2)
14230f76422SRudolf Cornelissen 				/* connector2 is used as primary output */
14330f76422SRudolf Cornelissen //				cross = true;
14430f76422SRudolf Cornelissen //			else
14530f76422SRudolf Cornelissen 				/* no CRT detected: assume connector1 is used as primary output */
14630f76422SRudolf Cornelissen //				cross = false;
14730f76422SRudolf Cornelissen //		}
14830f76422SRudolf Cornelissen 		/* set output connectors assignment if possible */
14930f76422SRudolf Cornelissen 		if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
15030f76422SRudolf Cornelissen 			/* invert output assignment in switch mode */
15106f4c439SRudolf Cornelissen 			nv_general_head_select(true);
15230f76422SRudolf Cornelissen 		else
15306f4c439SRudolf Cornelissen 			nv_general_head_select(false);
15430f76422SRudolf Cornelissen 
15508705d96Sshatty 		/* set the pixel clock PLL(s) */
15608705d96Sshatty 		LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
15730f76422SRudolf Cornelissen 		if (head1_set_pix_pll(target) == B_ERROR)
15808705d96Sshatty 			LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
15908705d96Sshatty 
16008705d96Sshatty 		/* we do not need to set the pixelclock here for a head that's in TVout mode */
16108705d96Sshatty 		if (!(target2.flags & TV_BITS))
16208705d96Sshatty 		{
16308705d96Sshatty 			LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
16430f76422SRudolf Cornelissen 			if (head2_set_pix_pll(target2) == B_ERROR)
165a3b9d212SRudolf Cornelissen 				LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
16608705d96Sshatty 		}
16708705d96Sshatty 
16808705d96Sshatty 		/*set the colour depth for CRTC1 and the DAC */
16908705d96Sshatty 		switch(target.space)
17008705d96Sshatty 		{
171bc5690abSRudolf Cornelissen 		case B_CMAP8:
172bc5690abSRudolf Cornelissen 			colour_depth1 =  8;
17330f76422SRudolf Cornelissen 			head1_mode(BPP8, 1.0);
1740669fe20SRudolf Cornelissen 			head1_depth(BPP8);
175bc5690abSRudolf Cornelissen 			break;
176bc5690abSRudolf Cornelissen 		case B_RGB15_LITTLE:
177bc5690abSRudolf Cornelissen 			colour_depth1 = 16;
17830f76422SRudolf Cornelissen 			head1_mode(BPP15, 1.0);
1790669fe20SRudolf Cornelissen 			head1_depth(BPP15);
180bc5690abSRudolf Cornelissen 			break;
18108705d96Sshatty 		case B_RGB16_LITTLE:
18208705d96Sshatty 			colour_depth1 = 16;
18330f76422SRudolf Cornelissen 			head1_mode(BPP16, 1.0);
1840669fe20SRudolf Cornelissen 			head1_depth(BPP16);
18508705d96Sshatty 			break;
18608705d96Sshatty 		case B_RGB32_LITTLE:
18708705d96Sshatty 			colour_depth1 = 32;
18830f76422SRudolf Cornelissen 			head1_mode(BPP32, 1.0);
1890669fe20SRudolf Cornelissen 			head1_depth(BPP32);
19008705d96Sshatty 			break;
19108705d96Sshatty 		}
192a3b9d212SRudolf Cornelissen 		/*set the colour depth for CRTC2 and DAC2 */
19308705d96Sshatty 		switch(target2.space)
19408705d96Sshatty 		{
195bc5690abSRudolf Cornelissen 		case B_CMAP8:
196bc5690abSRudolf Cornelissen 			colour_depth2 =  8;
19730f76422SRudolf Cornelissen 			head2_mode(BPP8, 1.0);
1980669fe20SRudolf Cornelissen 			head2_depth(BPP8);
199bc5690abSRudolf Cornelissen 			break;
200bc5690abSRudolf Cornelissen 		case B_RGB15_LITTLE:
201bc5690abSRudolf Cornelissen 			colour_depth2 = 16;
20230f76422SRudolf Cornelissen 			head2_mode(BPP15, 1.0);
2030669fe20SRudolf Cornelissen 			head2_depth(BPP15);
204bc5690abSRudolf Cornelissen 			break;
20508705d96Sshatty 		case B_RGB16_LITTLE:
20608705d96Sshatty 			colour_depth2 = 16;
20730f76422SRudolf Cornelissen 			head2_mode(BPP16, 1.0);
2080669fe20SRudolf Cornelissen 			head2_depth(BPP16);
20908705d96Sshatty 			break;
21008705d96Sshatty 		case B_RGB32_LITTLE:
21108705d96Sshatty 			colour_depth2 = 32;
21230f76422SRudolf Cornelissen 			head2_mode(BPP32, 1.0);
2130669fe20SRudolf Cornelissen 			head2_depth(BPP32);
21408705d96Sshatty 			break;
21508705d96Sshatty 		}
21608705d96Sshatty 
21708705d96Sshatty 		/* check if we are doing interlaced TVout mode */
218b2459715SRudolf Cornelissen 		//fixme: we don't support interlaced mode?
21908705d96Sshatty 		si->interlaced_tv_mode = false;
22008705d96Sshatty /*		if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
22108705d96Sshatty 			si->interlaced_tv_mode = true;
22208705d96Sshatty */
22308705d96Sshatty 		/*set the display(s) pitches*/
2240669fe20SRudolf Cornelissen 		head1_set_display_pitch ();
22508705d96Sshatty 		//fixme: seperate for real dualhead modes:
22608705d96Sshatty 		//we need a secondary si->fbc!
2270669fe20SRudolf Cornelissen 		head2_set_display_pitch ();
22808705d96Sshatty 
22908705d96Sshatty 		/*work out where the "right" screen starts*/
23008705d96Sshatty 		startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
23108705d96Sshatty 
23208705d96Sshatty 		/* Tell card what memory to display */
23308705d96Sshatty 		switch (target.flags & DUALHEAD_BITS)
23408705d96Sshatty 		{
23508705d96Sshatty 		case DUALHEAD_ON:
23608705d96Sshatty 		case DUALHEAD_SWITCH:
2370669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth1);
2380669fe20SRudolf Cornelissen 			head2_set_display_start(startadd_right,colour_depth2);
23908705d96Sshatty 			break;
24008705d96Sshatty 		case DUALHEAD_CLONE:
2410669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth1);
2420669fe20SRudolf Cornelissen 			head2_set_display_start(startadd,colour_depth2);
24308705d96Sshatty 			break;
24408705d96Sshatty 		}
24508705d96Sshatty 
24608705d96Sshatty 		/* set the timing */
2470669fe20SRudolf Cornelissen 		head1_set_timing(target);
24808705d96Sshatty 		/* we do not need to setup CRTC2 here for a head that's in TVout mode */
2490669fe20SRudolf Cornelissen 		if (!(target2.flags & TV_BITS))	result = head2_set_timing(target2);
25008705d96Sshatty 
25108705d96Sshatty 		/* TVout support: setup CRTC2 and it's pixelclock */
252b2459715SRudolf Cornelissen 		if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2);
25308705d96Sshatty 	}
25408705d96Sshatty 	else /* single head mode */
25508705d96Sshatty 	{
25608705d96Sshatty 		status_t status;
25708705d96Sshatty 		int colour_mode = BPP32;
25808705d96Sshatty 
25930f76422SRudolf Cornelissen 		/* connect output */
26030f76422SRudolf Cornelissen 		if (si->ps.secondary_head)
26130f76422SRudolf Cornelissen 		{
26230f76422SRudolf Cornelissen 			/* detect which connectors have a CRT connected */
26330f76422SRudolf Cornelissen 			//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
26430f76422SRudolf Cornelissen 			//or make it work with digital panels connected as well.
26530f76422SRudolf Cornelissen //			crt1 = nv_dac_crt_connected();
26630f76422SRudolf Cornelissen //			crt2 = nv_dac2_crt_connected();
26730f76422SRudolf Cornelissen 			/* connect outputs 'straight-through' */
26830f76422SRudolf Cornelissen //			if (crt1)
26930f76422SRudolf Cornelissen //			{
27030f76422SRudolf Cornelissen 				/* connector1 is used as primary output */
27130f76422SRudolf Cornelissen //				cross = false;
27230f76422SRudolf Cornelissen //			}
27330f76422SRudolf Cornelissen //			else
27430f76422SRudolf Cornelissen //			{
27530f76422SRudolf Cornelissen //				if (crt2)
27630f76422SRudolf Cornelissen 					/* connector2 is used as primary output */
27730f76422SRudolf Cornelissen //					cross = true;
27830f76422SRudolf Cornelissen //				else
27930f76422SRudolf Cornelissen 					/* no CRT detected: assume connector1 is used as primary output */
28030f76422SRudolf Cornelissen //					cross = false;
28130f76422SRudolf Cornelissen //			}
28230f76422SRudolf Cornelissen 			/* set output connectors assignment if possible */
28306f4c439SRudolf Cornelissen 			nv_general_head_select(false);
28430f76422SRudolf Cornelissen 		}
28530f76422SRudolf Cornelissen 
28608705d96Sshatty 		switch(target.space)
28708705d96Sshatty 		{
28808705d96Sshatty 		case B_CMAP8:        colour_depth1 =  8; colour_mode = BPP8;  break;
28908705d96Sshatty 		case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
29008705d96Sshatty 		case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
29108705d96Sshatty 		case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
29208705d96Sshatty 		default:
29308705d96Sshatty 			LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
29408705d96Sshatty 			return B_ERROR;
29508705d96Sshatty 		}
29608705d96Sshatty 
29708705d96Sshatty 		/* set the pixel clock PLL */
29830f76422SRudolf Cornelissen 		status = head1_set_pix_pll(target);
29908705d96Sshatty 
30008705d96Sshatty 		if (status==B_ERROR)
30108705d96Sshatty 			LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
30208705d96Sshatty 
30308705d96Sshatty 		/* set the colour depth for CRTC1 and the DAC */
30408705d96Sshatty 		/* first set the colordepth */
3050669fe20SRudolf Cornelissen 		head1_depth(colour_mode);
30608705d96Sshatty 		/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
30730f76422SRudolf Cornelissen 		head1_mode(colour_mode,1.0);
30808705d96Sshatty 
30908705d96Sshatty 		/* set the display pitch */
3100669fe20SRudolf Cornelissen 		head1_set_display_pitch();
31108705d96Sshatty 
31208705d96Sshatty 		/* tell the card what memory to display */
3130669fe20SRudolf Cornelissen 		head1_set_display_start(startadd,colour_depth1);
31408705d96Sshatty 
31508705d96Sshatty 		/* set the timing */
316b2459715SRudolf Cornelissen 		if (!(target.flags & TV_BITS)) head1_set_timing(target);
317b2459715SRudolf Cornelissen 
318b2459715SRudolf Cornelissen 		/* TVout support: setup CRTC and it's pixelclock */
319b2459715SRudolf Cornelissen 		if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target);
32008705d96Sshatty 
32108705d96Sshatty 		//fixme: shut-off the videoPLL if it exists...
32208705d96Sshatty 	}
32308705d96Sshatty 
32408705d96Sshatty 	/* update driver's mode store */
32508705d96Sshatty 	si->dm = target;
32608705d96Sshatty 
3273c4c0505SRudolf Cornelissen 	/* update FIFO data fetching according to mode */
3283c4c0505SRudolf Cornelissen 	nv_crtc_update_fifo();
3293c4c0505SRudolf Cornelissen 
33008705d96Sshatty 	/* turn screen one on */
3310669fe20SRudolf Cornelissen 	head1_dpms(display, h, v);
33208705d96Sshatty 	/* turn screen two on if a dualhead mode is active */
3330669fe20SRudolf Cornelissen 	if (target.flags & DUALHEAD_BITS) head2_dpms(display,h,v);
33408705d96Sshatty 
33508705d96Sshatty 	/* set up acceleration for this mode */
336dd43fd34SRudolf Cornelissen 	/* note:
3373c4c0505SRudolf Cornelissen 	 * Maybe later we can forget about non-DMA mode (depends on 3D acceleration
3383c4c0505SRudolf Cornelissen 	 * attempts). */
339dd446dd3SRudolf Cornelissen 	if (!si->settings.dma_acc)
340b4c44701Sshatty 		nv_acc_init();
341dd43fd34SRudolf Cornelissen 	else
342dd43fd34SRudolf Cornelissen 		nv_acc_init_dma();
343b4c44701Sshatty 	/* set up overlay unit for this mode */
344aa1e552fSshatty 	nv_bes_init();
34508705d96Sshatty 
34689d37d46SRudolf Cornelissen 	/* note freemem range */
34789d37d46SRudolf Cornelissen 	/* first free adress follows hardcursor and workspace */
34821545d00SRudolf Cornelissen 	si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height;
34921545d00SRudolf Cornelissen 	if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048;
35089d37d46SRudolf Cornelissen 	/* last free adress is end-of-ram minus max space needed for overlay bitmaps */
35189d37d46SRudolf Cornelissen 	//fixme possible:
35289d37d46SRudolf Cornelissen 	//if overlay buffers are allocated subtract buffersize from mem_high;
35389d37d46SRudolf Cornelissen 	//only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
35421545d00SRudolf Cornelissen 	si->engine.threeD.mem_high = si->ps.memory_size - 1;
355fee251bcSRudolf Cornelissen 	/* don't touch the DMA acceleration engine command buffer if it exists */
356fee251bcSRudolf Cornelissen 	/* note:
357fdd699c7SRudolf Cornelissen 	 * the buffer is 32kB in size. Keep some extra distance for safety (faulty apps). */
358fdd699c7SRudolf Cornelissen 	if (si->settings.dma_acc)
359fdd699c7SRudolf Cornelissen 	{
360fdd699c7SRudolf Cornelissen 		if (si->ps.card_arch < NV40A)
361fdd699c7SRudolf Cornelissen 		{
362fdd699c7SRudolf Cornelissen 			/* keeping 32kB distance from the DMA buffer */
36321545d00SRudolf Cornelissen 			si->engine.threeD.mem_high -= (64 * 1024);
364fdd699c7SRudolf Cornelissen 		}
365fdd699c7SRudolf Cornelissen 		else
366fdd699c7SRudolf Cornelissen 		{
367fdd699c7SRudolf Cornelissen 			/* 416kB distance is just OK: keeping another 64kB distance for safety;
368fdd699c7SRudolf Cornelissen 			 * confirmed for NV43. */
369fdd699c7SRudolf Cornelissen 			/* note:
370fdd699c7SRudolf Cornelissen 			 * if you get too close to the DMA command buffer on NV40 and NV43 at
371fdd699c7SRudolf Cornelissen 			 * least (both confirmed), the source DMA instance will mess-up for
372fdd699c7SRudolf Cornelissen 			 * at least engine cmd NV_IMAGE_BLIT and NV12_IMAGE_BLIT. */
37321545d00SRudolf Cornelissen 			si->engine.threeD.mem_high -= (512 * 1024);
374fdd699c7SRudolf Cornelissen 		}
375fdd699c7SRudolf Cornelissen 	}
37621545d00SRudolf Cornelissen 	si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */
37789d37d46SRudolf Cornelissen 
378255e5021SRudolf Cornelissen 	LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
37908705d96Sshatty 
38008705d96Sshatty 	/* enable interrupts using the kernel driver */
38108705d96Sshatty 	interrupt_enable(true);
38208705d96Sshatty 
383c9c0c72bSRudolf Cornelissen 	/* make sure a possible 3D add-on will re-initialize itself by signalling ready */
38421545d00SRudolf Cornelissen 	si->engine.threeD.mode_changing = false;
385c9c0c72bSRudolf Cornelissen 
38608705d96Sshatty 	/* optimize memory-access if needed */
3870669fe20SRudolf Cornelissen //	head1_mem_priority(colour_depth1);
38808705d96Sshatty 
38908705d96Sshatty 	/* Tune RAM CAS-latency if needed. Must be done *here*! */
39008705d96Sshatty 	nv_set_cas_latency();
39108705d96Sshatty 
39208705d96Sshatty 	return B_OK;
39308705d96Sshatty }
39408705d96Sshatty 
39508705d96Sshatty /*
39608705d96Sshatty 	Set which pixel of the virtual frame buffer will show up in the
39708705d96Sshatty 	top left corner of the display device.  Used for page-flipping
39808705d96Sshatty 	games and virtual desktops.
39908705d96Sshatty */
40008705d96Sshatty status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
40108705d96Sshatty 	uint8 colour_depth;
40208705d96Sshatty 	uint32 startadd,startadd_right;
40308705d96Sshatty 
40408705d96Sshatty 	LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
40508705d96Sshatty 
406255e5021SRudolf Cornelissen 	/* nVidia cards support pixelprecise panning on both heads in all modes:
407255e5021SRudolf Cornelissen 	 * No stepping granularity needed! */
408255e5021SRudolf Cornelissen 
409255e5021SRudolf Cornelissen 	/* determine bits used for the colordepth */
41008705d96Sshatty 	switch(si->dm.space)
41108705d96Sshatty 	{
41208705d96Sshatty 	case B_CMAP8:
41308705d96Sshatty 		colour_depth=8;
41408705d96Sshatty 		break;
415255e5021SRudolf Cornelissen 	case B_RGB15_LITTLE:
416255e5021SRudolf Cornelissen 	case B_RGB16_LITTLE:
41708705d96Sshatty 		colour_depth=16;
418255e5021SRudolf Cornelissen 		break;
419255e5021SRudolf Cornelissen 	case B_RGB24_LITTLE:
420255e5021SRudolf Cornelissen 		colour_depth=24;
42108705d96Sshatty 		break;
42208705d96Sshatty 	case B_RGB32_LITTLE:
42308705d96Sshatty 		colour_depth=32;
42408705d96Sshatty 		break;
42508705d96Sshatty 	default:
42608705d96Sshatty 		return B_ERROR;
42708705d96Sshatty 	}
42808705d96Sshatty 
42908705d96Sshatty 	/* do not run past end of display */
43008705d96Sshatty 	switch (si->dm.flags & DUALHEAD_BITS)
43108705d96Sshatty 	{
43208705d96Sshatty 	case DUALHEAD_ON:
43308705d96Sshatty 	case DUALHEAD_SWITCH:
43408705d96Sshatty 		if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
43508705d96Sshatty 			return B_ERROR;
43608705d96Sshatty 		break;
43708705d96Sshatty 	default:
43808705d96Sshatty 		if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
43908705d96Sshatty 			return B_ERROR;
44008705d96Sshatty 		break;
44108705d96Sshatty 	}
44208705d96Sshatty 	if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
44308705d96Sshatty 		return B_ERROR;
44408705d96Sshatty 
44508705d96Sshatty 	/* everybody remember where we parked... */
44608705d96Sshatty 	si->dm.h_display_start = h_display_start;
44708705d96Sshatty 	si->dm.v_display_start = v_display_start;
44808705d96Sshatty 
44908705d96Sshatty 	/* actually set the registers */
45008705d96Sshatty 	//fixme: seperate both heads: we need a secondary si->fbc!
45108705d96Sshatty 	startadd = v_display_start * si->fbc.bytes_per_row;
45208705d96Sshatty 	startadd += h_display_start * (colour_depth >> 3);
453f2777ca1SRudolf Cornelissen 	startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
45408705d96Sshatty 	startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
45508705d96Sshatty 
45608705d96Sshatty 	interrupt_enable(false);
45708705d96Sshatty 
45808705d96Sshatty 	switch (si->dm.flags & DUALHEAD_BITS)
45908705d96Sshatty 	{
46008705d96Sshatty 		case DUALHEAD_ON:
46108705d96Sshatty 		case DUALHEAD_SWITCH:
4620669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
4630669fe20SRudolf Cornelissen 			head2_set_display_start(startadd_right,colour_depth);
46408705d96Sshatty 			break;
46508705d96Sshatty 		case DUALHEAD_OFF:
4660669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
46708705d96Sshatty 			break;
46808705d96Sshatty 		case DUALHEAD_CLONE:
4690669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
4700669fe20SRudolf Cornelissen 			head2_set_display_start(startadd,colour_depth);
47108705d96Sshatty 			break;
47208705d96Sshatty 	}
47308705d96Sshatty 
47408705d96Sshatty 	interrupt_enable(true);
47508705d96Sshatty 	return B_OK;
47608705d96Sshatty }
47708705d96Sshatty 
478255e5021SRudolf Cornelissen /* Set the indexed color palette */
47908705d96Sshatty void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
48008705d96Sshatty 	int i;
48108705d96Sshatty 	uint8 *r,*g,*b;
48208705d96Sshatty 
48308705d96Sshatty 	/* Protect gamma correction when not in CMAP8 */
48408705d96Sshatty 	if (si->dm.space != B_CMAP8) return;
48508705d96Sshatty 
48608705d96Sshatty 	r=si->color_data;
48708705d96Sshatty 	g=r+256;
48808705d96Sshatty 	b=g+256;
48908705d96Sshatty 
49008705d96Sshatty 	i=first;
49108705d96Sshatty 	while (count--)
49208705d96Sshatty 	{
49308705d96Sshatty 		r[i]=*color_data++;
49408705d96Sshatty 		g[i]=*color_data++;
49508705d96Sshatty 		b[i]=*color_data++;
49608705d96Sshatty 		i++;
49708705d96Sshatty 	}
49830f76422SRudolf Cornelissen 	head1_palette(r,g,b);
49930f76422SRudolf Cornelissen 	if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
50008705d96Sshatty }
50108705d96Sshatty 
50208705d96Sshatty /* Put the display into one of the Display Power Management modes. */
50308705d96Sshatty status_t SET_DPMS_MODE(uint32 dpms_flags) {
50408705d96Sshatty 	interrupt_enable(false);
50508705d96Sshatty 
50608705d96Sshatty 	LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
50708705d96Sshatty 
50808705d96Sshatty 	if (si->dm.flags & DUALHEAD_BITS) /*dualhead*/
50908705d96Sshatty 	{
51008705d96Sshatty 		switch(dpms_flags)
51108705d96Sshatty 		{
51208705d96Sshatty 		case B_DPMS_ON:	/* H: on, V: on, display on */
5130669fe20SRudolf Cornelissen 			head1_dpms(true, true, true);
5140669fe20SRudolf Cornelissen 			if (si->ps.secondary_head) head2_dpms(true, true, true);
51508705d96Sshatty 			break;
51608705d96Sshatty 		case B_DPMS_STAND_BY:
5170669fe20SRudolf Cornelissen 			head1_dpms(false, false, true);
5180669fe20SRudolf Cornelissen 			if (si->ps.secondary_head) head2_dpms(false, false, true);
51908705d96Sshatty 			break;
52008705d96Sshatty 		case B_DPMS_SUSPEND:
5210669fe20SRudolf Cornelissen 			head1_dpms(false, true, false);
5220669fe20SRudolf Cornelissen 			if (si->ps.secondary_head) head2_dpms(false, true, false);
52308705d96Sshatty 			break;
52408705d96Sshatty 		case B_DPMS_OFF: /* H: off, V: off, display off */
5250669fe20SRudolf Cornelissen 			head1_dpms(false, false, false);
5260669fe20SRudolf Cornelissen 			if (si->ps.secondary_head) head2_dpms(false, false, false);
52708705d96Sshatty 			break;
52808705d96Sshatty 		default:
52908705d96Sshatty 			LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
53008705d96Sshatty 			interrupt_enable(true);
53108705d96Sshatty 			return B_ERROR;
53208705d96Sshatty 		}
53308705d96Sshatty 	}
53408705d96Sshatty 	else /* singlehead */
53508705d96Sshatty 	{
53608705d96Sshatty 		switch(dpms_flags)
53708705d96Sshatty 		{
53808705d96Sshatty 		case B_DPMS_ON:	/* H: on, V: on, display on */
5390669fe20SRudolf Cornelissen 			head1_dpms(true, true, true);
54008705d96Sshatty 			break;
54108705d96Sshatty 		case B_DPMS_STAND_BY:
5420669fe20SRudolf Cornelissen 			head1_dpms(false, false, true);
54308705d96Sshatty 			break;
54408705d96Sshatty 		case B_DPMS_SUSPEND:
5450669fe20SRudolf Cornelissen 			head1_dpms(false, true, false);
54608705d96Sshatty 			break;
54708705d96Sshatty 		case B_DPMS_OFF: /* H: off, V: off, display off */
5480669fe20SRudolf Cornelissen 			head1_dpms(false, false, false);
54908705d96Sshatty 			break;
55008705d96Sshatty 		default:
55108705d96Sshatty 			LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
55208705d96Sshatty 			interrupt_enable(true);
55308705d96Sshatty 			return B_ERROR;
55408705d96Sshatty 		}
55508705d96Sshatty 	}
55608705d96Sshatty 	interrupt_enable(true);
55708705d96Sshatty 	return B_OK;
55808705d96Sshatty }
55908705d96Sshatty 
56008705d96Sshatty /* Report device DPMS capabilities */
56108705d96Sshatty uint32 DPMS_CAPABILITIES(void) {
56208705d96Sshatty 	return 	(B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
56308705d96Sshatty }
56408705d96Sshatty 
56508705d96Sshatty /* Return the current DPMS mode */
56608705d96Sshatty uint32 DPMS_MODE(void) {
56708705d96Sshatty 	bool display, h, v;
56808705d96Sshatty 
56908705d96Sshatty 	interrupt_enable(false);
5700669fe20SRudolf Cornelissen 	head1_dpms_fetch(&display, &h, &v);
57108705d96Sshatty 	interrupt_enable(true);
57208705d96Sshatty 
57308705d96Sshatty 	if (display && h && v)
57408705d96Sshatty 		return B_DPMS_ON;
57508705d96Sshatty 	else if(v)
57608705d96Sshatty 		return B_DPMS_STAND_BY;
57708705d96Sshatty 	else if(h)
57808705d96Sshatty 		return B_DPMS_SUSPEND;
57908705d96Sshatty 	else
58008705d96Sshatty 		return B_DPMS_OFF;
58108705d96Sshatty }
582