xref: /haiku/src/add-ons/accelerants/radeon/multimon.c (revision e02e12de8ae0968a8772190f7ebbfb4b35d26e00)
1 /*
2 	Copyright (c) 2002-2004, 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
Radeon_DetectMultiMode(virtual_card * vc,display_mode * mode)16 void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
17 {
18 	(void)vc;
19 
20 	mode->timing.flags &= ~RADEON_MODE_MASK;
21 
22 	// combine mode is used if virtual area is twice as visible area
23 	// and if scrolling is enabled; if combining is impossible, use
24 	// cloning instead
25 	if( (mode->flags & B_SCROLL) == 0 )
26 		return;
27 
28 	SHOW_FLOW0( 3, "possibly combine mode" );
29 
30 	// remove scroll flag - we don't need it anymore
31 	mode->flags &= ~B_SCROLL;
32 
33 	mode->timing.flags &= ~RADEON_MODE_POSITION_MASK;
34 
35 	if( mode->virtual_width == 2 * mode->timing.h_display ) {
36 		SHOW_FLOW0( 2, "horizontal combine mode" );
37 		mode->timing.flags |= RADEON_MODE_POSITION_HORIZONTAL;
38 		mode->timing.flags &= ~RADEON_MODE_MASK;
39 		mode->timing.flags |= RADEON_MODE_COMBINE;
40 	} else if( mode->virtual_height == 2 * mode->timing.v_display ) {
41 		SHOW_FLOW0( 2, "vertical combine mode" );
42 		mode->timing.flags |= RADEON_MODE_POSITION_VERTICAL;
43 		mode->timing.flags &= ~RADEON_MODE_MASK;
44 		mode->timing.flags |= RADEON_MODE_COMBINE;
45 	} else {
46 		// ups, this isn't really a combine mode - restore flags
47 		SHOW_FLOW0( 2, "wasn't really a combine mode" );
48 		mode->timing.flags &= ~RADEON_MODE_MASK;
49 		mode->flags |= B_SCROLL;
50 	}
51 }
52 
53 // make sure selected multi-screen mode is valid; adapt it if needed
Radeon_VerifyMultiMode(virtual_card * vc,shared_info * si,display_mode * mode)54 void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode )
55 {
56 	// if there is no second port or no second monitor connected,
57 	// fall back to standard mode
58 	int num_usable_crtcs = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
59 
60 	if( si->num_crtc > 1 )
61 		num_usable_crtcs += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
62 
63 	if( num_usable_crtcs < 2 ) {
64 		SHOW_FLOW0( 2, "only one monitor - disabling any multi-mon mode" );
65 		// restore flags if combine mode is selected
66 		if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
67 			mode->flags |= B_SCROLL;
68 
69 		mode->timing.flags &= ~RADEON_MODE_MASK;
70 		mode->timing.flags |= RADEON_MODE_STANDARD;
71 	}
72 }
73 
74 // transform internal, multi-screen enabled display mode
75 // to official mode
Radeon_HideMultiMode(virtual_card * vc,display_mode * mode)76 void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
77 {
78 	(void) vc;
79 
80 	// restore flags for combine mode
81 	if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
82 		mode->flags |= B_SCROLL;
83 }
84 
85 
86 // initialize multi-screen mode dependant variables
Radeon_InitMultiModeVars(accelerator_info * ai,display_mode * mode)87 void Radeon_InitMultiModeVars(
88 	accelerator_info *ai, display_mode *mode )
89 {
90 	virtual_card *vc = ai->vc;
91 	shared_info *si = ai->si;
92 	uint32 x, y;
93 
94 	// setup single-screen mode
95 	vc->eff_width = mode->timing.h_display;
96 	vc->eff_height = mode->timing.v_display;
97 
98 	if( vc->used_crtc[0] ) {
99 		si->crtc[0].rel_x = 0;
100 		si->crtc[0].rel_y = 0;
101 	}
102 
103 	if( vc->used_crtc[1] ) {
104 		si->crtc[1].rel_x = 0;
105 		si->crtc[1].rel_y = 0;
106 	}
107 
108 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
109 	case RADEON_MODE_COMBINE:
110 		// detect where second screen must be located and
111 		// adapt total visible area accordingly
112 		if( (mode->timing.flags & RADEON_MODE_POSITION_MASK) == RADEON_MODE_POSITION_HORIZONTAL ) {
113 			vc->eff_width = 2 * mode->timing.h_display;
114 			x = mode->timing.h_display;
115 			y = 0;
116 		} else {
117 			vc->eff_height = 2 * mode->timing.v_display;
118 			x = 0;
119 			y = mode->timing.v_display;
120 		}
121 
122 		SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
123 
124 		// set relative offset
125 		if( !vc->swap_displays ) {
126 			si->crtc[1].rel_x = x;
127 			si->crtc[1].rel_y = y;
128 		} else {
129 			si->crtc[0].rel_x = x;
130 			si->crtc[0].rel_y = y;
131 		}
132 		break;
133 
134 	default:
135 		// else, ports are independant but show the same
136 		break;
137 	}
138 }
139 
140 
141 // mapping of internal TV standard code to public TV standard code
142 static const uint32 private2be[] = {
143 	0, 1, 3, 4, 103, 3/* PAL SCART - no public id, so I use PAL BDGHI */, 102 };
144 
145 // check and execute tunnel settings command
Radeon_CheckMultiMonTunnel(virtual_card * vc,display_mode * mode,const display_mode * low,const display_mode * high,bool * isTunneled)146 status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
147 	const display_mode *low, const display_mode *high, bool *isTunneled )
148 {
149 	if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 &&
150 		(mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 )
151 	{
152 		mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST;
153 		mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY;
154 
155 		// still process request, just in case someone set this flag
156 		// combination by mistake
157 
158 		// TBD: disabled to shorten syslog
159 		*isTunneled = true;
160 		return B_OK;
161 	}
162 
163 	// check magic params
164 	if( mode->space != 0 || low->space != 0 || high->space != 0
165 		|| low->virtual_width != 0xffff || low->virtual_height != 0xffff
166 		|| high->virtual_width != 0 || high->virtual_height != 0
167 		|| mode->timing.pixel_clock != 0
168 		|| low->timing.pixel_clock != 'TKTK' || high->timing.pixel_clock != 'KTKT' )
169 	{
170 		*isTunneled = false;
171 		return B_OK;
172 	}
173 
174 	*isTunneled = true;
175 
176 	/*SHOW_FLOW( 1, "tunnel access code=%d, command=%d",
177 		mode->h_display_start, mode->v_display_start );*/
178 
179 	switch( mode->h_display_start ) {
180 	case ms_swap:
181 		switch( mode->v_display_start ) {
182 		case 0:
183 			mode->timing.flags = vc->swap_displays;
184 			return B_OK;
185 
186 		case 1:
187 			vc->swap_displays = mode->timing.flags != 0;
188 			vc->enforce_mode_change = true;
189 			// write settings instantly
190 			Radeon_WriteSettings( vc );
191 			return B_OK;
192 		}
193 		break;
194 
195 	case ms_use_laptop_panel:
196 		// we must refuse this setting if there is no laptop panel;
197 		// else, the preferences dialog would show this (useless) option
198 		if( (vc->connected_displays & dd_lvds) == 0 )
199 			return B_ERROR;
200 
201 		switch( mode->v_display_start ) {
202 		case 0:
203 			mode->timing.flags = vc->use_laptop_panel;
204 			//SHOW_FLOW( 1, "get use_laptop_panel settings (%d)", mode->timing.flags );
205 			return B_OK;
206 
207 		case 1:
208 			vc->use_laptop_panel = mode->timing.flags != 0;
209 			//SHOW_FLOW( 1, "set use_laptop_panel settings (%d)", vc->use_laptop_panel );
210 			vc->enforce_mode_change = true;
211 			Radeon_WriteSettings( vc );
212 			return B_OK;
213 		}
214 		break;
215 
216 	case ms_tv_standard:
217 		switch( mode->v_display_start ) {
218 		case 0:
219 			mode->timing.flags = private2be[vc->tv_standard];
220 			/*SHOW_FLOW( 1, "read tv_standard (internal %d, public %d)",
221 				vc->tv_standard, mode->timing.flags );*/
222 			return B_OK;
223 
224 		case 1:
225 			switch( mode->timing.flags ) {
226 			case 0: vc->tv_standard = ts_off; break;
227 			case 1:	vc->tv_standard = ts_ntsc; break;
228 			case 2: break; // ntsc j
229 			case 3: vc->tv_standard = ts_pal_bdghi; break;
230 			case 4: vc->tv_standard = ts_pal_m; break;
231 			case 5: break; // pal n
232 			case 6: break; // secam - I reckon not supported by hardware
233 			case 101: break; // ntsc 443
234 			case 102: vc->tv_standard = ts_pal_60; break;
235 			case 103: vc->tv_standard = ts_pal_nc; break;
236 			}
237 
238 			SHOW_FLOW( 1, "set tv_standard (internal %d, public %d)",
239 				vc->tv_standard, mode->timing.flags );
240 
241 			vc->enforce_mode_change = true;
242 			Radeon_WriteSettings( vc );
243 			return B_OK;
244 
245 		case 2: {
246 			uint32 idx = mode->timing.flags;
247 
248 			// we limit it explicetely to NTSC and PAL as all other
249 			// modes are not fully implemented
250 			if( idx < sizeof( private2be ) / sizeof( private2be[0] ) &&
251 				idx < 3 ) {
252 				mode->timing.flags = private2be[idx];
253 				return B_OK;
254 			} else
255 				return B_ERROR;
256 			}
257 		}
258 	}
259 
260 	return B_ERROR;
261 }
262 
263 
264 // return true if both ports must be programmed
Radeon_NeedsSecondPort(display_mode * mode)265 bool Radeon_NeedsSecondPort( display_mode *mode )
266 {
267 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
268 	case RADEON_MODE_COMBINE:
269 		return true;
270 	default:
271 		return false;
272 	}
273 }
274 
275 
276 // return number of ports showing differents parts of frame buffer
Radeon_DifferentPorts(display_mode * mode)277 bool Radeon_DifferentPorts( display_mode *mode )
278 {
279 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
280 	case RADEON_MODE_COMBINE:
281 		return 2;
282 	default:
283 		return 1;
284 	}
285 }
286