Skip to content

Commit

Permalink
radeon_hd: Improve displayport support
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
kallisti5 committed Jan 7, 2013
1 parent 45f77dc commit 0423443
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 26 deletions.
48 changes: 33 additions & 15 deletions 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:
Expand All @@ -21,6 +21,7 @@
#include "accelerant_protos.h"
#include "bios.h"
#include "connector.h"
#include "displayport.h"
#include "encoder.h"


Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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);
}
}
Expand Down
95 changes: 88 additions & 7 deletions 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
*/


Expand Down Expand Up @@ -178,21 +179,27 @@ 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;
auxMessage[1] = address >> 8;

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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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()
{
Expand Down
14 changes: 10 additions & 4 deletions 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
Expand All @@ -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);
Expand All @@ -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 */

0 comments on commit 0423443

Please sign in to comment.