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)
- Fixed driver assuming enabling AGP mode succeeded on some occasions if it did not block it itself. Blocking AGP mode completely via the AGP busmanager (option 'block_agp') resulted in a crashing acceleration engine because it was setup for AGP transfers instead of using PCI transfers. Error was solved with help from user kraton.
- Fixed shared_info struct problem occuring when 3D 'accelerant' is used (tested Alpha 4.1): the TVencoder type definition list apparantly gets some memory assigned these days when done inside the definition of shared_info. Moved encoder list outside the shared_info definition.
@@ -23,7 +23,8 @@
- Fixed acceleration engine crashes on at least G72 cards (Geforce 7300/7400/7500) by powering up new part(s) of the acceleration engines too..
- Modified GPU PTimer programming which according to the Nouveau project fixes LVDS panel programming in some cases.
- Corrected/Added detection of third I2C bus on cards that support it. The old detection method for a third and (non-existing) fourth bus was faulty. The driver uses I2C channels for monitor DDC/EDID and TVencoder communications.
-
- DDC/EDID fetching now also works on GCC4 binaries due to a fixed fault in the accelerants/common code (which is used for that function).
+
- DDC/EDID fetching now also works on GCC4 binaries due to a fixed fault in the accelerants/common code (which is used for that function);
+
- Added support for Haiku specific driverhook GET_PREFERRED_DISPLAY_MODE. Laptops should now also startup in native mode automatically at first system boot.
nv_driver 0.80 (Rudolf)
@@ -253,7 +254,7 @@ The features below are shutdown because they are possibly dangerous without feed
Still todo:
- Extend TVout feature to support more encoder-types (Chrontel, Philips);
-
- Improve/extend various stuff when/if possible (like extending the use of DDC/EDID).
+
- Improve/extend various stuff when/if possible.