From 21bade017a1e67864f01a412f56c6baaad4e3db3 Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Wed, 27 May 2009 18:46:07 +0000 Subject: [PATCH] added more EDID stuff. Now extracting needed monitor specs and placing them in shared_info. More dumping to logfile added. The EDID info is not yet actually used: more testing is needed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30880 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../private/graphics/nvidia/DriverInterface.h | 12 +- .../accelerants/nvidia/engine/nv_i2c.c | 149 +++++++++++++++++- .../accelerants/nvidia/engine/nv_info.c | 17 +- .../accelerants/nvidia/engine/nv_proto.h | 2 +- 4 files changed, 163 insertions(+), 17 deletions(-) diff --git a/headers/private/graphics/nvidia/DriverInterface.h b/headers/private/graphics/nvidia/DriverInterface.h index 0009cb0306..c15684f939 100644 --- a/headers/private/graphics/nvidia/DriverInterface.h +++ b/headers/private/graphics/nvidia/DriverInterface.h @@ -5,7 +5,7 @@ Other authors: Mark Watson; Apsed; - Rudolf Cornelissen 10/2002-3/2009. + Rudolf Cornelissen 10/2002-5/2009. */ #ifndef DRIVERINTERFACE_H @@ -229,6 +229,14 @@ typedef struct { // apsed, see comments in nvidia.settings uint32 ram_clk; } nv_settings; +/* monitor info gathered via EDID */ +typedef struct { + bool have_edid; /* have read useable edid info from screen */ + bool digital; /* screen connection type: analog (VGA) or digital (DVI) */ + display_timing timing; /* 'native modeline' fetched for screen */ + float aspect; /* screen's aspect ratio */ +} edid_specs; + /* shared info */ typedef struct { /* a few ID things */ @@ -342,6 +350,8 @@ typedef struct { display_timing p2_timing; /* 'modeline' fetched for panel 2 */ float panel1_aspect; /* panel's aspect ratio */ float panel2_aspect; /* panel's aspect ratio */ + edid_specs con1_screen; /* EDID properties of the screen connected to connector 1 */ + edid_specs con2_screen; /* EDID properties of the screen connected to connector 1 */ bool crtc2_prim; /* using CRTC2 as primary CRTC */ bool i2c_bus0; /* we have a wired I2C bus 0 on board */ bool i2c_bus1; /* we have a wired I2C bus 1 on board */ diff --git a/src/add-ons/accelerants/nvidia/engine/nv_i2c.c b/src/add-ons/accelerants/nvidia/engine/nv_i2c.c index 2f8f0166cc..6b533cc2d1 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_i2c.c +++ b/src/add-ons/accelerants/nvidia/engine/nv_i2c.c @@ -9,6 +9,8 @@ #include "nv_std.h" +static void i2c_DumpSpecsEDID(edid_specs* specs); + char i2c_flag_error (char ErrNo) //error code list: //0 - OK status @@ -340,7 +342,12 @@ status_t i2c_init(void) LOG(4,("I2C: bus #%d wiring check: failed\n", bus)); } - i2c_TestEDID(); + //i2c_TestEDID(); + i2c_DetectScreens(); + LOG(4,("I2C: dumping EDID specs for connector 1:\n")); + i2c_DumpSpecsEDID(&si->ps.con1_screen); + LOG(4,("I2C: dumping EDID specs for connector 2:\n")); + i2c_DumpSpecsEDID(&si->ps.con2_screen); return result; } @@ -352,7 +359,7 @@ typedef struct { /* Dump EDID info in driver's logfile */ static void -i2c_edid_dump(edid1_info *edid) +i2c_DumpEDID(edid1_info *edid) { int i, j; @@ -534,7 +541,7 @@ set_signals(void *cookie, int clk, int data) } /* Read EDID information from monitor via the display data channel (DDC) */ -status_t +static status_t i2c_ReadEDID(uint8 BusNR, edid1_info *edid) { i2c_bus bus; @@ -556,8 +563,7 @@ i2c_ReadEDID(uint8 BusNR, edid1_info *edid) if (ddc2_read_edid1(&bus, edid, NULL, NULL) == B_OK) { LOG(4,("I2C: EDID succesfully read from monitor at bus %d\n", BusNR)); LOG(4,("I2C: EDID dump follows (bus %d):\n", BusNR)); -// has_edid = true; - i2c_edid_dump(edid); + i2c_DumpEDID(edid); LOG(4,("I2C: end EDID dump (bus %d).\n", BusNR)); } else { LOG(4,("I2C: reading EDID failed at bus %d!\n", BusNR)); @@ -579,3 +585,136 @@ void i2c_TestEDID(void) i2c_ReadEDID(bus, &edid); } } + +static status_t +i2c_ExtractSpecsEDID(edid1_info* edid, edid_specs* specs) +{ + uint32 i; + edid1_detailed_timing edid_timing; + + specs->have_edid = false; + specs->timing.h_display = 0; + specs->timing.v_display = 0; + + /* find the optimum (native) modeline */ + for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { + switch(edid->detailed_monitor[i].monitor_desc_type) { + case EDID1_IS_DETAILED_TIMING: + // TODO: handle flags correctly! + edid_timing = edid->detailed_monitor[i].data.detailed_timing; + + if (edid_timing.pixel_clock <= 0/* || edid_timing.sync != 3*/) + break; + + /* we want the optimum (native) modeline only, widescreen if possible. + * So only check for horizontal display, not for vertical display. */ + if (edid_timing.h_active <= specs->timing.h_display) + break; + + specs->timing.pixel_clock = edid_timing.pixel_clock * 10; + specs->timing.h_display = edid_timing.h_active; + specs->timing.h_sync_start = edid_timing.h_active + edid_timing.h_sync_off; + specs->timing.h_sync_end = specs->timing.h_sync_start + edid_timing.h_sync_width; + specs->timing.h_total = specs->timing.h_display + edid_timing.h_blank; + specs->timing.v_display = edid_timing.v_active; + specs->timing.v_sync_start = edid_timing.v_active + edid_timing.v_sync_off; + specs->timing.v_sync_end = specs->timing.v_sync_start + edid_timing.v_sync_width; + specs->timing.v_total = specs->timing.v_display + edid_timing.v_blank; + specs->timing.flags = 0; + if (edid_timing.sync == 3) { + if (edid_timing.misc & 1) + specs->timing.flags |= B_POSITIVE_HSYNC; + if (edid_timing.misc & 2) + specs->timing.flags |= B_POSITIVE_VSYNC; + } + if (edid_timing.interlaced) + specs->timing.flags |= B_TIMING_INTERLACED; + break; + } + } + + /* check if we actually got a modeline */ + if (!specs->timing.h_display || !specs->timing.v_display) return B_ERROR; + + /* we succesfully fetched the specs we need */ + specs->have_edid = true; + + /* determine screen aspect ratio */ + specs->aspect = + (specs->timing.h_display / ((float)specs->timing.v_display)); + + /* determine connection type */ + specs->digital = false; + if (edid->display.input_type) specs->digital = true; + + return B_OK; +} + +/* Dump EDID info in driver's logfile */ +static void +i2c_DumpSpecsEDID(edid_specs* specs) +{ + LOG(4,("I2C: specsEDID: have_edid: %s\n", specs->have_edid ? "True" : "False")); + if (!specs->have_edid) return; + LOG(4,("I2C: specsEDID: timing.pixel_clock %.3f Mhz\n", specs->timing.pixel_clock / 1000.0)); + LOG(4,("I2C: specsEDID: timing.h_display %d\n", specs->timing.h_display)); + LOG(4,("I2C: specsEDID: timing.h_sync_start %d\n", specs->timing.h_sync_start)); + LOG(4,("I2C: specsEDID: timing.h_sync_end %d\n", specs->timing.h_sync_end)); + LOG(4,("I2C: specsEDID: timing.h_total %d\n", specs->timing.h_total)); + LOG(4,("I2C: specsEDID: timing.v_display %d\n", specs->timing.v_display)); + LOG(4,("I2C: specsEDID: timing.v_sync_start %d\n", specs->timing.v_sync_start)); + LOG(4,("I2C: specsEDID: timing.v_sync_end %d\n", specs->timing.v_sync_end)); + LOG(4,("I2C: specsEDID: timing.v_total %d\n", specs->timing.v_total)); + LOG(4,("I2C: specsEDID: timing.flags $%08x\n", specs->timing.flags)); + LOG(4,("I2C: specsEDID: aspect: %1.2f\n", specs->aspect)); + LOG(4,("I2C: specsEDID: digital: %s\n", specs->digital ? "True" : "False")); +} + +/* notes: + * - con1 resides closest to the mainboard on for example NV25 and NV28, while for + * example on NV34 con2 sits closest to the mainboard. + * - con1 is connected to DAC1, and con2 is connected to DAC2 on all pre-NV40 + * architecture cards. On later cards it's vice versa. */ +//>>>fixme: +//- re-check if the latter note is true, +//- and check if it's dependant on the DAC cross connection switch.. +//- and check if analog or digital connection type influences this.. +void i2c_DetectScreens(void) +{ + edid1_info edid; + + si->ps.con1_screen.have_edid = false; + si->ps.con2_screen.have_edid = false; + + /* check existance of bus 0 */ + if (!si->ps.i2c_bus0) return; + + /* check I2C bus 0 for an EDID capable screen */ + if (i2c_ReadEDID(0, &edid) == B_OK) { + /* fetch optimum (native) modeline */ + switch (si->ps.card_arch) { + case NV40A: + i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen); + break; + default: + i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen); + break; + } + } + + /* check existance of bus 1 */ + if (!si->ps.i2c_bus1) return; + + /* check I2C bus 1 for an EDID screen */ + if (i2c_ReadEDID(1, &edid) == B_OK) { + /* fetch optimum (native) modeline */ + switch (si->ps.card_arch) { + case NV40A: + i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen); + break; + default: + i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen); + break; + } + } +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_info.c b/src/add-ons/accelerants/nvidia/engine/nv_info.c index 49a6c65cee..763884d46c 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_info.c +++ b/src/add-ons/accelerants/nvidia/engine/nv_info.c @@ -3175,8 +3175,7 @@ void dump_pins(void) char *msg = ""; LOG(2,("INFO: pinsdump follows:\n")); - LOG(2,("PLL type: ")); - if (si->ps.ext_pll) LOG(2,("extended\n")); else LOG(2,("standard\n")); + LOG(2,("PLL type: %s\n", si->ps.ext_pll ? "extended" : "standard")); LOG(2,("f_ref: %fMhz\n", si->ps.f_ref)); LOG(2,("max_system_vco: %dMhz\n", si->ps.max_system_vco)); LOG(2,("min_system_vco: %dMhz\n", si->ps.min_system_vco)); @@ -3198,10 +3197,8 @@ void dump_pins(void) LOG(2,("max_dac2_clock_24: %dMhz\n", si->ps.max_dac2_clock_24)); LOG(2,("max_dac2_clock_32: %dMhz\n", si->ps.max_dac2_clock_32)); LOG(2,("max_dac2_clock_32dh: %dMhz\n", si->ps.max_dac2_clock_32dh)); - LOG(2,("secondary_head: ")); - if (si->ps.secondary_head) LOG(2,("present\n")); else LOG(2,("absent\n")); - LOG(2,("tvout: ")); - if (si->ps.tvout) LOG(2,("present\n")); else LOG(2,("absent\n")); + LOG(2,("secondary_head: %s\n", si->ps.secondary_head ? "present" : "absent")); + LOG(2,("tvout: %s\n", si->ps.tvout ? "present" : "absent")); /* setup TVout logmessage text */ switch (si->ps.tv_encoder.type) { @@ -3268,15 +3265,15 @@ void dump_pins(void) if (si->ps.laptop) LOG(2,("yes\n")); else LOG(2,("no\n")); if (si->ps.tmds1_active) { - LOG(2,("found DFP (digital flatpanel) on CRTC1; CRTC1 is ")); - if (si->ps.slaved_tmds1) LOG(2,("slaved\n")); else LOG(2,("master\n")); + LOG(2,("found DFP (digital flatpanel) on CRTC1; CRTC1 is %s\n", + si->ps.slaved_tmds1 ? "slaved" : "master")); LOG(2,("panel width: %d, height: %d, aspect ratio: %1.2f\n", si->ps.p1_timing.h_display, si->ps.p1_timing.v_display, si->ps.panel1_aspect)); } if (si->ps.tmds2_active) { - LOG(2,("found DFP (digital flatpanel) on CRTC2; CRTC2 is ")); - if (si->ps.slaved_tmds2) LOG(2,("slaved\n")); else LOG(2,("master\n")); + LOG(2,("found DFP (digital flatpanel) on CRTC2; CRTC2 is %s\n", + si->ps.slaved_tmds2 ? "slaved" : "master")); LOG(2,("panel width: %d, height: %d, aspect ratio: %1.2f\n", si->ps.p2_timing.h_display, si->ps.p2_timing.v_display, si->ps.panel2_aspect)); } diff --git a/src/add-ons/accelerants/nvidia/engine/nv_proto.h b/src/add-ons/accelerants/nvidia/engine/nv_proto.h index 193532823a..bd3c822d74 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_proto.h +++ b/src/add-ons/accelerants/nvidia/engine/nv_proto.h @@ -34,8 +34,8 @@ bool i2c_writebyte (uint8 BusNR, uint8 byte); void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size); void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size); status_t i2c_init(void); -status_t i2c_ReadEDID(uint8 BusNR, edid1_info *edid); void i2c_TestEDID(void); +void i2c_DetectScreens(void); /* card info functions */ status_t parse_pins(void);