Commit 0078c924 authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher
Browse files

drm/amd/display: move eDP panel control logic to link_edp_panel_control



Create new file link_edp_panel_control.c and link_edp_panel_control.h,
and move eDP panel control logic into them.

Reviewed-by: default avatarGeorge Shen <George.Shen@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarAlan Liu <HaoPing.Liu@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent bc33f5e5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "dc_types.h"
#include "dccg.h"
#include "clk_mgr_internal.h"
#include "link.h"

#include "dce100/dce_clk_mgr.h"
#include "dce110/dce110_clk_mgr.h"
+1 −1
Original line number Diff line number Diff line
@@ -1659,7 +1659,7 @@ bool dc_validate_boot_timing(const struct dc *dc,
		return false;
	}

	if (is_edp_ilr_optimization_required(link, crtc_timing)) {
	if (link_is_edp_ilr_optimization_required(link, crtc_timing)) {
		DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n");
		return false;
	}
+4 −460
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
#include "link/protocols/link_dp_training.h"
#include "link/protocols/link_dp_phy.h"
#include "link/protocols/link_dp_capability.h"
#include "link/protocols/link_edp_panel_control.h"

#include "dc/dcn30/dcn30_vpg.h"

@@ -107,17 +108,6 @@ static void dc_link_destruct(struct dc_link *link)
		dc_sink_release(link->remote_sinks[i]);
}

bool dc_link_wait_for_t12(struct dc_link *link)
{
	if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
		link->dc->hwss.edp_wait_for_T12(link);

		return true;
	}

	return false;
}

/**
 * dc_link_detect_sink() - Determine if there is a sink connected
 *
@@ -1094,7 +1084,7 @@ static bool detect_link_and_local_sink(struct dc_link *link,
			(link->dpcd_sink_ext_caps.bits.oled == 1)) {
			dpcd_set_source_specific_data(link);
			msleep(post_oui_delay);
			dc_link_set_default_brightness_aux(link);
			set_default_brightness_aux(link);
			//TODO: use cached
		}

@@ -2067,10 +2057,10 @@ static enum dc_status enable_link_dp(struct dc_state *state,
	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
		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);
		link_backlight_enable_aux(link, true);
	}

	return status;
@@ -2740,22 +2730,6 @@ static void enable_link_lvds(struct pipe_ctx *pipe_ctx)

}

bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable)
{
	bool ret = false;
	union dpcd_alpm_configuration alpm_config;

	if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
		memset(&alpm_config, 0, sizeof(alpm_config));

		alpm_config.bits.ENABLE = (enable ? true : false);
		ret = dm_helpers_dp_write_dpcd(link->ctx, link,
				DP_RECEIVER_ALPM_CONFIG, &alpm_config.raw,
				sizeof(alpm_config.raw));
	}
	return ret;
}

/****************************enable_link***********************************/
static enum dc_status enable_link(
		struct dc_state *state,
@@ -3035,436 +3009,6 @@ enum dc_status dc_link_validate_mode_timing(
	return DC_OK;
}

static struct abm *get_abm_from_stream_res(const struct dc_link *link)
{
	int i;
	struct dc *dc = NULL;
	struct abm *abm = NULL;

	if (!link || !link->ctx)
		return NULL;

	dc = link->ctx->dc;

	for (i = 0; i < MAX_PIPES; i++) {
		struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
		struct dc_stream_state *stream = pipe_ctx.stream;

		if (stream && stream->link == link) {
			abm = pipe_ctx.stream_res.abm;
			break;
		}
	}
	return abm;
}

int dc_link_get_backlight_level(const struct dc_link *link)
{
	struct abm *abm = get_abm_from_stream_res(link);
	struct panel_cntl *panel_cntl = link->panel_cntl;
	struct dc  *dc = link->ctx->dc;
	struct dmcu *dmcu = dc->res_pool->dmcu;
	bool fw_set_brightness = true;

	if (dmcu)
		fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);

	if (!fw_set_brightness && panel_cntl->funcs->get_current_backlight)
		return panel_cntl->funcs->get_current_backlight(panel_cntl);
	else if (abm != NULL && abm->funcs->get_current_backlight != NULL)
		return (int) abm->funcs->get_current_backlight(abm);
	else
		return DC_ERROR_UNEXPECTED;
}

int dc_link_get_target_backlight_pwm(const struct dc_link *link)
{
	struct abm *abm = get_abm_from_stream_res(link);

	if (abm == NULL || abm->funcs->get_target_backlight == NULL)
		return DC_ERROR_UNEXPECTED;

	return (int) abm->funcs->get_target_backlight(abm);
}

