Example #1
0
status_t
detect_displays()
{
	// reset known displays
	for (uint32 id = 0; id < MAX_DISPLAY; id++) {
		gDisplay[id]->attached = false;
		gDisplay[id]->powered = false;
		gDisplay[id]->foundRanges = false;
	}

	uint32 displayIndex = 0;
	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
		if (gConnector[id]->valid == false)
			continue;
		if (displayIndex >= MAX_DISPLAY)
			continue;

		if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) {
			TRACE("%s: Skipping 9DIN connector (not yet supported)\n",
				__func__);
			continue;
		}

		// TODO: As DP aux transactions don't work yet, just use LVDS as a hack
		#if 0
		if (gConnector[id]->encoderExternal.isDPBridge == true) {
			// If this is a DisplayPort Bridge, setup ddc on bus
			// TRAVIS (LVDS) or NUTMEG (VGA)
			TRACE("%s: is bridge, performing bridge DDC setup\n", __func__);
			encoder_external_setup(id, 23860,
				EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
			gDisplay[displayIndex]->attached = true;
		} else if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
		#endif
		if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
			// If plain (non-DP) laptop LVDS, read mode info from AtomBIOS
			//TRACE("%s: non-DP laptop LVDS detected\n", __func__);
			gDisplay[displayIndex]->attached
				= connector_read_mode_lvds(id,
					&gDisplay[displayIndex]->preferredMode);
		}

		// If no display found yet, try more standard detection methods
		if (gDisplay[displayIndex]->attached == false) {
			TRACE("%s: bit-banging ddc for EDID on connector %" B_PRIu32 "\n",
				__func__, id);

			// Lets try bit-banging edid from connector
			gDisplay[displayIndex]->attached
				= connector_read_edid(id, &gDisplay[displayIndex]->edidData);

			// Since DVI-I shows up as two connectors, and there is only one
			// edid channel, we have to make *sure* the edid data received is
			// valid for te connector.

			// Found EDID data?
			if (gDisplay[displayIndex]->attached) {
				TRACE("%s: found EDID data on connector %" B_PRIu32 "\n",
					__func__, id);

				bool analogEncoder
					= gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC
					|| gConnector[id]->encoder.type == VIDEO_ENCODER_DAC;

				edid1_info* edid = &gDisplay[displayIndex]->edidData;
				if (!edid->display.input_type && analogEncoder) {
					// If non-digital EDID + the encoder is analog...
					TRACE("%s: connector %" B_PRIu32 " has non-digital EDID "
						"and a analog encoder.\n", __func__, id);
					gDisplay[displayIndex]->attached
						= encoder_analog_load_detect(id);
				} else if (edid->display.input_type && !analogEncoder) {
					// If EDID is digital, we make an assumption here.
					TRACE("%s: connector %" B_PRIu32 " has digital EDID "
						"and is not a analog encoder.\n", __func__, id);
				} else {
					// This generally means the monitor is of poor design
					// Since we *know* there is no load on the analog encoder
					// we assume that it is a digital display.
					TRACE("%s: Warning: monitor on connector %" B_PRIu32 " has "
						"false digital EDID flag and unloaded analog encoder!\n",
						__func__, id);
				}
			}
		}

		if (gDisplay[displayIndex]->attached != true) {
			// Nothing interesting here, move along
			continue;
		}

		// We found a valid / attached display

		gDisplay[displayIndex]->connectorIndex = id;
			// Populate physical connector index from gConnector

		init_registers(gDisplay[displayIndex]->regs, displayIndex);

		if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) {
			// Found a single preferred mode
			gDisplay[displayIndex]->foundRanges = false;
		} else {
			// Use edid data and pull ranges
			if (detect_crt_ranges(displayIndex) == B_OK)
				gDisplay[displayIndex]->foundRanges = true;
		}

		displayIndex++;
	}

	// fallback if no attached monitors were found
	if (displayIndex == 0) {
		// This is a hack, however as we don't support HPD just yet,
		// it tries to prevent a "no displays" situation.
		ERROR("%s: ERROR: 0 attached monitors were found on display connectors."
			" Injecting first connector as a last resort.\n", __func__);
		for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
			// skip TV DAC connectors as likely fallback isn't for TV
			if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC)
				continue;
			gDisplay[0]->attached = true;
			gDisplay[0]->connectorIndex = id;
			init_registers(gDisplay[0]->regs, 0);
			if (detect_crt_ranges(0) == B_OK)
				gDisplay[0]->foundRanges = true;
			break;
		}
	}

	// Initial boot state is the first two crtc's powered
	if (gDisplay[0]->attached == true)
		gDisplay[0]->powered = true;
	if (gDisplay[1]->attached == true)
		gDisplay[1]->powered = true;

	return B_OK;
}


