diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp b/src/add-ons/accelerants/radeon_hd/display.cpp index d09bd8f58db..7b212ee090a 100644 --- a/src/add-ons/accelerants/radeon_hd/display.cpp +++ b/src/add-ons/accelerants/radeon_hd/display.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2013, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -21,6 +21,7 @@ #include "accelerant_protos.h" #include "bios.h" #include "connector.h" +#include "displayport.h" #include "encoder.h" @@ -225,8 +226,7 @@ detect_crt_ranges(uint32 crtid) edid1_detailed_monitor* monitor = &edid->detailed_monitor[index]; - if (monitor->monitor_desc_type - == EDID1_MONITOR_RANGES) { + if (monitor->monitor_desc_type == EDID1_MONITOR_RANGES) { edid1_monitor_range range = monitor->data.monitor_range; gDisplay[crtid]->vfreqMin = range.min_v; /* in Hz */ gDisplay[crtid]->vfreqMax = range.max_v; @@ -258,11 +258,24 @@ detect_displays() continue; if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) { - TRACE("%s: Skipping 9DIN connector (not yet supported)\n", - __func__); + TRACE("%s: connector(%" B_PRIu32 "): Skipping 9DIN connector " + "(not yet supported)\n", __func__, id); continue; } + if (gConnector[id]->type == VIDEO_CONNECTOR_DP) { + edid1_info* edid = &gDisplay[displayIndex]->edidData; + + TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id); + status_t dpHasEDID = ddc2_dp_read_edid1(id, edid); + gDisplay[displayIndex]->attached + = (dpHasEDID == B_OK ? true : false); + if (gDisplay[displayIndex]->attached) { + TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n", + __func__); + } + } + // TODO: As DP aux transactions don't work yet, just use LVDS as a hack #if 0 if (gConnector[id]->encoderExternal.isDPBridge == true) { @@ -276,17 +289,22 @@ detect_displays() // TODO: DDC Router switching for DisplayPort (and others?) } else if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { #endif - if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { + + if (gDisplay[displayIndex]->attached == false + && 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); + 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: bit-banging ddc for EDID on connector %" B_PRIu32 "\n", + TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n", __func__, id); // Lets try bit-banging edid from connector @@ -299,7 +317,7 @@ detect_displays() // Found EDID data? if (gDisplay[displayIndex]->attached) { - TRACE("%s: found EDID data on connector %" B_PRIu32 "\n", + TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n", __func__, id); bool analogEncoder @@ -309,20 +327,20 @@ detect_displays() 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 " + 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 " + 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", + TRACE("%s: connector(%" B_PRIu32 "): Warning: monitor has " + "false digital EDID flag + unloaded analog encoder!\n", __func__, id); } } diff --git a/src/add-ons/accelerants/radeon_hd/displayport.cpp b/src/add-ons/accelerants/radeon_hd/displayport.cpp index 2aff239213d..3acd66d2673 100644 --- a/src/add-ons/accelerants/radeon_hd/displayport.cpp +++ b/src/add-ons/accelerants/radeon_hd/displayport.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2013, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Alexander von Gluck IV, kallisti5@unixzen.com + * Bill Randle, billr@neocat.org */ @@ -178,14 +179,14 @@ dpcd_reg_read(uint32 hwPin, uint16 address) status_t -dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) +dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool start, bool stop) { uint8 auxMessage[5]; int auxMessageBytes = 4; // 4 for read /* Set up the command byte */ auxMessage[2] = AUX_I2C_READ << 4; - if (end == false) + if (stop == false) auxMessage[2] |= AUX_I2C_MOT << 4; auxMessage[0] = address; @@ -193,6 +194,12 @@ dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) auxMessage[3] = auxMessageBytes << 4; + /* special case for sending the START or STOP */ + if (start || stop) { + auxMessage[3] = 3 << 4; + auxMessageBytes = 4; + } + int retry; for (retry = 0; retry < 4; retry++) { uint8 ack; @@ -249,14 +256,14 @@ dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) status_t -dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) +dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool start, bool stop) { uint8 auxMessage[5]; int auxMessageBytes = 5; // 5 for write /* Set up the command byte */ auxMessage[2] = AUX_I2C_WRITE << 4; - if (end == false) + if (stop == false) auxMessage[2] |= AUX_I2C_MOT << 4; auxMessage[0] = address; @@ -265,6 +272,12 @@ dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) auxMessage[3] = auxMessageBytes << 4; auxMessage[4] = *data; + /* special case for sending the START or STOP */ + if (start || stop) { + auxMessage[3] = 3 << 4; + auxMessageBytes = 4; + } + int retry; for (retry = 0; retry < 4; retry++) { uint8 ack; @@ -328,7 +341,7 @@ dp_get_lane_count(uint32 connectorIndex, display_mode* mode) size_t pixelChunk; size_t pixelsPerChunk; - status_t result = get_pixel_size_for((color_space)mode->space, &pixelChunk, + status_t result = dp_get_pixel_size_for((color_space)mode->space, &pixelChunk, NULL, &pixelsPerChunk); if (result != B_OK) { @@ -367,7 +380,7 @@ dp_get_link_rate(uint32 connectorIndex, display_mode* mode) size_t pixelChunk; size_t pixelsPerChunk; - status_t result = get_pixel_size_for((color_space)mode->space, &pixelChunk, + status_t result = dp_get_pixel_size_for((color_space)mode->space, &pixelChunk, NULL, &pixelsPerChunk); if (result != B_OK) { @@ -859,6 +872,74 @@ dp_link_train(uint32 connectorIndex, display_mode* mode) } +status_t +ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid) +{ + TRACE("%s\n", __func__); + + dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; + + if (!dpInfo->valid) + return B_ERROR; + + edid1_raw raw; + uint8* rdata = (uint8_t*)&raw; + uint8 sdata = 0; + + // The following sequence is from a trace of the Linux kernel + // radeon code; not sure if the initial writes to address 0 are + // requried. + dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, true, false); + dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, false, true); + + dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, true, false); + dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, false); + dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false); + dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, false, false); + dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, false, true); + dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, true, false); + dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, false); + dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false); + + for (uint32 i = 0; i < sizeof(raw); i++) { + status_t result = dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata++, + false, false); + if (result) { + ERROR("%s: error reading EDID data at index %" B_PRIu32 "\n", + __func__, i); + dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true); + return B_ERROR; + } + } + dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true); + + if (raw.version.version != 1 || raw.version.revision > 4) { + ERROR("%s: EDID version or revision out of range\n", __func__); + return B_ERROR; + } + + edid_decode(edid, &raw); + + return B_OK; +} + + +status_t +dp_get_pixel_size_for(color_space space, size_t *pixelChunk, + size_t *rowAlignment, size_t *pixelsPerChunk) +{ + status_t result = get_pixel_size_for(space, pixelChunk, NULL, + pixelsPerChunk); + + if ((space == B_RGB32) || (space == B_RGBA32) || (space == B_RGB32_BIG) + || (space == B_RGBA32_BIG)) { + *pixelChunk = 3; + } + + return result; +} + + void debug_dp_info() { diff --git a/src/add-ons/accelerants/radeon_hd/displayport.h b/src/add-ons/accelerants/radeon_hd/displayport.h index fa06dc6e741..ae484d081aa 100644 --- a/src/add-ons/accelerants/radeon_hd/displayport.h +++ b/src/add-ons/accelerants/radeon_hd/displayport.h @@ -1,9 +1,10 @@ /* - * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2013, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Alexander von Gluck IV, kallisti5@unixzen.com + * Bill Randle, billr@neocat.org */ #ifndef RADEON_HD_DISPLAYPORT_H #define RADEON_HD_DISPLAYPORT_H @@ -30,9 +31,9 @@ int dp_aux_write(uint32 hwPin, uint16 address, uint8* send, int dp_aux_read(uint32 hwPin, uint16 address, uint8* recv, int recvBytes, uint8 delay); status_t dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, - uint8* data, bool end); + uint8* data, bool start, bool stop); status_t dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, - uint8* data, bool end); + uint8* data, bool start, bool stop); uint32 dp_get_link_rate(uint32 connectorIndex, display_mode* mode); uint32 dp_get_lane_count(uint32 connectorIndex, display_mode* mode); @@ -45,4 +46,9 @@ status_t dp_link_train_ce(uint32 connectorIndex); void debug_dp_info(); -#endif /* RADEON_HD_DISPLAYPORT_H */ +status_t dp_get_pixel_size_for(color_space space, size_t *pixelChunk, + size_t *rowAlignment, size_t *pixelsPerChunk); +status_t ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info *edid); + + +#endif /* RADEON_HD_DISPLAYPORT_H */ \ No newline at end of file