static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link)
{
	int i;
	struct dc *dc = link->ctx->dc;
	struct pipe_ctx *pipe_ctx = NULL;

	for (i = 0; i < MAX_PIPES; i++) {
		if (dc->current_state->res_ctx.pipe_ctx[i].stream) {
			if (dc->current_state->res_ctx.pipe_ctx[i].stream->link == link) {
				pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
				break;
			}
		}
	}

	return pipe_ctx;
}

bool dc_link_set_backlight_level(const struct dc_link *link,
		uint32_t backlight_pwm_u16_16,
		uint32_t frame_ramp)
{
	struct dc  *dc = link->ctx->dc;

	DC_LOGGER_INIT(link->ctx->logger);
	DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
			backlight_pwm_u16_16, backlight_pwm_u16_16);

	if (dc_is_embedded_signal(link->connector_signal)) {
		struct pipe_ctx *pipe_ctx = get_pipe_from_link(link);

		if (pipe_ctx) {
			/* Disable brightness ramping when the display is blanked
			 * as it can hang the DMCU
			 */
			if (pipe_ctx->plane_state == NULL)
				frame_ramp = 0;
		} else {
			return false;
		}

		dc->hwss.set_backlight_level(
				pipe_ctx,
				backlight_pwm_u16_16,
				frame_ramp);
	}
	return true;
}

bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active,
		bool wait, bool force_static, const unsigned int *power_opts)
{
	struct dc  *dc = link->ctx->dc;
	struct dmcu *dmcu = dc->res_pool->dmcu;
	struct dmub_psr *psr = dc->res_pool->psr;
	unsigned int panel_inst;

	if (psr == NULL && force_static)
		return false;

	if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
		return false;

	if ((allow_active != NULL) && (*allow_active == true) && (link->type == dc_connection_none)) {
		// Don't enter PSR if panel is not connected
		return false;
	}

	/* Set power optimization flag */
	if (power_opts && link->psr_settings.psr_power_opt != *power_opts) {
		link->psr_settings.psr_power_opt = *power_opts;

		if (psr != NULL && link->psr_settings.psr_feature_enabled && psr->funcs->psr_set_power_opt)
			psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt, panel_inst);
	}

	if (psr != NULL && link->psr_settings.psr_feature_enabled &&
			force_static && psr->funcs->psr_force_static)
		psr->funcs->psr_force_static(psr, panel_inst);

	/* Enable or Disable PSR */
	if (allow_active && link->psr_settings.psr_allow_active != *allow_active) {
		link->psr_settings.psr_allow_active = *allow_active;

		if (!link->psr_settings.psr_allow_active)
			dc_z10_restore(dc);

		if (psr != NULL && link->psr_settings.psr_feature_enabled) {
			psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst);
		} else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) &&
			link->psr_settings.psr_feature_enabled)
			dmcu->funcs->set_psr_enable(dmcu, link->psr_settings.psr_allow_active, wait);
		else
			return false;
	}

	return true;
}

bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state)
{
	struct dc  *dc = link->ctx->dc;
	struct dmcu *dmcu = dc->res_pool->dmcu;
	struct dmub_psr *psr = dc->res_pool->psr;
	unsigned int panel_inst;

	if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
		return false;

	if (psr != NULL && link->psr_settings.psr_feature_enabled)
		psr->funcs->psr_get_state(psr, state, panel_inst);
	else if (dmcu != NULL && link->psr_settings.psr_feature_enabled)
		dmcu->funcs->get_psr_state(dmcu, state);

	return true;
}

static inline enum physical_phy_id
transmitter_to_phy_id(enum transmitter transmitter_value)
{
	switch (transmitter_value) {
	case TRANSMITTER_UNIPHY_A:
		return PHYLD_0;
	case TRANSMITTER_UNIPHY_B:
		return PHYLD_1;
	case TRANSMITTER_UNIPHY_C:
		return PHYLD_2;
	case TRANSMITTER_UNIPHY_D:
		return PHYLD_3;
	case TRANSMITTER_UNIPHY_E:
		return PHYLD_4;
	case TRANSMITTER_UNIPHY_F:
		return PHYLD_5;
	case TRANSMITTER_NUTMEG_CRT:
		return PHYLD_6;
	case TRANSMITTER_TRAVIS_CRT:
		return PHYLD_7;
	case TRANSMITTER_TRAVIS_LCD:
		return PHYLD_8;
	case TRANSMITTER_UNIPHY_G:
		return PHYLD_9;
	case TRANSMITTER_COUNT:
		return PHYLD_COUNT;
	case TRANSMITTER_UNKNOWN:
		return PHYLD_UNKNOWN;
	default:
		WARN_ONCE(1, "Unknown transmitter value %d\n",
			  transmitter_value);
		return PHYLD_UNKNOWN;
	}
}