void
debug_displays()
{
	TRACE("Currently detected monitors===============\n");
	for (uint32 id = 0; id < MAX_DISPLAY; id++) {
		ERROR("Display #%" B_PRIu32 " attached = %s\n",
			id, gDisplay[id]->attached ? "true" : "false");

		uint32 connectorIndex = gDisplay[id]->connectorIndex;

		if (gDisplay[id]->attached) {
			uint32 connectorType = gConnector[connectorIndex]->type;
			uint32 encoderType = gConnector[connectorIndex]->encoder.type;
			ERROR(" + connector ID:   %" B_PRIu32 "\n", connectorIndex);
			ERROR(" + connector type: %s\n", get_connector_name(connectorType));
			ERROR(" + encoder type:   %s\n", get_encoder_name(encoderType));
			ERROR(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
				gDisplay[id]->vfreqMin, gDisplay[id]->vfreqMax);
			ERROR(" + limits: Horz Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
				gDisplay[id]->hfreqMin, gDisplay[id]->hfreqMax);
		}
	}
	TRACE("==========================================\n");
}
Example #2
0
status_t
detect_displays()
{
    // reset known displays
    for (uint32 id = 0; id < MAX_DISPLAY; id++) {
        gDisplay[id]->attached = false;
        gDisplay[id]->powered = false;
        gDisplay[id]->foundRanges = false;
    }

    uint32 displayIndex = 0;
    for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
        if (gConnector[id]->valid == false)
            continue;
        if (displayIndex >= MAX_DISPLAY)
            continue;

        if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) {
            TRACE("%s: connector(%" B_PRIu32 "): Skipping 9DIN connector "
                  "(not yet supported)\n", __func__, id);
            continue;
        }

        if (gConnector[id]->type == VIDEO_CONNECTOR_DP) {
            TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id);

            edid1_info* edid = &gDisplay[displayIndex]->edidData;
            gDisplay[displayIndex]->attached
                = ddc2_dp_read_edid1(id, edid);

            if (gDisplay[displayIndex]->attached) {
                TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n",
                      __func__);
            }
        }

        // TODO: Handle external DP brides - ??
