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"); }
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"); }