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