#if 0
        if (gConnector[id]->encoderExternal.isDPBridge == true) {
            // If this is a DisplayPort Bridge, setup ddc on bus
            // TRAVIS (LVDS) or NUTMEG (VGA)
            TRACE("%s: is bridge, performing bridge DDC setup\n", __func__);
            encoder_external_setup(id, 23860,
                                   EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
            gDisplay[displayIndex]->attached = true;

            // TODO: DDC Router switching for DisplayPort (and others?)
        }
#endif

        if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
            display_mode preferredMode;
            bool lvdsInfoFound = connector_read_mode_lvds(id,
                                 &preferredMode);
            TRACE("%s: connector(%" B_PRIu32 "): bit-banging LVDS for EDID.\n",
                  __func__, id);

            gDisplay[displayIndex]->attached = connector_read_edid(id,
                                               &gDisplay[displayIndex]->edidData);

            if (!gDisplay[displayIndex]->attached && lvdsInfoFound) {
                // If we didn't find ddc edid data, fallback to lvdsInfo
                // We have to call connector_read_mode_lvds first to
                // collect SS data for the lvds connector
                TRACE("%s: connector(%" B_PRIu32 "): using AtomBIOS LVDS_Info "
                      "preferred mode\n", __func__, id);
                gDisplay[displayIndex]->attached = true;
                memcpy(&gDisplay[displayIndex]->preferredMode,
                       &preferredMode, sizeof(display_mode));
            }
        }

        // If no display found yet, try more standard detection methods
        if (gDisplay[displayIndex]->attached == false) {
            TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n",
                  __func__, id);

            // Bit-bang edid from connector
            gDisplay[displayIndex]->attached = connector_read_edid(id,
                                               &gDisplay[displayIndex]->edidData);

            // Found EDID data?
            if (gDisplay[displayIndex]->attached) {
                TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n",
                      __func__, id);

                if (gConnector[id]->type == VIDEO_CONNECTOR_DVII
                        || gConnector[id]->type == VIDEO_CONNECTOR_HDMIB) {
                    // These connectors can share gpio pins for data
                    // communication between digital and analog encoders
                    // (DVI-I is most common)
                    edid1_info* edid = &gDisplay[displayIndex]->edidData;

                    bool analogEncoder
                        = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC
                          || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC;
                    bool digitalEncoder
                        = gConnector[id]->encoder.type == VIDEO_ENCODER_TMDS;

                    bool digitalEdid = edid->display.input_type ? true : false;

                    if (digitalEdid && analogEncoder) {
                        // Digital EDID + analog encoder? Lets try a load test
                        gDisplay[displayIndex]->attached
                            = encoder_analog_load_detect(id);
                    } else if (!digitalEdid && digitalEncoder) {
                        // non-digital EDID + digital encoder? Nope.
                        gDisplay[displayIndex]->attached = false;
                    }

                    // Else... everything aligns as it should and attached = 1
                }
            }
        }

        if (gDisplay[displayIndex]->attached != true) {
            // Nothing interesting here, move along
            continue;
        }

        // We found a valid / attached display

        gDisplay[displayIndex]->connectorIndex = id;
        // Populate physical connector index from gConnector

        init_registers(gDisplay[displayIndex]->regs, displayIndex);

        if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) {
            // Found a single preferred mode
            gDisplay[displayIndex]->foundRanges = false;
        } else {
            // Use edid data and pull ranges
            if (detect_crt_ranges(displayIndex) == B_OK)
                gDisplay[displayIndex]->foundRanges = true;
        }

        displayIndex++;
    }

    // fallback if no attached monitors were found
    if (displayIndex == 0) {
        // This is a hack, however as we don't support HPD just yet,
        // it tries to prevent a "no displays" situation.
        ERROR("%s: ERROR: 0 attached monitors were found on display connectors."
              " Injecting first connector as a last resort.\n", __func__);
        for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
            // skip TV DAC connectors as likely fallback isn't for TV
            if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC)
                continue;
            gDisplay[0]->attached = true;
            gDisplay[0]->connectorIndex = id;
            init_registers(gDisplay[0]->regs, 0);
            if (detect_crt_ranges(0) == B_OK)
                gDisplay[0]->foundRanges = true;
            break;
        }
    }

    // Initial boot state is the first two crtc's powered
    if (gDisplay[0]->attached == true)
        gDisplay[0]->powered = true;
    if (gDisplay[1]->attached == true)
        gDisplay[1]->powered = true;

    return B_OK;
}
status_t
detect_displays()
{
    // reset known displays
    for (uint32 id = 0; id < MAX_DISPLAY; id++) {
        gDisplay[id]->attached = false;
        gDisplay[id]->powered = false;
        gDisplay[id]->foundRanges = false;
    }

    uint32 displayIndex = 0;
    for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
        if (gConnector[id]->valid == false)
            continue;
        if (displayIndex >= MAX_DISPLAY)
            continue;

        if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) {
            TRACE("%s: connector(%" B_PRIu32 "): Skipping 9DIN connector "
                  "(not yet supported)\n", __func__, id);
            continue;
        }

        if (gConnector[id]->type == VIDEO_CONNECTOR_DP) {
            TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id);

            edid1_info* edid = &gDisplay[displayIndex]->edidData;
            gDisplay[displayIndex]->attached
                = ddc2_dp_read_edid1(id, edid);

            if (gDisplay[displayIndex]->attached) {
                TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n",
                      __func__);
            }
        }
        // TODO: Handle external DP brides - ??
