radeon_hd: Move out some DisplayPort common code

* General DisplayPort functions in common dp.cpp
* DP port information struct in common header
* Please don't use this private accelerant common DP
  code just yet as it is very early.
This commit is contained in:
Alexander von Gluck IV 2012-04-06 13:34:03 -05:00
parent 33629ffdd3
commit 0de9d6cdef
9 changed files with 187 additions and 123 deletions

View File

@ -0,0 +1,46 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Alexander von Gluck, kallisti5@unixzen.com
*/
#ifndef _DP_H
#define _DP_H
#include <Accelerant.h>
#include "dp_raw.h"
#include <GraphicsDefs.h>
#include <OS.h>
typedef struct {
// Required configuration
bool valid; // Is valid DP information
uint32 auxPin; // Normally GPIO pin on GPU
uint8 config[8]; // DP Configuration Data
int laneCount;
uint32 linkRate; // DP Link Speed 162000, 270000, 540000
// Internal State information
uint8 linkStatus[DP_LINK_STATUS_SIZE];
bool trainingUseEncoder;
uint8 trainingAttempts;
uint8 trainingSet[4];
int trainingReadInterval;
} dp_info;
uint32 dp_encode_link_rate(uint32 linkRate);
uint32 dp_decode_link_rate(uint32 rawLinkRate);
uint32 dp_get_lane_count(dp_info* dpInfo, display_mode* mode);
#endif /* _DP_H */

View File

@ -12,6 +12,7 @@ StaticLibrary libaccelerantscommon.a :
create_display_modes.cpp
ddc.c
decode_edid.c
dp.cpp
dump_edid.c
i2c.c
validate_display_mode.cpp

View File

@ -0,0 +1,93 @@
/*
* Copyright 2012, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Alexander von Gluck, kallisti5@unixzen.com
*/
#include "dp.h"
#define TRACE_DISPLAY
#ifdef TRACE_DISPLAY
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x...) _sPrintf("radeon_hd: " x)
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) _sPrintf("radeon_hd: " x)
uint32
dp_encode_link_rate(uint32 linkRate)
{
switch (linkRate) {
case 162000:
// 1.62 Ghz
return DP_LINK_RATE_162;
case 270000:
// 2.7 Ghz
return DP_LINK_RATE_270;
case 540000:
// 5.4 Ghz
return DP_LINK_RATE_540;
}
ERROR("%s: Unknown DisplayPort Link Rate!\n",
__func__);
return DP_LINK_RATE_162;
}
uint32
dp_decode_link_rate(uint32 rawLinkRate)
{
switch (rawLinkRate) {
case DP_LINK_RATE_162:
return 162000;
case DP_LINK_RATE_270:
return 270000;
case DP_LINK_RATE_540:
return 540000;
}
ERROR("%s: Unknown DisplayPort Link Rate!\n",
__func__);
return 162000;
}
uint32
dp_get_lane_count(dp_info* dpInfo, display_mode* mode)
{
// TODO: Really need a function in GraphicDefs.h for this
uint32 bitsPerPixel;
switch (mode->space) {
case B_CMAP8:
bitsPerPixel = 8;
case B_RGB15_LITTLE:
bitsPerPixel = 15;
case B_RGB16_LITTLE:
bitsPerPixel = 16;
case B_RGB24_LITTLE:
case B_RGB32_LITTLE:
bitsPerPixel = 32;
}
uint32 maxLaneCount = dpInfo->config[DP_MAX_LANE_COUNT]
& DP_MAX_LANE_COUNT_MASK;
uint32 maxLinkRate = dp_decode_link_rate(dpInfo->config[DP_MAX_LINK_RATE]);
uint32 lane;
for (lane = 1; lane < maxLaneCount; lane <<= 1) {
uint32 maxDPPixelClock = (maxLinkRate * lane * 8) / bitsPerPixel;
if (mode->timing.pixel_clock <= maxDPPixelClock)
break;
}
TRACE("%s: Lanes: %" B_PRIu32 "\n", __func__, lane);
return lane;
}

View File