bool dc_link_setup_psr(struct dc_link *link,
		const struct dc_stream_state *stream, struct psr_config *psr_config,
		struct psr_context *psr_context)
{
	struct dc *dc;
	struct dmcu *dmcu;
	struct dmub_psr *psr;
	int i;
	unsigned int panel_inst;
	/* updateSinkPsrDpcdConfig*/
	union dpcd_psr_configuration psr_configuration;
	union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};

	psr_context->controllerId = CONTROLLER_ID_UNDEFINED;

	if (!link)
		return false;

	dc = link->ctx->dc;
	dmcu = dc->res_pool->dmcu;
	psr = dc->res_pool->psr;

	if (!dmcu && !psr)
		return false;

	if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
		return false;


	memset(&psr_configuration, 0, sizeof(psr_configuration));

	psr_configuration.bits.ENABLE                    = 1;
	psr_configuration.bits.CRC_VERIFICATION          = 1;
	psr_configuration.bits.FRAME_CAPTURE_INDICATION  =
			psr_config->psr_frame_capture_indication_req;

	/* Check for PSR v2*/
	if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
		/* For PSR v2 selective update.
		 * Indicates whether sink should start capturing
		 * immediately following active scan line,
		 * or starting with the 2nd active scan line.
		 */
		psr_configuration.bits.LINE_CAPTURE_INDICATION = 0;
		/*For PSR v2, determines whether Sink should generate
		 * IRQ_HPD when CRC mismatch is detected.
		 */
		psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR    = 1;
		/* For PSR v2, set the bit when the Source device will
		 * be enabling PSR2 operation.
		 */
		psr_configuration.bits.ENABLE_PSR2    = 1;
		/* For PSR v2, the Sink device must be able to receive
		 * SU region updates early in the frame time.
		 */
		psr_configuration.bits.EARLY_TRANSPORT_ENABLE    = 1;
	}

	dm_helpers_dp_write_dpcd(
		link->ctx,
		link,
		368,
		&psr_configuration.raw,
		sizeof(psr_configuration.raw));

	if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
		dc_power_alpm_dpcd_enable(link, true);
		psr_context->su_granularity_required =
			psr_config->su_granularity_required;
		psr_context->su_y_granularity =
			psr_config->su_y_granularity;
		psr_context->line_time_in_us =
			psr_config->line_time_in_us;

		if (link->psr_settings.psr_vtotal_control_support) {
			psr_context->rate_control_caps = psr_config->rate_control_caps;
			vtotal_control.bits.ENABLE = true;
			core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
							&vtotal_control.raw, sizeof(vtotal_control.raw));
		}
	}

	psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
	psr_context->transmitterId = link->link_enc->transmitter;
	psr_context->engineId = link->link_enc->preferred_engine;

	for (i = 0; i < MAX_PIPES; i++) {
		if (dc->current_state->res_ctx.pipe_ctx[i].stream
				== stream) {
			/* dmcu -1 for all controller id values,
			 * therefore +1 here
			 */
			psr_context->controllerId =
				dc->current_state->res_ctx.
				pipe_ctx[i].stream_res.tg->inst + 1;
			break;
		}
	}

	/* Hardcoded for now.  Can be Pcie or Uniphy (or Unknown)*/
	psr_context->phyType = PHY_TYPE_UNIPHY;
	/*PhyId is associated with the transmitter id*/
	psr_context->smuPhyId =
		transmitter_to_phy_id(link->link_enc->transmitter);

	psr_context->crtcTimingVerticalTotal = stream->timing.v_total;
	psr_context->vsync_rate_hz = div64_u64(div64_u64((stream->
					timing.pix_clk_100hz * 100),
					stream->timing.v_total),
					stream->timing.h_total);

	psr_context->psrSupportedDisplayConfig = true;
	psr_context->psrExitLinkTrainingRequired =
		psr_config->psr_exit_link_training_required;
	psr_context->sdpTransmitLineNumDeadline =
		psr_config->psr_sdp_transmit_line_num_deadline;
	psr_context->psrFrameCaptureIndicationReq =
		psr_config->psr_frame_capture_indication_req;

	psr_context->skipPsrWaitForPllLock = 0; /* only = 1 in KV */

	psr_context->numberOfControllers =
			link->dc->res_pool->timing_generator_count;

	psr_context->rfb_update_auto_en = true;

	/* 2 frames before enter PSR. */
	psr_context->timehyst_frames = 2;
	/* half a frame
	 * (units in 100 lines, i.e. a value of 1 represents 100 lines)
	 */
	psr_context->hyst_lines = stream->timing.v_total / 2 / 100;
	psr_context->aux_repeats = 10;

	psr_context->psr_level.u32all = 0;

	/*skip power down the single pipe since it blocks the cstate*/
