コード例 #1
0
ファイル: display.cpp プロジェクト: jscipione/haiku
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;
}
コード例 #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) {
            // 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;
}