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