Commit 96577cf8 authored by Hersen Wu's avatar Hersen Wu Committed by Alex Deucher

drm/amd/display: linux enable oled panel support dc part

[Why] old panel has been enabled for window driver but not linux.

[How] enable oled panel support for linux. this patch is dc part.
Signed-off-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Reviewed-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Reviewed-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 9edf202d
...@@ -599,6 +599,9 @@ static bool detect_dp( ...@@ -599,6 +599,9 @@ static bool detect_dp(
if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT; sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;
dpcd_set_source_specific_data(link);
if (!detect_dp_sink_caps(link)) if (!detect_dp_sink_caps(link))
return false; return false;
...@@ -769,8 +772,16 @@ static bool dc_link_detect_helper(struct dc_link *link, ...@@ -769,8 +772,16 @@ static bool dc_link_detect_helper(struct dc_link *link,
if ((link->connector_signal == SIGNAL_TYPE_LVDS || if ((link->connector_signal == SIGNAL_TYPE_LVDS ||
link->connector_signal == SIGNAL_TYPE_EDP) && link->connector_signal == SIGNAL_TYPE_EDP) &&
link->local_sink) link->local_sink) {
// need to re-write OUI and brightness in resume case
if (link->connector_signal == SIGNAL_TYPE_EDP) {
dpcd_set_source_specific_data(link);
dc_link_set_default_brightness_aux(link); //TODO: use cached
}
return true; return true;
}
if (false == dc_link_detect_sink(link, &new_connection_type)) { if (false == dc_link_detect_sink(link, &new_connection_type)) {
BREAK_TO_DEBUGGER(); BREAK_TO_DEBUGGER();
...@@ -818,6 +829,10 @@ static bool dc_link_detect_helper(struct dc_link *link, ...@@ -818,6 +829,10 @@ static bool dc_link_detect_helper(struct dc_link *link,
} }
case SIGNAL_TYPE_EDP: { case SIGNAL_TYPE_EDP: {
read_current_link_settings_on_detect(link);
dpcd_set_source_specific_data(link);
detect_edp_sink_caps(link); detect_edp_sink_caps(link);
read_current_link_settings_on_detect(link); read_current_link_settings_on_detect(link);
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX; sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
...@@ -1492,6 +1507,7 @@ static enum dc_status enable_link_dp( ...@@ -1492,6 +1507,7 @@ static enum dc_status enable_link_dp(
bool fec_enable; bool fec_enable;
int i; int i;
bool apply_seamless_boot_optimization = false; bool apply_seamless_boot_optimization = false;
uint32_t bl_oled_enable_delay = 50; // in ms
// check for seamless boot // check for seamless boot
for (i = 0; i < state->stream_count; i++) { for (i = 0; i < state->stream_count; i++) {
...@@ -1515,6 +1531,9 @@ static enum dc_status enable_link_dp( ...@@ -1515,6 +1531,9 @@ static enum dc_status enable_link_dp(
if (state->clk_mgr && !apply_seamless_boot_optimization) if (state->clk_mgr && !apply_seamless_boot_optimization)
state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false); state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false);
// during mode switch we do DP_SET_POWER off then on, and OUI is lost
dpcd_set_source_specific_data(link);
skip_video_pattern = true; skip_video_pattern = true;
if (link_settings.link_rate == LINK_RATE_LOW) if (link_settings.link_rate == LINK_RATE_LOW)
...@@ -1538,6 +1557,17 @@ static enum dc_status enable_link_dp( ...@@ -1538,6 +1557,17 @@ static enum dc_status enable_link_dp(
fec_enable = true; fec_enable = true;
dp_set_fec_enable(link, fec_enable); dp_set_fec_enable(link, fec_enable);
// during mode set we do DP_SET_POWER off then on, aux writes are lost
if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 ||
link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) {
dc_link_set_default_brightness_aux(link); // TODO: use cached if known
if (link->dpcd_sink_ext_caps.bits.oled == 1)
msleep(bl_oled_enable_delay);
dc_link_backlight_enable_aux(link, true);
}
return status; return status;
} }
......
...@@ -20,6 +20,14 @@ ...@@ -20,6 +20,14 @@
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 #define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
#define DP_SOURCE_TABLE_REVISION 0x310
#define DP_SOURCE_PAYLOAD_SIZE 0x311
#define DP_SOURCE_SINK_CAP 0x317
#define DP_SOURCE_BACKLIGHT_LEVEL 0x320
#define DP_SOURCE_BACKLIGHT_CURRENT_PEAK 0x326
#define DP_SOURCE_BACKLIGHT_CONTROL 0x32E
#define DP_SOURCE_BACKLIGHT_ENABLE 0x32F
/* maximum pre emphasis level allowed for each voltage swing level*/ /* maximum pre emphasis level allowed for each voltage swing level*/
static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
PRE_EMPHASIS_LEVEL3, PRE_EMPHASIS_LEVEL3,
...@@ -3166,6 +3174,23 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, ...@@ -3166,6 +3174,23 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
link->wa_flags.dp_keep_receiver_powered = false; link->wa_flags.dp_keep_receiver_powered = false;
} }
/* Read additional sink caps defined in source specific DPCD area
* This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP)
*/
static bool dpcd_read_sink_ext_caps(struct dc_link *link)
{
uint8_t dpcd_data;
if (!link)
return false;
if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK)
return false;
link->dpcd_sink_ext_caps.raw = dpcd_data;
return true;
}
static bool retrieve_link_cap(struct dc_link *link) static bool retrieve_link_cap(struct dc_link *link)
{ {
/* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
...@@ -3438,6 +3463,9 @@ static bool retrieve_link_cap(struct dc_link *link) ...@@ -3438,6 +3463,9 @@ static bool retrieve_link_cap(struct dc_link *link)
sizeof(link->dpcd_caps.dsc_caps.dsc_ext_caps.raw)); sizeof(link->dpcd_caps.dsc_caps.dsc_ext_caps.raw));
} }
if (!dpcd_read_sink_ext_caps(link))
link->dpcd_sink_ext_caps.raw = 0;
/* Connectivity log: detection */ /* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
...@@ -3590,6 +3618,8 @@ void detect_edp_sink_caps(struct dc_link *link) ...@@ -3590,6 +3618,8 @@ void detect_edp_sink_caps(struct dc_link *link)
} }
} }
link->verified_link_cap = link->reported_link_cap; link->verified_link_cap = link->reported_link_cap;
dc_link_set_default_brightness_aux(link);
} }
void dc_link_dp_enable_hpd(const struct dc_link *link) void dc_link_dp_enable_hpd(const struct dc_link *link)
...@@ -4147,3 +4177,141 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) ...@@ -4147,3 +4177,141 @@ void dp_set_fec_enable(struct dc_link *link, bool enable)
} }
} }
void dpcd_set_source_specific_data(struct dc_link *link)
{
struct dpcd_amd_signature amd_signature;
const uint32_t post_oui_delay = 30; // 30ms
amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0;
amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0;
amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A;
amd_signature.device_id_byte1 =
(uint8_t)(link->ctx->asic_id.chip_id);
amd_signature.device_id_byte2 =
(uint8_t)(link->ctx->asic_id.chip_id >> 8);
memset(&amd_signature.zero, 0, 4);
amd_signature.dce_version =
(uint8_t)(link->ctx->dce_version);
amd_signature.dal_version_byte1 = 0x0; // needed? where to get?
amd_signature.dal_version_byte2 = 0x0; // needed? where to get?
core_link_write_dpcd(link, DP_SOURCE_OUI,
(uint8_t *)(&amd_signature),
sizeof(amd_signature));
// Sink may need to configure internals based on vendor, so allow some
// time before proceeding with possibly vendor specific transactions
msleep(post_oui_delay);
}
bool dc_link_set_backlight_level_nits(struct dc_link *link,
bool isHDR,
uint32_t backlight_millinits,
uint32_t transition_time_in_ms)
{
struct dpcd_source_backlight_set dpcd_backlight_set;
uint8_t backlight_control = isHDR ? 1 : 0;
if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
return false;
// OLEDs have no PWM, they can only use AUX
if (link->dpcd_sink_ext_caps.bits.oled == 1)
backlight_control = 1;
*(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
*(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
(uint8_t *)(&dpcd_backlight_set),
sizeof(dpcd_backlight_set)) != DC_OK)
return false;
if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL,
&backlight_control, 1) != DC_OK)
return false;
return true;
}
bool dc_link_get_backlight_level_nits(struct dc_link *link,
uint32_t *backlight_millinits_avg,
uint32_t *backlight_millinits_peak)
{
union dpcd_source_backlight_get dpcd_backlight_get;
memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get));
if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
return false;
if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
dpcd_backlight_get.raw,
sizeof(union dpcd_source_backlight_get)))
return false;
*backlight_millinits_avg =
dpcd_backlight_get.bytes.backlight_millinits_avg;
*backlight_millinits_peak =
dpcd_backlight_get.bytes.backlight_millinits_peak;
/* On non-supported panels dpcd_read usually succeeds with 0 returned */
if (*backlight_millinits_avg == 0 ||
*backlight_millinits_avg > *backlight_millinits_peak)
return false;
return true;
}
bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable)
{
uint8_t backlight_enable = enable ? 1 : 0;
if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
return false;
if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
&backlight_enable, 1) != DC_OK)
return false;
return true;
}
// we read default from 0x320 because we expect BIOS wrote it there
// regular get_backlight_nit reads from panel set at 0x326
bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits)
{
if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
return false;
if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
(uint8_t *) backlight_millinits,
sizeof(uint32_t)))
return false;
return true;
}
bool dc_link_set_default_brightness_aux(struct dc_link *link)
{
uint32_t default_backlight;
if (link &&
(link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)) {
if (!dc_link_read_default_bl_aux(link, &default_backlight))
default_backlight = 150000;
// if < 5 nits or > 5000, it might be wrong readback
if (default_backlight < 5000 || default_backlight > 5000000)
default_backlight = 150000; //
return dc_link_set_backlight_level_nits(link, true,
default_backlight, 0);
}
return false;
}
...@@ -980,6 +980,20 @@ struct dpcd_caps { ...@@ -980,6 +980,20 @@ struct dpcd_caps {
}; };
union dpcd_sink_ext_caps {
struct {
/* 0 - Sink supports backlight adjust via PWM during SDR/HDR mode
* 1 - Sink supports backlight adjust via AUX during SDR/HDR mode.
*/
uint8_t sdr_aux_backlight_control : 1;
uint8_t hdr_aux_backlight_control : 1;
uint8_t reserved_1 : 2;
uint8_t oled : 1;
uint8_t reserved : 3;
} bits;
uint8_t raw;
};
#include "dc_link.h" #include "dc_link.h"
/******************************************************************************* /*******************************************************************************
......
...@@ -432,6 +432,40 @@ struct dp_sink_hw_fw_revision { ...@@ -432,6 +432,40 @@ struct dp_sink_hw_fw_revision {
uint8_t ieee_fw_rev[2]; uint8_t ieee_fw_rev[2];
}; };
struct dpcd_amd_signature {
uint8_t AMD_IEEE_TxSignature_byte1;
uint8_t AMD_IEEE_TxSignature_byte2;
uint8_t AMD_IEEE_TxSignature_byte3;
uint8_t device_id_byte1;
uint8_t device_id_byte2;
uint8_t zero[4];
uint8_t dce_version;
uint8_t dal_version_byte1;
uint8_t dal_version_byte2;
};
struct dpcd_source_backlight_set {
struct {
uint8_t byte0;
uint8_t byte1;
uint8_t byte2;
uint8_t byte3;
} backlight_level_millinits;
struct {
uint8_t byte0;
uint8_t byte1;
} backlight_transition_time_ms;
};
union dpcd_source_backlight_get {
struct {
uint32_t backlight_millinits_peak; /* 326h */
uint32_t backlight_millinits_avg; /* 32Ah */
} bytes;
uint8_t raw[8];
};
/*DPCD register of DP receiver capability field bits-*/ /*DPCD register of DP receiver capability field bits-*/
union edp_configuration_cap { union edp_configuration_cap {
struct { struct {
......
...@@ -128,6 +128,7 @@ struct dc_link { ...@@ -128,6 +128,7 @@ struct dc_link {
enum edp_revision edp_revision; enum edp_revision edp_revision;
bool psr_feature_enabled; bool psr_feature_enabled;
bool psr_allow_active; bool psr_allow_active;
union dpcd_sink_ext_caps dpcd_sink_ext_caps;
/* MST record stream using this link */ /* MST record stream using this link */
struct link_flags { struct link_flags {
...@@ -178,6 +179,21 @@ bool dc_link_set_backlight_level(const struct dc_link *dc_link, ...@@ -178,6 +179,21 @@ bool dc_link_set_backlight_level(const struct dc_link *dc_link,
uint32_t backlight_pwm_u16_16, uint32_t backlight_pwm_u16_16,
uint32_t frame_ramp); uint32_t frame_ramp);
/* Set/get nits-based backlight level of an embedded panel (eDP, LVDS). */
bool dc_link_set_backlight_level_nits(struct dc_link *link,
bool isHDR,
uint32_t backlight_millinits,
uint32_t transition_time_in_ms);
bool dc_link_get_backlight_level_nits(struct dc_link *link,
uint32_t *backlight_millinits,
uint32_t *backlight_millinits_peak);
bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable);
bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits);
bool dc_link_set_default_brightness_aux(struct dc_link *link);
int dc_link_get_backlight_level(const struct dc_link *dc_link); int dc_link_get_backlight_level(const struct dc_link *dc_link);
bool dc_link_set_abm_disable(const struct dc_link *dc_link); bool dc_link_set_abm_disable(const struct dc_link *dc_link);
......
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define PANEL_POWER_UP_TIMEOUT 300 #define PANEL_POWER_UP_TIMEOUT 300
#define PANEL_POWER_DOWN_TIMEOUT 500 #define PANEL_POWER_DOWN_TIMEOUT 500
#define HPD_CHECK_INTERVAL 10 #define HPD_CHECK_INTERVAL 10
#define OLED_POST_T7_DELAY 100
#define OLED_PRE_T11_DELAY 150
#define CTX \ #define CTX \
hws->ctx hws->ctx
...@@ -936,9 +938,21 @@ void dce110_edp_backlight_control( ...@@ -936,9 +938,21 @@ void dce110_edp_backlight_control(
if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
edp_receiver_ready_T7(link); edp_receiver_ready_T7(link);
link_transmitter_control(ctx->dc_bios, &cntl); link_transmitter_control(ctx->dc_bios, &cntl);
if (enable && link->dpcd_sink_ext_caps.bits.oled)
msleep(OLED_POST_T7_DELAY);
if (link->dpcd_sink_ext_caps.bits.oled ||
link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)
dc_link_backlight_enable_aux(link, enable);
/*edp 1.2*/ /*edp 1.2*/
if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF)
edp_receiver_ready_T9(link); edp_receiver_ready_T9(link);
if (!enable && link->dpcd_sink_ext_caps.bits.oled)
msleep(OLED_PRE_T11_DELAY);
} }
void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
......
...@@ -78,6 +78,8 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); ...@@ -78,6 +78,8 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
bool dp_overwrite_extended_receiver_cap(struct dc_link *link); bool dp_overwrite_extended_receiver_cap(struct dc_link *link);
void dpcd_set_source_specific_data(struct dc_link *link);
void dp_set_fec_ready(struct dc_link *link, bool ready); void dp_set_fec_ready(struct dc_link *link, bool ready);
void dp_set_fec_enable(struct dc_link *link, bool enable); void dp_set_fec_enable(struct dc_link *link, bool enable);
bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment