[haiku-commits] haiku: hrev43852 - in src/add-ons/accelerants/radeon_hd: . atombios

  • From: kallisti5@xxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 14 Mar 2012 18:16:22 +0100 (CET)

hrev43852 adds 5 changesets to branch 'master'
old head: a9c45d3774815a1ab0b81985e088520bc4bec5fa
new head: 83e3a8ea5013ca577e735016437d0b526c20b7db

----------------------------------------------------------------------------

32ef94a: radeon_hd: AtomBIOS loop failure detection now time based
  
  * If the same call is made for 5 seconds straight, fail.
  * Resolves random AtomBIOS failures.
  * AtomBIOS failures now represent *real* bugs :)

119cd5e: radeon_hd: Add missing load detection on DIG encoders

48b430f: radeon_hd: Add missing AtomBIOS tables

6f7c0aa: radeon_hd: Whitespace cleanup, no functional change

83e3a8e: radeon_hd: Start work on proper DP link training
  
  * The AtomBIOS timeout fix has made my DP bridge
    stop working
  * The current DisplayPort code is a little lacking
    on DP link training... I think thats the cause.
  * This puts the first steps towards DP training
    in place.
  * I plan on trying to make some of this DP stuff
    common accelerant stuff after it works.

                          [ Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

9 files changed, 383 insertions(+), 51 deletions(-)
.../private/graphics/radeon_hd/displayport_reg.h   |    1 +
src/add-ons/accelerants/radeon_hd/accelerant.h     |   12 +
.../accelerants/radeon_hd/atombios/atom-names.h    |    9 +-
.../accelerants/radeon_hd/atombios/atom.cpp        |   47 ++-
src/add-ons/accelerants/radeon_hd/display.cpp      |    8 +-
src/add-ons/accelerants/radeon_hd/displayport.cpp  |  291 ++++++++++++++--
src/add-ons/accelerants/radeon_hd/displayport.h    |    2 +
src/add-ons/accelerants/radeon_hd/encoder.cpp      |   62 ++++-
src/add-ons/accelerants/radeon_hd/encoder.h        |    2 +

############################################################################

Commit:      32ef94aa9145f192cbbee7a72d5fadd924246d21
URL:         http://cgit.haiku-os.org/haiku/commit/?id=32ef94a
Author:      Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date:        Tue Mar 13 09:29:59 2012 UTC

radeon_hd: AtomBIOS loop failure detection now time based

* If the same call is made for 5 seconds straight, fail.
* Resolves random AtomBIOS failures.
* AtomBIOS failures now represent *real* bugs :)

----------------------------------------------------------------------------

diff --git a/src/add-ons/accelerants/radeon_hd/atombios/atom.cpp 
b/src/add-ons/accelerants/radeon_hd/atombios/atom.cpp
index d23321f..fa8ced5 100644
--- a/src/add-ons/accelerants/radeon_hd/atombios/atom.cpp
+++ b/src/add-ons/accelerants/radeon_hd/atombios/atom.cpp
@@ -36,10 +36,10 @@
 
 
 /* AtomBIOS loop detection
- * Number of repeat AtomBIOS jmp operations
- * before bailing due to stuck in a loop
+ * Number of seconds of identical jmp operations
+ * before detecting a fault.
  */
-#define ATOM_OP_JMP_TIMEOUT 512
+#define ATOM_OP_JMP_TIMEOUT 5
 
 // *** Tracing
 #undef TRACE
@@ -77,8 +77,9 @@ typedef struct {
        uint32 *ps, *ws;
        int ps_shift;
        uint16 start;
-       uint16 last_jump;
-       uint16 last_jump_count;
+       uint16 lastJump;
+       uint32 lastJumpCount;
+       bigtime_t jumpStart;
        bool abort;
 } atom_exec_context;
 
