From 42529205ad4178166f00f66427ceaa514af0627f Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Thu, 27 Aug 2009 20:26:31 +0000 Subject: [PATCH] added support for haiku specific driverhook GET_PREFERRED_DISPLAY_MODE. Now laptops and other systems where EDID fails but a screen is digitally connected should also come up in their native modes from first system boot on.Updated docs. Bumped version to 0.97. +alphabranch git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32765 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../accelerants/nvidia/GetAccelerantHook.c | 1 + .../accelerants/nvidia/GetDeviceInfo.c | 100 ++++++++++++++---- .../accelerants/nvidia/ProposeDisplayMode.c | 6 +- .../accelerants/nvidia/be_driver_proto.h | 1 + .../accelerants/nvidia/engine/nv_general.c | 2 +- .../accelerants/nvidia/engine/nv_info.c | 57 +++++----- .../accelerants/nvidia/engine/nv_proto.h | 2 + .../drivers/graphics/nvidia/UPDATE.html | 7 +- 8 files changed, 118 insertions(+), 58 deletions(-) diff --git a/src/add-ons/accelerants/nvidia/GetAccelerantHook.c b/src/add-ons/accelerants/nvidia/GetAccelerantHook.c index 8ef60a5a67..db714ff565 100644 --- a/src/add-ons/accelerants/nvidia/GetAccelerantHook.c +++ b/src/add-ons/accelerants/nvidia/GetAccelerantHook.c @@ -65,6 +65,7 @@ void * get_accelerant_hook(uint32 feature, void *data) HOOK(GET_DISPLAY_MODE); #ifdef __HAIKU__ HOOK(GET_EDID_INFO); + HOOK(GET_PREFERRED_DISPLAY_MODE); #endif HOOK(GET_FRAME_BUFFER_CONFIG); HOOK(GET_PIXEL_CLOCK_LIMITS); diff --git a/src/add-ons/accelerants/nvidia/GetDeviceInfo.c b/src/add-ons/accelerants/nvidia/GetDeviceInfo.c index f11a8a887a..abdc7e0158 100644 --- a/src/add-ons/accelerants/nvidia/GetDeviceInfo.c +++ b/src/add-ons/accelerants/nvidia/GetDeviceInfo.c @@ -26,9 +26,10 @@ status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi) #ifdef __HAIKU__ +/* Get the info fetched from the attached screen */ status_t GET_EDID_INFO(void* info, size_t size, uint32* _version) { - if ((!si->ps.crtc1_screen.have_full_edid) && (!si->ps.crtc2_screen.have_full_edid)) { + if (!si->ps.crtc1_screen.have_full_edid && !si->ps.crtc2_screen.have_full_edid) { LOG(4,("GET_EDID_INFO: EDID info not available\n")); return B_ERROR; } @@ -40,28 +41,31 @@ status_t GET_EDID_INFO(void* info, size_t size, uint32* _version) LOG(4,("GET_EDID_INFO: returning info\n")); /* if we have two screens, make the best of it (go for the best compatible info) */ - if ((si->ps.crtc1_screen.have_full_edid) && (si->ps.crtc2_screen.have_full_edid)) { - /* return info on screen with lowest aspect (4:3 takes precedence over ws) */ - if (si->ps.crtc1_screen.aspect < si->ps.crtc2_screen.aspect) + if (si->ps.crtc1_screen.have_full_edid && si->ps.crtc2_screen.have_full_edid) { + /* return info on screen with lowest aspect (4:3 takes precedence over ws) + * NOTE: + * allow 0.10 difference so 4:3 and 5:4 aspect screens are regarded as being the same. */ + if (si->ps.crtc1_screen.aspect < (si->ps.crtc2_screen.aspect - 0.10)) { memcpy(info, &si->ps.crtc1_screen.full_edid, sizeof(struct edid1_info)); - if (si->ps.crtc1_screen.aspect > si->ps.crtc2_screen.aspect) - memcpy(info, &si->ps.crtc2_screen.full_edid, sizeof(struct edid1_info)); - - /* if both screens have the same aspect, return info on the one with - * the lowest native resolution */ - if (si->ps.crtc1_screen.aspect == si->ps.crtc2_screen.aspect) { - if ((si->ps.crtc1_screen.timing.h_display) < (si->ps.crtc2_screen.timing.h_display)) - memcpy(info, &si->ps.crtc1_screen.full_edid, sizeof(struct edid1_info)); - if ((si->ps.crtc1_screen.timing.h_display) > (si->ps.crtc2_screen.timing.h_display)) + } else { + if (si->ps.crtc1_screen.aspect > (si->ps.crtc2_screen.aspect + 0.10)) { memcpy(info, &si->ps.crtc2_screen.full_edid, sizeof(struct edid1_info)); - - /* if both screens have the same resolution and aspect, return info on the - * one used as main screen */ - if ((si->ps.crtc1_screen.timing.h_display) == (si->ps.crtc2_screen.timing.h_display)) { - if (si->ps.crtc2_prim) - memcpy(info, &si->ps.crtc2_screen.full_edid, sizeof(struct edid1_info)); - else + } else { + /* both screens have the same aspect, return info on the one with + * the lowest native resolution */ + if (si->ps.crtc1_screen.timing.h_display < si->ps.crtc2_screen.timing.h_display) memcpy(info, &si->ps.crtc1_screen.full_edid, sizeof(struct edid1_info)); + if (si->ps.crtc1_screen.timing.h_display > si->ps.crtc2_screen.timing.h_display) + memcpy(info, &si->ps.crtc2_screen.full_edid, sizeof(struct edid1_info)); + + /* if both screens have the same resolution and aspect, return info on the + * one used as main screen */ + if (si->ps.crtc1_screen.timing.h_display == si->ps.crtc2_screen.timing.h_display) { + if (si->ps.crtc2_prim) + memcpy(info, &si->ps.crtc2_screen.full_edid, sizeof(struct edid1_info)); + else + memcpy(info, &si->ps.crtc1_screen.full_edid, sizeof(struct edid1_info)); + } } } } else { @@ -76,4 +80,60 @@ status_t GET_EDID_INFO(void* info, size_t size, uint32* _version) return B_OK; } +/* Return the optimum (native) mode for the attached screen */ +status_t GET_PREFERRED_DISPLAY_MODE(display_mode* preferredMode) +{ + if (si->ps.crtc1_screen.have_full_edid || si->ps.crtc2_screen.have_full_edid) { + LOG(4,("GET_PREFERRED_DISPLAY_MODE: full EDID known, aborting (fetch EDID instead).\n")); + return B_ERROR; + } + + if (!si->ps.crtc1_screen.have_native_edid && !si->ps.crtc2_screen.have_native_edid) { + LOG(4,("GET_PREFERRED_DISPLAY_MODE: native mode(s) not known\n")); + return B_ERROR; + } + + /* if we got here then we're probably on a laptop, but DDC/EDID may have failed + * for another reason as well. */ + LOG(4,("GET_PREFERRED_DISPLAY_MODE: returning mode\n")); + + /* if we have two screens, make the best of it (go for the best compatible mode) */ + if (si->ps.crtc1_screen.have_native_edid && si->ps.crtc2_screen.have_native_edid) { + /* return mode of screen with lowest aspect (4:3 takes precedence over ws) + * NOTE: + * allow 0.10 difference so 4:3 and 5:4 aspect screens are regarded as being the same. */ + if (si->ps.crtc1_screen.aspect < (si->ps.crtc2_screen.aspect - 0.10)) { + get_crtc1_screen_native_mode(preferredMode); + } else { + if (si->ps.crtc1_screen.aspect > (si->ps.crtc2_screen.aspect + 0.10)) { + get_crtc2_screen_native_mode(preferredMode); + } else { + /* both screens have the same aspect, return mode of the one with + * the lowest native resolution */ + if (si->ps.crtc1_screen.timing.h_display < si->ps.crtc2_screen.timing.h_display) + get_crtc1_screen_native_mode(preferredMode); + if (si->ps.crtc1_screen.timing.h_display > si->ps.crtc2_screen.timing.h_display) + get_crtc2_screen_native_mode(preferredMode); + + /* if both screens have the same resolution and aspect, return mode of the + * one used as main screen */ + if (si->ps.crtc1_screen.timing.h_display == si->ps.crtc2_screen.timing.h_display) { + if (si->ps.crtc2_prim) + get_crtc2_screen_native_mode(preferredMode); + else + get_crtc1_screen_native_mode(preferredMode); + } + } + } + } else { + /* there's just one screen of which we have native mode information, return it's mode */ + if (si->ps.crtc1_screen.have_native_edid) + get_crtc1_screen_native_mode(preferredMode); + else + get_crtc2_screen_native_mode(preferredMode); + } + + return B_OK; +} + #endif // __HAIKU__ diff --git a/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c b/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c index 1a8f375986..b8141a998e 100644 --- a/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c +++ b/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c @@ -163,14 +163,14 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const displa case CRTC1_TMDS: /* digital panel on head 1, nothing on head 2 */ case CRTC1_VGA: /* analog connected screen on head 1, nothing on head 2 */ if (si->ps.crtc1_screen.aspect < (target_aspect - 0.10)) { - LOG(4, ("PROPOSEMODE: screen at crtc1 is not widescreen type, aborted.\n")); + LOG(4, ("PROPOSEMODE: screen at crtc1 is not widescreen (enough) type, aborted.\n")); return B_ERROR; } break; case CRTC2_TMDS: /* nothing on head 1, digital panel on head 2 */ case CRTC2_VGA: /* analog connected screen on head 2, nothing on head 1 */ if (si->ps.crtc2_screen.aspect < (target_aspect - 0.10)) { - LOG(4, ("PROPOSEMODE: screen at crtc2 is not widescreen type, aborted.\n")); + LOG(4, ("PROPOSEMODE: screen at crtc2 is not widescreen (enough) type, aborted.\n")); return B_ERROR; } break; @@ -181,7 +181,7 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const displa default: /* more than two screens connected (illegal setup) */ if ((si->ps.crtc1_screen.aspect < (target_aspect - 0.10)) || (si->ps.crtc2_screen.aspect < (target_aspect - 0.10))) { - LOG(4, ("PROPOSEMODE: not all connected screens are widescreen type, aborted.\n")); + LOG(4, ("PROPOSEMODE: not all connected screens are widescreen (enough) type, aborted.\n")); return B_ERROR; } break; diff --git a/src/add-ons/accelerants/nvidia/be_driver_proto.h b/src/add-ons/accelerants/nvidia/be_driver_proto.h index d54b7e26ce..6080569eb7 100644 --- a/src/add-ons/accelerants/nvidia/be_driver_proto.h +++ b/src/add-ons/accelerants/nvidia/be_driver_proto.h @@ -28,6 +28,7 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set); status_t GET_DISPLAY_MODE(display_mode *current_mode); #ifdef __HAIKU__ status_t GET_EDID_INFO(void* info, size_t size, uint32* _version); +status_t GET_PREFERRED_DISPLAY_MODE(display_mode* preferredMode); #endif status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer); status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high); diff --git a/src/add-ons/accelerants/nvidia/engine/nv_general.c b/src/add-ons/accelerants/nvidia/engine/nv_general.c index fc3df5b71f..c967440680 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_general.c +++ b/src/add-ons/accelerants/nvidia/engine/nv_general.c @@ -92,7 +92,7 @@ status_t nv_general_powerup() { status_t status; - LOG(1,("POWERUP: Haiku nVidia Accelerant 0.96 running.\n")); + LOG(1,("POWERUP: Haiku nVidia Accelerant 0.97 running.\n")); /* log VBLANK INT usability status */ if (si->ps.int_assigned) diff --git a/src/add-ons/accelerants/nvidia/engine/nv_info.c b/src/add-ons/accelerants/nvidia/engine/nv_info.c index 35949b7220..ce76e45c1a 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_info.c +++ b/src/add-ons/accelerants/nvidia/engine/nv_info.c @@ -2897,39 +2897,34 @@ static void setup_output_matrix() } } -void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2) +status_t get_crtc1_screen_native_mode(display_mode *mode) { - if (si->ps.monitors & CRTC1_TMDS) - { - /* timing ('modeline') */ - p1->timing = si->ps.p1_timing; - /* setup the rest */ - p1->space = B_CMAP8; - p1->virtual_width = p1->timing.h_display; - p1->virtual_height = p1->timing.v_display; - p1->h_display_start = 0; - p1->v_display_start = 0; - p1->flags = 0; - *pan1 = true; - } - else - *pan1 = false; + if (!si->ps.crtc1_screen.have_native_edid) return B_ERROR; - if (si->ps.monitors & CRTC2_TMDS) - { - /* timing ('modeline') */ - p2->timing = si->ps.p2_timing; - /* setup the rest */ - p2->space = B_CMAP8; - p2->virtual_width = p2->timing.h_display; - p2->virtual_height = p2->timing.v_display; - p2->h_display_start = 0; - p2->v_display_start = 0; - p2->flags = 0; - *pan2 = true; - } - else - *pan2 = false; + mode->space = B_RGB32_LITTLE; + mode->virtual_width = si->ps.crtc1_screen.timing.h_display; + mode->virtual_height = si->ps.crtc1_screen.timing.v_display; + mode->h_display_start = 0; + mode->v_display_start = 0; + mode->flags = 0; + memcpy(&mode->timing, &si->ps.crtc1_screen.timing, sizeof(mode->timing)); + + return B_OK; +} + +status_t get_crtc2_screen_native_mode(display_mode *mode) +{ + if (!si->ps.crtc2_screen.have_native_edid) return B_ERROR; + + mode->space = B_RGB32_LITTLE; + mode->virtual_width = si->ps.crtc2_screen.timing.h_display; + mode->virtual_height = si->ps.crtc2_screen.timing.v_display; + mode->h_display_start = 0; + mode->v_display_start = 0; + mode->flags = 0; + memcpy(&mode->timing, &si->ps.crtc2_screen.timing, sizeof(mode->timing)); + + return B_OK; } static void pinsnv4_fake(void) diff --git a/src/add-ons/accelerants/nvidia/engine/nv_proto.h b/src/add-ons/accelerants/nvidia/engine/nv_proto.h index bd3c822d74..047eb7bbed 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_proto.h +++ b/src/add-ons/accelerants/nvidia/engine/nv_proto.h @@ -42,6 +42,8 @@ status_t parse_pins(void); void set_pll(uint32 reg, uint32 clk); void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2); void fake_panel_start(void); +status_t get_crtc1_screen_native_mode(display_mode *mode); +status_t get_crtc2_screen_native_mode(display_mode *mode); void set_specs(void); void dump_pins(void); diff --git a/src/add-ons/kernel/drivers/graphics/nvidia/UPDATE.html b/src/add-ons/kernel/drivers/graphics/nvidia/UPDATE.html index 0142611ab2..a37f0b9c5a 100644 --- a/src/add-ons/kernel/drivers/graphics/nvidia/UPDATE.html +++ b/src/add-ons/kernel/drivers/graphics/nvidia/UPDATE.html @@ -4,7 +4,7 @@

Changes done for each driverversion:

-

head (SVN 0.96, Rudolf)

+

head (SVN 0.97, Rudolf)

nv_driver 0.80 (Rudolf)