#if defined(CONFIG_DRM_AMD_DC_DCN)
	if (link->ctx->asic_id.chip_family >= FAMILY_RV) {
		switch(link->ctx->asic_id.chip_family) {
		case FAMILY_YELLOW_CARP:
		case AMDGPU_FAMILY_GC_10_3_6:
		case AMDGPU_FAMILY_GC_11_0_1:
			if (dc->debug.disable_z10 || dc->debug.psr_skip_crtc_disable)
				psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
			break;
		default:
			psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
			break;
		}
	}
#else
	if (link->ctx->asic_id.chip_family >= FAMILY_RV)
		psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
#endif

	/* SMU will perform additional powerdown sequence.
	 * For unsupported ASICs, set psr_level flag to skip PSR
	 *  static screen notification to SMU.
	 *  (Always set for DAL2, did not check ASIC)
	 */
	psr_context->allow_smu_optimizations = psr_config->allow_smu_optimizations;
	psr_context->allow_multi_disp_optimizations = psr_config->allow_multi_disp_optimizations;

	/* Complete PSR entry before aborting to prevent intermittent
	 * freezes on certain eDPs
	 */
	psr_context->psr_level.bits.DISABLE_PSR_ENTRY_ABORT = 1;

	/* enable ALPM */
	psr_context->psr_level.bits.DISABLE_ALPM = 0;
	psr_context->psr_level.bits.ALPM_DEFAULT_PD_MODE = 1;

	/* Controls additional delay after remote frame capture before
	 * continuing power down, default = 0
	 */
	psr_context->frame_delay = 0;

	if (psr) {
		link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr,
			link, psr_context, panel_inst);
		link->psr_settings.psr_power_opt = 0;
		link->psr_settings.psr_allow_active = 0;
	}
	else
		link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context);

	/* psr_enabled == 0 indicates setup_psr did not succeed, but this
	 * should not happen since firmware should be running at this point
	 */
	if (link->psr_settings.psr_feature_enabled == 0)
		ASSERT(0);

	return true;

}

void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
{
	struct dc  *dc = link->ctx->dc;
	struct dmub_psr *psr = dc->res_pool->psr;
	unsigned int panel_inst;

	if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
		return;

	/* PSR residency measurements only supported on DMCUB */
	if (psr != NULL && link->psr_settings.psr_feature_enabled)
		psr->funcs->psr_get_residency(psr, residency, panel_inst);
	else
		*residency = 0;
}

bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
{
	struct dc *dc = link->ctx->dc;
	struct dmub_psr *psr = dc->res_pool->psr;

	if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
		return false;

	psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);

	return true;
}

const struct dc_link_status *dc_link_get_status(const struct dc_link *link)
{
	return &link->link_status;
+0 −339

File changed.

Preview size limit exceeded, changes collapsed.

+2 −11
Original line number Diff line number Diff line
@@ -370,11 +370,6 @@ 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_target_backlight_pwm(const struct dc_link *link);
@@ -388,16 +383,10 @@ bool dc_link_setup_psr(struct dc_link *dc_link,
		const struct dc_stream_state *stream, struct psr_config *psr_config,
		struct psr_context *psr_context);

bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable);

void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency);

void dc_link_blank_all_dp_displays(struct dc *dc);
void dc_link_blank_all_edp_displays(struct dc *dc);

void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init);
bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link,
		uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);

/* Request DC to detect if there is a Panel connected.
 * boot - If this call is during initial boot.
@@ -584,4 +573,6 @@ void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on);
bool dc_link_decide_edp_link_settings(struct dc_link *link,
		struct dc_link_settings *link_setting,
		uint32_t req_bw);
void dc_link_edp_panel_backlight_power_on(struct dc_link *link,
		bool wait_for_hpd);
#endif /* DC_LINK_H_ */
Loading