xref: /haiku/src/add-ons/accelerants/via/engine/general.c (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /* Authors:
2    Mark Watson 12/1999,
3    Apsed,
4    Rudolf Cornelissen 10/2002-4/2006
5 */
6 
7 #define MODULE_BIT 0x00008000
8 
9 #include "std.h"
10 
11 static status_t test_ram(void);
12 static status_t engxx_general_powerup (void);
13 static status_t eng_general_bios_to_powergraphics(void);
14 
15 static void eng_dump_configuration_space (void)
16 {
17 #define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \
18 	uint32 value = CFGR(reg); \
19 	MSG(("configuration_space 0x%02x %20s 0x%08x\n", \
20 		ENCFG_##reg, #reg, value)); \
21 } while (0)
22 	DUMP_CFG (DEVID,	0);
23 	DUMP_CFG (DEVCTRL,	0);
24 	DUMP_CFG (CLASS,	0);
25 	DUMP_CFG (HEADER,	0);
26 	DUMP_CFG (BASE1REGS,0);
27 	DUMP_CFG (BASE2FB,	0);
28 	DUMP_CFG (BASE3,	0);
29 	DUMP_CFG (BASE4,	0);
30 	DUMP_CFG (BASE5,	0);
31 	DUMP_CFG (BASE6,	0);
32 	DUMP_CFG (BASE7,	0);
33 	DUMP_CFG (SUBSYSID1,0);
34 	DUMP_CFG (ROMBASE,	0);
35 	DUMP_CFG (CAPPTR,	0);
36 	DUMP_CFG (CFG_1,	0);
37 	DUMP_CFG (INTERRUPT,0);
38 	DUMP_CFG (SUBSYSID2,0);
39 	DUMP_CFG (AGPREF,	0);
40 	DUMP_CFG (AGPSTAT,	0);
41 	DUMP_CFG (AGPCMD,	0);
42 	DUMP_CFG (ROMSHADOW,0);
43 	DUMP_CFG (VGA,		0);
44 	DUMP_CFG (SCHRATCH,	0);
45 	DUMP_CFG (CFG_10,	0);
46 	DUMP_CFG (CFG_11,	0);
47 	DUMP_CFG (CFG_12,	0);
48 	DUMP_CFG (CFG_13,	0);
49 	DUMP_CFG (CFG_14,	0);
50 	DUMP_CFG (CFG_15,	0);
51 	DUMP_CFG (CFG_16,	0);
52 	DUMP_CFG (CFG_17,	0);
53 	DUMP_CFG (CFG_18,	0);
54 	DUMP_CFG (CFG_19,	0);
55 	DUMP_CFG (CFG_20,	0);
56 	DUMP_CFG (CFG_21,	0);
57 	DUMP_CFG (CFG_22,	0);
58 	DUMP_CFG (CFG_23,	0);
59 	DUMP_CFG (CFG_24,	0);
60 	DUMP_CFG (CFG_25,	0);
61 	DUMP_CFG (CFG_26,	0);
62 	DUMP_CFG (CFG_27,	0);
63 	DUMP_CFG (CFG_28,	0);
64 	DUMP_CFG (CFG_29,	0);
65 	DUMP_CFG (CFG_30,	0);
66 	DUMP_CFG (CFG_31,	0);
67 	DUMP_CFG (CFG_32,	0);
68 	DUMP_CFG (CFG_33,	0);
69 	DUMP_CFG (CFG_34,	0);
70 	DUMP_CFG (CFG_35,	0);
71 	DUMP_CFG (CFG_36,	0);
72 	DUMP_CFG (CFG_37,	0);
73 	DUMP_CFG (CFG_38,	0);
74 	DUMP_CFG (CFG_39,	0);
75 	DUMP_CFG (CFG_40,	0);
76 	DUMP_CFG (CFG_41,	0);
77 	DUMP_CFG (CFG_42,	0);
78 	DUMP_CFG (CFG_43,	0);
79 	DUMP_CFG (CFG_44,	0);
80 	DUMP_CFG (CFG_45,	0);
81 	DUMP_CFG (CFG_46,	0);
82 	DUMP_CFG (CFG_47,	0);
83 	DUMP_CFG (CFG_48,	0);
84 	DUMP_CFG (CFG_49,	0);
85 	DUMP_CFG (CFG_50,	0);
86 #undef DUMP_CFG
87 }
88 
89 status_t eng_general_powerup()
90 {
91 	status_t status;
92 
93 	LOG(1,("POWERUP: Haiku VIA Accelerant 0.16 running.\n"));
94 
95 	/* preset no laptop */
96 	si->ps.laptop = false;
97 
98 	/* detect card type and power it up */
99 	switch(CFGR(DEVID))
100 	{
101 	/* Vendor Via */
102 	case 0x30221106:
103 		si->ps.card_type = CLE3022;
104 		si->ps.card_arch = CLE266;
105 		LOG(4,("POWERUP: Detected VIA CLE266 Unichrome Pro (CLE3022)\n"));
106 		status = engxx_general_powerup();
107 		break;
108 	case 0x31081106:
109 		//fixme: card_type unknown..
110 		si->ps.card_type = VT3204;
111 		si->ps.card_arch = K8M800;
112 		LOG(4,("POWERUP: Detected VIA K8M800 Unichrome Pro (unknown chiptype)\n"));
113 		status = engxx_general_powerup();
114 		break;
115 	case 0x31221106:
116 		si->ps.card_type = CLE3122;
117 		si->ps.card_arch = CLE266;
118 		LOG(4,("POWERUP: Detected VIA CLE266 Unichrome Pro (CLE3122)\n"));
119 		status = engxx_general_powerup();
120 		break;
121 	case 0x32051106:
122 		si->ps.card_type = VT3205;
123 		si->ps.card_arch = KM400;
124 		LOG(4,("POWERUP: Detected VIA KM400 Unichrome (VT3205)\n"));
125 		status = engxx_general_powerup();
126 		break;
127 	case 0x72051106:
128 		si->ps.card_type = VT7205;
129 		si->ps.card_arch = KM400;
130 		LOG(4,("POWERUP: Detected VIA KM400 Unichrome (VT7205)\n"));
131 		status = engxx_general_powerup();
132 		break;
133 	default:
134 		LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID)));
135 		return B_ERROR;
136 	}
137 
138 	return status;
139 }
140 
141 static status_t test_ram()
142 {
143 	uint32 value, offset;
144 	status_t result = B_OK;
145 
146 	/* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */
147 	if (si->fbc.frame_buffer == NULL)
148 	{
149 		LOG(8,("INIT: test_ram detected NULL pointer.\n"));
150 		return B_ERROR;
151 	}
152 
153 	for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
154 	{
155 		/* write testpattern to cardRAM */
156 		((uint32 *)si->fbc.frame_buffer)[offset] = value;
157 		/* toggle testpattern */
158 		value = 0xffffffff - value;
159 	}
160 
161 	for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
162 	{
163 		/* readback and verify testpattern from cardRAM */
164 		if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR;
165 		/* toggle testpattern */
166 		value = 0xffffffff - value;
167 	}
168 	return result;
169 }
170 
171 /* NOTE:
172  * This routine *has* to be done *after* SetDispplayMode has been executed,
173  * or test results will not be representative!
174  * (CAS latency is dependant on NV setup on some (DRAM) boards) */
175 status_t eng_set_cas_latency()
176 {
177 	status_t result = B_ERROR;
178 	uint8 latency = 0;
179 
180 	/* check current RAM access to see if we need to change anything */
181 	if (test_ram() == B_OK)
182 	{
183 		LOG(4,("INIT: RAM access OK.\n"));
184 		return B_OK;
185 	}
186 
187 	/* check if we read PINS at starttime so we have valid registersettings at our disposal */
188 	if (si->ps.pins_status != B_OK)
189 	{
190 		LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n"));
191 		return B_ERROR;
192 	}
193 
194 	/* OK. We might have a problem, try to fix it now.. */
195 	LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n"));
196 
197 	switch(si->ps.card_type)
198 	{
199 	default:
200 			LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n"));
201 			return B_OK;
202 			break;
203 	}
204 	if (result == B_OK)
205 		LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency));
206 	else
207 		LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency));
208 
209 	return result;
210 }
211 
212 void setup_virtualized_heads(bool cross)
213 {
214 	if (cross)
215 	{
216 		head1_validate_timing	= (crtc_validate_timing)	eng_crtc2_validate_timing;
217 		head1_set_timing		= (crtc_set_timing)			eng_crtc2_set_timing;
218 		head1_depth				= (crtc_depth)				eng_crtc2_depth;
219 		head1_dpms				= (crtc_dpms)				eng_crtc2_dpms;
220 		head1_dpms_fetch		= (crtc_dpms_fetch)			eng_crtc2_dpms_fetch;
221 		head1_set_display_pitch	= (crtc_set_display_pitch)	eng_crtc2_set_display_pitch;
222 		head1_set_display_start	= (crtc_set_display_start)	eng_crtc2_set_display_start;
223 		head1_cursor_init		= (crtc_cursor_init)		eng_crtc2_cursor_init;
224 		head1_cursor_show		= (crtc_cursor_show)		eng_crtc2_cursor_show;
225 		head1_cursor_hide		= (crtc_cursor_hide)		eng_crtc2_cursor_hide;
226 		head1_cursor_define		= (crtc_cursor_define)		eng_crtc2_cursor_define;
227 		head1_cursor_position	= (crtc_cursor_position)	eng_crtc2_cursor_position;
228 
229 		head1_mode				= (dac_mode)				eng_dac2_mode;
230 		head1_palette			= (dac_palette)				eng_dac2_palette;
231 		head1_set_pix_pll		= (dac_set_pix_pll)			eng_dac2_set_pix_pll;
232 		head1_pix_pll_find		= (dac_pix_pll_find)		eng_dac2_pix_pll_find;
233 
234 		head2_validate_timing	= (crtc_validate_timing)	eng_crtc_validate_timing;
235 		head2_set_timing		= (crtc_set_timing)			eng_crtc_set_timing;
236 		head2_depth				= (crtc_depth)				eng_crtc_depth;
237 		head2_dpms				= (crtc_dpms)				eng_crtc_dpms;
238 		head2_dpms_fetch		= (crtc_dpms_fetch)			eng_crtc_dpms_fetch;
239 		head2_set_display_pitch	= (crtc_set_display_pitch)	eng_crtc_set_display_pitch;
240 		head2_set_display_start	= (crtc_set_display_start)	eng_crtc_set_display_start;
241 		head2_cursor_init		= (crtc_cursor_init)		eng_crtc_cursor_init;
242 		head2_cursor_show		= (crtc_cursor_show)		eng_crtc_cursor_show;
243 		head2_cursor_hide		= (crtc_cursor_hide)		eng_crtc_cursor_hide;
244 		head2_cursor_define		= (crtc_cursor_define)		eng_crtc_cursor_define;
245 		head2_cursor_position	= (crtc_cursor_position)	eng_crtc_cursor_position;
246 
247 		head2_mode				= (dac_mode)				eng_dac_mode;
248 		head2_palette			= (dac_palette)				eng_dac_palette;
249 		head2_set_pix_pll		= (dac_set_pix_pll)			eng_dac_set_pix_pll;
250 		head2_pix_pll_find		= (dac_pix_pll_find)		eng_dac_pix_pll_find;
251 	}
252 	else
253 	{
254 		head1_validate_timing	= (crtc_validate_timing)	eng_crtc_validate_timing;
255 		head1_set_timing		= (crtc_set_timing)			eng_crtc_set_timing;
256 		head1_depth				= (crtc_depth)				eng_crtc_depth;
257 		head1_dpms				= (crtc_dpms)				eng_crtc_dpms;
258 		head1_dpms_fetch		= (crtc_dpms_fetch)			eng_crtc_dpms_fetch;
259 		head1_set_display_pitch	= (crtc_set_display_pitch)	eng_crtc_set_display_pitch;
260 		head1_set_display_start	= (crtc_set_display_start)	eng_crtc_set_display_start;
261 		head1_cursor_init		= (crtc_cursor_init)		eng_crtc_cursor_init;
262 		head1_cursor_show		= (crtc_cursor_show)		eng_crtc_cursor_show;
263 		head1_cursor_hide		= (crtc_cursor_hide)		eng_crtc_cursor_hide;
264 		head1_cursor_define		= (crtc_cursor_define)		eng_crtc_cursor_define;
265 		head1_cursor_position	= (crtc_cursor_position)	eng_crtc_cursor_position;
266 
267 		head1_mode				= (dac_mode)				eng_dac_mode;
268 		head1_palette			= (dac_palette)				eng_dac_palette;
269 		head1_set_pix_pll		= (dac_set_pix_pll)			eng_dac_set_pix_pll;
270 		head1_pix_pll_find		= (dac_pix_pll_find)		eng_dac_pix_pll_find;
271 
272 		head2_validate_timing	= (crtc_validate_timing)	eng_crtc2_validate_timing;
273 		head2_set_timing		= (crtc_set_timing)			eng_crtc2_set_timing;
274 		head2_depth				= (crtc_depth)				eng_crtc2_depth;
275 		head2_dpms				= (crtc_dpms)				eng_crtc2_dpms;
276 		head2_dpms_fetch		= (crtc_dpms_fetch)			eng_crtc2_dpms_fetch;
277 		head2_set_display_pitch	= (crtc_set_display_pitch)	eng_crtc2_set_display_pitch;
278 		head2_set_display_start	= (crtc_set_display_start)	eng_crtc2_set_display_start;
279 		head2_cursor_init		= (crtc_cursor_init)		eng_crtc2_cursor_init;
280 		head2_cursor_show		= (crtc_cursor_show)		eng_crtc2_cursor_show;
281 		head2_cursor_hide		= (crtc_cursor_hide)		eng_crtc2_cursor_hide;
282 		head2_cursor_define		= (crtc_cursor_define)		eng_crtc2_cursor_define;
283 		head2_cursor_position	= (crtc_cursor_position)	eng_crtc2_cursor_position;
284 
285 		head2_mode				= (dac_mode)				eng_dac2_mode;
286 		head2_palette			= (dac_palette)				eng_dac2_palette;
287 		head2_set_pix_pll		= (dac_set_pix_pll)			eng_dac2_set_pix_pll;
288 		head2_pix_pll_find		= (dac_pix_pll_find)		eng_dac2_pix_pll_find;
289 	}
290 }
291 
292 void set_crtc_owner(bool head)
293 {
294 	if (si->ps.secondary_head)
295 	{
296 		if (!head)
297 		{
298 			/* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's,
299 			 * while non-NV11 cards behave normally.
300 			 *
301 			 * Double-write action needed on those strange NV11 cards: */
302 			/* RESET: needed on NV11 */
303 			CRTCW(OWNER, 0xff);
304 			/* enable access to CRTC1, SEQ1, GRPH1, ATB1, ??? */
305 			CRTCW(OWNER, 0x00);
306 		}
307 		else
308 		{
309 			/* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's,
310 			 * while non-NV11 cards behave normally.
311 			 *
312 			 * Double-write action needed on those strange NV11 cards: */
313 			/* RESET: needed on NV11 */
314 			CRTC2W(OWNER, 0xff);
315 			/* enable access to CRTC2, SEQ2, GRPH2, ATB2, ??? */
316 			CRTC2W(OWNER, 0x03);
317 		}
318 	}
319 }
320 
321 static status_t engxx_general_powerup()
322 {
323 	LOG(4,("POWERUP: Chip revision is $%02x\n", si->ps.chip_rev));
324 	LOG(4, ("INIT: card powerup\n"));
325 
326 	/* setup cardspecs */
327 	/* note:
328 	 * this MUST be done before the driver attempts a card coldstart */
329 	set_specs();
330 
331 	/* only process BIOS for finetuning specs and coldstarting card if requested
332 	 * by the user;
333 	 * note:
334 	 * this in fact frees the driver from relying on the BIOS to be executed
335 	 * at system power-up POST time. */
336 	if (!si->settings.usebios)
337 	{
338 		LOG(2, ("INIT: Attempting card coldstart!\n"));
339 		/* update the cardspecs in the shared_info PINS struct according to reported
340 		 * specs as much as is possible;
341 		 * this also coldstarts the card if possible (executes BIOS CMD script(s)) */
342 //		parse_pins();
343 	}
344 	else
345 	{
346 		LOG(2, ("INIT: Skipping card coldstart!\n"));
347 	}
348 
349 	/* get RAM size and fake panel startup (panel init code is still missing) */
350 	fake_panel_start();
351 
352 	/* log the final card specifications */
353 	dump_pins();
354 
355 	/* dump config space as it is after a possible coldstart attempt */
356 	if (si->settings.logmask & 0x80000000) eng_dump_configuration_space();
357 
358 	/* setup CRTC and DAC functions access: determined in fake_panel_start */
359 	setup_virtualized_heads(si->ps.crtc2_prim);
360 
361 	/* do powerup needed from pre-inited card state as done by system POST cardBIOS
362 	 * execution or driver coldstart above */
363 	return eng_general_bios_to_powergraphics();
364 }
365 
366 /* this routine switches the CRTC/DAC sets to 'connectors', but only for analog
367  * outputs. We need this to make sure the analog 'switch' is set in the same way the
368  * digital 'switch' is set by the BIOS or we might not be able to use dualhead. */
369 status_t eng_general_output_select(bool cross)
370 {
371 	/* make sure this call is warranted */
372 	if (si->ps.secondary_head)
373 	{
374 		/* NV11 cards can't switch heads (confirmed) */
375 		if (si->ps.card_type != NV11)
376 		{
377 			if (cross)
378 			{
379 				LOG(4,("INIT: switching analog outputs to be cross-connected\n"));
380 
381 				/* enable head 2 on connector 1 */
382 				/* (b8 = select CRTC (head) for output,
383 				 *  b4 = ??? (confirmed not to be a FP switch),
384 				 *  b0 = enable CRT) */
385 				DACW(OUTPUT, 0x00000101);
386 				/* enable head 1 on connector 2 */
387 				DAC2W(OUTPUT, 0x00000001);
388 			}
389 			else
390 			{
391 				LOG(4,("INIT: switching analog outputs to be straight-through\n"));
392 
393 				/* enable head 1 on connector 1 */
394 				DACW(OUTPUT, 0x00000001);
395 				/* enable head 2 on connector 2 */
396 				DAC2W(OUTPUT, 0x00000101);
397 			}
398 		}
399 		else
400 		{
401 			LOG(4,("INIT: NV11 analog outputs are hardwired to be straight-through\n"));
402 		}
403 		return B_OK;
404 	}
405 	else
406 	{
407 		return B_ERROR;
408 	}
409 }
410 
411 /* this routine switches CRTC/DAC set use. We need this because it's unknown howto
412  * switch digital panels to/from a specific CRTC/DAC set. */
413 status_t eng_general_head_select(bool cross)
414 {
415 	/* make sure this call is warranted */
416 	if (si->ps.secondary_head)
417 	{
418 		/* invert CRTC/DAC use to do switching */
419 		if (cross)
420 		{
421 			LOG(4,("INIT: switching CRTC/DAC use to be cross-connected\n"));
422 			si->crtc_switch_mode = !si->ps.crtc2_prim;
423 		}
424 		else
425 		{
426 			LOG(4,("INIT: switching CRTC/DAC use to be straight-through\n"));
427 			si->crtc_switch_mode = si->ps.crtc2_prim;
428 		}
429 		/* update CRTC and DAC functions access */
430 		setup_virtualized_heads(si->crtc_switch_mode);
431 
432 		return B_OK;
433 	}
434 	else
435 	{
436 		return B_ERROR;
437 	}
438 }
439 
440 /* basic change of card state from VGA to enhanced mode:
441  * Should work from VGA BIOS POST init state. */
442 static status_t eng_general_bios_to_powergraphics()
443 {
444 	/* let acc engine make power off/power on cycle to start 'fresh' */
445 //	ENG_REG32(RG32_PWRUPCTRL) = 0x13110011;
446 	snooze(1000);
447 
448 	/* power-up all hardware function blocks */
449 //	ENG_REG32(RG32_PWRUPCTRL) = 0x13111111;
450 
451 	/* select colormode CRTC registers base adresses,
452 	 * but don't touch the current selected pixelclock source yet */
453 	ENG_REG8(RG8_MISCW) = (((ENG_REG8(RG8_MISCR)) & 0x0c) | 0xc3);
454 
455 	/* unlock (extended) registers for R/W access */
456 	SEQW(LOCK, 0x01);
457 	CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
458 
459 	/* turn off both displays and the hardcursors (also disables transfers) */
460 	head1_dpms(false, false, false);
461 	head1_cursor_hide();
462 	if (si->ps.secondary_head)
463 	{
464 //		head2_dpms(false, false, false);
465 //		head2_cursor_hide();
466 	}
467 
468 //	if (si->ps.secondary_head)
469 	if (0)
470 	{
471 		/* switch overlay engine to CRTC1 */
472 		/* bit 17: GPU FP port #1	(confirmed NV25, NV28, confirmed not on NV34),
473 		 * bit 16: GPU FP port #2	(confirmed NV25, NV28, NV34),
474 		 * bit 12: overlay engine	(all cards),
475 		 * bit  9: TVout chip #2	(confirmed on NV18, NV25, NV28),
476 		 * bit  8: TVout chip #1	(all cards),
477 		 * bit  4: both I2C busses	(all cards) */
478 		ENG_REG32(RG32_2FUNCSEL) &= ~0x00001000;
479 		ENG_REG32(RG32_FUNCSEL) |= 0x00001000;
480 	}
481 	si->overlay.crtc = false;
482 
483 	/* set card to 'enhanced' mode: (only VGA standard registers used here) */
484 	/* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */
485 	CRTCW(MODECTL, 0xc3);
486 	/* ... plain sequential memory use, more than 64Kb RAM installed,
487 	 * switch to graphics mode ... */
488 	SEQW(MEMMODE, 0x0e);
489 	/* ... disable bitplane tweaking ... */
490 	GRPHW(ENSETRESET, 0x00);
491 	/* ... no logical function tweaking with display data, no data rotation ... */
492 	GRPHW(DATAROTATE, 0x00);
493 	/* ... reset read map select to plane 0 ... */
494 	GRPHW(READMAPSEL, 0x00);
495 	/* ... set standard mode ... */
496 	GRPHW(MODE, 0x00);
497 	/* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again),
498 	 * select standard adressing ... */
499 	GRPHW(MISC, 0x05);
500 	/* ... disable bit masking ... */
501 	GRPHW(BITMASK, 0xff);
502 	/* ... attributes are in color, switch to graphics mode (again) ... */
503 	ATBW(MODECTL, 0x01);
504 	/* ... set overscan color to black ... */
505 	ATBW(OSCANCOLOR, 0x00);
506 	/* ... enable all color planes ... */
507 	ATBW(COLPLANE_EN, 0x0f);
508 	/* ... reset horizontal pixelpanning ... */
509 	ATBW(HORPIXPAN, 0x00);
510 	/* ...  reset colorpalette groupselect bits ... */
511 	ATBW(COLSEL, 0x00);
512 	/* ... do unknown standard VGA register ... */
513 	ATBW(0x16, 0x01);
514 	/* ... and enable all four byteplanes. */
515 	SEQW(MAPMASK, 0x0f);
516 	/* setup sequencer clocking mode */
517 	SEQW(CLKMODE, 0x21);
518 
519 	/* setup AGP:
520 	 * Note:
521 	 * This may only be done when no transfers are in progress on the bus, so now
522 	 * is probably a good time.. */
523 	eng_agp_setup();
524 
525 	/* turn screen one on */
526 	head1_dpms(true, true, true);
527 
528 	return B_OK;
529 }
530 
531 /* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify
532  * virtual_size to the nearest valid maximum for the mode on the card if not so.
533  * Also: check if virtual_width adheres to the cards granularity constraints, and
534  * create mode slopspace if not so.
535  * We use acc or crtc granularity constraints based on the 'worst case' scenario.
536  *
537  * Mode slopspace is reflected in fbc->bytes_per_row BTW. */
538 status_t eng_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode)
539 {
540 	uint32 video_pitch;
541 	uint32 acc_mask, crtc_mask;
542 	uint32 max_crtc_width, max_acc_width;
543 	uint8 depth = 8;
544 
545 	/* determine pixel multiple based on 2D/3D engine constraints */
546 //via fixme.
547 	switch (si->ps.card_arch)
548 	{
549 	default:
550 		/* confirmed for:
551 		 * TNT1, TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForceFX 5200 */
552 		switch (target->space)
553 		{
554 			case B_CMAP8: acc_mask = 0x0f; depth =  8; break;
555 			case B_RGB15: acc_mask = 0x07; depth = 16; break;
556 			case B_RGB16: acc_mask = 0x07; depth = 16; break;
557 			case B_RGB24: acc_mask = 0x0f; depth = 24; break;
558 			case B_RGB32: acc_mask = 0x03; depth = 32; break;
559 			default:
560 				LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
561 				return B_ERROR;
562 		}
563 		break;
564 	}
565 
566 //via ok:
567 	/* determine pixel multiple based on CRTC memory pitch constraints.
568 	 * (Note: Don't mix this up with CRTC timing contraints! Those are
569 	 *        multiples of 8 for horizontal, 1 for vertical timing.) */
570 	switch (si->ps.card_type)
571 	{
572 	default:
573 		switch (target->space)
574 		{
575 			case B_CMAP8: crtc_mask = 0x07; break;
576 			case B_RGB15: crtc_mask = 0x03; break;
577 			case B_RGB16: crtc_mask = 0x03; break;
578 			case B_RGB24: crtc_mask = 0x07; break;
579 			case B_RGB32: crtc_mask = 0x01; break;
580 			default:
581 				LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
582 				return B_ERROR;
583 		}
584 		break;
585 	}
586 
587 	/* set virtual_width limit for accelerated modes */
588 //via fixme:
589 	switch (si->ps.card_arch)
590 	{
591 	case NV04A:
592 		/* confirmed for:
593 		 * TNT1, TNT2, TNT2-M64 */
594 		switch(target->space)
595 		{
596 			case B_CMAP8: max_acc_width = 8176; break;
597 			case B_RGB15: max_acc_width = 4088; break;
598 			case B_RGB16: max_acc_width = 4088; break;
599 			case B_RGB24: max_acc_width = 2720; break;
600 			case B_RGB32: max_acc_width = 2044; break;
601 			default:
602 				LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
603 				return B_ERROR;
604 		}
605 		break;
606 	default:
607 		/* confirmed for:
608 		 * GeForce2 MX400, GeForce4 MX440, GeForceFX 5200 */
609 		switch(target->space)
610 		{
611 			case B_CMAP8: max_acc_width = 16368; break;
612 			case B_RGB15: max_acc_width =  8184; break;
613 			case B_RGB16: max_acc_width =  8184; break;
614 			case B_RGB24: max_acc_width =  5456; break;
615 			case B_RGB32: max_acc_width =  4092; break;
616 			default:
617 				LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
618 				return B_ERROR;
619 		}
620 		/* NV31 (confirmed GeForceFX 5600) has NV20A granularity!
621 		 * So let it fall through... */
622 		if (si->ps.card_type != NV31) break;
623 	case NV20A:
624 		/* confirmed for:
625 		 * GeForce4 Ti4200 */
626 		switch(target->space)
627 		{
628 			case B_CMAP8: max_acc_width = 16320; break;
629 			case B_RGB15: max_acc_width =  8160; break;
630 			case B_RGB16: max_acc_width =  8160; break;
631 			case B_RGB24: max_acc_width =  5440; break;
632 			case B_RGB32: max_acc_width =  4080; break;
633 			default:
634 				LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
635 				return B_ERROR;
636 		}
637 		break;
638 	}
639 
640 //via ok:
641 	/* set virtual_width limit for unaccelerated modes */
642 	switch (si->ps.card_type)
643 	{
644 	default:
645 		switch(target->space)
646 		{
647 			case B_CMAP8: max_crtc_width = 16376; break;
648 			case B_RGB15: max_crtc_width =  8188; break;
649 			case B_RGB16: max_crtc_width =  8188; break;
650 			case B_RGB24: max_crtc_width =  5456; break;
651 			case B_RGB32: max_crtc_width =  4094; break;
652 			default:
653 				LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
654 				return B_ERROR;
655 		}
656 		break;
657 	}
658 
659 	/* check for acc capability, and adjust mode to adhere to hardware constraints */
660 	if (max_acc_width <= max_crtc_width)
661 	{
662 		/* check if we can setup this mode with acceleration */
663 //		*acc_mode = true;
664 //blocking acc totally:
665 *acc_mode = false;
666 		/* virtual_width */
667 		if (target->virtual_width > max_acc_width) *acc_mode = false;
668 		/* virtual_height */
669 		/* (NV cards can even do more than this(?)...
670 		 *  but 4096 is confirmed on all cards at max. accelerated width.) */
671 		if (target->virtual_height > 4096) *acc_mode = false;
672 
673 		/* now check virtual_size based on CRTC constraints */
674 		if (target->virtual_width > max_crtc_width) target->virtual_width = max_crtc_width;
675 		/* virtual_height: The only constraint here is the cards memory size which is
676 		 * checked later on in ProposeMode: virtual_height is adjusted then if needed.
677 		 * 'Limiting here' to the variable size that's at least available (uint16). */
678 		if (target->virtual_height > 65535) target->virtual_height = 65535;
679 
680 		/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
681 		 * it was confined above, so we can finally calculate safely if we need slopspace
682 		 * for this mode... */
683 		if (*acc_mode)
684 		{
685 			/* the mode needs to adhere to the largest granularity imposed... */
686 			if (acc_mask < crtc_mask)
687 				video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
688 			else
689 				video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
690 		}
691 		else /* unaccelerated mode */
692 			video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
693 	}
694 	else /* max_acc_width > max_crtc_width */
695 	{
696 		/* check if we can setup this mode with acceleration */
697 //		*acc_mode = true;
698 //blocking acc totally:
699 *acc_mode = false;
700 		/* (we already know virtual_width will be no problem) */
701 		/* virtual_height */
702 		/* (NV cards can even do more than this(?)...
703 		 *  but 4096 is confirmed on all cards at max. accelerated width.) */
704 		if (target->virtual_height > 4096) *acc_mode = false;
705 
706 		/* now check virtual_size based on CRTC constraints */
707 		if (*acc_mode)
708 		{
709 			/* note that max_crtc_width already adheres to crtc_mask */
710 			if (target->virtual_width > (max_crtc_width & ~acc_mask))
711 					target->virtual_width = (max_crtc_width & ~acc_mask);
712 		}
713 		else /* unaccelerated mode */
714 		{
715 			if (target->virtual_width > max_crtc_width)
716 					target->virtual_width = max_crtc_width;
717 		}
718 		/* virtual_height: The only constraint here is the cards memory size which is
719 		 * checked later on in ProposeMode: virtual_height is adjusted then if needed.
720 		 * 'Limiting here' to the variable size that's at least available (uint16). */
721 		if (target->virtual_height > 65535) target->virtual_height = 65535;
722 
723 		/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
724 		 * it was confined above, so we can finally calculate safely if we need slopspace
725 		 * for this mode... */
726 		if (*acc_mode)
727 		{
728 			/* the mode needs to adhere to the largest granularity imposed... */
729 			if (acc_mask < crtc_mask)
730 				video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
731 			else
732 				video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
733 		}
734 		else /* unaccelerated mode */
735 			video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
736 	}
737 
738 	LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n",
739 														video_pitch, target->space));
740 	if (target->virtual_width != video_pitch)
741 		LOG(2,("INIT: effective mode slopspace is %d pixels\n",
742 											(video_pitch - target->virtual_width)));
743 
744 	/* now calculate bytes_per_row for this mode */
745 	*bytes_per_row = video_pitch * (depth >> 3);
746 
747 	return B_OK;
748 }
749