@@ -541,7 +542,7 @@ atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
        if (idx < ATOM_TABLE_NAMES_CNT) {
                TRACE("%s: table: %s (%d)\n", __func__, atom_table_names[idx], 
idx);
        } else {
-               TRACE("%s: table: unknown (%d)\n", __func__, idx);
+               ERROR("%s: table: unknown (%d)\n", __func__, idx);
        }
 
        if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) {
@@ -659,17 +660,20 @@ atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
                execute? "yes" : "no", target);
 
        if (execute) {
-               if (ctx->last_jump == (ctx->start + target)) {
-                       if (ctx->last_jump_count > ATOM_OP_JMP_TIMEOUT) {
-                               ERROR("%s: Error: AtomBIOS stuck in loop for 
more then %d"
-                                       " jumps... abort!\n", __func__, 
ATOM_OP_JMP_TIMEOUT);
+               // Time based jmp timeout
+               if (ctx->lastJump == (ctx->start + target)) {
+                       bigtime_t loopDuration = system_time() - ctx->jumpStart;
+                       if (loopDuration > ATOM_OP_JMP_TIMEOUT * 1000000) {
+                               ERROR("%s: Error: AtomBIOS stuck in loop for 
more then %d "
+                                       "seconds. (%" B_PRIu32 " identical jmp 
op's)\n", __func__,
+                                       ATOM_OP_JMP_TIMEOUT, 
ctx->lastJumpCount);
                                ctx->abort = true;
-                       } else {
-                               ctx->last_jump_count++;
-                       }
+                       } else
+                               ctx->lastJumpCount++;
                } else {
-                       ctx->last_jump = ctx->start + target;
-                       ctx->last_jump_count = 1;
+                       ctx->jumpStart = system_time();
+                       ctx->lastJump = ctx->start + target;
+                       ctx->lastJumpCount = 1;
                }
                *ptr = ctx->start + target;
        }
@@ -1137,8 +1141,10 @@ atom_execute_table_locked(atom_context *ctx, int index, 
uint32 * params)
        unsigned char op;
        atom_exec_context ectx;
 
-       if (!base)
+       if (!base) {
+               ERROR("%s: BUG: Table called doesn't exist in AtomBIOS!\n", 
__func__);
                return B_ERROR;
+       }
 
        len = CU16(base + ATOM_CT_SIZE_PTR);
        ws = CU8(base + ATOM_CT_WS_PTR);
@@ -1150,8 +1156,9 @@ atom_execute_table_locked(atom_context *ctx, int index, 
uint32 * params)
        ectx.start = base;
        ectx.ps = params;
        ectx.abort = false;
-       ectx.last_jump = 0;
-       ectx.last_jump_count = 0;
+       ectx.lastJump = 0;
+       ectx.lastJumpCount = 0;
+       ectx.jumpStart = 0;
        if (ws)
                ectx.ws = (uint32*)malloc(4 * ws);
        else
@@ -1212,8 +1219,8 @@ atom_execute_table(atom_context *ctx, int index, uint32 
*params)
                if (index < ATOM_TABLE_NAMES_CNT)
                        tableName = atom_table_names[index];
                else
-                       tableName = "Unknown"; 
-                       
+                       tableName = "Unknown";
+
                ERROR("%s: AtomBIOS parser was aborted in table %s (0x%" 
B_PRIX8 ")\n",
                        __func__, tableName, index);
        }

############################################################################

Commit:      119cd5e1c1a4d40cc19903094ec25f86d058a018
URL:         http://cgit.haiku-os.org/haiku/commit/?id=119cd5e
Author:      Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date:        Tue Mar 13 10:09:13 2012 UTC

radeon_hd: Add missing load detection on DIG encoders

----------------------------------------------------------------------------

diff --git a/src/add-ons/accelerants/radeon_hd/encoder.cpp 
b/src/add-ons/accelerants/radeon_hd/encoder.cpp
index f27a624..4058590 100644
--- a/src/add-ons/accelerants/radeon_hd/encoder.cpp
+++ b/src/add-ons/accelerants/radeon_hd/encoder.cpp
@@ -904,6 +904,20 @@ encoder_analog_load_detect(uint32 connectorIndex)
 {
        TRACE("%s\n", __func__);
 
+       uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
+
+       if (encoder_is_external(encoderID))
+               return encoder_dig_load_detect(connectorIndex);
+
+       return encoder_dac_load_detect(connectorIndex);
+}
+
+
+bool
+encoder_dac_load_detect(uint32 connectorIndex)
+{
+       TRACE("%s\n", __func__);
+
        uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags;
        uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
 
@@ -994,6 +1008,46 @@ encoder_analog_load_detect(uint32 connectorIndex)
 }
 
 
