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