@ -44,7 +44,6 @@ struct accelerant_info* gInfo;
display_info* gDisplay[MAX_DISPLAY];
connector_info* gConnector[ATOM_MAX_SUPPORTED_DEVICE];
gpio_info* gGPIOInfo[ATOM_MAX_SUPPORTED_DEVICE];
dp_info* gDPInfo[ATOM_MAX_SUPPORTED_DEVICE];
class AreaCloner {
@ -143,16 +142,6 @@ init_common(int device, bool isClone)
memset(gGPIOInfo[id], 0, sizeof(gpio_info));
}
// malloc for card DP information
for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
gDPInfo[id] = (dp_info*)malloc(sizeof(dp_info));
if (gDPInfo[id] == NULL)
return B_NO_MEMORY;
memset(gDPInfo[id], 0, sizeof(dp_info));
gDPInfo[id]->valid = false;
}
gInfo->is_clone = isClone;
gInfo->device = device;

View File

@ -14,7 +14,7 @@
#include <edid.h>
#include "atom.h"
#include "dp_raw.h"
#include "dp.h"
#include "encoder.h"
#include "mode.h"
#include "pll.h"
@ -125,28 +125,6 @@ typedef struct {
} gpio_info;
typedef struct {
bool valid;
uint32 connectorIndex;
uint32 auxPin; // normally GPIO pin on GPU
uint8 config[8]; // DP configuration data
uint8 sinkType;
uint8 clock;
int laneCount;
bool trainingUseEncoder;
uint8 trainingAttempts;
uint8 trainingSet[4];
int trainingReadInterval;
uint8 linkStatus[DP_LINK_STATUS_SIZE];
bool eDPOn;
} dp_info;
struct encoder_info {
bool valid;
uint16 objectID;
@ -169,6 +147,7 @@ typedef struct {
struct encoder_info encoder;
struct encoder_info encoderExternal;
// TODO struct radeon_hpd hpd;
dp_info dpInfo;
} connector_info;
@ -200,7 +179,6 @@ extern atom_context* gAtomContext;
extern display_info* gDisplay[MAX_DISPLAY];
extern connector_info* gConnector[ATOM_MAX_SUPPORTED_DEVICE];
extern gpio_info* gGPIOInfo[ATOM_MAX_SUPPORTED_DEVICE];
extern dp_info* gDPInfo[ATOM_MAX_SUPPORTED_DEVICE];
// register access

View File

@ -333,90 +333,39 @@ dp_get_link_clock(uint32 connectorIndex)
}
uint32
dp_get_link_clock_encode(uint32 dpLinkClock)
{
switch (dpLinkClock) {
case 270000:
return DP_LINK_RATE_270;
case 540000:
return DP_LINK_RATE_540;
}
return DP_LINK_RATE_162;
}
uint32
dp_get_link_clock_decode(uint32 dpLinkClock)
{
switch (dpLinkClock) {
case DP_LINK_RATE_270:
return 270000;
case DP_LINK_RATE_540:
return 540000;
}
return 162000;
}
uint32
dp_get_lane_count(uint32 connectorIndex, display_mode* mode)
{
uint32 bitsPerPixel = get_mode_bpp(mode);
uint32 maxLaneCount = gDPInfo[connectorIndex]->config[DP_MAX_LANE_COUNT]
& DP_MAX_LANE_COUNT_MASK;
uint32 maxLinkRate = dp_get_link_clock_decode(
gDPInfo[connectorIndex]->config[DP_MAX_LINK_RATE]);
uint32 lane;
for (lane = 1; lane < maxLaneCount; lane <<= 1) {
uint32 maxDPPixelClock = (maxLinkRate * lane * 8) / bitsPerPixel;
if (mode->timing.pixel_clock <= maxDPPixelClock)
break;
}
TRACE("%s: connector: %" B_PRIu32 ", lanes: %" B_PRIu32 "\n", __func__,
connectorIndex, lane);
return lane;
}
void
dp_setup_connectors()
{
TRACE("%s\n", __func__);
for (uint32 index = 0; index < ATOM_MAX_SUPPORTED_DEVICE; index++) {
gDPInfo[index]->valid = false;
dp_info* dpInfo = &gConnector[index]->dpInfo;
dpInfo->valid = false;
if (gConnector[index]->valid == false) {
gDPInfo[index]->config[0] = 0;
dpInfo->config[0] = 0;
continue;
}
if (connector_is_dp(index) == false) {
gDPInfo[index]->config[0] = 0;
dpInfo->config[0] = 0;
continue;
}
uint32 gpioID = gConnector[index]->gpioID;
uint32 auxPin = gGPIOInfo[gpioID]->hwPin;
gDPInfo[index]->auxPin = auxPin;
gDPInfo[index]->connectorIndex = index;
dpInfo->auxPin = auxPin;
uint8 auxMessage[25];
int result;
result = dp_aux_read(auxPin, DP_DPCD_REV, auxMessage, 8, 0);
if (result > 0) {
gDPInfo[index]->valid = true;
memcpy(gDPInfo[index]->config, auxMessage, 8);
dpInfo->valid = true;
memcpy(dpInfo->config, auxMessage, 8);
}
gDPInfo[index]->clock = dp_get_link_clock(index);
dpInfo->linkRate = dp_get_link_clock(index);
}
}
@ -462,11 +411,13 @@ dp_clock_recovery_ok(dp_info* dp)
static void
dp_update_vs_emph(dp_info* dp)
dp_update_vs_emph(uint32 connectorIndex)
{
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
// Set initial vs and emph on source
transmitter_dig_setup(dp->connectorIndex, dp->clock, 0, dp->trainingSet[0],
ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
transmitter_dig_setup(connectorIndex, dp->linkRate, 0,
dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
// Set vs and emph on the sink
dp_aux_write(dp->auxPin, DP_TRAIN_LANE0,
@ -543,11 +494,12 @@ dp_get_adjust_train(dp_info* dp)
static void
dp_set_tp(dp_info* dp, int trainingPattern)
dp_set_tp(uint32 connectorIndex, int trainingPattern)
{
TRACE("%s\n", __func__);
radeon_shared_info &info = *gInfo->shared_info;
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
int rawTrainingPattern = 0;
@ -565,7 +517,7 @@ dp_set_tp(dp_info* dp, int trainingPattern)
break;
}
// TODO: PixelClock 0 ok?
encoder_dig_setup(dp->connectorIndex, 0, rawTrainingPattern);
encoder_dig_setup(connectorIndex, 0, rawTrainingPattern);
} else {
ERROR("%s: TODO: dp_encoder_service\n", __func__);
return;
@ -590,19 +542,21 @@ dp_set_tp(dp_info* dp, int trainingPattern)
status_t
dp_link_train_cr(dp_info* dp)
dp_link_train_cr(uint32 connectorIndex)
{
TRACE("%s\n", __func__);
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
// Display Port Clock Recovery Training
bool clockRecovery = false;
uint8 voltage = 0xff;
int lane;
dp_set_tp(dp, DP_TRAIN_PATTERN_1);
dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1);
memset(dp->trainingSet, 0, 4);
dp_update_vs_emph(dp);
dp_update_vs_emph(connectorIndex);
while (1) {
if (dp->trainingReadInterval == 0)
@ -642,7 +596,7 @@ dp_link_train_cr(dp_info* dp)
// Compute new trainingSet as requested by sink
dp_get_adjust_train(dp);
dp_update_vs_emph(dp);
dp_update_vs_emph(connectorIndex);
}
if (!clockRecovery) {
@ -664,7 +618,7 @@ dp_link_train(uint8 crtcID, display_mode* mode)
TRACE("%s\n", __func__);
uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
dp_info* dp = gDPInfo[connectorIndex];
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
if (dp->valid != true) {
ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n",
@ -732,7 +686,7 @@ dp_link_train(uint8 crtcID, display_mode* mode)
dpcd_reg_write(hwPin, DP_LANE_COUNT, sandbox);
// Set the link rate on the DP sink
sandbox = dp_get_link_clock_encode(dp->clock);
sandbox = dp_encode_link_rate(dp->linkRate);
dpcd_reg_write(hwPin, DP_LINK_RATE, sandbox);
// Start link training on source
@ -747,7 +701,7 @@ dp_link_train(uint8 crtcID, display_mode* mode)
// Disable the training pattern on the sink
dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
dp_link_train_cr(dp);
dp_link_train_cr(connectorIndex);
// TODO: dp_link_train_ce

View File

@ -14,7 +14,7 @@
#include <SupportDefs.h>
#include "accelerant.h"
#include "dp_raw.h"
#include "dp.h"
// Radeon HD specific DisplayPort Configuration Data
@ -31,14 +31,12 @@ status_t dp_aux_set_i2c_byte(uint32 hwPin, uint16 address,
status_t dp_aux_get_i2c_byte(uint32 hwPin, uint16 address,
uint8* data, bool end);
uint32 dp_get_lane_count(uint32 connectorIndex, display_mode* mode);
uint32 dp_get_link_clock(uint32 connectorIndex);
uint32 dp_get_link_clock_encode(uint32 dpLinkClock);
uint32 dp_get_link_clock_decode(uint32 dpLinkClock);
void dp_setup_connectors();
status_t dp_link_train(uint8 crtcID, display_mode* mode);
status_t dp_link_train_cr(dp_info* dp);
status_t dp_link_train_cr(uint32 connectorIndex);
#endif /* RADEON_HD_DISPLAYPORT_H */

View File

@ -602,6 +602,7 @@ encoder_dig_setup(uint32 connectorIndex, uint32 pixelClock, int command)
TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
tableMajor, tableMinor);
dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
uint32 dpClock = dp_get_link_clock(connectorIndex);
switch (tableMinor) {
case 1:
@ -653,7 +654,7 @@ encoder_dig_setup(uint32 connectorIndex, uint32 pixelClock, int command)
if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
|| args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST) {
args.v1.ucLaneNum = gDPInfo[connectorIndex]->laneCount;
args.v1.ucLaneNum = dpInfo->laneCount;
} else if (pixelClock > 165000)
args.v1.ucLaneNum = 8;
else
@ -718,6 +719,8 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command)
encoder_info* encoder
= &gConnector[connectorIndex]->encoderExternal;
dp_info* dpInfo
= &gConnector[connectorIndex]->dpInfo;
if (encoder->valid != true) {
ERROR("%s: connector %" B_PRIu32 " doesn't have a valid "
@ -764,12 +767,12 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command)
= display_get_encoder_mode(connectorIndex);
if (connector_is_dp(connectorIndex)) {
if (gDPInfo[connectorIndex]->clock == 270000) {
if (dpInfo->linkRate == 270000) {
args.v1.sDigEncoder.ucConfig
|= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
}
args.v1.sDigEncoder.ucLaneNum
= gDPInfo[connectorIndex]->laneCount;
= dpInfo->laneCount;
} else if (pixelClock > 165000) {
args.v1.sDigEncoder.ucLaneNum = 8;
} else {
@ -791,15 +794,15 @@ encoder_external_setup(uint32 connectorIndex, uint32 pixelClock, int command)
= display_get_encoder_mode(connectorIndex);
if (connector_is_dp(connectorIndex)) {
if (gDPInfo[connectorIndex]->clock == 270000) {
if (dpInfo->linkRate == 270000) {
args.v3.sExtEncoder.ucConfig
|=EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
} else if (gDPInfo[connectorIndex]->clock == 540000) {
} else if (dpInfo->linkRate == 540000) {
args.v3.sExtEncoder.ucConfig
|=EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
}
args.v1.sDigEncoder.ucLaneNum
= gDPInfo[connectorIndex]->laneCount;
= dpInfo->laneCount;
} else if (pixelClock > 165000) {
args.v3.sExtEncoder.ucLaneNum = 8;
} else {
@ -1129,11 +1132,13 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
bool linkB = gConnector[connectorIndex]->encoderExternal.linkEnumeration
== GRAPH_OBJECT_ENUM_ID2 ? true : false;
dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
uint8 dpClock = 0;
int dpLaneCount = 0;
if (gDPInfo[connectorIndex]->valid == true) {
dpClock = gDPInfo[connectorIndex]->clock;
dpLaneCount = gDPInfo[connectorIndex]->laneCount;
if (dpInfo->valid == true) {
dpClock = dpInfo->linkRate;
dpLaneCount = dpInfo->laneCount;
}
switch (tableMajor) {

View File

@ -166,12 +166,12 @@ radeon_set_display_mode(display_mode* mode)
if (gDisplay[id]->attached == false)
continue;
uint16 connectorIndex = gDisplay[id]->connectorIndex;
uint32 connectorIndex = gDisplay[id]->connectorIndex;
dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo;
// Determine DP lanes if DP
if (connector_is_dp(connectorIndex))
gDPInfo[connectorIndex]->laneCount
= dp_get_lane_count(connectorIndex, mode);
dpInfo->laneCount = dp_get_lane_count(dpInfo, mode);
// *** encoder prep
encoder_output_lock(true);