+bool
+encoder_dig_load_detect(uint32 connectorIndex)
+{
+       TRACE("%s\n", __func__);
+       radeon_shared_info &info = *gInfo->shared_info;
+
+       if (info.dceMajor < 4) {
+               ERROR("%s: Strange: External DIG encoder on DCE < 4?\n", 
__func__);
+               return false;
+       }
+
+       encoder_external_setup(connectorIndex, 0,
+               EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
+
+       uint32 biosScratch0 = Read32(OUT, R600_BIOS_0_SCRATCH);
+
+       uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags;
+
+       if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0)
+               if ((biosScratch0 & ATOM_S0_CRT1_MASK) != 0)
+                       return true;
+       if ((encoderFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0)
+               if ((biosScratch0 & ATOM_S0_CRT2_MASK) != 0)
+                       return true;
+       if ((encoderFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
+               if ((biosScratch0 & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) != 0)
+                       return true;
+       if ((encoderFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
+               if ((biosScratch0
+                       & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) != 
0)
+                       return true; /* Composite connected */
+               else if ((biosScratch0
+                       & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) != 0)
+                       return true; /* S-Video connected */
+       }
+
+       return false;
+}
+
+
 status_t
 transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
        uint8 laneNumber, uint8 laneSet, int command)
diff --git a/src/add-ons/accelerants/radeon_hd/encoder.h 
b/src/add-ons/accelerants/radeon_hd/encoder.h
index 429d1c1..2451c62 100644
--- a/src/add-ons/accelerants/radeon_hd/encoder.h
+++ b/src/add-ons/accelerants/radeon_hd/encoder.h
@@ -30,6 +30,8 @@ status_t encoder_tv_setup(uint32 connectorIndex,
        uint32 pixelClock, int command);
 
 bool encoder_analog_load_detect(uint32 connectorIndex);
+bool encoder_dac_load_detect(uint32 connectorIndex);
+bool encoder_dig_load_detect(uint32 connectorIndex);
 void encoder_output_lock(bool lock);
 status_t transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
        uint8 laneNumber, uint8 laneSet, int command);

############################################################################

Commit:      48b430fe0b42d443d47aebf6ed33dbe34e802715
URL:         http://cgit.haiku-os.org/haiku/commit/?id=48b430f
Author:      Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date:        Tue Mar 13 10:49:10 2012 UTC

radeon_hd: Add missing AtomBIOS tables

----------------------------------------------------------------------------

diff --git a/src/add-ons/accelerants/radeon_hd/atombios/atom-names.h 
b/src/add-ons/accelerants/radeon_hd/atombios/atom-names.h
index fdc0b54..e837092 100644
--- a/src/add-ons/accelerants/radeon_hd/atombios/atom-names.h
+++ b/src/add-ons/accelerants/radeon_hd/atombios/atom-names.h
@@ -21,12 +21,13 @@
  *
  * Author: Stanislaw Skowronek
  */
-
 #ifndef ATOM_NAMES_H
 #define ATOM_NAMES_H
 
+
 #include "atom.h"
 
+
 #define ATOM_OP_NAMES_CNT 123
 const char *atom_op_names[ATOM_OP_NAMES_CNT] = {
 "RESERVED", "MOVE_REG", "MOVE_PS", "MOVE_WS", "MOVE_FB", "MOVE_PLL",
@@ -53,7 +54,7 @@ const char *atom_op_names[ATOM_OP_NAMES_CNT] = {
 "DEBUG", "CTB_DS",
 };
 
-#define ATOM_TABLE_NAMES_CNT 74
+#define ATOM_TABLE_NAMES_CNT 80
 const char *atom_table_names[ATOM_TABLE_NAMES_CNT] = {
 "ASIC_Init", "GetDisplaySurfaceSize", "ASIC_RegistersInit",
 "VRAM_BlockVenderDetection", "SetClocksRatio", "MemoryControllerInit",
@@ -79,7 +80,9 @@ const char *atom_table_names[ATOM_TABLE_NAMES_CNT] = {
 "VRAM_GetCurrentInfoBlock", "DynamicMemorySettings", "MemoryTraining",
 "EnableLVDS_SS", "DFP1OutputControl", "SetVoltage", "CRT1OutputControl",
 "CRT2OutputControl", "SetupHWAssistedI2CStatus", "ClockSource",
-"MemoryDeviceInit", "EnableYUV",
+"MemoryDeviceInit", "EnableYUV", "DIG1EncoderControl", "DIG2EncoderControl",
+"DIG1TransmitterControl (UNIPHY)", "DIG2TransmitterControl (LVTMA)",
+"ProcessAuxChannelTransaction", "DPEncoderService",
 };
 
 #define ATOM_IO_NAMES_CNT 5

############################################################################

Commit:      6f7c0aadbe2aa26986c4f8ea701caa36ce7d421c
URL:         http://cgit.haiku-os.org/haiku/commit/?id=6f7c0aa
Author:      Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date:        Tue Mar 13 11:18:57 2012 UTC

radeon_hd: Whitespace cleanup, no functional change

----------------------------------------------------------------------------

diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp 
b/src/add-ons/accelerants/radeon_hd/display.cpp
index 9a35988..c694b2e 100644
--- a/src/add-ons/accelerants/radeon_hd/display.cpp
+++ b/src/add-ons/accelerants/radeon_hd/display.cpp
@@ -477,7 +477,7 @@ display_crtc_dpms(uint8 crtcID, int mode)
        radeon_shared_info &info = *gInfo->shared_info;
 
        switch (mode) {
-        case B_DPMS_ON:
+               case B_DPMS_ON:
                        TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, 
crtcID);
                        if (gDisplay[crtcID]->attached == false)
                                return;
@@ -487,9 +487,9 @@ display_crtc_dpms(uint8 crtcID, int mode)
                                display_crtc_memreq(crtcID, ATOM_ENABLE);
                        display_crtc_blank(crtcID, ATOM_BLANKING_OFF);
                        break;
-        case B_DPMS_STAND_BY:
-        case B_DPMS_SUSPEND:
-        case B_DPMS_OFF:
+               case B_DPMS_STAND_BY:
+               case B_DPMS_SUSPEND:
+               case B_DPMS_OFF:
                        TRACE("%s: crtc %" B_PRIu8 " dpms powerdown\n", 
__func__, crtcID);
                        if (gDisplay[crtcID]->attached == false)
                                return;

############################################################################

Revision:    hrev43852
Commit:      83e3a8ea5013ca577e735016437d0b526c20b7db
URL:         http://cgit.haiku-os.org/haiku/commit/?id=83e3a8e
Author:      Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date:        Wed Mar 14 10:18:41 2012 UTC

radeon_hd: Start work on proper DP link training

* The AtomBIOS timeout fix has made my DP bridge
  stop working
* The current DisplayPort code is a little lacking
  on DP link training... I think thats the cause.
* This puts the first steps towards DP training
  in place.
* I plan on trying to make some of this DP stuff
  common accelerant stuff after it works.

----------------------------------------------------------------------------

diff --git a/headers/private/graphics/radeon_hd/displayport_reg.h 
b/headers/private/graphics/radeon_hd/displayport_reg.h
index a13ca8c..9d44c1d 100644
--- a/headers/private/graphics/radeon_hd/displayport_reg.h
+++ b/headers/private/graphics/radeon_hd/displayport_reg.h
@@ -136,6 +136,7 @@
 #define DP_INTERLANE_ALIGN_DONE                                (1 << 0)
 #define DP_DOWNSTREAM_PORT_STATUS_CHANGED      (1 << 6)
 #define DP_LINK_STATUS_UPDATED                         (1 << 7)
+#define DP_LINK_STATUS_SIZE                                    6
 
 #define DP_SINK_STATUS                                         0x205
 
diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h 
b/src/add-ons/accelerants/radeon_hd/accelerant.h
index 25898c7..b3bacb7 100644
--- a/src/add-ons/accelerants/radeon_hd/accelerant.h
+++ b/src/add-ons/accelerants/radeon_hd/accelerant.h
@@ -14,6 +14,7 @@
 #include <edid.h>
 
 #include "atom.h"
+#include "displayport_reg.h"
 #include "encoder.h"
 #include "mode.h"
 #include "pll.h"
@@ -126,11 +127,22 @@ typedef struct {
 
 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;
 
diff --git a/src/add-ons/accelerants/radeon_hd/displayport.cpp 
b/src/add-ons/accelerants/radeon_hd/displayport.cpp
index 4b15a48..19bd914 100644
--- a/src/add-ons/accelerants/radeon_hd/displayport.cpp
+++ b/src/add-ons/accelerants/radeon_hd/displayport.cpp
@@ -11,7 +11,6 @@
 
 #include <Debug.h>
 
-#include "accelerant.h"
 #include "accelerant_protos.h"
 #include "connector.h"
 #include "mode.h"
@@ -403,12 +402,15 @@ dp_setup_connectors()
                }
 
                uint32 gpioID = gConnector[index]->gpioID;
-               uint32 hwPin = gGPIOInfo[gpioID]->hwPin;
+
+               uint32 auxPin = gGPIOInfo[gpioID]->hwPin;
+               gDPInfo[index]->auxPin = auxPin;
+               gDPInfo[index]->connectorIndex = index;
 
                uint8 auxMessage[25];
                int result;
 
-               result = dp_aux_read(hwPin, DP_DPCD_REV, auxMessage, 8, 0);
+               result = dp_aux_read(auxPin, DP_DPCD_REV, auxMessage, 8, 0);
                if (result > 0) {
                        gDPInfo[index]->valid = true;
                        memcpy(gDPInfo[index]->config, auxMessage, 8);
@@ -419,14 +421,255 @@ dp_setup_connectors()
 }
 
 
+static bool
+dp_get_link_status(dp_info* dp)
+{
+       int result = dp_aux_read(dp->auxPin, DP_LANE0_1_STATUS,
+               dp->linkStatus, DP_LINK_STATUS_SIZE, 100);
+
+       if (result <= 0) {
+               ERROR("%s: DisplayPort link status failed\n", __func__);
+               return false;
+       }
+
+       return true;
+}
+
+
+static uint8
+dp_get_lane_status(dp_info* dp, int lane)
+{
+       int i = DP_LANE0_1_STATUS + (lane >> 1);
+       int s = (lane & 1) * 4;
+       uint8 l = dp->linkStatus[i - DP_LANE0_1_STATUS];
+       return (l >> s) & 0xf;
+}
+
+
+static bool
+dp_clock_recovery_ok(dp_info* dp)
+{
+       int lane;
+       uint8 laneStatus;
+
+       for (lane = 0; lane < dp->laneCount; lane++) {
+               laneStatus = dp_get_lane_status(dp, lane);
+               if ((laneStatus & DP_LANE_CR_DONE) == 0)
+                       return false;
+       }
+       return true;
+}
+
+
+static void
+dp_update_vs_emph(dp_info* dp)
+{
+       // Set initial vs and emph on source
+       transmitter_dig_setup(dp->connectorIndex, dp->clock, 0, 
dp->trainingSet[0],
+               ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
+
+       // Set vs and emph on the sink
+       dp_aux_write(dp->auxPin, DP_TRAINING_LANE0_SET,
+               dp->trainingSet, dp->laneCount, 0);
+}
+
+
+static uint8
+dp_get_adjust_request_voltage(dp_info* dp, int lane)
+{
+       int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int s = (((lane & 1) != 0) ? DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT
+               : DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
+       uint8 l = dp->linkStatus[i - DP_LANE0_1_STATUS];
+
+       return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
+}
+
+
+static uint8
+dp_get_adjust_request_pre_emphasis(dp_info* dp, int lane)
+{
+       int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int s = (((lane & 1) != 0) ? DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT
+               : DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
+       uint8 l = dp->linkStatus[i - DP_LANE0_1_STATUS];
+
+       return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+}
+
+
+#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
+#define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPHASIS_9_5
+
+
+static void
+dp_get_adjust_train(dp_info* dp)
+{
+       TRACE("%s\n", __func__);
+
+       const char* voltageNames[] = {
+               "0.4V", "0.6V", "0.8V", "1.2V"
+       };
+       const char* preEmphasisNames[] = {
+               "0dB", "3.5dB", "6dB", "9.5dB"
+       };
+
+       uint8 voltage = 0;
+       uint8 preEmphasis = 0;
+       int lane;
+
+       for (lane = 0; lane < dp->laneCount; lane++) {
+               uint8 laneVoltage = dp_get_adjust_request_voltage(dp, lane);
+               uint8 lanePreEmphasis = dp_get_adjust_request_pre_emphasis(dp, 
lane);
+
+               TRACE("%s: Requested %s at %s for lane %d\n", __func__,
+                       preEmphasisNames[lanePreEmphasis >> 
DP_TRAIN_PRE_EMPHASIS_SHIFT],
+                       voltageNames[laneVoltage >> 
DP_TRAIN_VOLTAGE_SWING_SHIFT],
+                       lane);
+
+               if (laneVoltage > voltage)
+                       voltage = laneVoltage;
+               if (lanePreEmphasis > preEmphasis)
+                       preEmphasis = lanePreEmphasis;
+       }
+
+       if (voltage >= DP_VOLTAGE_MAX)
+               voltage |= DP_TRAIN_MAX_SWING_REACHED;
+
+       if (preEmphasis >= DP_PRE_EMPHASIS_MAX)
+               preEmphasis |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+       for (lane = 0; lane < 4; lane++)
+               dp->trainingSet[lane] = voltage | preEmphasis;
+}
+
+
+static void
+dp_set_tp(dp_info* dp, int trainingPattern)
+{
+       TRACE("%s\n", __func__);
+
+       radeon_shared_info &info = *gInfo->shared_info;
+
+       int rawTrainingPattern = 0;
+
+       /* set training pattern on the source */
+       if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
+               switch (trainingPattern) {
+                       case DP_TRAINING_PATTERN_1:
+                               rawTrainingPattern = 
ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
+                               break;
+                       case DP_TRAINING_PATTERN_2:
+                               rawTrainingPattern = 
ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
+                               break;
+                       case DP_TRAINING_PATTERN_3:
+                               rawTrainingPattern = 
ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
+                               break;
+               }
+               // TODO: PixelClock 0 ok?
+               encoder_dig_setup(dp->connectorIndex, 0, rawTrainingPattern);
+       } else {
+               ERROR("%s: TODO: dp_encoder_service\n", __func__);
+               return;
+               #if 0
+               switch (trainingPattern) {
+                       case DP_TRAINING_PATTERN_1:
+                               rawTrainingPattern = 0;
+                               break;
+                       case DP_TRAINING_PATTERN_2:
+                               rawTrainingPattern = 1;
+                               break;
+               }
+               radeon_dp_encoder_service(dp_info->rdev,
+                       ATOM_DP_ACTION_TRAINING_PATTERN_SEL, dp_info->dp_clock,
+                       dp_info->enc_id, rawTrainingPattern);
+               #endif
+       }
+
+       // Enable training pattern on the sink
+       dpcd_reg_write(dp->auxPin, DP_TRAINING_PATTERN_SET, trainingPattern);
+}
+
+
+status_t
+dp_link_train_cr(dp_info* dp)
+{
+       TRACE("%s\n", __func__);
+
+       // Display Port Clock Recovery Training
+
+       bool clockRecovery = false;
+       uint8 voltage = 0xff;
+       int lane;
+
+       dp_set_tp(dp, DP_TRAINING_PATTERN_1);
+       memset(dp->trainingSet, 0, 4);
+       dp_update_vs_emph(dp);
+
+       while (1) {
+               if (dp->trainingReadInterval == 0)
+                       snooze(100);
+               else
+                       snooze(1000 * 4 * dp->trainingReadInterval);
+
+               if (!dp_get_link_status(dp))
+                       break;
+
+               if (dp_clock_recovery_ok(dp)) {
+                       clockRecovery = true;
+                       break;
+               }
+
+               for (lane = 0; lane < dp->laneCount; lane++) {
+                       if ((dp->trainingSet[lane] & 
DP_TRAIN_MAX_SWING_REACHED) == 0)
+                               break;
+               }
+
+               if (lane == dp->laneCount) {
+                       ERROR("%s: clock recovery reached max voltage\n", 
__func__);
+                       break;
+               }
+
+               if ((dp->trainingSet[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == 
voltage) {
+                       dp->trainingAttempts++;
+                       if (dp->trainingAttempts >= 5) {
+                               ERROR("%s: clock recovery tried 5 times\n", 
__func__);
+                               break;
+                       }
+               } else
+                       dp->trainingAttempts = 0;
+
+               voltage = dp->trainingSet[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+               // Compute new trainingSet as requested by sink
+               dp_get_adjust_train(dp);
+
+               dp_update_vs_emph(dp);
+       }
+
+       if (!clockRecovery) {
+               ERROR("%s: clock recovery failed\n", __func__);
+               return B_ERROR;
+       }
+
+       TRACE("%s: clock recovery at voltage %d pre-emphasis %d\n",
+               __func__, dp->trainingSet[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+               (dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
+               >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
+       return B_OK;
+}
+
+
 status_t
 dp_link_train(uint8 crtcID, display_mode* mode)
 {
        TRACE("%s\n", __func__);
 
        uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
-       if (gDPInfo[connectorIndex]->valid != true) {
-               ERROR("%s: started on non-DisplayPort connector #%" B_PRIu32 
"\n",
+       dp_info* dp = gDPInfo[connectorIndex];
+
+       if (dp->valid != true) {
+               ERROR("%s: started on invalid DisplayPort connector #%" 
B_PRIu32 "\n",
                        __func__, connectorIndex);
                return B_ERROR;
        }
@@ -436,13 +679,13 @@ dp_link_train(uint8 crtcID, display_mode* mode)
        uint8 tableMajor;
        uint8 tableMinor;
 
-       bool dpUseEncoder = true;
+       dp->trainingUseEncoder = true;
        if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
                == B_OK) {
                if (tableMinor > 1) {
                        // The AtomBIOS DPEncoderService greater then 1.1 can't 
program the
                        // training pattern properly.
-                       dpUseEncoder = false;
+                       dp->trainingUseEncoder = false;
                }
        }
 
@@ -461,22 +704,24 @@ dp_link_train(uint8 crtcID, display_mode* mode)
        else
                dpEncoderID |= ATOM_DP_CONFIG_LINK_A;
 
-       //uint8 dpReadInterval = dpcd_reg_read(hwPin, 
DP_TRAINING_AUX_RD_INTERVAL);
+       dp->trainingReadInterval
+               = dpcd_reg_read(hwPin, DP_TRAINING_AUX_RD_INTERVAL);
+
        uint8 sandbox = dpcd_reg_read(hwPin, DP_MAX_LANE_COUNT);
 
        radeon_shared_info &info = *gInfo->shared_info;
-       bool dpTPS3Supported = false;
-       if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0)
-               dpTPS3Supported = true;
+       //bool dpTPS3Supported = false;
+       //if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0)
+       //      dpTPS3Supported = true;
 
-       // DisplayPort training initialization
+       // *** DisplayPort link training initialization
 
        // Power up the DP sink
-       if (gDPInfo[connectorIndex]->config[0] >= 0x11)
+       if (dp->config[0] >= 0x11)
                dpcd_reg_write(hwPin, DP_SET_POWER, DP_SET_POWER_D0);
 
        // Possibly enable downspread on the sink
-       if ((gDPInfo[connectorIndex]->config[3] & 0x1) != 0)
+       if ((dp->config[3] & 0x1) != 0)
                dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
        else
                dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, 0);
@@ -484,16 +729,16 @@ dp_link_train(uint8 crtcID, display_mode* mode)
        encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
                ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
 
-       if (gDPInfo[connectorIndex]->config[0] >= 0x11)
+       if (dp->config[0] >= 0x11)
                sandbox |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
        dpcd_reg_write(hwPin, DP_LANE_COUNT_SET, sandbox);
 
        // Set the link rate on the DP sink
-       sandbox = dp_get_link_clock_encode(gDPInfo[connectorIndex]->clock);
+       sandbox = dp_get_link_clock_encode(dp->clock);
        dpcd_reg_write(hwPin, DP_LINK_BW_SET, sandbox);
 
        // Start link training on source
-       if (info.dceMajor >= 4 || !dpUseEncoder) {
+       if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
                encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
                        ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
        } else {
@@ -501,21 +746,23 @@ dp_link_train(uint8 crtcID, display_mode* mode)
                        __func__);
        }
 
-       /* disable the training pattern on the sink */
+       // Disable the training pattern on the sink
        dpcd_reg_write(hwPin, DP_TRAINING_PATTERN_SET,
                DP_TRAINING_PATTERN_DISABLE);
 
-       // TODO: dp_link_train_cr
+       dp_link_train_cr(dp);
        // TODO: dp_link_train_ce
 
+
+       // *** DisplayPort link training finish
        snooze(400);
 
-       /* disable the training pattern on the sink */
+       // Disable the training pattern on the sink
        dpcd_reg_write(hwPin, DP_TRAINING_PATTERN_SET,
                DP_TRAINING_PATTERN_DISABLE);
 
-       /* disable the training pattern on the source */
-       if (info.dceMajor >= 4 || !dpUseEncoder) {
+       // Disable the training pattern on the source
+       if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
                encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
                        ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
        } else {
diff --git a/src/add-ons/accelerants/radeon_hd/displayport.h 
b/src/add-ons/accelerants/radeon_hd/displayport.h
index 5a705dc..dff3f36 100644
--- a/src/add-ons/accelerants/radeon_hd/displayport.h
+++ b/src/add-ons/accelerants/radeon_hd/displayport.h
@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <SupportDefs.h>
 
+#include "accelerant.h"
 #include "displayport_reg.h"
 
 
@@ -32,6 +33,7 @@ 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);
 
 
 #endif /* RADEON_HD_DISPLAYPORT_H */
diff --git a/src/add-ons/accelerants/radeon_hd/encoder.cpp 
b/src/add-ons/accelerants/radeon_hd/encoder.cpp
index 4058590..4ec0991 100644
--- a/src/add-ons/accelerants/radeon_hd/encoder.cpp
+++ b/src/add-ons/accelerants/radeon_hd/encoder.cpp
@@ -1069,8 +1069,12 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 
pixelClock,
                        index = GetIndexIntoMasterTable(COMMAND, 
LVTMATransmitterControl);
                        break;
                default:
-                       ERROR("%s: called on non-dig encoder!\n", __func__);
-                       return B_ERROR;
+                       // Multiple encoders can be wired to a single connector
+                       // An example is UNIPHY -> DP -> TRAVIS -> LVDS
+                       ERROR("%s: BUG: guessing UNIPHY as this isn't a dig 
encoder!\n",
+                               __func__);
+                       index = GetIndexIntoMasterTable(COMMAND, 
UNIPHYTransmitterControl);
+                       break;
        }
 
        if (index < 0) {


Other related posts:

  • » [haiku-commits] haiku: hrev43852 - in src/add-ons/accelerants/radeon_hd: . atombios - kallisti5