first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <debug.h>
|
||||
#include <drivers/displayport/displayport.h>
|
||||
#include <drivers/displayport.h>
|
||||
#include <sys/task.h>
|
||||
|
||||
#if WITH_HW_MCU
|
||||
#include <drivers/process_edid.h>
|
||||
#endif
|
||||
|
||||
#include "dpcd.h"
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// debug support
|
||||
|
||||
#define DP_DEBUG_MASK ( \
|
||||
DP_DEBUG_INIT | \
|
||||
DP_DEBUG_ERROR | \
|
||||
DP_DEBUG_INFO | \
|
||||
DP_DEBUG_TRAINING | \
|
||||
0)
|
||||
|
||||
#undef DP_DEBUG_MASK
|
||||
#define DP_DEBUG_MASK (DP_DEBUG_INIT | DP_DEBUG_ERROR)
|
||||
|
||||
#define DP_DEBUG_INIT (1<<16) // initialisation
|
||||
#define DP_DEBUG_ERROR (1<<17) // errors
|
||||
#define DP_DEBUG_INFO (1<<18) // info
|
||||
#define DP_DEBUG_TRAINING (1<<19) // link training
|
||||
#define DP_DEBUG_ALWAYS (1<<31) // unconditional output
|
||||
|
||||
#define debug(_fac, _fmt, _args...) \
|
||||
do { \
|
||||
if ((DP_DEBUG_ ## _fac) & (DP_DEBUG_MASK | DP_DEBUG_ALWAYS)) \
|
||||
dprintf(DEBUG_CRITICAL, "DPC: %s, %d: " _fmt, __FUNCTION__, __LINE__, ##_args); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// consts, macros
|
||||
|
||||
#define kMaxRetry 5
|
||||
#define kClockRecoveryDelay 100
|
||||
#define kEQDelay 400
|
||||
#define kMaxClockRecoveryIterations 100
|
||||
|
||||
|
||||
#define require(assertion, exception_label) \
|
||||
do { \
|
||||
if (__builtin_expect(!(assertion), 0)) \
|
||||
{ \
|
||||
goto exception_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define require_action(assertion, exception_label, action) \
|
||||
do { \
|
||||
if (__builtin_expect(!(assertion), 0)) \
|
||||
{ \
|
||||
{ \
|
||||
action; \
|
||||
} \
|
||||
goto exception_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define require_noerr(error_code, exception_label) \
|
||||
do { \
|
||||
if (__builtin_expect(0 != (error_code), 0)) \
|
||||
{ \
|
||||
goto exception_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define require_noerr_action(error_code, exception_label, action) \
|
||||
do { \
|
||||
if (__builtin_expect(0 != (error_code), 0)) \
|
||||
{ \
|
||||
{ \
|
||||
action; \
|
||||
} \
|
||||
goto exception_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// typedefs, enums, structs
|
||||
|
||||
enum {
|
||||
kLinkTrainingStateIdle,
|
||||
kLinkTrainingStateStart,
|
||||
kLinkTrainingStateClockRecovery,
|
||||
kLinkTrainingStateEQTraining
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// local variables
|
||||
|
||||
static u_int8_t dp_link_clock_recovery_retry[kDPMaxLanes];
|
||||
static bool dp_link_voltage_swing_max[kDPMaxLanes];
|
||||
static bool dp_link_eq_max[kDPMaxLanes];
|
||||
static u_int8_t dp_link_eq_retry;
|
||||
static u_int32_t dp_link_clock_recovery_iterations;
|
||||
static u_int8_t dp_link_eq_iterations;
|
||||
static struct video_link_data dp_video_data;
|
||||
static int eq_pattern = kDPTrainingPattern2;
|
||||
static dp_t dp_link_config = {
|
||||
.mode = kDPControllerMode_Master,
|
||||
.type = kDPControllerType_DP,
|
||||
.min_link_rate = 0x6,
|
||||
.max_link_rate = 0x6,
|
||||
.lanes = 4,
|
||||
.ssc = 0,
|
||||
.alpm = 0,
|
||||
.vrr_enable = 0,
|
||||
.vrr_on = 0,
|
||||
};
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// local functions declaration
|
||||
|
||||
static int run_link_training_state_machine(struct dp_link_train_data *data);
|
||||
static int process_link_state_start(struct dp_link_train_data *data, u_int32_t *state);
|
||||
static int process_link_state_clock_recovery(struct dp_link_train_data *data, u_int32_t *state);
|
||||
static int process_link_state_eq_training(struct dp_link_train_data *data, u_int32_t *state);
|
||||
static int process_link_state_eq_training_internal(struct dp_link_train_data *data, uint32_t lane, bool *done);
|
||||
static int process_link_state_clock_recovery_internal(struct dp_link_train_data * data, uint32_t lane, bool *p_done);
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// DisplayPort global functions
|
||||
|
||||
int displayport_init(dp_t *dp)
|
||||
{
|
||||
// defaults to External display, and Master mode
|
||||
if ( dp_controller_start(dp) != 0 )
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int displayport_init_with_timing_info(struct display_timing *timing_info)
|
||||
{
|
||||
memcpy(&dp_link_config, timing_info->display_config, sizeof(dp_t));
|
||||
|
||||
displayport_set_timings(timing_info);
|
||||
|
||||
if ( dp_controller_start(&dp_link_config) != 0 )
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int displayport_set_timings(struct display_timing *timing_info)
|
||||
{
|
||||
u_int8_t mode;
|
||||
|
||||
memcpy(&dp_link_config, timing_info->display_config, sizeof(dp_t));
|
||||
mode = dp_link_config.mode;
|
||||
|
||||
bzero(&dp_video_data, sizeof(struct video_link_data));
|
||||
|
||||
dp_video_data.mirror_mode = (mode == kDPControllerMode_Slave) ? true : false;
|
||||
dp_video_data.test_mode = 0;
|
||||
dp_video_data.color.depth = 8;
|
||||
dp_video_data.color.space = kDisplayColorSpacesRGB;
|
||||
dp_video_data.color.range = kDisplayColorDynamicRangeVESA;
|
||||
dp_video_data.color.coefficient = kDisplayColorCoefficientITU601;
|
||||
dp_video_data.timing.axis[0].total = timing_info->h_active + timing_info->h_back_porch +
|
||||
timing_info->h_front_porch + timing_info->h_pulse_width;
|
||||
dp_video_data.timing.axis[0].active = timing_info->h_active;
|
||||
dp_video_data.timing.axis[0].sync_width = timing_info->h_pulse_width;
|
||||
dp_video_data.timing.axis[0].back_porch = timing_info->h_back_porch;
|
||||
dp_video_data.timing.axis[0].front_porch = timing_info->h_front_porch;
|
||||
dp_video_data.timing.axis[0].sync_rate = 0;
|
||||
// Hsync polarity: 0->negative, 1->positive.
|
||||
dp_video_data.timing.axis[0].sync_polarity = timing_info->neg_hsync ? 0 : 1;
|
||||
dp_video_data.timing.axis[1].total = timing_info->v_active + timing_info->v_back_porch +
|
||||
timing_info->v_front_porch + timing_info->v_pulse_width;
|
||||
dp_video_data.timing.axis[1].active = timing_info->v_active;
|
||||
dp_video_data.timing.axis[1].sync_width = timing_info->v_pulse_width;
|
||||
dp_video_data.timing.axis[1].back_porch = timing_info->v_back_porch;
|
||||
dp_video_data.timing.axis[1].front_porch = timing_info->v_front_porch;
|
||||
dp_video_data.timing.axis[1].sync_rate = (60 << 16);
|
||||
// Vsync polarity: 0->negative, 1->positive.
|
||||
dp_video_data.timing.axis[1].sync_polarity = timing_info->neg_vsync ? 0 : 1;
|
||||
|
||||
debug(INFO, "vTotal:%d hTotal:%d\n", dp_video_data.timing.axis[1].total, dp_video_data.timing.axis[0].total);
|
||||
|
||||
#if WITH_HW_MCU
|
||||
// Restrict EDID choices to timings matching these, otherwise the
|
||||
// framebuffer dimensions will mismatch.
|
||||
restrict_edid(dp_video_data.timing.axis[0].active,
|
||||
dp_video_data.timing.axis[1].active);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void displayport_quiesce()
|
||||
{
|
||||
dp_controller_stop();
|
||||
}
|
||||
|
||||
int displayport_start_video(void)
|
||||
{
|
||||
#if WITH_HW_MCU && WITH_HW_HOOVER
|
||||
int downstream_type = get_edid_downstream_type();
|
||||
if (downstream_type == kDPDownstreamTypeDVI) {
|
||||
uint8_t data;
|
||||
dp_controller_read_bytes_dpcd(DPCD_ADDR_HDMI_DVI_MODE_SELECT, &data, sizeof(data));
|
||||
data |= DPCD_ADDR_HDMI_DVI_MODE_SELECT_DVI;
|
||||
debug(INFO, "Reprogramming Hoover to be in DVI mode: data 0x%x\n", data);
|
||||
dp_controller_write_bytes_dpcd(DPCD_ADDR_HDMI_DVI_MODE_SELECT, &data, sizeof(data));
|
||||
}
|
||||
#endif
|
||||
return dp_controller_start_video(&dp_video_data);
|
||||
}
|
||||
|
||||
int displayport_enable_alpm(bool enable)
|
||||
{
|
||||
return dp_controller_enable_alpm(enable, &dp_video_data);
|
||||
}
|
||||
|
||||
#if WITH_HW_DISPLAY_EDP
|
||||
int displayport_get_raw_panel_id(u_int8_t *raw_panel_id)
|
||||
{
|
||||
//caller is responsible for waiting for HPD
|
||||
return dp_device_get_raw_panel_id(raw_panel_id);
|
||||
}
|
||||
#endif // WITH_HW_DISPLAY_EDP
|
||||
|
||||
bool displayport_video_configured()
|
||||
{
|
||||
return dp_controller_video_configured();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// controller global functions
|
||||
|
||||
int dp_controller_train_link(struct dp_link_train_data *data)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t lc;
|
||||
u_int32_t lr;
|
||||
u_int32_t retry = 0;
|
||||
|
||||
ret = -1;
|
||||
|
||||
lc = data->lane_count;
|
||||
lr = data->link_rate;
|
||||
|
||||
do {
|
||||
|
||||
data->lane_count = __min((dp_controller_get_max_lane_count()), lc);
|
||||
data->link_rate = __min((dp_controller_get_max_link_rate()), lr);
|
||||
|
||||
do {
|
||||
// check if the device has sufficient bandwidth
|
||||
if ( data->lane_count < dp_controller_get_min_lane_count() ) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = run_link_training_state_machine(data);
|
||||
|
||||
if ( ret != 0 ) {
|
||||
if ( !data->fast ) {
|
||||
data->link_rate = __min((dp_controller_get_max_link_rate()), lr);
|
||||
data->lane_count = data->lane_count/2;
|
||||
} else {
|
||||
data->fast = false;
|
||||
}
|
||||
}
|
||||
} while ( ret != 0 );
|
||||
|
||||
} while ( ret != 0 && ++retry < 5 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// controller local functions
|
||||
|
||||
static int run_link_training_state_machine(struct dp_link_train_data *data)
|
||||
{
|
||||
u_int32_t state = kLinkTrainingStateStart;
|
||||
int ret;
|
||||
|
||||
debug(TRAINING, "Preparing to establish new link\n");
|
||||
|
||||
// establish link training
|
||||
do {
|
||||
switch(state) {
|
||||
case kLinkTrainingStateStart:
|
||||
ret = process_link_state_start(data, &state);
|
||||
break;
|
||||
case kLinkTrainingStateClockRecovery:
|
||||
ret = process_link_state_clock_recovery(data, &state);
|
||||
break;
|
||||
case kLinkTrainingStateEQTraining:
|
||||
ret = process_link_state_eq_training(data, &state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
debug(TRAINING, "Performing Link training state=%d result=%d\n", state, ret);
|
||||
|
||||
if ( ret != 0 )
|
||||
state = kLinkTrainingStateIdle;
|
||||
|
||||
} while ( state != kLinkTrainingStateIdle );
|
||||
|
||||
debug(TRAINING, "Link training result=%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int process_link_state_start(struct dp_link_train_data *data, u_int32_t *state)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t index;
|
||||
#if DISPLAYPORT_VERSION > 2
|
||||
eq_pattern = dp_device_get_supports_training_pattern3() ? kDPTrainingPattern3 : kDPTrainingPattern2;
|
||||
#endif
|
||||
|
||||
ret = -1;
|
||||
|
||||
debug(TRAINING, "Begining START phase of link traing. Initial lanecount=%d linkRate=%u bps\n",
|
||||
data->lane_count, data->link_rate);
|
||||
|
||||
bzero(dp_link_clock_recovery_retry, sizeof(dp_link_clock_recovery_retry));
|
||||
bzero(dp_link_voltage_swing_max, sizeof(dp_link_voltage_swing_max));
|
||||
bzero(dp_link_eq_max, sizeof(dp_link_eq_max));
|
||||
dp_link_eq_retry = 0;
|
||||
dp_link_clock_recovery_iterations = 0;
|
||||
dp_link_eq_iterations = 0;
|
||||
|
||||
// Set link rate and count as you want to establish
|
||||
// set device
|
||||
ret = dp_device_set_enhanced_mode(data->enhanced_mode);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device enhanced mode\n"));
|
||||
|
||||
ret = dp_device_set_ASSR(data->assr);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device assr\n"));
|
||||
|
||||
ret = dp_device_set_downspread(data->downspread);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device downspread\n"));
|
||||
|
||||
ret = dp_device_set_link_rate(data->link_rate);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device link rate\n"));
|
||||
|
||||
ret = dp_device_set_lane_count(data->lane_count);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device lane count\n"));
|
||||
|
||||
// set controller
|
||||
ret = dp_controller_set_link_rate(data->link_rate);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller link rate\n"));
|
||||
|
||||
ret = dp_controller_set_enhanced_mode(data->enhanced_mode);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller enhanced mode\n"));
|
||||
|
||||
ret = dp_controller_set_ASSR(data->assr);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller assr\n"));
|
||||
|
||||
ret = dp_controller_set_downspread(data->downspread);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller downspread\n"));
|
||||
|
||||
ret = dp_controller_set_lane_count(data->lane_count);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller lane count\n"));
|
||||
|
||||
for ( index=0; index<data->lane_count; index++) {
|
||||
ret = dp_controller_set_adjustment_levels(index, kDPVoltageLevelMin, kDPEQLevelMin, NULL, NULL);
|
||||
if ( ret != 0 ) {
|
||||
debug(ERROR, "Failed to set controller adjustment\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = dp_device_set_adjustment_levels(index, kDPVoltageLevelMin, kDPEQLevelMin, false, false);
|
||||
if ( ret != 0 ) {
|
||||
debug(ERROR, "Failed to set device adjustment\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to adjustment levels\n"));
|
||||
|
||||
ret = dp_controller_set_training_pattern(kDPTrainingPattern1, false);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller training pattern\n"));
|
||||
|
||||
ret = dp_device_set_training_pattern(kDPTrainingPattern1, false);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device training pattern\n"));
|
||||
|
||||
require(!data->fast, train_fast);
|
||||
|
||||
*state = kLinkTrainingStateClockRecovery;
|
||||
|
||||
return ret;
|
||||
|
||||
train_fast:
|
||||
debug(TRAINING, "Skipping to fast link training\n");
|
||||
|
||||
task_sleep(1 * 1000);
|
||||
|
||||
ret = dp_controller_set_training_pattern(eq_pattern, false);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller training pattern\n"));
|
||||
|
||||
ret = dp_device_set_training_pattern(eq_pattern, false);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device training pattern\n"));
|
||||
|
||||
task_sleep(1 * 1000);
|
||||
|
||||
ret = dp_controller_set_training_pattern(kDPTrainingPatternNone, true);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set controller training pattern\n"));
|
||||
|
||||
ret = dp_device_set_training_pattern(kDPTrainingPatternNone, true);
|
||||
require_noerr_action(ret, exit, debug(ERROR, "Failed to set device training pattern\n"));
|
||||
|
||||
exit:
|
||||
*state = kLinkTrainingStateIdle;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int process_link_state_clock_recovery(struct dp_link_train_data *data, u_int32_t *state)
|
||||
{
|
||||
uint32_t lane;
|
||||
uint32_t alignment_status;
|
||||
bool done = true;
|
||||
bool succeed = true;
|
||||
int ret = 0;
|
||||
|
||||
spin(kClockRecoveryDelay);
|
||||
|
||||
ret = dp_device_get_alignment_status_mask(&alignment_status);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
for ( lane=0; lane<data->lane_count; lane++ ) {
|
||||
ret = process_link_state_clock_recovery_internal(data, lane, &done);
|
||||
succeed &= ( ret == 0 );
|
||||
}
|
||||
|
||||
if ( !done ) {
|
||||
ret = dp_device_set_training_pattern(kDPTrainingPattern1, false);
|
||||
require_noerr(ret, exit);
|
||||
}
|
||||
|
||||
if ( !succeed ) {
|
||||
debug(TRAINING, "loop failed: linkRate=%u bps\n", data->link_rate);
|
||||
// traing pattern : Set to Normal
|
||||
ret = dp_controller_set_training_pattern(kDPTrainingPatternNone, true);
|
||||
require_noerr(ret, exit);
|
||||
ret = dp_device_set_training_pattern(kDPTrainingPatternNone, true);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
// reduce bit rate
|
||||
if ( (data->link_rate > dp_controller_get_min_link_rate()) && (data->link_rate == kLinkRate270Gbps) ) {
|
||||
data->link_rate = kLinkRate162Gbps;
|
||||
debug(TRAINING, "retry @ linkRate=%d\n", data->link_rate);
|
||||
*state = kLinkTrainingStateStart;
|
||||
}
|
||||
// already in reduced bit-rate
|
||||
else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else if ( done ) {
|
||||
// set training pattern 2 for EQ
|
||||
ret = dp_controller_set_training_pattern(eq_pattern, false);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
// set the training pattern
|
||||
ret = dp_device_set_training_pattern(eq_pattern, false);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
*state = kLinkTrainingStateEQTraining;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (++dp_link_clock_recovery_iterations > kMaxClockRecoveryIterations) {
|
||||
debug(TRAINING, "Max clock recovery iterations exceeded\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int process_link_state_clock_recovery_internal(struct dp_link_train_data * data, uint32_t lane,
|
||||
bool *p_done)
|
||||
{
|
||||
int ret = 0;
|
||||
bool done = false;
|
||||
uint32_t lane_status = 0;
|
||||
uint32_t eq = kDPEQLevelMin;
|
||||
uint32_t voltage_swing = kDPVoltageLevelMin;
|
||||
uint32_t phy_eq;
|
||||
uint32_t phy_voltage_swing;
|
||||
|
||||
// might as well read the values for lane
|
||||
ret = dp_device_get_lane_status_mask(lane, &lane_status);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
debug(TRAINING, "Reading lane status: lane=%d status=0x%08x\n",lane, lane_status);
|
||||
|
||||
require_action(!(lane_status & kDPLaneStatusFlagClockRecoveryDone), exit, done = true);
|
||||
|
||||
ret = dp_device_get_requested_adjustment_levels(lane, &voltage_swing, &eq);
|
||||
require_noerr(ret, exit);
|
||||
ret = dp_controller_get_adjustment_levels(lane, &phy_voltage_swing, &phy_eq);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
debug(TRAINING, "Reading lane adjust request: Lane%d: voltage=%d eq=%d\n",lane, voltage_swing, eq);
|
||||
debug(TRAINING, "Current phy lane properties: Lane%d: voltage=%d eq=%d\n",lane, phy_voltage_swing, phy_eq);
|
||||
|
||||
data->lane[lane].voltage = voltage_swing;
|
||||
data->lane[lane].eq = eq;
|
||||
|
||||
// lane same voltage count
|
||||
if (phy_voltage_swing == voltage_swing)
|
||||
dp_link_clock_recovery_retry[lane]++;
|
||||
else
|
||||
dp_link_clock_recovery_retry[lane] = 0;
|
||||
|
||||
debug(TRAINING, "_linkClockRecoveryRetry[%d]=%d\n", lane, dp_link_clock_recovery_retry[lane]);
|
||||
|
||||
require_action((dp_link_clock_recovery_retry[lane] < kMaxRetry) && !dp_link_voltage_swing_max[lane],
|
||||
exit, ret=-1);
|
||||
|
||||
// increase voltage swing as requested,write an updated value
|
||||
debug(TRAINING, "Setting lane adjust request: Lane%d: voltage=%d eq=%d\n",lane, voltage_swing, eq);
|
||||
// set voltage drive ONLY on the PHY
|
||||
ret = dp_controller_set_adjustment_levels(lane, voltage_swing, eq, &dp_link_voltage_swing_max[lane],
|
||||
&dp_link_eq_max[lane]);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
// set voltage drive and EQ on the SINK
|
||||
ret = dp_device_set_adjustment_levels(lane, voltage_swing, eq, dp_link_voltage_swing_max[lane],
|
||||
dp_link_eq_max[lane]);
|
||||
|
||||
exit:
|
||||
*p_done &= done;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int process_link_state_eq_training(struct dp_link_train_data *data, u_int32_t *state)
|
||||
{
|
||||
uint32_t lane;
|
||||
uint32_t alignment_status;
|
||||
bool done = true;
|
||||
bool succeed = true;
|
||||
bool abort = false;
|
||||
bool clear = false;
|
||||
bool reduce = false;
|
||||
bool restart = false;
|
||||
int ret = 0;
|
||||
|
||||
debug(TRAINING, "Begining EQ phase of link traing\n");
|
||||
|
||||
spin(kEQDelay);
|
||||
|
||||
dp_link_eq_retry++;
|
||||
|
||||
ret = dp_device_get_alignment_status_mask(&alignment_status);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
debug(TRAINING, "alignment_status=0x%08x\n", alignment_status);
|
||||
|
||||
// process the eq state for each lane
|
||||
for ( lane=0; lane<data->lane_count; lane++ ) {
|
||||
ret = process_link_state_eq_training_internal(data, lane, &done);
|
||||
|
||||
if ( ret == 0 )
|
||||
continue;
|
||||
|
||||
abort = (ret == -1);
|
||||
succeed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
require(!abort, exit);
|
||||
|
||||
done &= (alignment_status & kDPAlignmentStatusFlagsDone) != 0;
|
||||
|
||||
// reapply the training pattern
|
||||
// this does a bulk write
|
||||
if ( !done ) {
|
||||
ret = dp_device_set_training_pattern(eq_pattern, false);
|
||||
require_noerr(ret, exit);
|
||||
}
|
||||
|
||||
if ( done ) {
|
||||
debug(TRAINING, "Link trainking success @ %d lanes and %u Gbps\n", data->lane_count,
|
||||
data->link_rate);
|
||||
clear = true;
|
||||
*state = kLinkTrainingStateIdle;
|
||||
} else if ( !abort && (!succeed || dp_link_eq_retry > kMaxRetry) ) {
|
||||
reduce = true;
|
||||
}
|
||||
|
||||
if ( reduce ) {
|
||||
debug(TRAINING, "loop failed: laneCount=%d linkRate=%u Gbps\n", data->lane_count, data->link_rate);
|
||||
clear = true;
|
||||
// reduce bit rate and restart
|
||||
if ( (data->link_rate > dp_controller_get_min_link_rate()) && (data->link_rate == kLinkRate270Gbps) ) {
|
||||
data->link_rate = kLinkRate162Gbps;
|
||||
debug(TRAINING, "retry @ linkRate=%d\n", data->link_rate);
|
||||
restart = true;
|
||||
}
|
||||
// already in reduced bit-rate
|
||||
else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( restart ) {
|
||||
*state = kLinkTrainingStateStart;
|
||||
}
|
||||
|
||||
if ( clear ) {
|
||||
// traing pattern : Set to Normal
|
||||
dp_controller_set_training_pattern(kDPTrainingPatternNone, true);
|
||||
dp_device_set_training_pattern(kDPTrainingPatternNone, true);
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int process_link_state_eq_training_internal(struct dp_link_train_data *data, uint32_t lane, bool *p_done)
|
||||
{
|
||||
int ret = 0;
|
||||
bool done = false;
|
||||
uint32_t lane_status = 0;
|
||||
uint32_t eq;
|
||||
uint32_t voltage_swing;
|
||||
uint32_t phy_eq;
|
||||
uint32_t phy_voltage_swing;
|
||||
|
||||
// might as well read the values for lane
|
||||
ret = dp_device_get_lane_status_mask(lane, &lane_status);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
debug(TRAINING, "Reading lane status: lane=%d lane_status=0x%08x\n",lane, lane_status);
|
||||
|
||||
require_action(lane_status & kDPLaneStatusFlagClockRecoveryDone, exit, ret = -1);
|
||||
|
||||
done = (lane_status & (kDPLaneStatusFlagsEQDone|kDPLaneStatusFlagsSymbolLocked))==(kDPLaneStatusFlagsEQDone|kDPLaneStatusFlagsSymbolLocked);
|
||||
require(!done, exit);
|
||||
|
||||
ret = dp_device_get_requested_adjustment_levels(lane, &voltage_swing, &eq);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
ret = dp_controller_get_adjustment_levels(lane, &phy_voltage_swing, &phy_eq);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
debug(TRAINING, "Reading lane adjust request: Lane%d: voltage=%d eq=%d\n",lane, voltage_swing, eq);
|
||||
debug(TRAINING, "Current phy lane properties: Lane%d: voltage=%d eq=%d\n",lane, phy_voltage_swing, phy_eq);
|
||||
|
||||
data->lane[lane].voltage = voltage_swing;
|
||||
data->lane[lane].eq = eq;
|
||||
|
||||
// set voltage drive and EQ on the PHY
|
||||
ret = dp_controller_set_adjustment_levels(lane, voltage_swing, eq,
|
||||
&dp_link_voltage_swing_max[lane], &dp_link_eq_max[lane]);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
// set voltage drive and EQ on the SINK
|
||||
ret = dp_device_set_adjustment_levels(lane, voltage_swing, eq,
|
||||
dp_link_voltage_swing_max[lane], dp_link_eq_max[lane]);
|
||||
|
||||
exit:
|
||||
*p_done &= done;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <debug.h>
|
||||
#include <sys.h>
|
||||
#include <sys/menu.h>
|
||||
#include <sys/task.h>
|
||||
#include <platform/int.h>
|
||||
#include <platform/soc/hwisr.h>
|
||||
|
||||
#include <drivers/display.h>
|
||||
#include <drivers/displayport/displayport.h>
|
||||
#include <drivers/displayport.h>
|
||||
|
||||
#if defined(WITH_MENU) && WITH_MENU
|
||||
|
||||
static struct video_link_data dp_video_data;
|
||||
|
||||
int do_dp(int argc, struct cmd_arg *args)
|
||||
{
|
||||
if (argc < 2) {
|
||||
puts("not enough arguments.\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (strcmp("start", args[1].str) == 0) {
|
||||
static struct display_timing timing_list[] =
|
||||
{
|
||||
#if SUB_TARGET_J1 || SUB_TARGET_J2 || SUB_TARGET_J2A
|
||||
{ "ipad3", 0, 252200000, 264, 2048, 5, 150, 5, 1536, 9, 3, 1, 0, 0, 0, 0, 24, DISPLAY_TYPE_EDP, NULL },
|
||||
#endif
|
||||
#if WITH_HW_DISPLAY_DISPLAYPORT
|
||||
{ "720p", 0, 00000000, 243, 1280, 220, 110, 40, 720, 20, 5, 5, 0, 0, 0, 0, 24, DISPLAY_TYPE_DP, NULL },
|
||||
#endif
|
||||
};
|
||||
#if SUB_TARGET_J1 || SUB_TARGET_J2 || SUB_TARGET_J2A
|
||||
dp_t dp = {
|
||||
.mode = 0x1,
|
||||
.type = 0x1,
|
||||
.min_link_rate = 0x6,
|
||||
.max_link_rate = 0x6,
|
||||
.lanes = 0x4,
|
||||
.ssc = 0x0,
|
||||
.alpm = 0x0,
|
||||
.vrr_enable = 0x0,
|
||||
.vrr_on = 0x0,
|
||||
};
|
||||
#elif WITH_HW_DISPLAY_DISPLAYPORT
|
||||
dp_t dp = {
|
||||
.mode = 0x1,
|
||||
.type = 0x1,
|
||||
.min_link_rate = 0x6,
|
||||
.max_link_rate = 0x6,
|
||||
.lanes = 0x2,
|
||||
.ssc = 0x0,
|
||||
.alpm = 0x0,
|
||||
.vrr_enable = 0x0,
|
||||
};
|
||||
#else
|
||||
dp_t dp;
|
||||
#endif
|
||||
timing_list[0].display_config = (void *)&dp;
|
||||
|
||||
displayport_init(&dp);
|
||||
|
||||
bzero(&dp_video_data, sizeof(struct video_link_data));
|
||||
|
||||
dp_video_data.mirror_mode = false;
|
||||
dp_video_data.test_mode = 0;
|
||||
dp_video_data.color.depth = 8;
|
||||
dp_video_data.color.space = kDisplayColorSpacesRGB;
|
||||
dp_video_data.color.range = kDisplayColorDynamicRangeVESA;
|
||||
dp_video_data.color.coefficient = kDisplayColorCoefficientITU601;
|
||||
dp_video_data.timing.axis[0].total = timing_list[0].h_active + timing_list[0].h_back_porch + timing_list[0].h_front_porch + timing_list[0].h_pulse_width;
|
||||
dp_video_data.timing.axis[0].active = timing_list[0].h_active;
|
||||
dp_video_data.timing.axis[0].sync_width = timing_list[0].h_pulse_width;
|
||||
dp_video_data.timing.axis[0].back_porch = timing_list[0].h_back_porch;
|
||||
dp_video_data.timing.axis[0].front_porch = timing_list[0].h_front_porch;
|
||||
dp_video_data.timing.axis[0].sync_rate = 0;
|
||||
dp_video_data.timing.axis[0].sync_polarity = 0;
|
||||
dp_video_data.timing.axis[1].total = timing_list[0].v_active + timing_list[0].v_back_porch + timing_list[0].v_front_porch + timing_list[0].v_pulse_width;
|
||||
dp_video_data.timing.axis[1].active = timing_list[0].v_active;
|
||||
dp_video_data.timing.axis[1].sync_width = timing_list[0].v_pulse_width;
|
||||
dp_video_data.timing.axis[1].back_porch = timing_list[0].v_back_porch;
|
||||
dp_video_data.timing.axis[1].front_porch = timing_list[0].v_front_porch;
|
||||
dp_video_data.timing.axis[1].sync_rate = 60 << 16;
|
||||
dp_video_data.timing.axis[1].sync_polarity = 0;
|
||||
|
||||
} else if (strcmp("stop", args[1].str) == 0) {
|
||||
displayport_quiesce();
|
||||
} else if (strcmp("video", args[1].str) == 0) {
|
||||
if (strcmp("logo", args[2].str) == 0) {
|
||||
dp_video_data.mirror_mode = false;
|
||||
dp_video_data.test_mode = 0;
|
||||
|
||||
dp_controller_start_video(&dp_video_data);
|
||||
}
|
||||
if (strcmp("bist", args[2].str) == 0) {
|
||||
|
||||
dp_video_data.mirror_mode = false;
|
||||
dp_video_data.test_mode = 1;
|
||||
|
||||
dp_controller_start_video(&dp_video_data);
|
||||
}
|
||||
if (strcmp("mirror", args[2].str) == 0) {
|
||||
dp_video_data.mirror_mode = true;
|
||||
dp_video_data.test_mode = 0;
|
||||
|
||||
dp_controller_start_video(&dp_video_data);
|
||||
}
|
||||
} else if (strcmp("dpcd", args[1].str) == 0) {
|
||||
uint8_t data[16];
|
||||
int len = args[3].n;
|
||||
uint32_t intr = 0;
|
||||
|
||||
if (len > 16)
|
||||
len = 16;
|
||||
|
||||
printf("dpcd read %d bytes from 0x%x\n", len, args[2].n);
|
||||
#if WITH_HW_DISPLAY_DISPLAYPORT
|
||||
intr = INT_DPORT0;
|
||||
#elif WITH_HW_DISPLAY_EDP
|
||||
intr = INT_EDP0;
|
||||
#endif
|
||||
//cuz AppleTV only defines display in iBoot but declares drivers in iBEC
|
||||
if (intr) mask_int(intr);
|
||||
dp_controller_read_bytes_dpcd(args[2].n, data, len);
|
||||
if (intr) unmask_int(intr);
|
||||
|
||||
for (int i=0; i < len; i++) {
|
||||
printf("0x%02x ", data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
puts("unrecognized command.\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
printf("%s start\n", args[0].str);
|
||||
printf("%s video logo\n", args[0].str);
|
||||
printf("%s video bist\n", args[0].str);
|
||||
printf("%s video mirror\n", args[0].str);
|
||||
printf("%s stop\n", args[0].str);
|
||||
printf("%s dpcd <addr> <len>. Len is max 16 bytes\n", args[0].str);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEVELOPMENT(dp, do_dp, "displayport stuff", NULL);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,810 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include <drivers/displayport/displayport.h>
|
||||
#include <drivers/displayport.h>
|
||||
#include <sys/task.h>
|
||||
#include "dpcd.h"
|
||||
|
||||
#if WITH_HW_MCU
|
||||
#include <drivers/mcu.h>
|
||||
#include <drivers/process_edid.h>
|
||||
#endif
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// debug support
|
||||
|
||||
#define DP_DEBUG_MASK ( \
|
||||
DP_DEBUG_INIT | \
|
||||
DP_DEBUG_ERROR | \
|
||||
DP_DEBUG_INFO | \
|
||||
DP_DEBUG_TRAINING | \
|
||||
0)
|
||||
|
||||
#undef DP_DEBUG_MASK
|
||||
#define DP_DEBUG_MASK (DP_DEBUG_INIT | DP_DEBUG_ERROR)
|
||||
|
||||
#define DP_DEBUG_INIT (1<<16) // initialisation
|
||||
#define DP_DEBUG_INFO (1<<17) // info
|
||||
#define DP_DEBUG_TRAINING (1<<18) // link training
|
||||
#define DP_DEBUG_WAIT (1<<19) // start wait
|
||||
#define DP_DEBUG_ERROR (1<<20) // error
|
||||
#define DP_DEBUG_ALWAYS (1<<31) // unconditional output
|
||||
|
||||
#define debug(_fac, _fmt, _args...) \
|
||||
do { \
|
||||
if ((DP_DEBUG_ ## _fac) & (DP_DEBUG_MASK | DP_DEBUG_ALWAYS)) \
|
||||
dprintf(DEBUG_CRITICAL, "DPD: %s, %d: " _fmt, __FUNCTION__, __LINE__, ##_args); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// consts
|
||||
|
||||
#define kDPDeviceMaxCapabilityBytes 0x0c
|
||||
#define kDPDeviceMaxDownstreamPorts 16
|
||||
#define kEDPRawPanelIdReadTimeout (1 * 1000 * 1000)
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// typedefs, enums, structs
|
||||
|
||||
#define require_action(assertion, exception_label, action) \
|
||||
do { \
|
||||
if (__builtin_expect(!(assertion), 0)) \
|
||||
{ \
|
||||
{ \
|
||||
action; \
|
||||
} \
|
||||
goto exception_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define require_noerr(error_code, exception_label) \
|
||||
do { \
|
||||
if (__builtin_expect(0 != (error_code), 0)) \
|
||||
{ \
|
||||
goto exception_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// local variables
|
||||
|
||||
static uint8_t dp_device_downstream_port_capability_bytes[kDPDeviceMaxDownstreamPorts];
|
||||
static uint8_t dp_device_capability_bytes[kDPDeviceMaxCapabilityBytes];
|
||||
static u_int32_t dp_device_voltage_adjustment_level[kDPMaxLanes];
|
||||
static u_int32_t dp_device_eq_adjustment_level[kDPMaxLanes];
|
||||
static uint8_t dp_device_adjustment_bytes[5];
|
||||
static uint8_t dp_device_lane_status_mask[kDPMaxLanes];
|
||||
static bool alpm_enabled;
|
||||
#if WITH_HW_DISPLAY_EDP
|
||||
static u_int8_t dp_device_raw_panel_id[kEDPRawPanelIdLength];
|
||||
#endif // WITH_HW_DISPLAY_EDP
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// local functions declaration
|
||||
|
||||
static int set_power(bool enable);
|
||||
static int train_link();
|
||||
static int enable_alpm(bool enable);
|
||||
static int cache_capabilities();
|
||||
static int update_lane_status_mask();
|
||||
static int update_requested_adjustment_levels();
|
||||
static int read_raw_panel_id();
|
||||
|
||||
static struct task_event dp_device_start_event =
|
||||
EVENT_STATIC_INIT(dp_device_start_event, false, EVENT_FLAG_AUTO_UNSIGNAL);
|
||||
static bool dp_device_started;
|
||||
static bool dp_device_start_error;
|
||||
static utime_t dp_device_started_time;
|
||||
static struct task_event dp_device_raw_panel_id_ready_event;
|
||||
|
||||
extern utime_t gPowerOnTime;
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// dp-device global functions
|
||||
|
||||
int dp_device_start(bool edp_panel)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if ( dp_device_started )
|
||||
return 0;
|
||||
|
||||
debug(INIT, "starting\n");
|
||||
|
||||
event_init(&dp_device_raw_panel_id_ready_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
||||
|
||||
if ( set_power(true) != 0 ) {
|
||||
debug(ERROR, "failed to set power\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ( cache_capabilities() != 0 ) {
|
||||
debug(ERROR, "failed to cache capabilities\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#if WITH_HW_DISPLAY_EDP
|
||||
if ( edp_panel ) {
|
||||
if ( read_raw_panel_id() != 0 ) {
|
||||
debug(ERROR, "failed to read raw panel id\n");
|
||||
goto exit;
|
||||
} else {
|
||||
debug(INFO, "successfully read panel id: ");
|
||||
for ( unsigned i=0; i<sizeof(dp_device_raw_panel_id); i++)
|
||||
debug(INFO, "%02x ", dp_device_raw_panel_id[i]);
|
||||
|
||||
debug(INFO, "\n");
|
||||
}
|
||||
event_signal(&dp_device_raw_panel_id_ready_event);
|
||||
}
|
||||
#endif // WITH_HW_DISPLAY_EDP
|
||||
|
||||
if ( train_link() != 0 ) {
|
||||
debug(ERROR, "failed to train link\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#if WITH_HW_MCU
|
||||
uint8_t sink_count;
|
||||
dp_device_get_sink_count(&sink_count);
|
||||
if (sink_count == 0) {
|
||||
debug(ERROR, "sink count is 0\n");
|
||||
goto exit;
|
||||
}
|
||||
// Trained link first, validate timings vs trained bandwidth.
|
||||
if ( obtain_edid() == 0 ) {
|
||||
// Enable info frames if HDMI endpoint connected, so
|
||||
// we get the right color space.
|
||||
if (get_edid_downstream_type() == kDPDownstreamTypeHDMI) {
|
||||
debug(ALWAYS, "Sending AVI info frames\n");
|
||||
#if WITH_HW_BS
|
||||
(void) mcu_send_info_frames(true);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
// Non-fatal.
|
||||
debug(ERROR, "Couldn't get EDID\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( displayport_start_video() != 0 ) {
|
||||
debug(ERROR, "failed to start video\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
alpm_enabled = false;
|
||||
|
||||
if (enable_alpm(true) != 0) {
|
||||
debug(ERROR, "failed enable alpm\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ( dp_device_hdcp_enable(false) != 0 ) {
|
||||
debug(ERROR, "failed to Disable HDCP\n");
|
||||
goto exit;
|
||||
}
|
||||
debug(ALWAYS, "HDCP Disabled\n");
|
||||
|
||||
dp_device_started = true;
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
if (ret != 0) {
|
||||
dp_device_start_error = true;
|
||||
debug(ERROR, "error starting device\n");
|
||||
}
|
||||
|
||||
dp_device_started_time = system_time();
|
||||
event_signal(&dp_device_start_event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_wait_started(utime_t timeout)
|
||||
{
|
||||
utime_t wait_start = system_time();
|
||||
|
||||
if (dp_device_started || dp_device_start_error) {
|
||||
debug(WAIT, "DisplayPort done with %d usecs to spare\n",
|
||||
(int) (wait_start - dp_device_started_time));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (!dp_device_started && !dp_device_start_error) {
|
||||
utime_t now = system_time();
|
||||
if (now >= timeout) {
|
||||
debug(WAIT, "Timeout waiting for displayport start\n");
|
||||
return -1;
|
||||
}
|
||||
event_wait_timeout(&dp_device_start_event, timeout - now);
|
||||
}
|
||||
debug(WAIT, "Delayed boot by %lld usecs\n", system_time() - wait_start);
|
||||
exit:
|
||||
debug(WAIT, "Started waiting %lld usecs after power on\n",
|
||||
wait_start - gPowerOnTime);
|
||||
return dp_device_start_error ? -1 : 0;
|
||||
}
|
||||
|
||||
void dp_device_stop()
|
||||
{
|
||||
if ( !dp_device_started )
|
||||
return;
|
||||
|
||||
set_power(false);
|
||||
|
||||
dp_device_started = false;
|
||||
alpm_enabled = false;
|
||||
}
|
||||
|
||||
bool dp_device_is_alpm_enabled()
|
||||
{
|
||||
return alpm_enabled;
|
||||
}
|
||||
|
||||
#if WITH_HW_DISPLAY_EDP
|
||||
int dp_device_get_raw_panel_id(u_int8_t *raw_panel_id)
|
||||
{
|
||||
if (event_wait_timeout(&dp_device_raw_panel_id_ready_event, kEDPRawPanelIdReadTimeout) == false)
|
||||
return -1;
|
||||
|
||||
if (raw_panel_id == NULL)
|
||||
return -1;
|
||||
|
||||
memset(raw_panel_id, 0, kEDPRawPanelIdLength);
|
||||
|
||||
memcpy(raw_panel_id, dp_device_raw_panel_id, kEDPRawPanelIdLength);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // WITH_HW_DISPLAY_EDP
|
||||
|
||||
int dp_device_get_alignment_status_mask(u_int32_t *mask)
|
||||
{
|
||||
int ret;
|
||||
uint8_t value;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &value, 1);
|
||||
|
||||
update_lane_status_mask();
|
||||
update_requested_adjustment_levels();
|
||||
|
||||
if ( mask )
|
||||
*mask = value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_get_lane_status_mask(uint32_t lane, uint32_t *mask)
|
||||
{
|
||||
if ( lane > dp_device_get_max_lane_count() )
|
||||
return -1;
|
||||
|
||||
*mask = dp_device_lane_status_mask[lane];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_device_get_training_pattern(uint32_t *value, bool *scramble)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_TRAINING_PATTERN_SET, &val, 1);
|
||||
if ( ret == 0 ) {
|
||||
if ( value )
|
||||
*value = (u_int32_t)(val & DPCD_ADDR_PATTERN_SET_MASK);
|
||||
if ( scramble )
|
||||
*scramble = (val & DPCD_ADDR_TRAINING_PATTERN_SET_SCRMB_DISABLE) == 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_set_training_pattern(uint32_t value, bool scramble)
|
||||
{
|
||||
uint8_t reg_val = value & DPCD_ADDR_PATTERN_SET_MASK;
|
||||
|
||||
if ( !scramble )
|
||||
reg_val |= DPCD_ADDR_TRAINING_PATTERN_SET_SCRMB_DISABLE;
|
||||
|
||||
dp_device_adjustment_bytes[0] = reg_val;
|
||||
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_TRAINING_PATTERN_SET, dp_device_adjustment_bytes, 5);
|
||||
}
|
||||
|
||||
int dp_device_get_requested_adjustment_levels(uint32_t lane, u_int32_t *voltage, u_int32_t *eq)
|
||||
{
|
||||
if ( lane > dp_device_get_max_lane_count() )
|
||||
return -1;
|
||||
|
||||
*voltage = dp_device_voltage_adjustment_level[lane];
|
||||
*eq = dp_device_eq_adjustment_level[lane];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_device_set_adjustment_levels(uint32_t lane, u_int32_t voltage_swing, u_int32_t eq,
|
||||
bool voltage_max_reached, bool eq_max_reached)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
if ( lane > dp_device_get_max_lane_count() )
|
||||
return -1;
|
||||
|
||||
value = (eq << DPCD_ADDR_TRAINNIG_SET_PRE_EMPH_SHIFT) |
|
||||
(voltage_swing << DPCD_ADDR_TRAINNIG_SET_VOL_SWING_SHIFT);
|
||||
|
||||
if (voltage_max_reached) {
|
||||
value |= DPCD_ADDR_TRAINNIG_SET_VOL_SWING_MAX;
|
||||
}
|
||||
|
||||
if ( eq_max_reached ) {
|
||||
value |= DPCD_ADDR_TRAINNIG_SET_PRE_EMPH_MAX;
|
||||
}
|
||||
|
||||
dp_device_adjustment_bytes[lane+1] = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_device_get_enhanced_mode(bool * value)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_LANE_COUNT_SET, &val, 1);
|
||||
if ( ret == 0 ) {
|
||||
*value = val & DPCD_ADDR_LANE_COUNT_SET_ENHANCED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_get_sink_count(uint8_t * value)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_SINK_COUNT, &val, 1);
|
||||
if ( ret == 0 ) {
|
||||
*value = val;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_set_enhanced_mode(bool value)
|
||||
{
|
||||
uint32_t lane_count = 0;
|
||||
|
||||
dp_device_get_lane_count(&lane_count);
|
||||
lane_count &= DPCD_ADDR_LANE_COUNT_SET_COUNT_MASK;
|
||||
|
||||
if ( value )
|
||||
lane_count |= DPCD_ADDR_LANE_COUNT_SET_ENHANCED;
|
||||
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_LANE_COUNT_SET, (uint8_t *)&lane_count, 1);
|
||||
}
|
||||
|
||||
int dp_device_get_ASSR(bool * value)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_RECEIVER_EDP_CONFIG, &val, 1);
|
||||
if ( ret == 0 ) {
|
||||
*value = val & DPCD_ADDR_RECEIVER_EDP_CONFIG_ASSR_ENABLE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_set_ASSR(bool value)
|
||||
{
|
||||
uint8_t val = 0;
|
||||
|
||||
if ( value )
|
||||
val |= DPCD_ADDR_RECEIVER_EDP_CONFIG_ASSR_ENABLE;
|
||||
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_RECEIVER_EDP_CONFIG, (uint8_t *)&val, 1);
|
||||
}
|
||||
|
||||
int dp_device_get_downspread(bool * value)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_DOWNSPREAD_CTRL, &val, 1);
|
||||
if ( ret == 0 ) {
|
||||
*value = val & DPCD_ADDR_DOWNSPREAD_ENABLE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_set_downspread(bool value)
|
||||
{
|
||||
uint8_t reg_val = 0;
|
||||
|
||||
reg_val = value ? DPCD_ADDR_DOWNSPREAD_ENABLE : 0;
|
||||
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_DOWNSPREAD_CTRL, (uint8_t *)®_val, 1);
|
||||
}
|
||||
|
||||
int dp_device_get_lane_count(uint32_t * value)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_LANE_COUNT_SET, &val, 1);
|
||||
if ( ret == 0 ) {
|
||||
*value = val & DPCD_ADDR_LANE_COUNT_SET_COUNT_MASK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dp_device_set_lane_count(uint32_t value)
|
||||
{
|
||||
bool enhanced_mode = false;
|
||||
|
||||
value &= DPCD_ADDR_LANE_COUNT_SET_COUNT_MASK;
|
||||
|
||||
dp_device_get_enhanced_mode(&enhanced_mode);
|
||||
if ( enhanced_mode )
|
||||
value |= DPCD_ADDR_LANE_COUNT_SET_ENHANCED;
|
||||
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_LANE_COUNT_SET, (uint8_t *)&value, 1);
|
||||
}
|
||||
|
||||
int dp_device_get_link_rate(u_int32_t * value)
|
||||
{
|
||||
return dp_controller_read_bytes_dpcd(DPCD_ADDR_LINK_BW_SET, (uint8_t*)value, 1);
|
||||
}
|
||||
|
||||
int dp_device_set_link_rate(u_int32_t value)
|
||||
{
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_LINK_BW_SET, (uint8_t *)&value, 1);
|
||||
}
|
||||
|
||||
int dp_device_hdcp_enable(bool enable)
|
||||
{
|
||||
#if WITH_HW_HOOVER
|
||||
uint8_t value;
|
||||
dp_controller_read_bytes_dpcd(DPCD_ADDR_HDMI_DVI_MODE_SELECT, &value, 1);
|
||||
|
||||
if (!enable) value |= DPCD_HDCP_DISABLE;
|
||||
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_HDMI_DVI_MODE_SELECT, &value, 1);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int dp_device_get_downstream_port_type(int *ret_value)
|
||||
{
|
||||
#if WITH_HW_MCU
|
||||
// BlueSteel is reporting DP, but we know for sure it's HDMI.
|
||||
if (ret_value) *ret_value = kDPDownstreamTypeHDMI;
|
||||
return 0;
|
||||
#else
|
||||
int ret = 0;
|
||||
int value = kDPDownstreamTypeOther;
|
||||
if (dp_device_get_revision() == 0x11) {
|
||||
value = dp_device_downstream_port_capability_bytes[0] & 0x07;
|
||||
}
|
||||
|
||||
if (value == kDPDownstreamTypeDP) {
|
||||
uint8_t reg_val;
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_DOWNSTREAMPORT_PRESENT, ®_val, 1);
|
||||
if (ret != 0) goto exit;
|
||||
|
||||
switch (((reg_val >> 1 ) & 3)) {
|
||||
case 0:
|
||||
value = kDPDownstreamTypeDP;
|
||||
break;
|
||||
case 1:
|
||||
value = kDPDownstreamTypeVGA;
|
||||
break;
|
||||
case 2:
|
||||
value = kDPDownstreamTypeHDMI;
|
||||
break;
|
||||
case 3:
|
||||
value = kDPDownstreamTypeOther;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret_value) *ret_value = value;
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int dp_device_enable_alpm(bool enable)
|
||||
{
|
||||
uint8_t alpm_data = enable;
|
||||
return dp_controller_write_bytes_dpcd(DPCD_ADDR_ALPM_CTRL, &alpm_data, 1);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////// dp-device local functions
|
||||
|
||||
static int set_power(bool state)
|
||||
{
|
||||
int ret;
|
||||
u_int8_t byte;
|
||||
bool current_state;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_SINK_POWER_STATE, &byte, 1);
|
||||
debug(INFO, "Read sink power state: ret=%d\n", ret);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
current_state = (byte == DPCD_ADDR_SINK_POWER_STATE_ON);
|
||||
|
||||
require_action(state != current_state, exit, debug(INFO, "power level already = %d\n", state));
|
||||
|
||||
debug(INFO, "setting power level = %d\n", state);
|
||||
|
||||
byte = state ? DPCD_ADDR_SINK_POWER_STATE_ON : DPCD_ADDR_SINK_POWER_STATE_OFF;
|
||||
ret = dp_controller_write_bytes_dpcd(DPCD_ADDR_SINK_POWER_STATE, &byte, 1);
|
||||
|
||||
// see DportV1.1a section 5.2.5
|
||||
if ( state )
|
||||
task_sleep(20 * 1000);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cache_capabilities()
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_DPCD_REV, dp_device_capability_bytes,
|
||||
(uint32_t)sizeof(dp_device_capability_bytes));
|
||||
if ( ret != 0 ) {
|
||||
debug(ERROR, "failed to read capabilities\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_DOWNSTREAMPORT_0_CAPS,
|
||||
dp_device_downstream_port_capability_bytes,
|
||||
(uint32_t)sizeof(dp_device_downstream_port_capability_bytes));
|
||||
if ( ret != 0 ) {
|
||||
debug(ERROR, "failed to read downstream ports capabilities\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if WITH_HW_DISPLAY_EDP
|
||||
static int read_raw_panel_id()
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCP_ADDR_VENDOR_BYTES, dp_device_raw_panel_id, kEDPRawPanelIdLength);
|
||||
if (ret != 0) {
|
||||
debug(ERROR, "failed to read raw panel id\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // WITH_HW_DISPLAY_EDP
|
||||
|
||||
u_int32_t dp_device_get_revision()
|
||||
{
|
||||
return dp_device_capability_bytes[DPCD_ADDR_DPCD_REV];
|
||||
}
|
||||
|
||||
u_int32_t dp_device_get_max_lane_count()
|
||||
{
|
||||
return dp_device_capability_bytes[DPCD_ADDR_MAX_LANE_COUNT] & DPCD_ADDR_LANE_COUNT_SET_COUNT_MASK;
|
||||
}
|
||||
|
||||
u_int32_t dp_device_get_max_link_rate()
|
||||
{
|
||||
return dp_device_capability_bytes[DPCD_ADDR_MAX_LINK_RATE];
|
||||
}
|
||||
|
||||
bool dp_device_get_supports_enhanced_mode()
|
||||
{
|
||||
if ( dp_device_get_revision() < 0x11 )
|
||||
return false;
|
||||
|
||||
return dp_device_capability_bytes[DPCD_ADDR_MAX_LANE_COUNT] & DPCD_ADDR_LANE_COUNT_SET_ENHANCED;
|
||||
}
|
||||
|
||||
bool dp_device_get_supports_training_pattern3()
|
||||
{
|
||||
if ( dp_device_get_revision() < 0x12 )
|
||||
return false;
|
||||
|
||||
return dp_device_capability_bytes[DPCD_ADDR_MAX_LANE_COUNT] & DPCD_ADDR_LANE_COUNT_TPS3_SUPPORTED;
|
||||
}
|
||||
|
||||
bool dp_device_get_supports_fast_link_training()
|
||||
{
|
||||
int ret;
|
||||
uint8_t value = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_MAX_DOWNSPREAD, &value, 1);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
exit:
|
||||
#if WITH_HW_HOOVER
|
||||
return (false);
|
||||
#else
|
||||
return (value & (1<<6) ? true : false);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool dp_device_get_supports_alpm()
|
||||
{
|
||||
int ret;
|
||||
uint8_t value = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_ALPM_CAP, &value, 1);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
exit:
|
||||
return (value & 1 ? true : false);
|
||||
}
|
||||
|
||||
bool dp_device_get_supports_assr()
|
||||
{
|
||||
int ret;
|
||||
uint8_t value = 0;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_ALTERNATE_SCRAMBLE, &value, 1);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
exit:
|
||||
return (value & DPCD_ADDR_ALTERNATE_SCRAMBLER_RESET_CAP ? true : false);
|
||||
}
|
||||
|
||||
bool dp_device_get_supports_downspread()
|
||||
{
|
||||
int ret;
|
||||
uint8_t value = 0;
|
||||
|
||||
if ( dp_device_get_revision() >= 0x11 )
|
||||
return true;
|
||||
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_MAX_DOWNSPREAD, &value, 1);
|
||||
require_noerr(ret, exit);
|
||||
|
||||
exit:
|
||||
return (value & (1<<0) ? true : false);
|
||||
}
|
||||
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static int train_link()
|
||||
{
|
||||
struct dp_link_train_data data;
|
||||
int ret;
|
||||
uint8_t ignore[8];
|
||||
|
||||
bzero(&data, sizeof(struct dp_link_train_data));
|
||||
|
||||
// collect data needed for link training
|
||||
data.lane_count = dp_device_get_max_lane_count();
|
||||
data.link_rate = dp_device_get_max_link_rate();
|
||||
data.enhanced_mode = dp_device_get_supports_enhanced_mode();
|
||||
data.assr = dp_device_get_supports_assr();
|
||||
data.fast = dp_device_get_supports_fast_link_training() && dp_controller_get_supports_fast_link_training();
|
||||
data.downspread = min(dp_device_get_supports_downspread(),dp_controller_get_supports_downspread());
|
||||
|
||||
debug(INIT, "lane_count: %d, link_rate: %d, enhanced_mode: %d, assr: %d, fast: %d downspread: %d\n",
|
||||
data.lane_count, data.link_rate, data.enhanced_mode, data.assr, data.fast, data.downspread);
|
||||
|
||||
if ( !data.lane_count || !data.link_rate ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = dp_controller_train_link(&data);
|
||||
if ( ret != 0 )
|
||||
return -1;
|
||||
|
||||
// clear error bits
|
||||
dp_controller_read_bytes_dpcd(DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE0_BYTE0, ignore, sizeof(ignore));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_alpm(bool enable)
|
||||
{
|
||||
bool supports_alpm;
|
||||
int ret = 0;
|
||||
|
||||
supports_alpm = dp_device_get_supports_alpm() && dp_controller_get_supports_alpm();
|
||||
|
||||
printf("supports_alpm %d\n", supports_alpm);
|
||||
if (supports_alpm) {
|
||||
ret = dp_device_enable_alpm(enable);
|
||||
if (ret != 0) {
|
||||
debug(ERROR, "Failed to %s device alpm\n", enable ? "enable" : "disable");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = displayport_enable_alpm(enable);
|
||||
if (ret != 0) {
|
||||
debug(ERROR, "Failed to %s controller alpm\n", enable ? "enable" : "disable");
|
||||
}
|
||||
alpm_enabled =true;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int update_lane_status_mask()
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t value, lane;
|
||||
|
||||
for (lane=0; lane<dp_device_get_max_lane_count(); lane++) {
|
||||
|
||||
if ( !(lane % 2) )
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_LANE0_1_STATUS+(lane>>1), &value, 1);
|
||||
|
||||
if ( ret != 0 )
|
||||
break;
|
||||
|
||||
if ( lane % 2 )
|
||||
dp_device_lane_status_mask[lane] = (value >> DPCD_ADDR_LANEX_Y_STATUS_Y_SHIFT) &
|
||||
kDPLaneStatusFlagsMask;
|
||||
else
|
||||
dp_device_lane_status_mask[lane] = (value >> DPCD_ADDR_LANEX_Y_STATUS_X_SHIFT) &
|
||||
kDPLaneStatusFlagsMask;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int update_requested_adjustment_levels()
|
||||
{
|
||||
int ret;
|
||||
uint8_t value, lane;
|
||||
|
||||
ret = 0;
|
||||
|
||||
for (lane=0; lane<dp_device_get_max_lane_count(); lane++) {
|
||||
|
||||
if ( !(lane % 2) )
|
||||
ret = dp_controller_read_bytes_dpcd(DPCD_ADDR_ADJUST_REQUEST_LANE0_1+(lane>>1), &value, 1);
|
||||
|
||||
if ( ret != 0 )
|
||||
break;
|
||||
|
||||
if ( lane % 2 ) {
|
||||
dp_device_eq_adjustment_level[lane] = ((value & DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_Y_MASK) >> DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_Y_SHIFT);
|
||||
dp_device_voltage_adjustment_level[lane] = ((value & DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_Y_MASK) >> DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_Y_SHIFT);
|
||||
}
|
||||
else {
|
||||
dp_device_eq_adjustment_level[lane] = ((value & DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_X_MASK) >> DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_X_SHIFT);
|
||||
dp_device_voltage_adjustment_level[lane] = ((value & DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_X_MASK) >> DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_X_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#define DPCD_ADDR_DPCD_REV 0x00000
|
||||
#define DPCD_ADDR_DPCD_REV_MAJOR_SHIFT 4
|
||||
#define DPCD_ADDR_DPCD_REV_MAJOR_MASK (0xf << DPCD_ADDR_DPCD_REV_MAJOR_SHIFT)
|
||||
#define DPCD_ADDR_DPCD_REV_MINOR_SHIFT 0
|
||||
#define DPCD_ADDR_DPCD_REV_MINOR_MASK (0xf << DPCD_ADDR_DPCD_REV_MINOR_SHIFT)
|
||||
|
||||
#define DPCD_ADDR_MAX_LINK_RATE 0x00001
|
||||
#define DPCD_ADDR_MAX_LANE_COUNT 0x00002
|
||||
#define DPCD_ADDR_MAX_DOWNSPREAD 0x00003
|
||||
#define DPCD_ADDR_NORP 0x00004
|
||||
#define DPCD_ADDR_DOWNSTREAMPORT_PRESENT 0x00005
|
||||
|
||||
#define DPCD_ADDR_RECEIVE_PORT0_CAP_0 0x00008
|
||||
#define DPCD_ADDR_RECEIVE_PORT0_CAP_0_EDID (1 << 1)
|
||||
|
||||
#define DPCD_ADDR_DOWNSTREAMPORT_COUNT 0x00007
|
||||
#define DPCD_ADDR_RECEIVE_PORT0_CAP_1 0x00009
|
||||
#define DPCD_ADDR_RECEIVE_PORT0_CAP_2 0x0000a
|
||||
#define DPCD_ADDR_RECEIVE_PORT0_CAP_3 0x0000b
|
||||
|
||||
#define DPCD_ADDR_ALTERNATE_SCRAMBLE 0x0000d
|
||||
#define DPCD_ADDR_ALTERNATE_SCRAMBLER_RESET_CAP (1 << 0)
|
||||
#define DPCD_ADDR_FRAMING_CHANGE_CAP (1 << 1)
|
||||
#define DPCD_ADDR_INVERTED_TRAINING_BIT_CAP (1 << 2)
|
||||
|
||||
#define DPCD_ADDR_DOWNSTREAMPORT_0_CAPS 0x00080
|
||||
#define DPCD_ADDR_ALPM_CAP 0x0002e
|
||||
|
||||
|
||||
#define DPCD_ADDR_LINK_BW_SET 0x00100
|
||||
|
||||
#define DPCD_ADDR_LANE_COUNT_SET 0x00101
|
||||
#define DPCD_ADDR_LANE_COUNT_SET_ENHANCED (1 << 7)
|
||||
#define DPCD_ADDR_LANE_COUNT_SET_COUNT_MASK (0x1f)
|
||||
#define DPCD_ADDR_LANE_COUNT_TPS3_SUPPORTED (1 << 6)
|
||||
|
||||
#define DPCD_ADDR_TRAINING_PATTERN_SET 0x00102
|
||||
#define DPCD_ADDR_PATTERN_SET_MASK 0x3
|
||||
#define DPCD_ADDR_QUALITY_PATTERN_SHIFT 2
|
||||
#define DPCD_ADDR_TRAINING_PATTERN_SET_SCRMB_DISABLE (1 << 5)
|
||||
|
||||
#define DPCD_ADDR_TRAINNIG_LANE0_SET 0x00103
|
||||
#define DPCD_ADDR_TRAINNIG_LANE1_SET 0x00104
|
||||
#define DPCD_ADDR_TRAINNIG_LANE2_SET 0x00105
|
||||
#define DPCD_ADDR_TRAINNIG_LANE3_SET 0x00106
|
||||
#define DPCD_ADDR_TRAINNIG_SET_VOL_SWING_SHIFT 0
|
||||
#define DPCD_ADDR_TRAINNIG_SET_VOL_SWING_MASK (0x3 << DPCD_ADDR_TRAINNIG_SET_VOL_SWING_SHIFT)
|
||||
#define DPCD_ADDR_TRAINNIG_SET_VOL_SWING_MAX (0x1 << 2)
|
||||
#define DPCD_ADDR_TRAINNIG_SET_PRE_EMPH_SHIFT 3
|
||||
#define DPCD_ADDR_TRAINNIG_SET_PRE_EMPH_MASK (0x3 << DPCD_ADDR_TRAINNIG_SET_PRE_EMPH_SHIFT)
|
||||
#define DPCD_ADDR_TRAINNIG_SET_PRE_EMPH_MAX (0x1 << 5)
|
||||
|
||||
#define DPCD_ADDR_DOWNSPREAD_CTRL 0x00107
|
||||
#define DPCD_ADDR_DOWNSPREAD_ENABLE (1 << 4)
|
||||
|
||||
// eDP (DPCD 1.2)
|
||||
#define DPCD_ADDR_RECEIVER_EDP_CONFIG 0x0010a
|
||||
#define DPCD_ADDR_RECEIVER_EDP_CONFIG_ASSR_ENABLE (1<<0)
|
||||
|
||||
#define DPCD_ADDR_ALPM_CTRL 0x00116
|
||||
#define DPCD_ADDR_ALPM_ENABLE (1 << 0)
|
||||
#define DPCD_ADDR_ALPM_ALPM_LOCK_ERROR_IRQ_HPD (1 << 1)
|
||||
|
||||
#define DPCD_ADDR_SINK_COUNT 0x00200
|
||||
|
||||
#define DPCD_ADDR_DEVICE_SERVICE_IRQ_VECTOR 0x00201
|
||||
#define DPCD_IRQ_VECTOR_REMOTE_COMMAND (1 << 0)
|
||||
#define DPCD_IRQ_VECTOR_AUTOMATED_TEST (1 << 1)
|
||||
#define DPCD_IRQ_VECTOR_CP_IRQ (1 << 2)
|
||||
#define DPCD_IRQ_VECTOR_SINK_SPECIFIC (1 << 6)
|
||||
|
||||
#define DPCD_ADDR_LANE0_1_STATUS 0x00202
|
||||
#define DPCD_ADDR_LANE2_3_STATUS 0x00203
|
||||
#define DPCD_ADDR_LANEX_Y_STATUS_X_SHIFT (0)
|
||||
#define DPCD_ADDR_LANEX_Y_STATUS_Y_SHIFT (4)
|
||||
|
||||
#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x00204
|
||||
#define DPCD_ADDR_SINK_STATUS 0x00205
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x00206
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x00207
|
||||
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_X_SHIFT 0
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_X_MASK (0x3 << DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_X_SHIFT)
|
||||
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_X_SHIFT 2
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_X_MASK (0x3 << DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_X_SHIFT)
|
||||
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_Y_SHIFT 4
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_Y_MASK (0x3 << DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_VOL_SWG_Y_SHIFT)
|
||||
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_Y_SHIFT 6
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_Y_MASK (0x3 << DPCD_ADDR_ADJUST_REQUEST_LANEX_Y_PRE_EMP_Y_SHIFT)
|
||||
|
||||
#define DPCD_ADDR_TRAINING_SCORE_LANE0 0x00208
|
||||
#define DPCD_ADDR_TRAINING_SCORE_LANE1 0x00209
|
||||
#define DPCD_ADDR_TRAINING_SCORE_LANE2 0x0020a
|
||||
#define DPCD_ADDR_TRAINING_SCORE_LANE3 0x0020b
|
||||
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE0_BYTE0 0x00210
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE0_BYTE1 0x00211
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE1_BYTE0 0x00212
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE1_BYTE1 0x00213
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE2_BYTE0 0x00214
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE2_BYTE1 0x00215
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE3_BYTE0 0x00216
|
||||
#define DPCD_ADDR_SYMBOL_ERROR_COUNT_LANE3_BYTE1 0x00217
|
||||
|
||||
#define DPCD_ADDR_TEST_REQUEST 0x00218
|
||||
#define DPCD_ADDR_TEST_REQUEST_LINK (1 << 0)
|
||||
#define DPCD_ADDR_TEST_REQUEST_PATTERN (1 << 1)
|
||||
#define DPCD_ADDR_TEST_REQUEST_EDID (1 << 2)
|
||||
#define DPCD_ADDR_TEST_REQUEST_PHY (1 << 3)
|
||||
|
||||
#define DPCD_ADDR_TEST_LINK_RATE 0x00219
|
||||
#define DPCD_ADDR_TEST_LANE_COUNT 0x00220
|
||||
#define DPCD_ADDR_TEST_PATTERN 0x00221
|
||||
|
||||
#define DPCD_ADDR_TEST_H_TOTAL_H 0x00222
|
||||
#define DPCD_ADDR_TEST_H_TOTAL_L 0x00223
|
||||
#define DPCD_ADDR_TEST_V_TOTAL_H 0x00224
|
||||
#define DPCD_ADDR_TEST_V_TOTAL_L 0x00225
|
||||
#define DPCD_ADDR_TEST_H_START_H 0x00226
|
||||
#define DPCD_ADDR_TEST_H_START_L 0x00227
|
||||
#define DPCD_ADDR_TEST_V_START_H 0x00228
|
||||
#define DPCD_ADDR_TEST_V_START_L 0x00229
|
||||
#define DPCD_ADDR_TEST_HSYNC_H 0x0022a
|
||||
#define DPCD_ADDR_TEST_HSYNC_L 0x0022b
|
||||
#define DPCD_ADDR_TEST_VSYNC_H 0x0022c
|
||||
#define DPCD_ADDR_TEST_VSYNC_L 0x0022d
|
||||
#define DPCD_ADDR_TEST_H_WIDTH_H 0x0022e
|
||||
#define DPCD_ADDR_TEST_H_WIDTH_L 0x0022f
|
||||
#define DPCD_ADDR_TEST_V_HEGHT_H 0x00230
|
||||
#define DPCD_ADDR_TEST_V_HEGHT_L 0x00231
|
||||
|
||||
#define DPCD_ADDR_TEST_PHY 0x00248
|
||||
#define DPCD_ADDR_TEST_PHY_SEL_MASK 3
|
||||
|
||||
|
||||
#define DPCD_ADDR_TEST_RESPONSE 0x00260
|
||||
#define DPCD_ADDR_TEST_RESPONSE_ACK (1 << 0)
|
||||
#define DPCD_ADDR_TEST_RESPONSE_NACK (1 << 1)
|
||||
#define DPCD_ADDR_TEST_RESPONSE_EDID (1 << 2)
|
||||
|
||||
#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x00261
|
||||
|
||||
|
||||
|
||||
#define DPCD_ADDR_SOURCE_IEEE_OUI_7_0 0x00300
|
||||
#define DPCD_ADDR_SOURCE_IEEE_OUI_15_8 0x00301
|
||||
#define DPCD_ADDR_SOURCE_IEEE_OUI_23_16 0x00302
|
||||
|
||||
#define DPCD_ADDR_SOURCE_DEVICE_ID_BYTE_0 0x00303
|
||||
|
||||
#define DPCD_ADDR_SINK_IEEE_OUI_7_0 0x00400
|
||||
#define DPCD_ADDR_SINK_IEEE_OUI_15_8 0x00401
|
||||
#define DPCD_ADDR_SINK_IEEE_OUI_23_16 0x00402
|
||||
|
||||
#define DPCD_ADDR_SINK_DEVICE_ID_BYTE_0 0x00403
|
||||
|
||||
#define DPCP_ADDR_VENDOR_BYTES 0x00430
|
||||
|
||||
#define DPCD_ADDR_BRANCH_IEEE_OUI_7_0 0x00500
|
||||
#define DPCD_ADDR_BRANCH_IEEE_OUI_15_8 0x00501
|
||||
#define DPCD_ADDR_BRANCH_IEEE_OUI_23_16 0x00502
|
||||
|
||||
#define DPCD_ADDR_BRANCH_DEVICE_ID_BYTE_0 0x00503
|
||||
|
||||
#define DPCD_ADDR_HDMI_DVI_MODE_SELECT 0x00519
|
||||
#define DPCD_HDMI_DVI_SELECT_DEFAULT 0x00
|
||||
#define DPCD_ADDR_HDMI_DVI_MODE_SELECT_DVI 0x01
|
||||
#define DPCD_HDCP_ENABLE 0x00
|
||||
#define DPCD_HDCP_DISABLE 0x02
|
||||
|
||||
#define DPCD_ADDR_SINK_POWER_STATE 0x00600
|
||||
#define DPCD_ADDR_SINK_POWER_STATE_ON 0x1
|
||||
#define DPCD_ADDR_SINK_POWER_STATE_OFF 0x2
|
||||
|
||||
|
||||
#define DPCD_ADDR_HDCP_BKSV_0 0x68000
|
||||
#define DPCD_ADDR_HDCP_BKSV_1 0x68001
|
||||
#define DPCD_ADDR_HDCP_BKSV_2 0x68002
|
||||
#define DPCD_ADDR_HDCP_BKSV_3 0x68003
|
||||
#define DPCD_ADDR_HDCP_BKSV_4 0x68004
|
||||
#define DPCD_ADDR_HDCP_R0_0 0x68005
|
||||
#define DPCD_ADDR_HDCP_R0_1 0x68006
|
||||
#define DPCD_ADDR_HDCP_AKSV_0 0x68007
|
||||
#define DPCD_ADDR_HDCP_AKSV_1 0x68008
|
||||
#define DPCD_ADDR_HDCP_AKSV_2 0x68009
|
||||
#define DPCD_ADDR_HDCP_AKSV_3 0x6800a
|
||||
#define DPCD_ADDR_HDCP_AKSV_4 0x6800b
|
||||
#define DPCD_ADDR_HDCP_AN_0 0x6800c
|
||||
#define DPCD_ADDR_HDCP_AN_1 0x6800d
|
||||
#define DPCD_ADDR_HDCP_AN_2 0x6800e
|
||||
#define DPCD_ADDR_HDCP_AN_3 0x6800f
|
||||
#define DPCD_ADDR_HDCP_AN_4 0x68010
|
||||
#define DPCD_ADDR_HDCP_AN_5 0x68011
|
||||
#define DPCD_ADDR_HDCP_AN_6 0x68012
|
||||
#define DPCD_ADDR_HDCP_AN_7 0x68013
|
||||
#define DPCD_ADDR_HDCP_H0_0 0x68014
|
||||
#define DPCD_ADDR_HDCP_H0_1 0x68015
|
||||
#define DPCD_ADDR_HDCP_H0_2 0x68016
|
||||
#define DPCD_ADDR_HDCP_H0_3 0x68017
|
||||
#define DPCD_ADDR_HDCP_H1_0 0x68018
|
||||
#define DPCD_ADDR_HDCP_H1_1 0x68019
|
||||
#define DPCD_ADDR_HDCP_H1_2 0x6801a
|
||||
#define DPCD_ADDR_HDCP_H1_3 0x6801b
|
||||
#define DPCD_ADDR_HDCP_H2_0 0x6801c
|
||||
#define DPCD_ADDR_HDCP_H2_1 0x6801d
|
||||
#define DPCD_ADDR_HDCP_H2_2 0x6801e
|
||||
#define DPCD_ADDR_HDCP_H2_3 0x6801f
|
||||
#define DPCD_ADDR_HDCP_H3_0 0x68020
|
||||
#define DPCD_ADDR_HDCP_H3_1 0x68021
|
||||
#define DPCD_ADDR_HDCP_H3_2 0x68022
|
||||
#define DPCD_ADDR_HDCP_H3_3 0x68023
|
||||
#define DPCD_ADDR_HDCP_H4_0 0x68024
|
||||
#define DPCD_ADDR_HDCP_H4_1 0x68025
|
||||
#define DPCD_ADDR_HDCP_H4_2 0x68026
|
||||
#define DPCD_ADDR_HDCP_H4_3 0x68027
|
||||
|
||||
#define DPCD_ADDR_HDCP_BCAPS 0x68028
|
||||
#define DPCD_ADDR_HDCP_BCAPS_HDCP_CAPABLE (1 << 0)
|
||||
#define DPCD_ADDR_HDCP_BCAPS_IS_REPEATER (1 << 1)
|
||||
|
||||
#define DPCD_ADDR_HDCP_STATUS 0x68029
|
||||
#define DPCD_ADDR_HDCP_STATUS_LINK_INTEGRITY_FAILURE (1 << 2)
|
||||
#define DPCD_ADDR_HDCP_STATUS_R0PRIME_AVAILABLE (1 << 1)
|
||||
#define DPCD_ADDR_HDCP_STATUS_READY (1 << 0)
|
||||
|
||||
#define DPCD_ADDR_HDCP_BINFO_0 0x6802a
|
||||
|
||||
#define DPCD_ADDR_HDCP_BINFO_1 0x6802b
|
||||
#define DPCD_ADDR_HDCP_INFO_MAX_CASCADE_EXCEEDED (1 << 11)
|
||||
#define DPCD_ADDR_HDCP_INFO_MAX_DEVS_EXCEEDED (1 << 7)
|
||||
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_0 0x6802c
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_1 0x6802d
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_2 0x6802e
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_3 0x6802f
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_4 0x68030
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_5 0x68031
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_6 0x68032
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_7 0x68033
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_8 0x68034
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_9 0x68035
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_10 0x68036
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_11 0x68037
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_12 0x68038
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_13 0x68039
|
||||
#define DPCD_ADDR_HDCP_KSV_FIFO_14 0x6803a
|
||||
#define DPCD_ADDR_HDCP_RSVD 0x6803b
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* Copyright (c) 1999-2009 Apple Computer, Inc. All Rights Reserved.
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef _IOKIT_EDID_H
|
||||
#define _IOKIT_EDID_H
|
||||
|
||||
|
||||
#define kEDIDEstablishedTimingsCount 24
|
||||
#define kEDIDEstablishedTimingsIIICount 48
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedHeader {
|
||||
uint8_t header[2];
|
||||
}EDIDDetailedHeader;
|
||||
|
||||
//__packed
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedTiming {
|
||||
uint8_t pixelClock[2];
|
||||
|
||||
uint8_t hor_addr_low;
|
||||
uint8_t hor_blank_low;
|
||||
uint8_t hor_addr_blank_high;
|
||||
uint8_t ver_addr_low;
|
||||
uint8_t ver_blank_low;
|
||||
uint8_t ver_addr_blank_high;
|
||||
|
||||
uint8_t hor_fporch; // #8
|
||||
uint8_t hor_sync;
|
||||
uint8_t ver_fporch_sync;
|
||||
|
||||
uint8_t hor_ver_porch_sync_high;
|
||||
uint8_t inmm[3]; // in milimeter
|
||||
uint8_t hor_border;
|
||||
uint8_t ver_border;
|
||||
uint8_t detailed;
|
||||
} EDIDDetailedTiming;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDString{
|
||||
uint8_t flag;
|
||||
char string[13];
|
||||
} EDIDString;
|
||||
|
||||
typedef enum {
|
||||
kEDIDDetailedRangeFlagRateOffsetVerticalMin = (1<<0),
|
||||
kEDIDDetailedRangeFlagRateOffsetVerticalMax = (1<<1),
|
||||
kEDIDDetailedRangeFlagRateOffsetHorizontalMin = (1<<2),
|
||||
kEDIDDetailedRangeFlagRateOffsetHorizontalMax = (1<<3)
|
||||
} EDIDDetailedRangeFlags;
|
||||
|
||||
enum {
|
||||
kEDIDDetailedRangeVideoTimingTypeGTF = 0,
|
||||
kEDIDDetailedRangeVideoTimingTypeRangeLimitsOnly = 1,
|
||||
kEDIDDetailedRangeVideoTimingTypeSecondaryGTF = 2,
|
||||
kEDIDDetailedRangeVideoTimingTypeCVT = 4
|
||||
};
|
||||
typedef uint8_t EDIDDetailedRangeVideoTimingType;
|
||||
|
||||
typedef enum {
|
||||
kEDIDSupportedAspectFlag15_9 = (1<<3),
|
||||
kEDIDSupportedAspectFlag5_4 = (1<<4),
|
||||
kEDIDSupportedAspectFlag16_10 = (1<<5),
|
||||
kEDIDSupportedAspectFlag16_9 = (1<<6),
|
||||
kEDIDSupportedAspectFlag4_3 = (1<<7)
|
||||
} EDIDSupportedAspectFlags;
|
||||
|
||||
typedef enum {
|
||||
kEDIDPreferredAspectType4_3,
|
||||
kEDIDPreferredAspectType16_9,
|
||||
kEDIDPreferredAspectType16_10,
|
||||
kEDIDPreferredAspectType5_4,
|
||||
kEDIDPreferredAspectType15_9,
|
||||
kEDIDPreferredAspectTypeShift = 5,
|
||||
kEDIDPreferredAspectTypeMask = 0x7,
|
||||
|
||||
} EDIDPreferredAspectType;
|
||||
|
||||
typedef enum {
|
||||
kEDIDCVTBlankingFlagStandard = (1<<3),
|
||||
kEDIDCVTBlankingFlagReduced = (1<<4),
|
||||
} EDIDCVTBlankingFlags;
|
||||
|
||||
typedef enum {
|
||||
kEDIDDigitalScalingFlagVerticalStretch = (1<<4),
|
||||
kEDIDDigitalScalingFlagVerticalShrink = (1<<5),
|
||||
kEDIDDigitalScalingFlagHorizontalStretch = (1<<6),
|
||||
kEDIDDigitalScalingFlagHorizontalShrink = (1<<7)
|
||||
} EDIDDigitalScalingFlags;
|
||||
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedRangeGTF {
|
||||
uint8_t reserved;
|
||||
uint8_t breakFrequency; // horizontal freq / 2 (khz)
|
||||
uint8_t c; // c*2
|
||||
uint8_t m[2];
|
||||
uint8_t k;
|
||||
uint8_t j; // j*2
|
||||
} EDIDDetailedRangeGTF;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedRangeCVT {
|
||||
uint8_t version;
|
||||
// Max. Pix Clk = [(range.maxPixelClockRate) × 10] – [(Byte 12: bits 7-2) × 0.25MHz]
|
||||
uint8_t precision_activeMaxMSB; // pixel clock precision * 0.25Mhz (bits 7-2) | max active pixels per line MSB (bits 1-0)
|
||||
uint8_t activeMaxLSB; // max active pixels per line MSB
|
||||
uint8_t supportedFlags;
|
||||
uint8_t preferredFlags;
|
||||
uint8_t scaling;
|
||||
uint8_t verticalRefreshRate; //hz
|
||||
} EDIDDetailedRangeCVT;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedRange{
|
||||
uint8_t flag;
|
||||
uint8_t minVerticalRate;
|
||||
uint8_t maxVerticalRate;
|
||||
uint8_t minHorizontalRate;
|
||||
uint8_t maxHorizontalRate;
|
||||
uint8_t maxPixelClockRate;
|
||||
|
||||
struct {
|
||||
EDIDDetailedRangeVideoTimingType type;
|
||||
|
||||
union {
|
||||
EDIDDetailedRangeGTF gtf;
|
||||
EDIDDetailedRangeCVT cvt;
|
||||
} data;
|
||||
}timing;
|
||||
|
||||
} EDIDDetailedRange;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedWhitePoint {
|
||||
uint8_t index;
|
||||
uint8_t xyLSB;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t gamma;
|
||||
} EDIDDetailedWhitePoint;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedColorPoint {
|
||||
EDIDDetailedWhitePoint whitePoint[2];
|
||||
} EDIDDetailedColorPoint;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedEstablishedTimingsIII {
|
||||
uint8_t data[6];
|
||||
} EDIDDetailedEstablishedTimingsIII;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDDetailedDescriptor {
|
||||
uint8_t zero[2];
|
||||
uint8_t flag;
|
||||
uint8_t type;
|
||||
|
||||
union {
|
||||
EDIDString name;
|
||||
EDIDDetailedRange range;
|
||||
EDIDDetailedColorPoint color;
|
||||
uint8_t standard[12];
|
||||
uint8_t cvt[12];
|
||||
EDIDDetailedEstablishedTimingsIII established;
|
||||
}data;
|
||||
|
||||
}EDIDDetailedDescriptor;
|
||||
|
||||
|
||||
typedef struct __attribute__((packed)) EDIDDetailed {
|
||||
|
||||
union {
|
||||
EDIDDetailedHeader header;
|
||||
EDIDDetailedTiming timing;
|
||||
EDIDDetailedDescriptor descriptor;
|
||||
} data;
|
||||
|
||||
} EDIDDetailed;
|
||||
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDHeader {
|
||||
uint8_t header[8];
|
||||
} EDIDHeader;
|
||||
|
||||
typedef enum {
|
||||
kEDIDStandardFeatureFlagGTF = (1<<0),
|
||||
kEDIDStandardFeatureFlagPreferredNative = (1<<1),
|
||||
kEDIDStandardFeatureFlagSRGB = (1<<2),
|
||||
kEDIDStandardFeatureFlagColorDepth = (3<<3),
|
||||
kEDIDStandardFeatureFlagActiveOff = (1<<5),
|
||||
kEDIDStandardFeatureFlagSuspend = (1<<6),
|
||||
kEDIDStandardFeatureFlagStandby = (1<<7)
|
||||
} EDIDStandardFeatureFlags;
|
||||
|
||||
// STANDARD STUFF
|
||||
typedef struct __attribute__((packed)) _EDIDStandard {
|
||||
uint8_t header[8];
|
||||
// Vender / Product
|
||||
uint8_t vendorID[2];
|
||||
uint8_t productID[2];
|
||||
uint8_t serialNumber[4];
|
||||
uint8_t weekOfManu;
|
||||
uint8_t yearOfManu;
|
||||
// EDID structure version / rev.
|
||||
uint8_t version;
|
||||
uint8_t revision;
|
||||
// Basic Display Parameters / Features
|
||||
uint8_t videoInputDef;
|
||||
uint8_t maxHorzSize; // cm
|
||||
uint8_t maxVertSize; // cm
|
||||
uint8_t dispTransferChr;
|
||||
uint8_t feature;
|
||||
// Color Characteristics
|
||||
uint8_t redGreenLowBits;
|
||||
uint8_t blueWhiteLowBits;
|
||||
uint8_t redX;
|
||||
uint8_t redY;
|
||||
uint8_t greenX;
|
||||
uint8_t greenY;
|
||||
uint8_t blueX;
|
||||
uint8_t blueY;
|
||||
uint8_t whiteX;
|
||||
uint8_t whiteY;
|
||||
// Established Timings
|
||||
uint8_t established[3];
|
||||
// Standard Timing Identification
|
||||
uint8_t standard[16];
|
||||
EDIDDetailed preferred;
|
||||
EDIDDetailed detailed[3];
|
||||
// Extra
|
||||
uint8_t extensionFlag;
|
||||
uint8_t checksum;
|
||||
} EDIDStandard;
|
||||
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDEXTHeader {
|
||||
uint8_t tag;
|
||||
uint8_t revision;
|
||||
} EDIDEXTHeader;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCVT {
|
||||
uint8_t data[3];
|
||||
} EDIDCVT;
|
||||
|
||||
// CEA STUFF
|
||||
|
||||
typedef enum {
|
||||
kEDIDCEA3DataBlockTypeReserved,
|
||||
kEDIDCEA3DataBlockTypeAudio,
|
||||
kEDIDCEA3DataBlockTypeVideo,
|
||||
kEDIDCEA3DataBlockTypeVenderSpecific,
|
||||
kEDIDCEA3DataBlockTypeSpeakerAllocation,
|
||||
kEDIDCEA3DataBlockTypeVESADTC,
|
||||
kEDIDCEA3DataBlockTypeReserved1,
|
||||
kEDIDCEA3DataBlockTypeExtended
|
||||
} EDIDCEA3DataBlockType;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA3DataBlockAudio {
|
||||
uint8_t descriptor[0];
|
||||
} EDIDCEA3DataBlockAudio;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA3DataBlockVideo {
|
||||
uint8_t descriptor[0];
|
||||
} EDIDCEA3DataBlockVideo;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA3DataBlockVendorSpecific {
|
||||
uint8_t ieeeOui[3];
|
||||
uint8_t data[0];
|
||||
} EDIDCEA3DataBlockVendorSpecific;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA3DataBlockSpeakerAllocation {
|
||||
uint8_t data[3];
|
||||
} EDIDCEA3DataBlockSpeakerAllocation;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA3DataBlockExtended {
|
||||
uint8_t tag;
|
||||
uint8_t data[31];
|
||||
} EDIDCEA3DataBlockExtended;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA3DataBlock {
|
||||
uint8_t flags;
|
||||
|
||||
union {
|
||||
EDIDCEA3DataBlockAudio audio;
|
||||
EDIDCEA3DataBlockVideo video;
|
||||
EDIDCEA3DataBlockVendorSpecific vendor;
|
||||
EDIDCEA3DataBlockSpeakerAllocation speaker;
|
||||
EDIDCEA3DataBlockExtended extended;
|
||||
} data;
|
||||
|
||||
} EDIDCEA3DataBlock;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA_1 {
|
||||
struct {
|
||||
uint8_t tag;
|
||||
uint8_t revision;
|
||||
uint8_t dataOffset;
|
||||
uint8_t reserved;
|
||||
} header;
|
||||
|
||||
uint8_t data[123];
|
||||
uint8_t checksum;
|
||||
} EDIDCEA_1;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA_2 {
|
||||
struct {
|
||||
uint8_t tag;
|
||||
uint8_t revision;
|
||||
uint8_t dataOffset;
|
||||
uint8_t detailedFlags;
|
||||
} header;
|
||||
|
||||
uint8_t data[123];
|
||||
uint8_t checksum;
|
||||
} EDIDCEA_2;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA_3 {
|
||||
struct {
|
||||
uint8_t tag;
|
||||
uint8_t revision;
|
||||
uint8_t dataLength;
|
||||
uint8_t detailedFlags;
|
||||
} header;
|
||||
uint8_t data[123];
|
||||
uint8_t checksum;
|
||||
} EDIDCEA_3;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDCEA {
|
||||
union {
|
||||
EDIDEXTHeader header;
|
||||
EDIDCEA_1 cea1;
|
||||
EDIDCEA_2 cea2;
|
||||
EDIDCEA_3 cea3;
|
||||
} data;
|
||||
} EDIDCEA;
|
||||
|
||||
typedef struct __attribute__((packed)) _EDIDVTB{
|
||||
EDIDEXTHeader header;
|
||||
uint8_t dtbCount;
|
||||
uint8_t cvtCount;
|
||||
uint8_t stCount;
|
||||
uint8_t data[122];
|
||||
uint8_t checksum;
|
||||
} EDIDVTB;
|
||||
|
||||
typedef enum {
|
||||
kEDIDTypeCEA = 0x02,
|
||||
KEDIDTypeVTB = 0x10,
|
||||
kEDIDTypeDI = 0x40,
|
||||
} EDIDType;
|
||||
|
||||
// __packed
|
||||
typedef struct __attribute__((packed)) _EDID{
|
||||
union {
|
||||
EDIDHeader header;
|
||||
EDIDStandard standard;
|
||||
EDIDCEA cea;
|
||||
EDIDVTB vtb;
|
||||
} data;
|
||||
|
||||
} EDID;
|
||||
|
||||
|
||||
|
||||
#endif /* _IOKIT_EDID_H */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,18 @@
|
||||
# Copyright (C) 2009 Apple Computer, Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Computer, Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Computer, Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
GLOBAL_INCLUDES +=
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/controller.o \
|
||||
$(LOCAL_DIR)/device.o \
|
||||
$(LOCAL_DIR)/debug.o \
|
||||
$(LOCAL_DIR)/process_edid.o
|
||||
Reference in new issue
Block a user