driver now sets up internal EDID info related to CRTCs next to earlier introcuded code for EDID info related to connectors which makes it much more useable later on. This commit also hopefully fixes the problem introduced in R31183 shutting off some screens in 'invalid' connector setups that the driver tries to correct.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31291 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Rudolf Cornelissen 2009-06-28 14:53:07 +00:00
parent c1094043c9
commit c8453f43a4
5 changed files with 150 additions and 136 deletions

View File

@ -350,12 +350,12 @@ typedef struct {
bool slaved_tmds2; /* external TMDS encoder active on CRTC2 */
bool master_tmds1; /* on die TMDS encoder active on CRTC1 */
bool master_tmds2; /* on die TMDS encoder active on CRTC2 */
display_timing p1_timing; /* 'modeline' fetched for panel 1 */
display_timing p2_timing; /* 'modeline' fetched for panel 2 */
float crtc1_aspect; /* screen's aspect ratio */
float crtc2_aspect; /* screen's aspect ratio */
display_timing p1_timing; /* 'modeline' fetched for panel at CRTC1 */
display_timing p2_timing; /* 'modeline' fetched for panel at CRTC2 */
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 2 */
edid_specs crtc1_screen; /* EDID properties of the screen connected to CRTC1 */
edid_specs crtc2_screen; /* EDID properties of the screen connected to CRTC2 */
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 */

View File

@ -160,14 +160,14 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const displa
break;
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_aspect < (target_aspect - 0.10)) {
if (si->ps.crtc1_screen.aspect < (target_aspect - 0.10)) {
LOG(4, ("PROPOSEMODE: screen at crtc1 is not widescreen 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_aspect < (target_aspect - 0.10)) {
if (si->ps.crtc2_screen.aspect < (target_aspect - 0.10)) {
LOG(4, ("PROPOSEMODE: screen at crtc2 is not widescreen type, aborted.\n"));
return B_ERROR;
}
@ -177,8 +177,8 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const displa
case CRTC1_TMDS | CRTC2_VGA: /* digital panel on head 1, analog connected screen on head 2 */
case CRTC1_VGA | CRTC2_TMDS: /* analog connected screen on head 1, digital panel on head 2 */
default: /* more than two screens connected (illegal setup) */
if ((si->ps.crtc1_aspect < (target_aspect - 0.10)) ||
(si->ps.crtc2_aspect < (target_aspect - 0.10))) {
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"));
return B_ERROR;
}
@ -204,15 +204,15 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const displa
//still expand/update concerning edid, among others.. (setup accounting for cross-connected vga screens...):
/*
if (si->ps.monitors & CRTC1_VGA) {
if (target->timing.h_display > si->ps.xxx_timing.h_display
|| target->timing.v_display > si->ps.xxx_timing.v_display) {
if (target->timing.h_display > si->ps.crtc1_screen.timing.h_display
|| target->timing.v_display > si->ps.crtc1_screen.timing.v_display) {
LOG(4, ("PROPOSEMODE: analog screen at crtc1 can't display requested resolution, aborted.\n"));
return B_ERROR;
}
}
if (si->ps.monitors & CRTC2_VGA) {
if (target->timing.h_display > si->ps.yyy_timing.h_display
|| target->timing.v_display > si->ps.yyy_timing.v_display) {
if (target->timing.h_display > si->ps.crtc2_screen.timing.h_display
|| target->timing.v_display > si->ps.crtc2_screen.timing.v_display) {
LOG(4, ("PROPOSEMODE: analog screen at crtc2 can't display requested resolution, aborted.\n"));
return B_ERROR;
}

View File

@ -485,7 +485,7 @@ status_t nv_crtc_set_timing(display_mode target)
* 1400 x 1050 (1.33). */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_x != (1 << 12)) && (si->ps.crtc1_aspect > (dm_aspect + 0.10)))
if ((iscale_x != (1 << 12)) && (si->ps.crtc1_screen.aspect > (dm_aspect + 0.10)))
{
uint16 diff;
@ -505,7 +505,7 @@ status_t nv_crtc_set_timing(display_mode target)
/* correct for portrait panels... */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_y != (1 << 12)) && (si->ps.crtc1_aspect < (dm_aspect - 0.10)))
if ((iscale_y != (1 << 12)) && (si->ps.crtc1_screen.aspect < (dm_aspect - 0.10)))
{
LOG(2,("CRTC: (relative) portrait panel: should tune vertical scaling\n"));
/* fixme: implement if this kind of portrait panels exist on nVidia... */

View File

@ -468,7 +468,7 @@ status_t nv_crtc2_set_timing(display_mode target)
* 1400 x 1050 (1.33). */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_x != (1 << 12)) && (si->ps.crtc2_aspect > (dm_aspect + 0.10)))
if ((iscale_x != (1 << 12)) && (si->ps.crtc2_screen.aspect > (dm_aspect + 0.10)))
{
uint16 diff;
@ -488,7 +488,7 @@ status_t nv_crtc2_set_timing(display_mode target)
/* correct for portrait panels... */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_y != (1 << 12)) && (si->ps.crtc2_aspect < (dm_aspect - 0.10)))
if ((iscale_y != (1 << 12)) && (si->ps.crtc2_screen.aspect < (dm_aspect - 0.10)))
{
LOG(2,("CRTC2: (relative) portrait panel: should tune vertical scaling\n"));
/* fixme: implement if this kind of portrait panels exist on nVidia... */

View File

@ -2176,6 +2176,7 @@ void fake_panel_start(void)
si->ps.tvout = false;
si->ps.tv_encoder.type = NONE;
si->ps.tv_encoder.version = 0;
/* I2C init currently also fetches DDC EDID info from all connected screens */
i2c_init();
//fixme: add support for more encoders...
BT_probe();
@ -2280,10 +2281,10 @@ static void detect_panels()
/* do some presets */
si->ps.p1_timing.h_display = 0;
si->ps.p1_timing.v_display = 0;
si->ps.crtc1_aspect = 0;
si->ps.crtc1_screen.aspect = 0;
si->ps.p2_timing.h_display = 0;
si->ps.p2_timing.v_display = 0;
si->ps.crtc2_aspect = 0;
si->ps.crtc2_screen.aspect = 0;
si->ps.slaved_tmds1 = false;
si->ps.slaved_tmds2 = false;
si->ps.master_tmds1 = false;
@ -2415,10 +2416,8 @@ static void detect_panels()
if (si->ps.monitors & CRTC1_TMDS)
{
/* determine panel aspect ratio */
si->ps.crtc1_aspect =
si->ps.crtc1_screen.aspect =
(si->ps.p1_timing.h_display / ((float)si->ps.p1_timing.v_display));
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
/* horizontal timing */
si->ps.p1_timing.h_sync_start = (DACR(FP_HSYNC_S) & 0x0000ffff) + 1;
si->ps.p1_timing.h_sync_end = (DACR(FP_HSYNC_E) & 0x0000ffff) + 1;
@ -2441,10 +2440,8 @@ static void detect_panels()
if (si->ps.monitors & CRTC2_TMDS)
{
/* determine panel aspect ratio */
si->ps.crtc2_aspect =
si->ps.crtc2_screen.aspect =
(si->ps.p2_timing.h_display / ((float)si->ps.p2_timing.v_display));
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc2_aspect = 1.60;
/* horizontal timing */
si->ps.p2_timing.h_sync_start = (DAC2R(FP_HSYNC_S) & 0x0000ffff) + 1;
si->ps.p2_timing.h_sync_end = (DAC2R(FP_HSYNC_E) & 0x0000ffff) + 1;
@ -2525,6 +2522,10 @@ static void detect_panels()
LOG(2,("DAC2: PANEL_PWR: $%08x\n", NV_REG32(NV32_2PANEL_PWR)));
}
/* if something goes wrong during driver init reading those registers below might
* result in a hanging system. Without reading them at least a blind (or KDL)
* restart becomes possible. Leaving the code here for debugging purposes. */
if (0) {
/* determine flatpanel type(s) */
/* note:
* - on NV11 accessing registerset(s) hangs card.
@ -2555,6 +2556,7 @@ static void detect_panels()
else
LOG(2,("INFO: Flatpanel on head 2 is TMDS type\n"));
}
}
LOG(2,("INFO: End flatpanel registers dump.\n"));
}
@ -2564,56 +2566,113 @@ static void setup_output_matrix()
/* setup defaults: */
/* head 1 will be the primary head */
si->ps.crtc2_prim = false;
/* no screens usable */
si->ps.crtc1_screen.have_edid = false;
si->ps.crtc1_screen.timing.h_display = 0;
si->ps.crtc1_screen.timing.v_display = 0;
si->ps.crtc2_screen.have_edid = false;
si->ps.crtc2_screen.timing.h_display = 0;
si->ps.crtc2_screen.timing.v_display = 0;
/* setup output devices and heads */
if (si->ps.secondary_head)
{
if (si->ps.card_type != NV11)
{
/* setup defaults: */
/* connect analog outputs straight through */
/* connect analog outputs straight through if possible */
if ((si->ps.secondary_head) && (si->ps.card_type != NV11))
nv_general_output_select(false);
/* panels are pre-connected to a CRTC (1 or 2) by the card's BIOS,
* we can't change this (lack of info) */
/* detect analog monitors. First try EDID, else use load sensing. */
/* (load sensing is confirmed working OK on NV18, NV28 and NV34.) */
/* (load sensing is confirmed working OK on NV04, NV05, NV11, NV18, NV28 and NV34.) */
/* primary connector: */
if (si->ps.con1_screen.have_edid) {
if (!si->ps.con1_screen.digital) {
si->ps.monitors |= CRTC1_VGA;
si->ps.crtc1_aspect = si->ps.con1_screen.aspect;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
}
if (!si->ps.con1_screen.digital) si->ps.monitors |= CRTC1_VGA;
} else {
if (nv_dac_crt_connected()) {
si->ps.monitors |= CRTC1_VGA;
/* assume 4:3 monitor */
si->ps.crtc1_aspect = 1.33;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
/* assume 4:3 monitor on con1 */
si->ps.con1_screen.aspect = 1.33;
}
}
/* Note: digitally connected panels take precedence over analog connected screens. */
/* fill-out crtc1_screen from panel info gathered from BIOS programming since
* we don't know which connector connects to crtc1 (so EDID use not possible).
* Also the BIOS might have programmed for a lower mode than EDID reports:
* which limits our use of the panel (LVDS link setup too slow). */
if(si->ps.monitors & CRTC1_TMDS) {
si->ps.crtc1_screen.timing.pixel_clock = si->ps.p1_timing.pixel_clock;
si->ps.crtc1_screen.timing.h_display = si->ps.p1_timing.h_display;
si->ps.crtc1_screen.timing.h_sync_start = si->ps.p1_timing.h_sync_start;
si->ps.crtc1_screen.timing.h_sync_end = si->ps.p1_timing.h_sync_end;
si->ps.crtc1_screen.timing.h_total = si->ps.p1_timing.h_total;
si->ps.crtc1_screen.timing.v_display = si->ps.p1_timing.h_display;
si->ps.crtc1_screen.timing.v_sync_start = si->ps.p1_timing.v_sync_start;
si->ps.crtc1_screen.timing.v_sync_end = si->ps.p1_timing.v_sync_end;
si->ps.crtc1_screen.timing.v_total = si->ps.p1_timing.v_total;
si->ps.crtc1_screen.timing.flags = si->ps.p1_timing.flags;
si->ps.crtc1_screen.have_edid = true;
//note: crtc1_screen.aspect was already filled in...
//si->ps.crtc1_screen.aspect = si->ps.p1_aspect;
si->ps.crtc1_screen.digital = true;
} else if(si->ps.monitors & CRTC1_VGA) {
/* fill-out crtc1_screen from EDID info, or faked info if EDID failed. */
memcpy(&(si->ps.crtc1_screen), &(si->ps.con1_screen), sizeof(si->ps.crtc1_screen));
}
/* force widescreen types if requested */
if (si->settings.force_ws) si->ps.crtc1_screen.aspect = 1.60;
/* setup output devices and heads */
if (si->ps.secondary_head)
{
if (si->ps.card_type != NV11)
{
/* panels are pre-connected to a CRTC (1 or 2) by the card's BIOS,
* we can't change this (lack of info) */
/* detect analog monitors. First try EDID, else use load sensing. */
/* (load sensing is confirmed working OK on NV18, NV28 and NV34.) */
/* secondary connector */
if (si->ps.con2_screen.have_edid) {
if (!si->ps.con2_screen.digital) {
si->ps.monitors |= CRTC2_VGA;
si->ps.crtc2_aspect = si->ps.con2_screen.aspect;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc2_aspect = 1.60;
}
if (!si->ps.con2_screen.digital) si->ps.monitors |= CRTC2_VGA;
} else {
if (nv_dac2_crt_connected()) {
si->ps.monitors |= CRTC2_VGA;
/* assume 4:3 monitor */
si->ps.crtc2_aspect = 1.33;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc2_aspect = 1.60;
/* assume 4:3 monitor on con2 */
si->ps.con2_screen.aspect = 1.33;
}
}
/* Note: digitally connected panels take precedence over analog connected screens. */
/* fill-out crtc2_screen from panel info gathered from BIOS programming since
* we don't know which connector connects to crtc2 (so EDID use not possible).
* Also the BIOS might have programmed for a lower mode than EDID reports:
* which limits our use of the panel (LVDS link setup too slow). */
if(si->ps.monitors & CRTC2_TMDS) {
si->ps.crtc2_screen.timing.pixel_clock = si->ps.p1_timing.pixel_clock;
si->ps.crtc2_screen.timing.h_display = si->ps.p1_timing.h_display;
si->ps.crtc2_screen.timing.h_sync_start = si->ps.p1_timing.h_sync_start;
si->ps.crtc2_screen.timing.h_sync_end = si->ps.p1_timing.h_sync_end;
si->ps.crtc2_screen.timing.h_total = si->ps.p1_timing.h_total;
si->ps.crtc2_screen.timing.v_display = si->ps.p1_timing.h_display;
si->ps.crtc2_screen.timing.v_sync_start = si->ps.p1_timing.v_sync_start;
si->ps.crtc2_screen.timing.v_sync_end = si->ps.p1_timing.v_sync_end;
si->ps.crtc2_screen.timing.v_total = si->ps.p1_timing.v_total;
si->ps.crtc2_screen.timing.flags = si->ps.p1_timing.flags;
si->ps.crtc2_screen.have_edid = true;
//note: crtc2_screen.aspect was already filled in...
//si->ps.crtc2_screen.aspect = si->ps.p2_aspect;
si->ps.crtc2_screen.digital = true;
} else if(si->ps.monitors & CRTC2_VGA) {
/* fill-out crtc2_screen from EDID info, or faked info if EDID failed. */
memcpy(&(si->ps.crtc2_screen), &(si->ps.con2_screen), sizeof(si->ps.crtc2_screen));
}
/* force widescreen types if requested */
if (si->settings.force_ws) si->ps.crtc2_screen.aspect = 1.60;
/* setup correct output and head use */
//fixme? add TVout (only, so no CRT(s) connected) support...
switch (si->ps.monitors)
@ -2640,8 +2699,8 @@ static void setup_output_matrix()
/* cross connect analog outputs so analog panel or CRT gets head 2 */
nv_general_output_select(true);
si->ps.monitors = 0x21;
si->ps.crtc1_aspect = si->ps.con2_screen.aspect;
si->ps.crtc2_aspect = si->ps.con1_screen.aspect;
/* tell head 2 it now has a screen (connected at connector 1) */
memcpy(&(si->ps.crtc2_screen), &(si->ps.con1_screen), sizeof(si->ps.crtc2_screen));
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
@ -2665,8 +2724,8 @@ static void setup_output_matrix()
/* cross connect analog outputs so analog panel or CRT gets head 1 */
nv_general_output_select(true);
si->ps.monitors = 0x12;
si->ps.crtc1_aspect = si->ps.con2_screen.aspect;
si->ps.crtc2_aspect = si->ps.con1_screen.aspect;
/* tell head 1 it now has a screen (connected at connector 2) */
memcpy(&(si->ps.crtc1_screen), &(si->ps.con2_screen), sizeof(si->ps.crtc1_screen));
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
@ -2722,29 +2781,7 @@ static void setup_output_matrix()
/* confirmed no analog output switch-options for NV11 */
LOG(2,("INFO: NV11 outputs are hardwired to be straight-through\n"));
/* panels are pre-connected to a CRTC (1 or 2) by the card's BIOS,
* we can't change this (lack of info) */
/* detect analog monitors. First try EDID, else use load sensing. */
/* (load sensing is confirmed working OK on NV11.) */
/* primary connector: */
if (si->ps.con1_screen.have_edid) {
if (!si->ps.con1_screen.digital) {
si->ps.monitors |= CRTC1_VGA;
si->ps.crtc1_aspect = si->ps.con1_screen.aspect;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
}
} else {
if (nv_dac_crt_connected()) {
si->ps.monitors |= CRTC1_VGA;
/* assume 4:3 monitor */
si->ps.crtc1_aspect = 1.33;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
}
}
/* (sense analog monitor on secondary connector is impossible on NV11) */
/* (DDC or load sense analog monitor on secondary connector is impossible on NV11) */
/* setup correct output and head use */
//fixme? add TVout (only, so no CRT(s) connected) support...
@ -2797,29 +2834,6 @@ static void setup_output_matrix()
}
else /* singlehead cards */
{
/* panels are pre-setup by the card's BIOS,
* we can't change this (lack of info) */
/* detect analog monitors. First try EDID, else use load sensing. */
/* (load sensing is confirmed working OK on all cards.) */
/* primary connector: */
if (si->ps.con1_screen.have_edid) {
if (!si->ps.con1_screen.digital) {
si->ps.monitors |= CRTC1_VGA;
si->ps.crtc1_aspect = si->ps.con1_screen.aspect;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
}
} else {
if (nv_dac_crt_connected()) {
si->ps.monitors |= CRTC1_VGA;
/* assume 4:3 monitor */
si->ps.crtc1_aspect = 1.33;
/* force widescreen type if requested */
if (si->settings.force_ws) si->ps.crtc1_aspect = 1.60;
}
}
//fixme? add TVout (only, so no CRT connected) support...
}
}
@ -3354,14 +3368,14 @@ void dump_pins(void)
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.crtc1_aspect));
si->ps.p1_timing.h_display, si->ps.p1_timing.v_display, si->ps.crtc1_screen.aspect));
}
if (si->ps.monitors & CRTC2_TMDS)
{
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.crtc2_aspect));
si->ps.p2_timing.h_display, si->ps.p2_timing.v_display, si->ps.crtc2_screen.aspect));
}
LOG(2,("monitor (output devices) setup matrix: $%02x\n", si->ps.monitors));
LOG(2,("INFO: end pinsdump.\n"));