radeon_hd: Improve displayport support
* Modified patch submitted by Bill Randle. * DisplayPort aux communications now working. * DP Link Training still not functioning properly. * The DP edid data isn't used yet as we still use the vesa edid during the mode setting.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user