#if 0
        if (gConnector[id]->encoderExternal.isDPBridge == true) {
            // If this is a DisplayPort Bridge, setup ddc on bus
            // TRAVIS (LVDS) or NUTMEG (VGA)
            TRACE("%s: is bridge, performing bridge DDC setup\n", __func__);
            encoder_external_setup(id, 23860,
                                   EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
            gDisplay[displayIndex]->attached = true;

            // TODO: DDC Router switching for DisplayPort (and others?)
        }
#endif
        if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
            // If plain (non-DP) laptop LVDS, read mode info from AtomBIOS
            //TRACE("%s: non-DP laptop LVDS detected\n", __func__);
            gDisplay[displayIndex]->attached = connector_read_mode_lvds(id,
                                               &gDisplay[displayIndex]->preferredMode);
            if (gDisplay[displayIndex]->attached) {
                TRACE("%s: connector(%" B_PRIu32 "): found LVDS preferred "
                      "mode\n", __func__, id);
            }
        }

        // If no display found yet, try more standard detection methods
        if (gDisplay[displayIndex]->attached == false) {
            TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n",
                  __func__, id);

            // Lets try bit-banging edid from connector
            gDisplay[displayIndex]->attached
                = connector_read_edid(id, &gDisplay[displayIndex]->edidData);

            // Since DVI-I shows up as two connectors, and there is only one
            // edid channel, we have to make *sure* the edid data received is
            // valid for the connector.

            // Found EDID data?
            if (gDisplay[displayIndex]->attached) {
                TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n",
                      __func__, id);

                bool analogEncoder
                    = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC
                      || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC;

                edid1_info* edid = &gDisplay[displayIndex]->edidData;
                if (!edid->display.input_type && analogEncoder) {
                    // If non-digital EDID + the encoder is analog...
                    TRACE("%s: connector(%" B_PRIu32 "): has non-digital EDID "
                          "and a analog encoder.\n", __func__, id);
                    gDisplay[displayIndex]->attached
                        = encoder_analog_load_detect(id);
                    remove_dup_displays(displayIndex, id);
                } else if (edid->display.input_type && !analogEncoder) {
                    // If EDID is digital, we make an assumption here.
                    TRACE("%s: connector(%" B_PRIu32 "): has digital EDID "
                          "and is not a analog encoder.\n", __func__, id);
                } else {
                    // This generally means the monitor is of poor design
                    // Since we *know* there is no load on the analog encoder
                    // we assume that it is a digital display.
                    // This can also occur when a display has both DVI and VGA
                    // inputs and the graphics board has a DVI-I connector
                    // (reported as both digital and analog connectors) and the
                    // analog connection is the one in use. In that case, we
                    // get here when checking the digital connector and want
                    // to disable that display in favor of the analog one.
                    TRACE("%s: connector(%" B_PRIu32 "): Warning: monitor has "
                          "false digital EDID flag + unloaded analog encoder!\n",
                          __func__, id);
                    gDisplay[displayIndex]->attached = false;
                }
            }
        }

        if (gDisplay[displayIndex]->attached != true) {
            // Nothing interesting here, move along
            continue;
        }

        // We found a valid / attached display

        gDisplay[displayIndex]->connectorIndex = id;
        // Populate physical connector index from gConnector

        init_registers(gDisplay[displayIndex]->regs, displayIndex);

        if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) {
            // Found a single preferred mode
            gDisplay[displayIndex]->foundRanges = false;
        } else {
            // Use edid data and pull ranges
            if (detect_crt_ranges(displayIndex) == B_OK)
                gDisplay[displayIndex]->foundRanges = true;
        }

        displayIndex++;
    }

    // fallback if no attached monitors were found
    if (displayIndex == 0) {
        // This is a hack, however as we don't support HPD just yet,
        // it tries to prevent a "no displays" situation.
        ERROR("%s: ERROR: 0 attached monitors were found on display connectors."
              " Injecting first connector as a last resort.\n", __func__);
        for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
            // skip TV DAC connectors as likely fallback isn't for TV
            if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC)
                continue;
            gDisplay[0]->attached = true;
            gDisplay[0]->connectorIndex = id;
            init_registers(gDisplay[0]->regs, 0);
            if (detect_crt_ranges(0) == B_OK)
                gDisplay[0]->foundRanges = true;
            break;
        }
    }

    // Initial boot state is the first two crtc's powered
    if (gDisplay[0]->attached == true)
        gDisplay[0]->powered = true;
    if (gDisplay[1]->attached == true)
        gDisplay[1]->powered = true;

    return B_OK;
}