xref: /haiku/src/add-ons/accelerants/radeon/SetDisplayMode.c (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
1 /*
2 	Copyright (c) 2002-2004, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Sets display modes, colour palette and handles DPMS
8 */
9 
10 
11 #include "GlobalData.h"
12 #include "generic.h"
13 #include <sys/ioctl.h>
14 #include "radeon_regs.h"
15 #include "mmio.h"
16 #include "crtc_regs.h"
17 #include <GraphicsDefs.h>
18 
19 #include "crtc_regs.h"
20 #include "overlay_regs.h"
21 #include "rbbm_regs.h"
22 #include "dac_regs.h"
23 #include "fp_regs.h"
24 #include "gpiopad_regs.h"
25 
26 #include "pll_regs.h"
27 #include "tv_out_regs.h"
28 #include "config_regs.h"
29 #include "ddc_regs.h"
30 #include "pll_access.h"
31 #include "theatre_regs.h"
32 #include "set_mode.h"
33 #include "ddc.h"
34 
35 #include "set_mode.h"
36 
37 #include <string.h>
38 
39 status_t Radeon_SetMode(
40 	accelerator_info *ai, crtc_info *crtc, display_mode *mode, impactv_params *tv_params );
41 
42 // round virtual width up to next valid size
43 uint32 Radeon_RoundVWidth(
44 	int virtual_width, int bpp )
45 {
46 	// we have to make both the CRTC and the accelerator happy:
47 	// - the CRTC wants virtual width in pixels to be a multiple of 8
48 	// - the accelerator expects width in bytes to be a multiple of 64
49 
50 	// to put that together, width (in bytes) must be a multiple of the least
51 	// common nominator of bytes-per-pixel*8 (CRTC) and 64 (accelerator);
52 
53 	// if bytes-per-pixel is a power of two and less than 8, the LCM is 64;
54 	// almost all colour depth satisfy that apart from 24 bit; in this case,
55 	// the LCM is 64*3=192
56 
57 	// after dividing by bytes-per-pixel we get pixels: in first case,
58 	// width must be multiple of 64/bytes-per-pixel; in second case,
59 	// width must be multiple of 64*3/3=64
60 
61 	if( bpp != 3 )
62 		return (virtual_width + 64/bpp - 1) & ~(64/bpp - 1);
63 	else
64 		return (virtual_width + 63) & ~63;
65 }
66 
67 
68 // list of registers that must be reset before display mode switch
69 // to avoid interferences
70 static struct {
71 	uint16 reg;
72 	uint32 val;
73 } common_regs[] = {
74 	{ RADEON_OVR_CLR, 0 },
75 	{ RADEON_OVR_WID_LEFT_RIGHT, 0 },
76 	{ RADEON_OVR_WID_TOP_BOTTOM, 0 },
77 	{ RADEON_OV0_SCALE_CNTL, 0 },		// disable overlay
78 	{ RADEON_SUBPIC_CNTL, 0 },
79 	{ RADEON_I2C_CNTL_1, 0 },
80 };
81 
82 
83 static void Radeon_InitCommonRegs(
84 	accelerator_info *ai )
85 {
86 	vuint8 *regs = ai->regs;
87 	uint i;
88 
89 	for( i = 0; i < sizeof( common_regs) / sizeof( common_regs[0] ); ++i )
90 		OUTREG( regs, common_regs[i].reg, common_regs[i].val );
91 
92 	// enable extended display modes
93 	OUTREGP( regs, RADEON_CRTC_GEN_CNTL,
94 		RADEON_CRTC_EXT_DISP_EN, ~RADEON_CRTC_EXT_DISP_EN );
95 
96 	// disable flat panel auto-centering
97 	// (if we have a CRT on CRTC1, this must be disabled;
98 	//  if we have a flat panel on CRTC1, we setup CRTC manually, not
99 	//  using the auto-centre, automatic-sync-override magic)
100 	OUTREG( regs, RADEON_CRTC_MORE_CNTL, 0 );
101 }
102 
103 
104 // set display mode of one head;
105 // port restrictions, like fixed-sync TFTs connected to it, are taken care of
106 status_t Radeon_SetMode(
107 	accelerator_info *ai, crtc_info *crtc, display_mode *mode, impactv_params *tv_params )
108 {
109 	virtual_card *vc = ai->vc;
110 	shared_info *si = ai->si;
111 	vuint8 *regs = ai->regs;
112 	int    format;
113 	int    bpp;
114 	display_device_e disp_devices;
115 	fp_info *fp_info;
116 
117 	crtc_regs		crtc_values;
118 	pll_regs		pll_values;
119 	fp_regs			fp_values;
120 	impactv_regs	impactv_values;
121 	uint32			surface_cntl;
122 
123 	bool internal_tv_encoder;
124 	pll_dividers dividers;
125 
126 	crtc->mode = *mode;
127 
128 	// don't destroy passed values, use our copy instead
129 	mode = &crtc->mode;
130 
131 	disp_devices = crtc->chosen_displays;
132 	fp_info = &si->flatpanels[crtc->flatpanel_port];
133 
134 	// if using an flat panel or LCD, maximum resolution
135 	// is determined by the physical resolution;
136 	// also, all timing is fixed
137 	if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) {
138 		SHOW_FLOW0( 0, "requested resolution higher than native panel" );
139 		if( mode->timing.h_display > fp_info->panel_xres )
140 			mode->timing.h_display = fp_info->panel_xres;
141 		if(	mode->timing.v_display > fp_info->panel_yres )
142 			mode->timing.v_display = fp_info->panel_yres;
143 
144 		if( (disp_devices & dd_dvi_ext) != 0 ) {
145 			SHOW_FLOW0( 0, "requested resolution less than second native panel" );
146 			if( mode->timing.h_display < fp_info->panel_xres )
147 				mode->timing.h_display = fp_info->panel_xres;
148 			if(	mode->timing.v_display < fp_info->panel_yres )
149 				mode->timing.v_display = fp_info->panel_yres;
150 
151 			//TODO at this point we know we are going to do centered timing
152 			//need to set flags to a. blank the unused memory, b.center screen
153 			//for now it's in the top corner, and surrounded by garbage.
154 			// although if the DVI panels are the same size and we are cloning
155 			// we can switch the FP2 source to RMX, and drive both screens from
156 			// the RMX unit.
157 		}
158 		mode->timing.h_total = mode->timing.h_display + fp_info->h_blank;
159 		mode->timing.h_sync_start = mode->timing.h_display + fp_info->h_over_plus;
160 		mode->timing.h_sync_end = mode->timing.h_sync_start + fp_info->h_sync_width;
161 		mode->timing.v_total = mode->timing.v_display + fp_info->v_blank;
162 		mode->timing.v_sync_start = mode->timing.v_display + fp_info->v_over_plus;
163 		mode->timing.v_sync_end = mode->timing.v_sync_start + fp_info->v_sync_width;
164 
165 		mode->timing.pixel_clock = fp_info->dot_clock;
166 	}
167 
168 	// TV-out supports at most 1024x768
169 	if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
170 		if( mode->timing.h_display > 1024 )
171 			mode->timing.h_display = 1024;
172 
173 		if( mode->timing.v_display > 768 )
174 			mode->timing.v_display = 768;
175 	}
176 
177 	// if using TV-Out, the timing of the source signal must be tweaked to
178 	// get proper timing
179 	internal_tv_encoder = IS_INTERNAL_TV_OUT( si->tv_chip );
180 
181 	// we need higher accuracy then Be thought of
182 	mode->timing.pixel_clock *= 1000;
183 
184 	// TV stuff must be done first as it tweaks the display mode
185 	if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
186 		display_mode tweaked_mode;
187 
188 		Radeon_CalcImpacTVParams(
189 			&si->pll, tv_params, vc->tv_standard, internal_tv_encoder,
190 			mode, &tweaked_mode );
191 
192 		*mode = tweaked_mode;
193 	}
194 
195 	Radeon_GetFormat( mode->space, &format, &bpp );
196 
197 	vc->bpp = bpp;
198 	vc->datatype = format;
199 
200 	// time to read original register content
201 	// lock hardware so noone bothers us
202 	Radeon_WaitForIdle( ai, true );
203 
204 	if( (disp_devices & (dd_dvi | dd_lvds | dd_dvi_ext)) != 0 ) {
205 		if( crtc->crtc_idx == 0 )
206 			Radeon_ReadRMXRegisters( ai, &fp_values );
207 
208 		Radeon_ReadFPRegisters( ai, &fp_values );
209 	}
210 
211 	if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
212 		// some register's content isn't created from scratch but
213 		// only modified, so we need the original content first
214 		if( internal_tv_encoder )
215 			Radeon_InternalTVOutReadRegisters( ai, &impactv_values );
216 		else
217 			Radeon_TheatreReadTVRegisters( ai, &impactv_values );
218 	}
219 
220 
221 	// calculate all hardware register values
222 	Radeon_CalcCRTCRegisters( ai, crtc, mode, &crtc_values );
223 
224 	surface_cntl = RADEON_SURF_TRANSLATION_DIS;
225 
226 	if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
227 		Radeon_CalcImpacTVRegisters( ai, mode, tv_params, &impactv_values,
228 			crtc->crtc_idx, internal_tv_encoder, vc->tv_standard, disp_devices );
229 	}
230 
231 	if( (disp_devices & (dd_stv | dd_ctv)) == 0 )
232 		Radeon_CalcCRTPLLDividers( &si->pll, mode, &dividers );
233 	else
234 		dividers = tv_params->crt_dividers;
235 
236 	if( (disp_devices & dd_lvds) != 0 && si->flatpanels[0].fixed_dividers ) {
237 		SHOW_FLOW0( 0, "Using fixed dividers for laptop panel" );
238 		dividers.feedback = si->flatpanels[0].feedback_div;
239 		dividers.post_code = si->flatpanels[0].post_div;
240 		dividers.ref = si->flatpanels[0].ref_div;
241 	}
242 
243 	Radeon_CalcPLLRegisters( mode, &dividers, &pll_values );
244 
245 	// for first CRTC1, we need to setup RMX properly
246 	if( crtc->crtc_idx == 0 )
247 		Radeon_CalcRMXRegisters( fp_info, mode,
248 			(disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0,
249 			&fp_values );
250 
251 	if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
252 		Radeon_CalcFPRegisters( ai, crtc, fp_info, &crtc_values, &fp_values );
253 
254 	// we don't use pixel clock anymore, so it can be reset to Be's kHz
255 	mode->timing.pixel_clock /= 1000;
256 
257 	// write values to registers
258 
259 	Radeon_InitCommonRegs( ai );
260 
261 	Radeon_ProgramCRTCRegisters( ai, crtc->crtc_idx, &crtc_values );
262 
263 	OUTREG( regs, RADEON_SURFACE_CNTL, surface_cntl );
264 
265 	if( crtc->crtc_idx == 0 )
266 		Radeon_ProgramRMXRegisters( ai, &fp_values );
267 
268 	if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
269 		Radeon_ProgramFPRegisters( ai, crtc, fp_info, &fp_values );
270 
271 	//if( mode->timing.pixel_clock )
272 	Radeon_ProgramPLL( ai, crtc->crtc_idx, &pll_values );
273 
274 	if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
275 		if( internal_tv_encoder )
276 			Radeon_InternalTVOutProgramRegisters( ai, &impactv_values );
277 		else
278 			Radeon_TheatreProgramTVRegisters( ai, &impactv_values );
279 	}
280 
281 	// spit out some debug stuff in a radeontool stylee
282 	SHOW_FLOW0( 0, "" );
283 	SHOW_FLOW( 0, "RADEON_DAC_CNTL %08X ", INREG( regs, RADEON_DAC_CNTL ));
284 	SHOW_FLOW( 0, "RADEON_DAC_CNTL2 %08X ", INREG( regs, RADEON_DAC_CNTL2 ));
285 	SHOW_FLOW( 0, "RADEON_TV_DAC_CNTL %08X ", INREG( regs, RADEON_TV_DAC_CNTL ));
286 	SHOW_FLOW( 0, "RADEON_DISP_OUTPUT_CNTL %08X ", INREG( regs, RADEON_DISP_OUTPUT_CNTL ));
287 	SHOW_FLOW( 0, "RADEON_AUX_SC_CNTL %08X ", INREG( regs, RADEON_AUX_SC_CNTL ));
288 	SHOW_FLOW( 0, "RADEON_CRTC_EXT_CNTL %08X ", INREG( regs, RADEON_CRTC_EXT_CNTL ));
289 	SHOW_FLOW( 0, "RADEON_CRTC_GEN_CNTL %08X ", INREG( regs, RADEON_CRTC_GEN_CNTL ));
290 	SHOW_FLOW( 0, "RADEON_CRTC2_GEN_CNTL %08X ", INREG( regs, RADEON_CRTC2_GEN_CNTL ));
291 	SHOW_FLOW( 0, "RADEON_DISP_MISC_CNTL %08X ", INREG( regs, RADEON_DISP_MISC_CNTL ));
292 	SHOW_FLOW( 0, "RADEON_FP_GEN_CNTL %08X ", INREG( regs, RADEON_FP_GEN_CNTL ));
293 	SHOW_FLOW( 0, "RADEON_FP2_GEN_CNTL %08X ", INREG( regs, RADEON_FP2_GEN_CNTL ));
294 	SHOW_FLOW( 0, "RADEON_LVDS_GEN_CNTL %08X ", INREG( regs, RADEON_LVDS_GEN_CNTL ));
295 	SHOW_FLOW( 0, "RADEON_TMDS_PLL_CNTL %08X ", INREG( regs, RADEON_TMDS_PLL_CNTL ));
296 	SHOW_FLOW( 0, "RADEON_TMDS_TRANSMITTER_CNTL %08X ", INREG( regs, RADEON_TMDS_TRANSMITTER_CNTL ));
297 	SHOW_FLOW( 0, "RADEON_FP_H_SYNC_STRT_WID %08X ", INREG( regs, RADEON_FP_H_SYNC_STRT_WID ));
298 	SHOW_FLOW( 0, "RADEON_FP_V_SYNC_STRT_WID %08X ", INREG( regs, RADEON_FP_V_SYNC_STRT_WID ));
299 	SHOW_FLOW( 0, "RADEON_FP_H2_SYNC_STRT_WID %08X ", INREG( regs, RADEON_FP_H2_SYNC_STRT_WID ));
300 	SHOW_FLOW( 0, "RADEON_FP_V2_SYNC_STRT_WID %08X ", INREG( regs, RADEON_FP_V2_SYNC_STRT_WID ));
301 	// spit end
302 
303 	crtc->active_displays = disp_devices;
304 
305 	// programming is over, so hardware can be used again
306 	RELEASE_BEN( si->cp.lock );
307 
308 	// overlay must be setup again after modeswitch (whoever was using it)
309 	// TBD: this won't work if another virtual card was using it,
310 	// but currently, virtual cards don't work anyway...
311 	si->active_overlay.crtc_idx = -1;
312 
313 	return B_OK;
314 }
315 
316 
317 // enable or disable VBlank interrupts
318 void Radeon_EnableIRQ(
319 	accelerator_info *ai, bool enable )
320 {
321 	shared_info *si = ai->si;
322 	uint32 int_cntl, int_mask;
323 
324 	int_cntl = INREG( ai->regs, RADEON_GEN_INT_CNTL );
325 	int_mask =
326 		RADEON_CRTC_VBLANK_MASK
327 		| (si->num_crtc > 1 ? RADEON_CRTC2_VBLANK_MASK : 0);
328 
329 	if( enable )
330 		int_cntl |= int_mask;
331 	else
332 		int_cntl &= ~int_mask;
333 
334 	OUTREG( ai->regs, RADEON_GEN_INT_CNTL, int_cntl );
335 
336 	if( enable ) {
337 		// on enable, we have to acknowledge all IRQs as the graphics card
338 		// waits for that before it issues further IRQs
339 		OUTREG( ai->regs, RADEON_GEN_INT_STATUS, int_cntl );
340 	}
341 
342 	si->enable_virtual_irq = enable;
343 }
344 
345 
346 // public function: set display mode
347 status_t SET_DISPLAY_MODE(
348 	display_mode *mode_in )
349 {
350 	virtual_card *vc = ai->vc;
351 	shared_info *si = ai->si;
352 	display_mode bounds, mode;
353 
354 	mode = bounds = *mode_in;
355 
356 	ACQUIRE_BEN( si->engine.lock );
357 
358 	SHOW_FLOW( 2, "width=%d, height=%d", mode.timing.h_display, mode.timing.v_display );
359 
360 	// check mode and tweak parameters so we can program hardware
361 	// without any further checks
362 	if( PROPOSE_DISPLAY_MODE( &mode, &bounds, &bounds ) == B_ERROR ) {
363 		SHOW_ERROR0( 2, "invalid mode" );
364 
365 		RELEASE_BEN( si->engine.lock );
366 		return B_ERROR;
367 	}
368 
369 	// already done by propose_display_mode, but it was undone on return;
370 	// do this before equality check to recognize changes of multi-monitor mode
371 	Radeon_DetectMultiMode( vc, &mode );
372 
373 	// mode switches can take quite long and are visible,
374 	// so avoid them if possible
375 	if( memcmp( &mode, &vc->mode, sizeof( display_mode )) == 0 &&
376 		!vc->enforce_mode_change ) {
377 		RELEASE_BEN( si->engine.lock );
378 		return B_OK;
379 	}
380 
381 	// this flag was set when some internal parameter has changed that
382 	// affects effective display mode
383 	vc->enforce_mode_change = false;
384 
385 	// make sure, we don't get disturbed
386 	//Radeon_Finish( ai );
387 	Radeon_EnableIRQ( ai, false );
388 
389 	// free cursor and framebuffer memory
390 	{
391 		radeon_free_mem fm;
392 
393 		fm.magic = RADEON_PRIVATE_DATA_MAGIC;
394 		fm.memory_type = mt_local;
395 		fm.global = true;
396 
397 		if( vc->cursor.mem_handle ) {
398 			fm.handle = vc->cursor.mem_handle;
399 			ioctl( ai->fd, RADEON_FREE_MEM, &fm );
400 		}
401 
402 		if( vc->fb_mem_handle ) {
403 			fm.handle = vc->fb_mem_handle;
404 			ioctl( ai->fd, RADEON_FREE_MEM, &fm );
405 		}
406 	}
407 
408 	memcpy( &vc->mode, &mode, sizeof( display_mode ));
409 
410 	// verify hardware restrictions *after* saving mode
411 	// e.g. if you want a span mode but have one monitor disconnected,
412 	// configuration shouldn't be touched, so you can continue working
413 	// with two monitors later on just like nothing has happened
414 	Radeon_VerifyMultiMode( vc, si, &mode );
415 
416 	// set main flags
417 	vc->independant_heads = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
418 
419 	if( si->num_crtc > 1 )
420 		vc->independant_heads += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
421 
422 	vc->different_heads = Radeon_DifferentPorts( &mode );
423 	SHOW_FLOW( 2, "independant heads: %d, different heads: %d",
424 		vc->independant_heads, vc->different_heads );
425 	vc->scroll = mode.flags & B_SCROLL;
426 	SHOW_FLOW( 2, "scrolling %s", vc->scroll ? "enabled" : "disabled" );
427 
428 	// allocate frame buffer and cursor image memory
429 	{
430 		radeon_alloc_mem am;
431 		int format, bpp;
432 
433 		// alloc cursor memory
434 		am.magic = RADEON_PRIVATE_DATA_MAGIC;
435 		am.size = 1024;
436 		am.memory_type = mt_local;
437 		am.global = true;
438 
439 		if( ioctl( ai->fd, RADEON_ALLOC_MEM, &am ) == B_OK ) {
440 			vc->cursor.mem_handle = am.handle;
441 			vc->cursor.fb_offset = am.offset;
442 		} else {
443 			// too bad that we are out of mem -> set reasonable values as
444 			// it's too late to give up (ouch!)
445 			SHOW_ERROR0( 2, "no memory for cursor image!" );
446 			vc->cursor.mem_handle = 0;
447 			vc->cursor.fb_offset = 0;
448 		}
449 
450 		vc->cursor.data = si->local_mem + vc->cursor.fb_offset;
451 
452 		// alloc frame buffer
453 		Radeon_GetFormat( mode.space, &format, &bpp );
454 		vc->pitch = Radeon_RoundVWidth( mode.virtual_width, bpp ) * bpp;
455 		am.size = vc->pitch * mode.virtual_height;
456 
457 		if( ioctl( ai->fd, RADEON_ALLOC_MEM, &am ) == B_OK ) {
458 			vc->fb_mem_handle = am.handle;
459 			vc->fb_offset = am.offset;
460 		} else 	{
461 			// ouch again - set reasonable values
462 			SHOW_ERROR0( 2, "no memory for frame buffer!" );
463 			vc->fb_mem_handle = 0;
464 			vc->fb_offset = 1024;
465 		}
466 
467 		vc->fbc.frame_buffer = si->local_mem + vc->fb_offset;
468 		vc->fbc.frame_buffer_dma = (void *)((uint8 *)si->framebuffer_pci + vc->fb_offset);
469 		vc->fbc.bytes_per_row = vc->pitch;
470 
471 		SHOW_FLOW( 0, "frame buffer CPU-address=%x, phys-address=%x",
472 			vc->fbc.frame_buffer, vc->fbc.frame_buffer_dma );
473 	}
474 
475 	// multi-screen stuff
476 	Radeon_InitMultiModeVars( ai, &mode );
477 
478 	// GO!
479 
480 	{
481 		routing_regs routing_values;
482 		impactv_params tv_params;
483 		status_t err1 , err2;
484 		err1 = err2 = B_OK;
485 
486 		// we first switch off all output, so the monitor(s) won't get invalid signals
487 		if( vc->assigned_crtc[0] ) {
488 			// overwrite list of active displays to switch off displays
489 			// someone else turned on
490 			si->crtc[0].active_displays = vc->controlled_displays;
491 			Radeon_SetDPMS( ai, 0, B_DPMS_SUSPEND );
492 		}
493 		if( vc->assigned_crtc[1] ) {
494 			si->crtc[1].active_displays = vc->controlled_displays;
495 			Radeon_SetDPMS( ai, 1, B_DPMS_SUSPEND );
496 		}
497 
498 		// mark crtc that will be used from now on
499 		vc->used_crtc[0] = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
500 		vc->used_crtc[1] = vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
501 
502 		// then change the mode
503 		if( vc->used_crtc[0] )
504 			err1 = Radeon_SetMode( ai, &si->crtc[0], &mode, &tv_params );
505 		if( vc->used_crtc[1] )
506 			err2 = Radeon_SetMode( ai, &si->crtc[1], &mode, &tv_params );
507 
508 
509 		SHOW_FLOW( 2, "SetModes 1=%s, 2=%s",
510 			(err1 == B_OK) ? "OK" : "FAIL", (err2 == B_OK) ? "OK" : "FAIL");
511 
512 		// setup signal routing
513 		Radeon_ReadMonitorRoutingRegs( ai, &routing_values );
514 		Radeon_CalcMonitorRouting( ai, &tv_params, &routing_values );
515 		Radeon_ProgramMonitorRouting( ai, &routing_values );
516 
517 		// finally, switch display(s) on
518 		if( vc->used_crtc[0] )
519 			Radeon_SetDPMS( ai, 0, (err1 == B_OK) ? B_DPMS_ON : B_DPMS_SUSPEND );
520 		if( vc->used_crtc[1] )
521 			Radeon_SetDPMS( ai, 1, (err2 == B_OK) ? B_DPMS_ON : B_DPMS_SUSPEND );
522 
523 		OUTREGP( ai->regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS );
524 	}
525 
526    	SHOW_FLOW( 3, "pitch=%ld", vc->pitch );
527 
528    	// we'll modify bits of this reg, so save it for async access
529 	si->dac_cntl2 = INREG( ai->regs, RADEON_DAC_CNTL2 );
530 
531 	// setup 2D registers
532 	Radeon_Init2D( ai );
533 	// setup position of framebuffer for 2D commands
534 	Radeon_FillStateBuffer( ai, vc->datatype );
535 
536 	// remember that 2D accelerator is not prepared for any virtual card
537 	si->active_vc = -1;
538 
539 	// first move to well-defined position (to setup CRTC offset)
540 	Radeon_MoveDisplay( ai, 0, 0 );
541 	// then to (probably faulty) user-defined pos
542 	Radeon_MoveDisplay( ai, mode.h_display_start, mode.v_display_start );
543 
544 	// set standard palette in direct-colour modes
545 	if( vc->used_crtc[0] )
546 		Radeon_InitPalette( ai, 0 );
547 	if( vc->used_crtc[1] )
548 		Radeon_InitPalette( ai, 1 );
549 
550 	// initialize cursor data
551 	if( vc->used_crtc[0] )
552 		Radeon_SetCursorColors( ai, 0 );
553 	if( vc->used_crtc[1] )
554 		Radeon_SetCursorColors( ai, 1 );
555 
556 	// sync should be settled now, so we can reenable IRQs
557 	Radeon_EnableIRQ( ai, true );
558 
559 	RELEASE_BEN( si->engine.lock );
560 
561 	// !! all this must be done after lock has been
562 	//    released to avoid dead-lock !!
563 	// TBD: any invalid intermediate states?
564 
565 	// move_cursor sets all cursor-related variables and registers
566 	vc->cursor.is_visible = false;
567 	MOVE_CURSOR( 0, 0 );
568 
569 	return B_OK;
570 }
571