xref: /haiku/src/add-ons/accelerants/radeon/multimon.c (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 /*
2 	Copyright (c) 2002, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Multi-monitor management
8 */
9 
10 #include "radeon_accelerant.h"
11 #include "generic.h"
12 #include "GlobalData.h"
13 
14 
15 // transform official mode to internal, multi-screen mode enhanced mode
16 void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
17 {
18 //	uint32 x, y, offset;
19 
20 	mode->timing.flags &= ~RADEON_MODE_MASK;
21 
22 	switch( vc->wanted_multi_mode ) {
23 	case mm_mirror:
24 		mode->timing.flags |= RADEON_MODE_MIRROR;
25 		break;
26 	case mm_clone:
27 		mode->timing.flags |= RADEON_MODE_CLONE;
28 		break;
29 	case mm_combine:
30 		mode->timing.flags |= RADEON_MODE_COMBINE;
31 		break;
32 	case mm_none:
33 	default:
34 	}
35 
36 	// swap displays if asked for
37 	if( vc->swapDisplays )
38 		mode->timing.flags |= RADEON_MODE_DISPLAYS_SWAPPED;
39 	else
40 		mode->timing.flags &= ~RADEON_MODE_DISPLAYS_SWAPPED;
41 
42 	// combine mode is used if virtual area is twice as visible area
43 	// and if scrolling is enabled; if combining is impossible, use
44 	// cloning instead
45 	if( (mode->flags & B_SCROLL) == 0 ) {
46 		if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE ) {
47 			SHOW_FLOW0( 3, "This isn't a combine mode, falling back to clone" );
48 			mode->timing.flags &= ~RADEON_MODE_MASK;
49 			mode->timing.flags |= RADEON_MODE_CLONE;
50 		}
51 		return;
52 	}
53 
54 	SHOW_FLOW0( 3, "possibly combine mode" );
55 
56 	// remove scroll flag - we don't need it anymore
57 	mode->flags &= ~B_SCROLL;
58 
59 	mode->timing.flags &= ~RADEON_MODE_POSITION_MASK;
60 
61 	if( mode->virtual_width == 2 * mode->timing.h_display ) {
62 		SHOW_FLOW0( 3, "horizontal combine mode" );
63 		mode->timing.flags |= RADEON_MODE_POSITION_HORIZONTAL;
64 		mode->timing.flags &= ~RADEON_MODE_MASK;
65 		mode->timing.flags |= RADEON_MODE_COMBINE;
66 	} else if( mode->virtual_height == 2 * mode->timing.v_display ) {
67 		SHOW_FLOW0( 3, "vertical combine mode" );
68 		mode->timing.flags |= RADEON_MODE_POSITION_VERTICAL;
69 		mode->timing.flags &= ~RADEON_MODE_MASK;
70 		mode->timing.flags |= RADEON_MODE_COMBINE;
71 	} else {
72 		// ups, this isn't really a combine mode - restore flags
73 		SHOW_FLOW0( 3, "wasn't really a combine mode" );
74 		mode->timing.flags &= ~RADEON_MODE_MASK;
75 		mode->timing.flags |= RADEON_MODE_CLONE;
76 		mode->flags |= ~B_SCROLL;
77 	}
78 }
79 
80 // make sure selected multi-screen mode is valid; adapt it if needed
81 void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode )
82 {
83 	// if there is no second port or no second monitor connected,
84 	// fall back to standard mode
85 	if( vc->num_ports == 1 ||
86 		(si->ports[vc->ports[0].physical_port].disp_type == dt_none ||
87 		 si->ports[vc->ports[1].physical_port].disp_type == dt_none) )
88 	{
89 		SHOW_FLOW0( 3, "only one monitor - disabling any multi-mon mode" );
90 		// restore flags if combine mode is selected
91 		if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
92 			mode->flags |= B_SCROLL;
93 
94 		mode->timing.flags &= ~RADEON_MODE_MASK;
95 		mode->timing.flags |= RADEON_MODE_STANDARD;
96 	}
97 }
98 
99 // transform internal, multi-screen enabled display mode
100 // to official mode
101 void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
102 {
103 	// restore flags for combine mode
104 	if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
105 		mode->flags |= B_SCROLL;
106 }
107 
108 
109 // initialize multi-screen mode dependant variables
110 void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode )
111 {
112 //	uint32 offset;
113 	uint32 x, y;
114 
115 	// setup single-screen mode
116 	vc->eff_width = mode->timing.h_display;
117 	vc->eff_height = mode->timing.v_display;
118 
119 	vc->ports[0].rel_x = 0;
120 	vc->ports[0].rel_y = 0;
121 
122 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
123 	case RADEON_MODE_CLONE:
124 		// in clone mode, ports are independant but show the same
125 		vc->ports[1].rel_x = 0;
126 		vc->ports[1].rel_y = 0;
127 		break;
128 
129 	case RADEON_MODE_COMBINE:
130 		// detect where second screen must be located and
131 		// adapt total visible area accordingly
132 		if( (mode->timing.flags & RADEON_MODE_POSITION_MASK) == RADEON_MODE_POSITION_HORIZONTAL ) {
133 			vc->eff_width = 2 * mode->timing.h_display;
134 			x = mode->timing.h_display;
135 			y = 0;
136 		} else {
137 			vc->eff_height = 2 * mode->timing.v_display;
138 			x = 0;
139 			y = mode->timing.v_display;
140 		}
141 
142 		SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
143 
144 		vc->ports[1].rel_x = 0;
145 		vc->ports[1].rel_y = 0;
146 
147 		// set relative offset
148 		if( (mode->timing.flags & RADEON_MODE_DISPLAYS_SWAPPED) == 0 ) {
149 			vc->ports[1].rel_x = x;
150 			vc->ports[1].rel_y = y;
151 		} else {
152 			vc->ports[0].rel_x = x;
153 			vc->ports[0].rel_y = y;
154 		}
155 		break;
156 
157 	case RADEON_MODE_STANDARD:
158 	case RADEON_MODE_MIRROR:
159 		break;
160 	}
161 }
162 
163 
164 // check and execute tunnel settings command
165 status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
166 	const display_mode *low, const display_mode *high, bool *isTunneled )
167 {
168 	if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 &&
169 		(mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 )
170 	{
171 		mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST;
172 		mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY;
173 
174 		// still process request, just in case someone set this flag
175 		// combination by mistake
176 
177 		// TBD: disabled to shorten syslog
178 		*isTunneled = true;
179 		return B_OK;
180 	}
181 
182 	// check magic params
183 	if( mode->space != 0 || low->space != 0 || high->space != 0
184 		|| low->virtual_width != 0xffff || low->virtual_height != 0xffff
185 		|| high->virtual_width != 0 || high->virtual_height != 0
186 		|| mode->timing.pixel_clock != 0
187 		|| low->timing.pixel_clock != 'TKTK' || high->timing.pixel_clock != 'KTKT' )
188 	{
189 		*isTunneled = false;
190 		return B_OK;
191 	}
192 
193 	*isTunneled = true;
194 
195 	switch( mode->h_display_start ) {
196 	case ms_swap:
197 		if( mode->v_display_start != 0 )
198 			vc->swapDisplays = mode->timing.flags != 0;
199 		else
200 			mode->timing.flags = vc->swapDisplays;
201 
202 		// write settings instantly
203 		Radeon_WriteSettings( vc );
204 		return B_OK;
205 
206 /*	case ms_overlay_port:
207 		if( mode->v_display_start != 0 )
208 			vc->whished_overlay_port = mode->timing.flags;
209 		else
210 			mode->timing.flags = vc->whished_overlay_port;
211 
212 		Radeon_WriteSettings( vc );
213 		return B_OK;*/
214 
215 	default:
216 		return B_BAD_INDEX;
217 	}
218 }
219 
220 
221 // return true if both ports must be programmed
222 bool Radeon_NeedsSecondPort( display_mode *mode )
223 {
224 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
225 	case RADEON_MODE_COMBINE:
226 	case RADEON_MODE_CLONE:
227 		return true;
228 	default:
229 		return false;
230 	}
231 }
232 
233 // return number of ports showing differents parts of frame buffer
234 bool Radeon_DifferentPorts( display_mode *mode )
235 {
236 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
237 	case RADEON_MODE_COMBINE:
238 		return 2;
239 	default:
240 		return 1;
241 	}
242 }
243