#include "link_dp_phy.h"
#include "link_dpcd.h"
#include "link_dp_training.h"
#include "link_dp_capability.h"
#include "clk_mgr.h"
#include "resource.h"
#include "link_enc_cfg.h"
#include "atomfirmware.h"
#define DC_LOGGER \
link->ctx->logger
void dpcd_write_rx_power_ctrl(struct dc_link *link, bool on)
{
uint8_t state;
state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
if (link->sync_lt_in_progress)
return;
core_link_write_dpcd(link, DP_SET_POWER, &state,
sizeof(state));
}
void dp_enable_link_phy(
struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal,
enum clock_source_id clock_source,
const struct dc_link_settings *link_settings)
{
link->cur_link_settings = *link_settings;
link->dc->hwss.enable_dp_link_output(link, link_res, signal,
clock_source, link_settings);
dpcd_write_rx_power_ctrl(link, true);
}
void dp_disable_link_phy(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal)
{
struct dc *dc = link->ctx->dc;
if (!link->wa_flags.dp_keep_receiver_powered &&
!link->skip_implict_edp_power_control &&
link->type != dc_connection_none)
dpcd_write_rx_power_ctrl(link, false);
dc->hwss.disable_link_output(link, link_res, signal);
memset(&link->cur_link_settings, 0,
sizeof(link->cur_link_settings));
if (dc->clk_mgr->funcs->notify_link_rate_change)
dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
}
static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
{
return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ==
offset);
}
void dp_set_hw_lane_settings(
struct dc_link *link,
const struct link_resource *link_res,
const struct link_training_settings *link_settings,
uint32_t offset)
{
const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) &&
!is_immediate_downstream(link, offset) &&
(!((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) == AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) ||
link_dp_get_encoding_format(&link_settings->link_settings) == DP_8b_10b_ENCODING))
return;
if (link_hwss->ext.set_dp_lane_settings)
link_hwss->ext.set_dp_lane_settings(link, link_res,
&link_settings->link_settings,
link_settings->hw_lane_settings);
memmove(link->cur_lane_setting,
link_settings->hw_lane_settings,
sizeof(link->cur_lane_setting));
}
void dp_set_drive_settings(
struct dc_link *link,
const struct link_resource *link_res,
struct link_training_settings *lt_settings)
{
dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
dp_hw_to_dpcd_lane_settings(lt_settings,
lt_settings->hw_lane_settings,
lt_settings->dpcd_lane_settings);
dpcd_set_lane_settings(link, lt_settings, DPRX);
}
enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready)
{
struct link_encoder *link_enc = link_res->dio_link_enc;
enum dc_status status = DC_OK;
uint8_t fec_config = 0;
if (!link->dc->config.unify_link_enc_assignment)
link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
if (link_enc->funcs->fec_set_ready == NULL)
return DC_NOT_SUPPORTED;
if (ready && dp_should_enable_fec(link)) {
fec_config = 1;
status = core_link_write_dpcd(link, DP_FEC_CONFIGURATION,
&fec_config, sizeof(fec_config));
if (status == DC_OK) {
link_enc->funcs->fec_set_ready(link_enc, true);
link->fec_state = dc_link_fec_ready;
}
} else {
if (link->fec_state == dc_link_fec_ready) {
fec_config = 0;
if (link->type != dc_connection_none)
core_link_write_dpcd(link, DP_FEC_CONFIGURATION,
&fec_config, sizeof(fec_config));
link_enc->funcs->fec_set_ready(link_enc, false);
link->fec_state = dc_link_fec_not_ready;
}
}
return status;
}
void dp_set_fec_enable(struct dc_link *link, const struct link_resource *link_res, bool enable)
{
struct link_encoder *link_enc = link_res->dio_link_enc;
if (!link->dc->config.unify_link_enc_assignment)
link_enc = link_enc_cfg_get_link_enc(link);
if (link_enc == NULL || link_enc->funcs == NULL || link_enc->funcs->fec_set_enable == NULL)
return;
if (enable && dp_should_enable_fec(link)) {
if (link->fec_state == dc_link_fec_ready) {
udelay(7);
link_enc->funcs->fec_set_enable(link_enc, true);
link->fec_state = dc_link_fec_enabled;
}
} else {
if (link->fec_state == dc_link_fec_enabled) {
link_enc->funcs->fec_set_enable(link_enc, false);
link->fec_state = dc_link_fec_ready;
}
}
}