xref: /haiku/src/add-ons/accelerants/nvidia/SetDisplayMode.c (revision bab64f65bb775dc23060e276f1f1c4498ab7af6c)
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,
9*06343681SRudolfC 	Rudolf Cornelissen 11/2002-12/2015
1008705d96Sshatty */
1108705d96Sshatty 
1208705d96Sshatty #define MODULE_BIT 0x00200000
1308705d96Sshatty 
1408705d96Sshatty #include "acc_std.h"
1508705d96Sshatty 
1608705d96Sshatty /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
SET_DISPLAY_MODE(display_mode * mode_to_set)1708705d96Sshatty status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
1808705d96Sshatty {
1908705d96Sshatty 	/* BOUNDS WARNING:
2008705d96Sshatty 	 * It's impossible to deviate whatever small amount in a display_mode if the lower
2108705d96Sshatty 	 * and upper limits are the same!
2208705d96Sshatty 	 * Besides:
2308705d96Sshatty 	 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
2408705d96Sshatty 	 * returns B_BAD_VALUE!
2508705d96Sshatty 	 * Which means PROPOSEMODE should not return that on anything except on
2608705d96Sshatty 	 * deviations for:
2708705d96Sshatty 	 * display_mode.virtual_width;
2808705d96Sshatty 	 * display_mode.virtual_height;
2908705d96Sshatty 	 * display_mode.timing.h_display;
3008705d96Sshatty 	 * display_mode.timing.v_display;
3108705d96Sshatty 	 * So:
3208705d96Sshatty 	 * We don't use bounds here by making sure bounds and target are the same struct!
3308705d96Sshatty 	 * (See the call to PROPOSE_DISPLAY_MODE below) */
3408705d96Sshatty 	display_mode /*bounds,*/ target;
3508705d96Sshatty 
3608705d96Sshatty 	uint8 colour_depth1 = 32;
3708705d96Sshatty 	uint32 startadd,startadd_right;
3830f76422SRudolf Cornelissen //	bool crt1, crt2, cross;
3908705d96Sshatty 
4008705d96Sshatty 	/* Adjust mode to valid one and fail if invalid */
4108705d96Sshatty 	target /*= bounds*/ = *mode_to_set;
4208705d96Sshatty 	/* show the mode bits */
4308705d96Sshatty 	LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
44*06343681SRudolfC 	LOG(1, ("SETMODE: requested target pixelclock %ukHz\n",  target.timing.pixel_clock));
45*06343681SRudolfC 	LOG(1, ("SETMODE: requested virtual_width %u, virtual_height %u\n",
4608705d96Sshatty 										target.virtual_width, target.virtual_height));
4708705d96Sshatty 
4808705d96Sshatty 	/* See BOUNDS WARNING above... */
4908705d96Sshatty 	if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR)	return B_ERROR;
5008705d96Sshatty 
51c9c0c72bSRudolf Cornelissen 	/* make sure a possible 3D add-on will block rendering and re-initialize itself.
52c9c0c72bSRudolf Cornelissen 	 * note: update in _this_ order only */
53c9c0c72bSRudolf Cornelissen 	/* SET_DISPLAY_MODE will reset this flag when it's done. */
5421545d00SRudolf Cornelissen 	si->engine.threeD.mode_changing = true;
5521545d00SRudolf Cornelissen 	/* every 3D add-on will reset this bit-flag when it's done. */
5621545d00SRudolf Cornelissen 	si->engine.threeD.newmode = 0xffffffff;
5721545d00SRudolf Cornelissen 	/* every 3D clone needs to reclaim a slot.
5821545d00SRudolf Cornelissen 	 * note: this also cleans up reserved channels for killed 3D clones.. */
5921545d00SRudolf Cornelissen 	si->engine.threeD.clones = 0x00000000;
60afb207acSRudolf Cornelissen 
6108705d96Sshatty 	/* disable interrupts using the kernel driver */
62155a2ad0SRudolf Cornelissen 	head1_interrupt_enable(false);
63155a2ad0SRudolf Cornelissen 	if (si->ps.secondary_head) head2_interrupt_enable(false);
6408705d96Sshatty 
650703480cSRudolf Cornelissen 	/* disable TVout if supported */
660703480cSRudolf Cornelissen 	if (si->ps.tvout) BT_stop_tvout();
670b36eea4SRudolf Cornelissen 
6820603b95SRudolf Cornelissen 	/* turn off screen(s) _after_ TVout is disabled (if applicable) */
694022652cSRudolf Cornelissen 	head1_dpms(false, false, false, true);
704022652cSRudolf Cornelissen 	if (si->ps.secondary_head) head2_dpms(false, false, false, true);
713aa21459SRudolf Cornelissen 	if (si->ps.tvout) BT_dpms(false);
7208705d96Sshatty 
7308705d96Sshatty 	/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
74f2777ca1SRudolf Cornelissen 	startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
7508705d96Sshatty 
7608705d96Sshatty 	/* calculate and set new mode bytes_per_row */
7705ed3229SRudolf Cornelissen 	nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
7808705d96Sshatty 
7908705d96Sshatty 	/*Perform the very long mode switch!*/
8008705d96Sshatty 	if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
8108705d96Sshatty 	{
8208705d96Sshatty 		uint8 colour_depth2 = colour_depth1;
8308705d96Sshatty 
8408705d96Sshatty 		/* init display mode for secondary head */
8508705d96Sshatty 		display_mode target2 = target;
8608705d96Sshatty 
8708705d96Sshatty 		LOG(1,("SETMODE: setting DUALHEAD mode\n"));
8808705d96Sshatty 
8908705d96Sshatty 		/* validate flags for secondary TVout */
90b2459715SRudolf Cornelissen 		//fixme: remove or block on autodetect fail. (is now shutoff)
91b2459715SRudolf Cornelissen 		if ((0) && (target2.flags & TV_BITS))
9208705d96Sshatty 		{
9308705d96Sshatty 			target.flags &= ~TV_BITS;//still needed for some routines...
9408705d96Sshatty 			target2.flags &= ~TV_BITS;
9508705d96Sshatty 			LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
9608705d96Sshatty 		}
9708705d96Sshatty 
9830f76422SRudolf Cornelissen 		/* detect which connectors have a CRT connected */
9930f76422SRudolf Cornelissen 		//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
10030f76422SRudolf Cornelissen 		//or make it work with digital panels connected as well.
10130f76422SRudolf Cornelissen //		crt1 = nv_dac_crt_connected();
10230f76422SRudolf Cornelissen //		crt2 = nv_dac2_crt_connected();
10330f76422SRudolf Cornelissen 		/* connect outputs 'straight-through' */
10430f76422SRudolf Cornelissen //		if (crt1)
10530f76422SRudolf Cornelissen //		{
10630f76422SRudolf Cornelissen 			/* connector1 is used as primary output */
10730f76422SRudolf Cornelissen //			cross = false;
10830f76422SRudolf Cornelissen //		}
10930f76422SRudolf Cornelissen //		else
11030f76422SRudolf Cornelissen //		{
11130f76422SRudolf Cornelissen //			if (crt2)
11230f76422SRudolf Cornelissen 				/* connector2 is used as primary output */
11330f76422SRudolf Cornelissen //				cross = true;
11430f76422SRudolf Cornelissen //			else
11530f76422SRudolf Cornelissen 				/* no CRT detected: assume connector1 is used as primary output */
11630f76422SRudolf Cornelissen //				cross = false;
11730f76422SRudolf Cornelissen //		}
11830f76422SRudolf Cornelissen 		/* set output connectors assignment if possible */
11930f76422SRudolf Cornelissen 		if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
12030f76422SRudolf Cornelissen 			/* invert output assignment in switch mode */
12106f4c439SRudolf Cornelissen 			nv_general_head_select(true);
12230f76422SRudolf Cornelissen 		else
12306f4c439SRudolf Cornelissen 			nv_general_head_select(false);
12430f76422SRudolf Cornelissen 
12508705d96Sshatty 		/* set the pixel clock PLL(s) */
12608705d96Sshatty 		LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
12730f76422SRudolf Cornelissen 		if (head1_set_pix_pll(target) == B_ERROR)
12808705d96Sshatty 			LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
12908705d96Sshatty 
13008705d96Sshatty 		LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
13130f76422SRudolf Cornelissen 		if (head2_set_pix_pll(target2) == B_ERROR)
132a3b9d212SRudolf Cornelissen 			LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
13308705d96Sshatty 
13408705d96Sshatty 		/*set the colour depth for CRTC1 and the DAC */
13508705d96Sshatty 		switch(target.space)
13608705d96Sshatty 		{
137bc5690abSRudolf Cornelissen 		case B_CMAP8:
138bc5690abSRudolf Cornelissen 			colour_depth1 =  8;
13930f76422SRudolf Cornelissen 			head1_mode(BPP8, 1.0);
1400669fe20SRudolf Cornelissen 			head1_depth(BPP8);
141bc5690abSRudolf Cornelissen 			break;
142bc5690abSRudolf Cornelissen 		case B_RGB15_LITTLE:
143bc5690abSRudolf Cornelissen 			colour_depth1 = 16;
14430f76422SRudolf Cornelissen 			head1_mode(BPP15, 1.0);
1450669fe20SRudolf Cornelissen 			head1_depth(BPP15);
146bc5690abSRudolf Cornelissen 			break;
14708705d96Sshatty 		case B_RGB16_LITTLE:
14808705d96Sshatty 			colour_depth1 = 16;
14930f76422SRudolf Cornelissen 			head1_mode(BPP16, 1.0);
1500669fe20SRudolf Cornelissen 			head1_depth(BPP16);
15108705d96Sshatty 			break;
15208705d96Sshatty 		case B_RGB32_LITTLE:
15308705d96Sshatty 			colour_depth1 = 32;
15430f76422SRudolf Cornelissen 			head1_mode(BPP32, 1.0);
1550669fe20SRudolf Cornelissen 			head1_depth(BPP32);
15608705d96Sshatty 			break;
15708705d96Sshatty 		}
158a3b9d212SRudolf Cornelissen 		/*set the colour depth for CRTC2 and DAC2 */
15908705d96Sshatty 		switch(target2.space)
16008705d96Sshatty 		{
161bc5690abSRudolf Cornelissen 		case B_CMAP8:
162bc5690abSRudolf Cornelissen 			colour_depth2 =  8;
16330f76422SRudolf Cornelissen 			head2_mode(BPP8, 1.0);
1640669fe20SRudolf Cornelissen 			head2_depth(BPP8);
165bc5690abSRudolf Cornelissen 			break;
166bc5690abSRudolf Cornelissen 		case B_RGB15_LITTLE:
167bc5690abSRudolf Cornelissen 			colour_depth2 = 16;
16830f76422SRudolf Cornelissen 			head2_mode(BPP15, 1.0);
1690669fe20SRudolf Cornelissen 			head2_depth(BPP15);
170bc5690abSRudolf Cornelissen 			break;
17108705d96Sshatty 		case B_RGB16_LITTLE:
17208705d96Sshatty 			colour_depth2 = 16;
17330f76422SRudolf Cornelissen 			head2_mode(BPP16, 1.0);
1740669fe20SRudolf Cornelissen 			head2_depth(BPP16);
17508705d96Sshatty 			break;
17608705d96Sshatty 		case B_RGB32_LITTLE:
17708705d96Sshatty 			colour_depth2 = 32;
17830f76422SRudolf Cornelissen 			head2_mode(BPP32, 1.0);
1790669fe20SRudolf Cornelissen 			head2_depth(BPP32);
18008705d96Sshatty 			break;
18108705d96Sshatty 		}
18208705d96Sshatty 
18308705d96Sshatty 		/* check if we are doing interlaced TVout mode */
184b2459715SRudolf Cornelissen 		//fixme: we don't support interlaced mode?
18508705d96Sshatty 		si->interlaced_tv_mode = false;
186c0ebc619SRudolf Cornelissen 
18708705d96Sshatty 		/*set the display(s) pitches*/
1880669fe20SRudolf Cornelissen 		head1_set_display_pitch ();
18908705d96Sshatty 		//fixme: seperate for real dualhead modes:
19008705d96Sshatty 		//we need a secondary si->fbc!
1910669fe20SRudolf Cornelissen 		head2_set_display_pitch ();
19208705d96Sshatty 
19308705d96Sshatty 		/*work out where the "right" screen starts*/
19408705d96Sshatty 		startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
19508705d96Sshatty 
19608705d96Sshatty 		/* Tell card what memory to display */
19708705d96Sshatty 		switch (target.flags & DUALHEAD_BITS)
19808705d96Sshatty 		{
19908705d96Sshatty 		case DUALHEAD_ON:
20008705d96Sshatty 		case DUALHEAD_SWITCH:
2010669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth1);
2020669fe20SRudolf Cornelissen 			head2_set_display_start(startadd_right,colour_depth2);
20308705d96Sshatty 			break;
20408705d96Sshatty 		case DUALHEAD_CLONE:
2050669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth1);
2060669fe20SRudolf Cornelissen 			head2_set_display_start(startadd,colour_depth2);
20708705d96Sshatty 			break;
20808705d96Sshatty 		}
20908705d96Sshatty 
21008705d96Sshatty 		/* set the timing */
2110669fe20SRudolf Cornelissen 		head1_set_timing(target);
212c0ebc619SRudolf Cornelissen 		head2_set_timing(target2);
21308705d96Sshatty 
214c0ebc619SRudolf Cornelissen 		/* TVout support: program TVout encoder and modify CRTC timing */
215b2459715SRudolf Cornelissen 		if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2);
21608705d96Sshatty 	}
21708705d96Sshatty 	else /* single head mode */
21808705d96Sshatty 	{
21908705d96Sshatty 		int colour_mode = BPP32;
22008705d96Sshatty 
22130f76422SRudolf Cornelissen 		/* connect output */
22230f76422SRudolf Cornelissen 		if (si->ps.secondary_head)
22330f76422SRudolf Cornelissen 		{
22430f76422SRudolf Cornelissen 			/* detect which connectors have a CRT connected */
22530f76422SRudolf Cornelissen 			//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
22630f76422SRudolf Cornelissen 			//or make it work with digital panels connected as well.
22730f76422SRudolf Cornelissen //			crt1 = nv_dac_crt_connected();
22830f76422SRudolf Cornelissen //			crt2 = nv_dac2_crt_connected();
22930f76422SRudolf Cornelissen 			/* connect outputs 'straight-through' */
23030f76422SRudolf Cornelissen //			if (crt1)
23130f76422SRudolf Cornelissen //			{
23230f76422SRudolf Cornelissen 				/* connector1 is used as primary output */
23330f76422SRudolf Cornelissen //				cross = false;
23430f76422SRudolf Cornelissen //			}
23530f76422SRudolf Cornelissen //			else
23630f76422SRudolf Cornelissen //			{
23730f76422SRudolf Cornelissen //				if (crt2)
23830f76422SRudolf Cornelissen 					/* connector2 is used as primary output */
23930f76422SRudolf Cornelissen //					cross = true;
24030f76422SRudolf Cornelissen //				else
24130f76422SRudolf Cornelissen 					/* no CRT detected: assume connector1 is used as primary output */
24230f76422SRudolf Cornelissen //					cross = false;
24330f76422SRudolf Cornelissen //			}
24430f76422SRudolf Cornelissen 			/* set output connectors assignment if possible */
24506f4c439SRudolf Cornelissen 			nv_general_head_select(false);
24630f76422SRudolf Cornelissen 		}
24730f76422SRudolf Cornelissen 
24808705d96Sshatty 		switch(target.space)
24908705d96Sshatty 		{
25008705d96Sshatty 		case B_CMAP8:        colour_depth1 =  8; colour_mode = BPP8;  break;
25108705d96Sshatty 		case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
25208705d96Sshatty 		case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
25308705d96Sshatty 		case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
25408705d96Sshatty 		default:
25508705d96Sshatty 			LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
25608705d96Sshatty 			return B_ERROR;
25708705d96Sshatty 		}
25808705d96Sshatty 
25908705d96Sshatty 		/* set the pixel clock PLL */
260c0ebc619SRudolf Cornelissen 		if (head1_set_pix_pll(target) == B_ERROR)
26108705d96Sshatty 			LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
26208705d96Sshatty 
26308705d96Sshatty 		/* set the colour depth for CRTC1 and the DAC */
26408705d96Sshatty 		/* first set the colordepth */
2650669fe20SRudolf Cornelissen 		head1_depth(colour_mode);
26608705d96Sshatty 		/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
26730f76422SRudolf Cornelissen 		head1_mode(colour_mode,1.0);
26808705d96Sshatty 
26908705d96Sshatty 		/* set the display pitch */
2700669fe20SRudolf Cornelissen 		head1_set_display_pitch();
27108705d96Sshatty 
27208705d96Sshatty 		/* tell the card what memory to display */
2730669fe20SRudolf Cornelissen 		head1_set_display_start(startadd,colour_depth1);
27408705d96Sshatty 
27508705d96Sshatty 		/* set the timing */
276c0ebc619SRudolf Cornelissen 		head1_set_timing(target);
277b2459715SRudolf Cornelissen 
278c0ebc619SRudolf Cornelissen 		/* TVout support: program TVout encoder and modify CRTC timing */
279b2459715SRudolf Cornelissen 		if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target);
28008705d96Sshatty 
28108705d96Sshatty 		//fixme: shut-off the videoPLL if it exists...
28208705d96Sshatty 	}
28308705d96Sshatty 
28408705d96Sshatty 	/* update driver's mode store */
28508705d96Sshatty 	si->dm = target;
28608705d96Sshatty 
2873c4c0505SRudolf Cornelissen 	/* update FIFO data fetching according to mode */
2883c4c0505SRudolf Cornelissen 	nv_crtc_update_fifo();
289a393eaf8SRudolf Cornelissen 	if (si->ps.secondary_head) nv_crtc2_update_fifo();
2903c4c0505SRudolf Cornelissen 
29108705d96Sshatty 	/* set up acceleration for this mode */
292dd43fd34SRudolf Cornelissen 	/* note:
2933c4c0505SRudolf Cornelissen 	 * Maybe later we can forget about non-DMA mode (depends on 3D acceleration
2943c4c0505SRudolf Cornelissen 	 * attempts). */
2956042b7b6SRudolf Cornelissen 	if (!si->settings.block_acc) {
296dd446dd3SRudolf Cornelissen 		if (!si->settings.dma_acc)
297b4c44701Sshatty 			nv_acc_init();
298dd43fd34SRudolf Cornelissen 		else
299dd43fd34SRudolf Cornelissen 			nv_acc_init_dma();
3006042b7b6SRudolf Cornelissen 	}
30169ca2102SRudolf Cornelissen 
302b4c44701Sshatty 	/* set up overlay unit for this mode */
303aa1e552fSshatty 	nv_bes_init();
30408705d96Sshatty 
30589d37d46SRudolf Cornelissen 	/* note freemem range */
30689d37d46SRudolf Cornelissen 	/* first free adress follows hardcursor and workspace */
30721545d00SRudolf Cornelissen 	si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height;
30821545d00SRudolf Cornelissen 	if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048;
30989d37d46SRudolf Cornelissen 	/* last free adress is end-of-ram minus max space needed for overlay bitmaps */
31089d37d46SRudolf Cornelissen 	//fixme possible:
31189d37d46SRudolf Cornelissen 	//if overlay buffers are allocated subtract buffersize from mem_high;
31289d37d46SRudolf Cornelissen 	//only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
31321545d00SRudolf Cornelissen 	si->engine.threeD.mem_high = si->ps.memory_size - 1;
314f67620f9SRudolf Cornelissen 	/* Keep some extra distance as a workaround for certain bugs (see
315f67620f9SRudolf Cornelissen 	 * DriverInterface.h for an explanation). */
316fdd699c7SRudolf Cornelissen 	if (si->ps.card_arch < NV40A)
317f67620f9SRudolf Cornelissen 		si->engine.threeD.mem_high -= PRE_NV40_OFFSET;
318fdd699c7SRudolf Cornelissen 	else
319f67620f9SRudolf Cornelissen 		si->engine.threeD.mem_high -= NV40_PLUS_OFFSET;
320f67620f9SRudolf Cornelissen 
32121545d00SRudolf Cornelissen 	si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */
32289d37d46SRudolf Cornelissen 
323bfecd0cdSRudolf Cornelissen 	/* restore screen(s) output state(s) */
324bfecd0cdSRudolf Cornelissen 	SET_DPMS_MODE(si->dpms_flags);
32508705d96Sshatty 
32608705d96Sshatty 	/* enable interrupts using the kernel driver */
327155a2ad0SRudolf Cornelissen 	//fixme:
328155a2ad0SRudolf Cornelissen 	//add head2 once we use one driver instance 'per head' (instead of 'per card')
329155a2ad0SRudolf Cornelissen 	head1_interrupt_enable(true);
33008705d96Sshatty 
331c9c0c72bSRudolf Cornelissen 	/* make sure a possible 3D add-on will re-initialize itself by signalling ready */
33221545d00SRudolf Cornelissen 	si->engine.threeD.mode_changing = false;
333c9c0c72bSRudolf Cornelissen 
33408705d96Sshatty 	/* optimize memory-access if needed */
3350669fe20SRudolf Cornelissen //	head1_mem_priority(colour_depth1);
33608705d96Sshatty 
33708705d96Sshatty 	/* Tune RAM CAS-latency if needed. Must be done *here*! */
33808705d96Sshatty 	nv_set_cas_latency();
33908705d96Sshatty 
340bfecd0cdSRudolf Cornelissen 	LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
341bfecd0cdSRudolf Cornelissen 
34208705d96Sshatty 	return B_OK;
34308705d96Sshatty }
34408705d96Sshatty 
34508705d96Sshatty /*
34608705d96Sshatty 	Set which pixel of the virtual frame buffer will show up in the
34708705d96Sshatty 	top left corner of the display device.  Used for page-flipping
34808705d96Sshatty 	games and virtual desktops.
34908705d96Sshatty */
MOVE_DISPLAY(uint16 h_display_start,uint16 v_display_start)35008705d96Sshatty status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
35108705d96Sshatty 	uint8 colour_depth;
35208705d96Sshatty 	uint32 startadd,startadd_right;
35308705d96Sshatty 
35408705d96Sshatty 	LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
35508705d96Sshatty 
356255e5021SRudolf Cornelissen 	/* nVidia cards support pixelprecise panning on both heads in all modes:
357255e5021SRudolf Cornelissen 	 * No stepping granularity needed! */
358255e5021SRudolf Cornelissen 
359255e5021SRudolf Cornelissen 	/* determine bits used for the colordepth */
36008705d96Sshatty 	switch(si->dm.space)
36108705d96Sshatty 	{
36208705d96Sshatty 	case B_CMAP8:
36308705d96Sshatty 		colour_depth=8;
36408705d96Sshatty 		break;
365255e5021SRudolf Cornelissen 	case B_RGB15_LITTLE:
366255e5021SRudolf Cornelissen 	case B_RGB16_LITTLE:
36708705d96Sshatty 		colour_depth=16;
368255e5021SRudolf Cornelissen 		break;
369255e5021SRudolf Cornelissen 	case B_RGB24_LITTLE:
370255e5021SRudolf Cornelissen 		colour_depth=24;
37108705d96Sshatty 		break;
37208705d96Sshatty 	case B_RGB32_LITTLE:
37308705d96Sshatty 		colour_depth=32;
37408705d96Sshatty 		break;
37508705d96Sshatty 	default:
37608705d96Sshatty 		return B_ERROR;
37708705d96Sshatty 	}
37808705d96Sshatty 
37908705d96Sshatty 	/* do not run past end of display */
38008705d96Sshatty 	switch (si->dm.flags & DUALHEAD_BITS)
38108705d96Sshatty 	{
38208705d96Sshatty 	case DUALHEAD_ON:
38308705d96Sshatty 	case DUALHEAD_SWITCH:
38408705d96Sshatty 		if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
38508705d96Sshatty 			return B_ERROR;
38608705d96Sshatty 		break;
38708705d96Sshatty 	default:
38808705d96Sshatty 		if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
38908705d96Sshatty 			return B_ERROR;
39008705d96Sshatty 		break;
39108705d96Sshatty 	}
39208705d96Sshatty 	if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
39308705d96Sshatty 		return B_ERROR;
39408705d96Sshatty 
39508705d96Sshatty 	/* everybody remember where we parked... */
39608705d96Sshatty 	si->dm.h_display_start = h_display_start;
39708705d96Sshatty 	si->dm.v_display_start = v_display_start;
39808705d96Sshatty 
39908705d96Sshatty 	/* actually set the registers */
40008705d96Sshatty 	//fixme: seperate both heads: we need a secondary si->fbc!
40108705d96Sshatty 	startadd = v_display_start * si->fbc.bytes_per_row;
40208705d96Sshatty 	startadd += h_display_start * (colour_depth >> 3);
403f2777ca1SRudolf Cornelissen 	startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
40408705d96Sshatty 	startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
40508705d96Sshatty 
406155a2ad0SRudolf Cornelissen 	/* disable interrupts using the kernel driver */
407155a2ad0SRudolf Cornelissen 	head1_interrupt_enable(false);
408155a2ad0SRudolf Cornelissen 	if (si->ps.secondary_head) head2_interrupt_enable(false);
40908705d96Sshatty 
41008705d96Sshatty 	switch (si->dm.flags & DUALHEAD_BITS)
41108705d96Sshatty 	{
41208705d96Sshatty 		case DUALHEAD_ON:
41308705d96Sshatty 		case DUALHEAD_SWITCH:
4140669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
4150669fe20SRudolf Cornelissen 			head2_set_display_start(startadd_right,colour_depth);
41608705d96Sshatty 			break;
41708705d96Sshatty 		case DUALHEAD_OFF:
4180669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
41908705d96Sshatty 			break;
42008705d96Sshatty 		case DUALHEAD_CLONE:
4210669fe20SRudolf Cornelissen 			head1_set_display_start(startadd,colour_depth);
4220669fe20SRudolf Cornelissen 			head2_set_display_start(startadd,colour_depth);
42308705d96Sshatty 			break;
42408705d96Sshatty 	}
42508705d96Sshatty 
426155a2ad0SRudolf Cornelissen 	//fixme:
427155a2ad0SRudolf Cornelissen 	//add head2 once we use one driver instance 'per head' (instead of 'per card')
428155a2ad0SRudolf Cornelissen 	head1_interrupt_enable(true);
429155a2ad0SRudolf Cornelissen 
43008705d96Sshatty 	return B_OK;
43108705d96Sshatty }
43208705d96Sshatty 
433255e5021SRudolf Cornelissen /* Set the indexed color palette */
SET_INDEXED_COLORS(uint count,uint8 first,uint8 * color_data,uint32 flags)43408705d96Sshatty void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
43508705d96Sshatty 	int i;
43608705d96Sshatty 	uint8 *r,*g,*b;
43708705d96Sshatty 
43808705d96Sshatty 	/* Protect gamma correction when not in CMAP8 */
43908705d96Sshatty 	if (si->dm.space != B_CMAP8) return;
44008705d96Sshatty 
44108705d96Sshatty 	r=si->color_data;
44208705d96Sshatty 	g=r+256;
44308705d96Sshatty 	b=g+256;
44408705d96Sshatty 
44508705d96Sshatty 	i=first;
44608705d96Sshatty 	while (count--)
44708705d96Sshatty 	{
44808705d96Sshatty 		r[i]=*color_data++;
44908705d96Sshatty 		g[i]=*color_data++;
45008705d96Sshatty 		b[i]=*color_data++;
45108705d96Sshatty 		i++;
45208705d96Sshatty 	}
45330f76422SRudolf Cornelissen 	head1_palette(r,g,b);
45430f76422SRudolf Cornelissen 	if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
45508705d96Sshatty }
45608705d96Sshatty 
45708705d96Sshatty /* Put the display into one of the Display Power Management modes. */
SET_DPMS_MODE(uint32 dpms_flags)458bfecd0cdSRudolf Cornelissen status_t SET_DPMS_MODE(uint32 dpms_flags)
459bfecd0cdSRudolf Cornelissen {
4604022652cSRudolf Cornelissen 	bool display, h1h, h1v, h2h, h2v, do_p1, do_p2;
46120603b95SRudolf Cornelissen 
462155a2ad0SRudolf Cornelissen 	/* disable interrupts using the kernel driver */
463155a2ad0SRudolf Cornelissen 	head1_interrupt_enable(false);
464155a2ad0SRudolf Cornelissen 	if (si->ps.secondary_head) head2_interrupt_enable(false);
46508705d96Sshatty 
4664022652cSRudolf Cornelissen 	LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags));
46708705d96Sshatty 
468bfecd0cdSRudolf Cornelissen 	/* note current DPMS state for our reference */
469bfecd0cdSRudolf Cornelissen 	si->dpms_flags = dpms_flags;
470bfecd0cdSRudolf Cornelissen 
4714022652cSRudolf Cornelissen 	/* preset: DPMS for panels should be executed */
4724022652cSRudolf Cornelissen 	do_p1 = do_p2 = true;
4734022652cSRudolf Cornelissen 
47420603b95SRudolf Cornelissen 	/* determine signals to send to head(s) */
47520603b95SRudolf Cornelissen 	display = h1h = h1v = h2h = h2v = true;
47608705d96Sshatty 	switch(dpms_flags)
47708705d96Sshatty 	{
47808705d96Sshatty 	case B_DPMS_ON:	/* H: on, V: on, display on */
47908705d96Sshatty 		break;
48008705d96Sshatty 	case B_DPMS_STAND_BY:
48120603b95SRudolf Cornelissen 		display = h1h = h2h = false;
48208705d96Sshatty 		break;
48308705d96Sshatty 	case B_DPMS_SUSPEND:
48420603b95SRudolf Cornelissen 		display = h1v = h2v = false;
48508705d96Sshatty 		break;
48608705d96Sshatty 	case B_DPMS_OFF: /* H: off, V: off, display off */
48720603b95SRudolf Cornelissen 		display = h1h = h1v = h2h = h2v = false;
48808705d96Sshatty 		break;
48908705d96Sshatty 	default:
4904022652cSRudolf Cornelissen 		LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags));
491155a2ad0SRudolf Cornelissen 		//fixme:
492155a2ad0SRudolf Cornelissen 		//add head2 once we use one driver instance 'per head' (instead of 'per card')
493155a2ad0SRudolf Cornelissen 		head1_interrupt_enable(true);
494155a2ad0SRudolf Cornelissen 
49508705d96Sshatty 		return B_ERROR;
49608705d96Sshatty 	}
49720603b95SRudolf Cornelissen 
49820603b95SRudolf Cornelissen 	/* CRTC used for TVout needs specific DPMS programming */
49920603b95SRudolf Cornelissen 	if (si->dm.flags & TV_BITS)
50008705d96Sshatty 	{
5013c71b494SRudolf Cornelissen 		/* TV_PRIMARY tells us that the head to be used with TVout is the head that's
5023c71b494SRudolf Cornelissen 		 * actually assigned as being the primary head at powerup:
5033c71b494SRudolf Cornelissen 		 * so non dualhead-mode-dependant, and not 'fixed' CRTC1! */
504a658603aSRudolf Cornelissen 		if (si->dm.flags & TV_PRIMARY)
505a658603aSRudolf Cornelissen 		{
506a658603aSRudolf Cornelissen 			LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n"));
50720603b95SRudolf Cornelissen 
5083c71b494SRudolf Cornelissen 			if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
5093c71b494SRudolf Cornelissen 			{
51020603b95SRudolf Cornelissen 				if (!(si->settings.vga_on_tv))
51108705d96Sshatty 				{
51220603b95SRudolf Cornelissen 					/* block VGA output on head displaying on TV */
51320603b95SRudolf Cornelissen 					/* Note:
51420603b95SRudolf Cornelissen 					 * this specific sync setting is required: Vsync is used to keep TVout
51520603b95SRudolf Cornelissen 					 * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs).
51620603b95SRudolf Cornelissen 					 * This leaves Hsync only for shutting off the VGA screen. */
51720603b95SRudolf Cornelissen 					h1h = false;
51820603b95SRudolf Cornelissen 					h1v = true;
5194022652cSRudolf Cornelissen 					/* block panel DPMS updates */
5204022652cSRudolf Cornelissen 					do_p1 = false;
52120603b95SRudolf Cornelissen 				}
52220603b95SRudolf Cornelissen 				else
52320603b95SRudolf Cornelissen 				{
52420603b95SRudolf Cornelissen 					/* when concurrent VGA is used alongside TVout on a head, DPMS is safest
52520603b95SRudolf Cornelissen 					 * applied this way: Vsync is needed for stopping TVout successfully when
52620603b95SRudolf Cornelissen 					 * a (new) modeswitch occurs.
52720603b95SRudolf Cornelissen 					 * (see routine BT_stop_tvout() in nv_brooktreetv.c) */
52820603b95SRudolf Cornelissen 					/* Note:
52920603b95SRudolf Cornelissen 					 * applying 'normal' DPMS here and forcing Vsync on in the above mentioned
53020603b95SRudolf Cornelissen 					 * routine seems to not always be enough: sometimes image generation will
53120603b95SRudolf Cornelissen 					 * not resume in that case. */
53220603b95SRudolf Cornelissen 					h1h = display;
53320603b95SRudolf Cornelissen 					h1v = true;
53408705d96Sshatty 				}
53508705d96Sshatty 			}
536a658603aSRudolf Cornelissen 			else
537a658603aSRudolf Cornelissen 			{
538a658603aSRudolf Cornelissen 				if (!(si->settings.vga_on_tv))
539a658603aSRudolf Cornelissen 				{
540a658603aSRudolf Cornelissen 					h2h = false;
541a658603aSRudolf Cornelissen 					h2v = true;
5424022652cSRudolf Cornelissen 					do_p2 = false;
543a658603aSRudolf Cornelissen 				}
544a658603aSRudolf Cornelissen 				else
545a658603aSRudolf Cornelissen 				{
546a658603aSRudolf Cornelissen 					h2h = display;
547a658603aSRudolf Cornelissen 					h2v = true;
548a658603aSRudolf Cornelissen 				}
549a658603aSRudolf Cornelissen 			}
550a658603aSRudolf Cornelissen 		}
5513c71b494SRudolf Cornelissen 		else
5523c71b494SRudolf Cornelissen 		{
5533c71b494SRudolf Cornelissen 			LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n"));
5543c71b494SRudolf Cornelissen 
5553c71b494SRudolf Cornelissen 			if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
5563c71b494SRudolf Cornelissen 			{
5573c71b494SRudolf Cornelissen 				if (!(si->settings.vga_on_tv))
5583c71b494SRudolf Cornelissen 				{
5593c71b494SRudolf Cornelissen 					h2h = false;
5603c71b494SRudolf Cornelissen 					h2v = true;
5614022652cSRudolf Cornelissen 					do_p2 = false;
5623c71b494SRudolf Cornelissen 				}
5633c71b494SRudolf Cornelissen 				else
5643c71b494SRudolf Cornelissen 				{
5653c71b494SRudolf Cornelissen 					h2h = display;
5663c71b494SRudolf Cornelissen 					h2v = true;
5673c71b494SRudolf Cornelissen 				}
5683c71b494SRudolf Cornelissen 			}
5693c71b494SRudolf Cornelissen 			else
5703c71b494SRudolf Cornelissen 			{
5713c71b494SRudolf Cornelissen 				if (!(si->settings.vga_on_tv))
5723c71b494SRudolf Cornelissen 				{
5733c71b494SRudolf Cornelissen 					h1h = false;
5743c71b494SRudolf Cornelissen 					h1v = true;
5754022652cSRudolf Cornelissen 					do_p1 = false;
5763c71b494SRudolf Cornelissen 				}
5773c71b494SRudolf Cornelissen 				else
5783c71b494SRudolf Cornelissen 				{
5793c71b494SRudolf Cornelissen 					h1h = display;
5803c71b494SRudolf Cornelissen 					h1v = true;
5813c71b494SRudolf Cornelissen 				}
5823c71b494SRudolf Cornelissen 			}
5833c71b494SRudolf Cornelissen 		}
5843c71b494SRudolf Cornelissen 	}
5853aa21459SRudolf Cornelissen 
58620603b95SRudolf Cornelissen 	/* issue actual DPMS commands as far as applicable */
5874022652cSRudolf Cornelissen 	head1_dpms(display, h1h, h1v, do_p1);
58820603b95SRudolf Cornelissen 	if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS))
5894022652cSRudolf Cornelissen 		head2_dpms(display, h2h, h2v, do_p2);
59020603b95SRudolf Cornelissen 	if (si->dm.flags & TV_BITS)
59120603b95SRudolf Cornelissen 		BT_dpms(display);
59220603b95SRudolf Cornelissen 
593155a2ad0SRudolf Cornelissen 	//fixme:
594155a2ad0SRudolf Cornelissen 	//add head2 once we use one driver instance 'per head' (instead of 'per card')
595155a2ad0SRudolf Cornelissen 	head1_interrupt_enable(true);
596155a2ad0SRudolf Cornelissen 
59708705d96Sshatty 	return B_OK;
59808705d96Sshatty }
59908705d96Sshatty 
60008705d96Sshatty /* Report device DPMS capabilities */
DPMS_CAPABILITIES(void)60120603b95SRudolf Cornelissen uint32 DPMS_CAPABILITIES(void)
60220603b95SRudolf Cornelissen {
60308705d96Sshatty 	return 	(B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
60408705d96Sshatty }
60508705d96Sshatty 
60608705d96Sshatty /* Return the current DPMS mode */
DPMS_MODE(void)607bfecd0cdSRudolf Cornelissen uint32 DPMS_MODE(void)
608bfecd0cdSRudolf Cornelissen {
609bfecd0cdSRudolf Cornelissen 	return si->dpms_flags;
61008705d96Sshatty }
611