xref: /haiku/src/add-ons/accelerants/nvidia/engine/nv_i2c.c (revision e7c8829c5d8e5d34a2a1e111f1c06aceff256013)
1 /*
2  * i2c interface.
3  * Bus should be run at max. 100kHz: see original Philips I2C specification
4  *
5  * Rudolf Cornelissen 12/2002-5/2009
6  */
7 
8 #define MODULE_BIT 0x00004000
9 
10 #include "nv_std.h"
11 
12 static void i2c_DumpSpecsEDID(edid_specs* specs);
13 
14 char i2c_flag_error (char ErrNo)
15 //error code list:
16 //0 - OK status
17 //1 - SCL locked low by device (bus is still busy)
18 //2 - SDA locked low by device (bus is still busy)
19 //3 - No Acknowledge from device (no handshake)
20 //4 - SDA not released for master to generate STOP bit
21 {
22 	static char I2CError = 0;
23 
24 	if (!I2CError) I2CError = ErrNo;
25 	if (ErrNo == -1) I2CError = 0;
26 	return I2CError;
27 }
28 
29 static void i2c_select_bus_set(bool set)
30 {
31 	/* I/O pins set selection is only valid on dualhead cards */
32 	if (!si->ps.secondary_head) return;
33 
34 	/* select GPU I/O pins set to connect to I2C 'registers' */
35 	if (set)
36 	{
37 		NV_REG32(NV32_FUNCSEL) &= ~0x00000010;
38 		NV_REG32(NV32_2FUNCSEL) |= 0x00000010;
39 	}
40 	else
41 	{
42 		NV_REG32(NV32_2FUNCSEL) &= ~0x00000010;
43 		NV_REG32(NV32_FUNCSEL) |= 0x00000010;
44 	}
45 }
46 
47 static void OutSCL(uint8 BusNR, bool Bit)
48 {
49 	uint8 data;
50 
51 	if (BusNR & 0x01)
52 	{
53 		data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01;
54 		if (Bit)
55 			CRTCW(WR_I2CBUS_1, (data | 0x20));
56 		else
57 			CRTCW(WR_I2CBUS_1, (data & ~0x20));
58 	}
59 	else
60 	{
61 		data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01;
62 		if (Bit)
63 			CRTCW(WR_I2CBUS_0, (data | 0x20));
64 		else
65 			CRTCW(WR_I2CBUS_0, (data & ~0x20));
66 	}
67 }
68 
69 static void OutSDA(uint8 BusNR, bool Bit)
70 {
71 	uint8 data;
72 
73 	if (BusNR & 0x01)
74 	{
75 		data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01;
76 		if (Bit)
77 			CRTCW(WR_I2CBUS_1, (data | 0x10));
78 		else
79 			CRTCW(WR_I2CBUS_1, (data & ~0x10));
80 	}
81 	else
82 	{
83 		data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01;
84 		if (Bit)
85 			CRTCW(WR_I2CBUS_0, (data | 0x10));
86 		else
87 			CRTCW(WR_I2CBUS_0, (data & ~0x10));
88 	}
89 }
90 
91 static bool InSCL(uint8 BusNR)
92 {
93 	if (BusNR & 0x01)
94 	{
95 		if ((CRTCR(RD_I2CBUS_1) & 0x04)) return true;
96 	}
97 	else
98 	{
99 		if ((CRTCR(RD_I2CBUS_0) & 0x04)) return true;
100 	}
101 
102 	return false;
103 }
104 
105 static bool InSDA(uint8 BusNR)
106 {
107 	if (BusNR & 0x01)
108 	{
109 		if ((CRTCR(RD_I2CBUS_1) & 0x08)) return true;
110 	}
111 	else
112 	{
113 		if ((CRTCR(RD_I2CBUS_0) & 0x08)) return true;
114 	}
115 
116 	return false;
117 }
118 
119 static void TXBit (uint8 BusNR, bool Bit)
120 {
121 	/* send out databit */
122 	if (Bit)
123 	{
124 		OutSDA(BusNR, true);
125 		snooze(3);
126 		if (!InSDA(BusNR)) i2c_flag_error (2);
127 	}
128 	else
129 	{
130 		OutSDA(BusNR, false);
131 	}
132 	/* generate clock pulse */
133 	snooze(6);
134 	OutSCL(BusNR, true);
135 	snooze(3);
136 	if (!InSCL(BusNR)) i2c_flag_error (1);
137 	snooze(6);
138 	OutSCL(BusNR, false);
139 	snooze(6);
140 }
141 
142 static uint8 RXBit (uint8 BusNR)
143 {
144 	uint8 Bit = 0;
145 
146 	/* set SDA so input is possible */
147 	OutSDA(BusNR, true);
148 	/* generate clock pulse */
149 	snooze(6);
150 	OutSCL(BusNR, true);
151 	snooze(3);
152 	if (!InSCL(BusNR)) i2c_flag_error (1);
153 	snooze(3);
154 	/* read databit */
155 	if (InSDA(BusNR)) Bit = 1;
156 	/* finish clockpulse */
157 	OutSCL(BusNR, false);
158 	snooze(6);
159 
160 	return Bit;
161 }
162 
163 void i2c_bstart (uint8 BusNR)
164 {
165 	/* select GPU I/O pins set */
166 	i2c_select_bus_set(BusNR & 0x02);
167 
168 	/* enable access to primary head */
169 	set_crtc_owner(0);
170 
171 	/* make sure SDA is high */
172 	OutSDA(BusNR, true);
173 	snooze(3);
174 	OutSCL(BusNR, true);
175 	snooze(3);
176 	if (!InSCL(BusNR)) i2c_flag_error (1);
177 	snooze(6);
178 	/* clear SDA while SCL set (bus-start condition) */
179 	OutSDA(BusNR, false);
180 	snooze(6);
181 	OutSCL(BusNR, false);
182 	snooze(6);
183 
184 	LOG(4,("I2C: START condition generated on bus %d; status is %d\n",
185 		BusNR, i2c_flag_error (0)));
186 }
187 
188 void i2c_bstop (uint8 BusNR)
189 {
190 	/* select GPU I/O pins set */
191 	i2c_select_bus_set(BusNR & 0x02);
192 
193 	/* enable access to primary head */
194 	set_crtc_owner(0);
195 
196 	/* make sure SDA is low */
197 	OutSDA(BusNR, false);
198 	snooze(3);
199 	OutSCL(BusNR, true);
200 	snooze(3);
201 	if (!InSCL(BusNR)) i2c_flag_error (1);
202 	snooze(6);
203 	/* set SDA while SCL set (bus-stop condition) */
204 	OutSDA(BusNR, true);
205 	snooze(3);
206 	if (!InSDA(BusNR)) i2c_flag_error (4);
207 	snooze(3);
208 
209 	LOG(4,("I2C: STOP condition generated on bus %d; status is %d\n",
210 		BusNR, i2c_flag_error (0)));
211 }
212 
213 uint8 i2c_readbyte(uint8 BusNR, bool Ack)
214 {
215 	uint8 cnt, bit, byte = 0;
216 
217 	/* select GPU I/O pins set */
218 	i2c_select_bus_set(BusNR & 0x02);
219 
220 	/* enable access to primary head */
221 	set_crtc_owner(0);
222 
223 	/* read data */
224 	for (cnt = 8; cnt > 0; cnt--)
225 	{
226 		byte <<= 1;
227 		bit = RXBit (BusNR);
228 		byte += bit;
229 	}
230 	/* send acknowledge */
231 	TXBit (BusNR, Ack);
232 
233 	LOG(4,("I2C: read byte ($%02x) from bus #%d; status is %d\n",
234 		byte, BusNR, i2c_flag_error(0)));
235 
236 	return byte;
237 }
238 
239 bool i2c_writebyte (uint8 BusNR, uint8 byte)
240 {
241 	uint8 cnt;
242 	bool bit;
243 	uint8 tmp = byte;
244 
245 	/* select GPU I/O pins set */
246 	i2c_select_bus_set(BusNR & 0x02);
247 
248 	/* enable access to primary head */
249 	set_crtc_owner(0);
250 
251 	/* write data */
252 	for (cnt = 8; cnt > 0; cnt--)
253 	{
254 		bit = (tmp & 0x80);
255 		TXBit (BusNR, bit);
256 		tmp <<= 1;
257 	}
258 	/* read acknowledge */
259 	bit = RXBit (BusNR);
260 	if (bit) i2c_flag_error (3);
261 
262 	LOG(4,("I2C: written byte ($%02x) to bus #%d; status is %d\n",
263 		byte, BusNR, i2c_flag_error(0)));
264 
265 	return bit;
266 }
267 
268 void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size)
269 {
270 	uint8 cnt;
271 
272 	for (cnt = 0; cnt < size; cnt++)
273 	{
274 		buf[cnt] = i2c_readbyte(BusNR, buf[cnt]);
275 	}
276 }
277 
278 void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size)
279 {
280 	uint8 cnt;
281 
282 	for (cnt = 0; cnt < size; cnt++)
283 	{
284 		i2c_writebyte(BusNR, buf[cnt]);
285 	}
286 }
287 
288 status_t i2c_init(void)
289 {
290 	uint8 bus, buses;
291 	bool *i2c_bus = &(si->ps.i2c_bus0);
292 	status_t result = B_ERROR;
293 
294 	LOG(4,("I2C: searching for wired I2C buses...\n"));
295 
296 	/* enable access to primary head */
297 	set_crtc_owner(0);
298 
299 	/* preset no board wired buses */
300 	si->ps.i2c_bus0 = false;
301 	si->ps.i2c_bus1 = false;
302 	si->ps.i2c_bus2 = false;
303 	si->ps.i2c_bus3 = false;
304 
305 	/* set number of buses to test for */
306 	buses = 2;
307 	if (si->ps.secondary_head) buses = 4;
308 
309 	/* find existing buses */
310 	for (bus = 0; bus < buses; bus++)
311 	{
312 		/* reset status */
313 		i2c_flag_error (-1);
314 		snooze(6);
315 		/* init and/or stop I2C bus */
316 		i2c_bstop(bus);
317 		/* check for hardware coupling of SCL and SDA -out and -in lines */
318 		snooze(6);
319 		OutSCL(bus, false);
320 		OutSDA(bus, true);
321 		snooze(3);
322 		if (InSCL(bus) || !InSDA(bus)) continue;
323 		snooze(3);
324 		OutSCL(bus, true);
325 		OutSDA(bus, false);
326 		snooze(3);
327 		if (!InSCL(bus) || InSDA(bus)) continue;
328 		i2c_bus[bus] = true;
329 		snooze(3);
330 		/* re-init bus */
331 		i2c_bstop(bus);
332 	}
333 
334 	for (bus = 0; bus < buses; bus++)
335 	{
336 		if (i2c_bus[bus])
337 		{
338 			LOG(4,("I2C: bus #%d wiring check: passed\n", bus));
339 			result = B_OK;
340 		}
341 		else
342 			LOG(4,("I2C: bus #%d wiring check: failed\n", bus));
343 	}
344 
345 	//i2c_TestEDID();
346 	i2c_DetectScreens();
347 	LOG(4,("I2C: dumping EDID specs for connector 1:\n"));
348 	i2c_DumpSpecsEDID(&si->ps.con1_screen);
349 	LOG(4,("I2C: dumping EDID specs for connector 2:\n"));
350 	i2c_DumpSpecsEDID(&si->ps.con2_screen);
351 
352 	return result;
353 }
354 
355 /*** DDC/EDID library use ***/
356 typedef struct {
357 	uint32 port;
358 } ddc_port_info;
359 
360 /* Dump EDID info in driver's logfile */
361 static void
362 i2c_DumpEDID(edid1_info *edid)
363 {
364 	int i, j;
365 
366 	LOG(4,("Vendor: %s\n", edid->vendor.manufacturer));
367 	LOG(4,("Product ID: %d\n", (int)edid->vendor.prod_id));
368 	LOG(4,("Serial #: %d\n", (int)edid->vendor.serial));
369 	LOG(4,("Produced in week/year: %d/%d\n", edid->vendor.week, edid->vendor.year));
370 
371 	LOG(4,("EDID version: %d.%d\n", edid->version.version, edid->version.revision));
372 
373 	LOG(4,("Type: %s\n", edid->display.input_type ? "Digital" : "Analog"));
374 	LOG(4,("Size: %d cm x %d cm\n", edid->display.h_size, edid->display.v_size));
375 	LOG(4,("Gamma=%.3f\n", (edid->display.gamma + 100) / 100.0));
376 	LOG(4,("White (X,Y)=(%.3f,%.3f)\n", edid->display.white_x / 1024.0,
377 		edid->display.white_y / 1024.0));
378 
379 	LOG(4,("Supported Future Video Modes:\n"));
380 	for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
381 		if (edid->std_timing[i].h_size <= 256)
382 			continue;
383 
384 		LOG(4,("%dx%d@%dHz (id=%d)\n",
385 			edid->std_timing[i].h_size, edid->std_timing[i].v_size,
386 			edid->std_timing[i].refresh, edid->std_timing[i].id));
387 	}
388 
389 	LOG(4,("Supported VESA Video Modes:\n"));
390 	if (edid->established_timing.res_720x400x70)
391 		LOG(4,("720x400@70\n"));
392 	if (edid->established_timing.res_720x400x88)
393 		LOG(4,("720x400@88\n"));
394 	if (edid->established_timing.res_640x480x60)
395 		LOG(4,("640x480@60\n"));
396 	if (edid->established_timing.res_640x480x67)
397 		LOG(4,("640x480x67\n"));
398 	if (edid->established_timing.res_640x480x72)
399 		LOG(4,("640x480x72\n"));
400 	if (edid->established_timing.res_640x480x75)
401 		LOG(4,("640x480x75\n"));
402 	if (edid->established_timing.res_800x600x56)
403 		LOG(4,("800x600@56\n"));
404 	if (edid->established_timing.res_800x600x60)
405 		LOG(4,("800x600@60\n"));
406 
407 	if (edid->established_timing.res_800x600x72)
408 		LOG(4,("800x600@72\n"));
409 	if (edid->established_timing.res_800x600x75)
410 		LOG(4,("800x600@75\n"));
411 	if (edid->established_timing.res_832x624x75)
412 		LOG(4,("832x624@75\n"));
413 	if (edid->established_timing.res_1024x768x87i)
414 		LOG(4,("1024x768@87 interlaced\n"));
415 	if (edid->established_timing.res_1024x768x60)
416 		LOG(4,("1024x768@60\n"));
417 	if (edid->established_timing.res_1024x768x70)
418 		LOG(4,("1024x768@70\n"));
419 	if (edid->established_timing.res_1024x768x75)
420 		LOG(4,("1024x768@75\n"));
421 	if (edid->established_timing.res_1280x1024x75)
422 		LOG(4,("1280x1024@75\n"));
423 
424 	if (edid->established_timing.res_1152x870x75)
425 		LOG(4,("1152x870@75\n"));
426 
427 	for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
428 		edid1_detailed_monitor *monitor = &edid->detailed_monitor[i];
429 
430 		switch(monitor->monitor_desc_type) {
431 			case EDID1_SERIAL_NUMBER:
432 				LOG(4,("Serial Number: %s\n", monitor->data.serial_number));
433 				break;
434 
435 			case EDID1_ASCII_DATA:
436 				LOG(4,(" %s\n", monitor->data.serial_number));
437 				break;
438 
439 			case EDID1_MONITOR_RANGES:
440 			{
441 				edid1_monitor_range monitor_range = monitor->data.monitor_range;
442 
443 				LOG(4,("Horizontal frequency range = %d..%d kHz\n",
444 					monitor_range.min_h, monitor_range.max_h));
445 				LOG(4,("Vertical frequency range = %d..%d Hz\n",
446 					monitor_range.min_v, monitor_range.max_v));
447 				LOG(4,("Maximum pixel clock = %d MHz\n", (uint16)monitor_range.max_clock * 10));
448 				break;
449 			}
450 
451 			case EDID1_MONITOR_NAME:
452 				LOG(4,("Monitor Name: %s\n", monitor->data.monitor_name));
453 				break;
454 
455 			case EDID1_ADD_COLOUR_POINTER:
456 			{
457 				for (j = 0; j < EDID1_NUM_EXTRA_WHITEPOINTS; ++j) {
458 					edid1_whitepoint *whitepoint = &monitor->data.whitepoint[j];
459 
460 					if (whitepoint->index == 0)
461 						continue;
462 
463 					LOG(4,("Additional whitepoint: (X,Y)=(%f,%f) gamma=%f index=%i\n",
464 						whitepoint->white_x / 1024.0,
465 						whitepoint->white_y / 1024.0,
466 						(whitepoint->gamma + 100) / 100.0,
467 						whitepoint->index));
468 				}
469 				break;
470 			}
471 
472 			case EDID1_ADD_STD_TIMING:
473 			{
474 				for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) {
475 					edid1_std_timing *timing = &monitor->data.std_timing[j];
476 
477 					if (timing->h_size <= 256)
478 						continue;
479 
480 					LOG(4,("%dx%d@%dHz (id=%d)\n",
481 						timing->h_size, timing->v_size,
482 						timing->refresh, timing->id));
483 				}
484 				break;
485 			}
486 
487 			case EDID1_IS_DETAILED_TIMING:
488 			{
489 				edid1_detailed_timing *timing = &monitor->data.detailed_timing;
490 
491 				LOG(4,("Additional Video Mode:\n"));
492 				LOG(4,("clock=%f MHz\n", timing->pixel_clock / 100.0));
493 				LOG(4,("h: (%d, %d, %d, %d)\n",
494 					timing->h_active, timing->h_active + timing->h_sync_off,
495 					timing->h_active + timing->h_sync_off + timing->h_sync_width,
496 					timing->h_active + timing->h_blank));
497 				LOG(4,("v: (%d, %d, %d, %d)\n",
498 					timing->v_active, timing->v_active + timing->v_sync_off,
499 					timing->v_active + timing->v_sync_off + timing->v_sync_width,
500 					timing->v_active + timing->v_blank));
501 				LOG(4,("size: %.1f cm x %.1f cm\n",
502 					timing->h_size / 10.0, timing->v_size / 10.0));
503 				LOG(4,("border: %.1f cm x %.1f cm\n",
504 					timing->h_border / 10.0, timing->v_border / 10.0));
505 				break;
506 			}
507 		}
508 	}
509 }
510 
511 /* callback for getting signals from I2C bus */
512 static status_t
513 get_signals(void *cookie, int *clk, int *data)
514 {
515 	ddc_port_info *info = (ddc_port_info *)cookie;
516 
517 	*clk = *data = 0x0000;
518 	if (InSCL(info->port)) *clk = 0x0001;
519 	if (InSDA(info->port)) *data = 0x0001;
520 
521 	return B_OK;
522 }
523 
524 /* callback for setting signals on I2C bus */
525 static status_t
526 set_signals(void *cookie, int clk, int data)
527 {
528 	ddc_port_info *info = (ddc_port_info *)cookie;
529 
530 	if (clk)
531 		OutSCL(info->port, true);
532 	else
533 		OutSCL(info->port, false);
534 
535 	if (data)
536 		OutSDA(info->port, true);
537 	else
538 		OutSDA(info->port, false);
539 
540 	return B_OK;
541 }
542 
543 /* Read EDID information from monitor via the display data channel (DDC) */
544 static status_t
545 i2c_ReadEDID(uint8 BusNR, edid1_info *edid)
546 {
547 	i2c_bus bus;
548 	ddc_port_info info;
549 
550 	info.port = BusNR;
551 
552 	bus.cookie = &info;
553 	bus.set_signals = &set_signals;
554 	bus.get_signals = &get_signals;
555 	ddc2_init_timing(&bus);
556 
557 	/* select GPU I/O pins set */
558 	i2c_select_bus_set(BusNR & 0x02);
559 
560 	/* enable access to primary head */
561 	set_crtc_owner(0);
562 
563 	if (ddc2_read_edid1(&bus, edid, NULL, NULL) == B_OK) {
564 		LOG(4,("I2C: EDID succesfully read from monitor at bus %d\n", BusNR));
565 		LOG(4,("I2C: EDID dump follows (bus %d):\n", BusNR));
566 		i2c_DumpEDID(edid);
567 		LOG(4,("I2C: end EDID dump (bus %d).\n", BusNR));
568 	} else {
569 		LOG(4,("I2C: reading EDID failed at bus %d!\n", BusNR));
570 		return B_ERROR;
571 	}
572 
573 	return B_OK;
574 }
575 
576 void i2c_TestEDID(void)
577 {
578 	uint8 bus;
579 	edid1_info edid;
580 	bool *i2c_bus = &(si->ps.i2c_bus0);
581 
582 	/* test wired bus(es) */
583 	for (bus = 0; bus < 4; bus++) {
584 		if (i2c_bus[bus])
585 			i2c_ReadEDID(bus, &edid);
586 	}
587 }
588 
589 static status_t
590 i2c_ExtractSpecsEDID(edid1_info* edid, edid_specs* specs)
591 {
592 	uint32 i;
593 	edid1_detailed_timing edid_timing;
594 
595 	specs->have_edid = false;
596 	specs->timing.h_display = 0;
597 	specs->timing.v_display = 0;
598 
599 	/* find the optimum (native) modeline */
600 	for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
601 		switch(edid->detailed_monitor[i].monitor_desc_type) {
602 		case EDID1_IS_DETAILED_TIMING:
603 			// TODO: handle flags correctly!
604 			edid_timing = edid->detailed_monitor[i].data.detailed_timing;
605 
606 			if (edid_timing.pixel_clock <= 0/* || edid_timing.sync != 3*/)
607 				break;
608 
609 			/* we want the optimum (native) modeline only, widescreen if possible.
610 			 * So only check for horizontal display, not for vertical display. */
611 			if (edid_timing.h_active <= specs->timing.h_display)
612 				break;
613 
614 			specs->timing.pixel_clock = edid_timing.pixel_clock * 10;
615 			specs->timing.h_display = edid_timing.h_active;
616 			specs->timing.h_sync_start = edid_timing.h_active + edid_timing.h_sync_off;
617 			specs->timing.h_sync_end = specs->timing.h_sync_start + edid_timing.h_sync_width;
618 			specs->timing.h_total = specs->timing.h_display + edid_timing.h_blank;
619 			specs->timing.v_display = edid_timing.v_active;
620 			specs->timing.v_sync_start = edid_timing.v_active + edid_timing.v_sync_off;
621 			specs->timing.v_sync_end = specs->timing.v_sync_start + edid_timing.v_sync_width;
622 			specs->timing.v_total = specs->timing.v_display + edid_timing.v_blank;
623 			specs->timing.flags = 0;
624 			if (edid_timing.sync == 3) {
625 				if (edid_timing.misc & 1)
626 					specs->timing.flags |= B_POSITIVE_HSYNC;
627 				if (edid_timing.misc & 2)
628 					specs->timing.flags |= B_POSITIVE_VSYNC;
629 			}
630 			if (edid_timing.interlaced)
631 				specs->timing.flags |= B_TIMING_INTERLACED;
632 			break;
633 		}
634 	}
635 
636 	/* check if we actually got a modeline */
637 	if (!specs->timing.h_display || !specs->timing.v_display) return B_ERROR;
638 
639 	/* we succesfully fetched the specs we need */
640 	specs->have_edid = true;
641 
642 	/* determine screen aspect ratio */
643 	specs->aspect =
644 		(specs->timing.h_display / ((float)specs->timing.v_display));
645 
646 	/* determine connection type */
647 	specs->digital = false;
648 	if (edid->display.input_type) specs->digital = true;
649 
650 	return B_OK;
651 }
652 
653 /* Dump EDID info in driver's logfile */
654 static void
655 i2c_DumpSpecsEDID(edid_specs* specs)
656 {
657 	LOG(4,("I2C: specsEDID: have_edid: %s\n", specs->have_edid ? "True" : "False"));
658 	if (!specs->have_edid) return;
659 	LOG(4,("I2C: specsEDID: timing.pixel_clock %.3f Mhz\n", specs->timing.pixel_clock / 1000.0));
660 	LOG(4,("I2C: specsEDID: timing.h_display %d\n", specs->timing.h_display));
661 	LOG(4,("I2C: specsEDID: timing.h_sync_start %d\n", specs->timing.h_sync_start));
662 	LOG(4,("I2C: specsEDID: timing.h_sync_end %d\n", specs->timing.h_sync_end));
663 	LOG(4,("I2C: specsEDID: timing.h_total %d\n", specs->timing.h_total));
664 	LOG(4,("I2C: specsEDID: timing.v_display %d\n", specs->timing.v_display));
665 	LOG(4,("I2C: specsEDID: timing.v_sync_start %d\n", specs->timing.v_sync_start));
666 	LOG(4,("I2C: specsEDID: timing.v_sync_end %d\n", specs->timing.v_sync_end));
667 	LOG(4,("I2C: specsEDID: timing.v_total %d\n", specs->timing.v_total));
668 	LOG(4,("I2C: specsEDID: timing.flags $%08x\n", specs->timing.flags));
669 	LOG(4,("I2C: specsEDID: aspect: %1.2f\n", specs->aspect));
670 	LOG(4,("I2C: specsEDID: digital: %s\n", specs->digital ? "True" : "False"));
671 }
672 
673 /* notes:
674  * - con1 resides closest to the mainboard on for example NV25 and NV28, while for
675  *   example on NV34 con2 sits closest to the mainboard.
676  * - i2c bus0 is connected to con1, and i2c bus1 is connected to con2 on all pre-NV40
677  *   architecture cards. On later cards it's vice versa. */
678 //>>>fixme:
679 //- re-check if the latter note is true,
680 //- and check if it's dependant on the DAC cross connection switch..
681 //- and check if analog or digital connection type influences this..
682 void i2c_DetectScreens(void)
683 {
684 	edid1_info edid;
685 
686 	si->ps.con1_screen.have_edid = false;
687 	si->ps.con2_screen.have_edid = false;
688 
689 	/* check existance of bus 0 */
690 	if (!si->ps.i2c_bus0) return;
691 
692 	/* check I2C bus 0 for an EDID capable screen */
693 	if (i2c_ReadEDID(0, &edid) == B_OK) {
694 		/* fetch optimum (native) modeline */
695 		switch (si->ps.card_arch) {
696 		case NV40A:
697 			i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen);
698 			break;
699 		default:
700 			i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen);
701 			break;
702 		}
703 	}
704 
705 	/* check existance of bus 1 */
706 	if (!si->ps.i2c_bus1) return;
707 
708 	/* check I2C bus 1 for an EDID screen */
709 	if (i2c_ReadEDID(1, &edid) == B_OK) {
710 		/* fetch optimum (native) modeline */
711 		switch (si->ps.card_arch) {
712 		case NV40A:
713 			i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen);
714 			break;
715 		default:
716 			i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen);
717 			break;
718 		}
719 	}
720 }
721