Commit a185048c authored by Tony Cheng's avatar Tony Cheng Committed by Alex Deucher
Browse files

drm/amd/display: refactor pplib/smu communication



new per SoC interface instead legacy interface with lots of un-used
field that only cause confusion

model pp_smu like one of our HW objects with func_ptr interface
to call into it.  struct pp_smu as handle to call pp/smu

Signed-off-by: default avatarTony Cheng <tony.cheng@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 1e8635ea
Loading
Loading
Loading
Loading
+5 −8
Original line number Diff line number Diff line
@@ -401,14 +401,6 @@ bool dm_pp_notify_wm_clock_changes(
	return false;
}

bool dm_pp_notify_wm_clock_changes_soc15(
	const struct dc_context *ctx,
	struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
{
	/* TODO: to be implemented */
	return false;
}

bool dm_pp_apply_power_level_change_request(
	const struct dc_context *ctx,
	struct dm_pp_power_level_change_request *level_change_req)
@@ -433,4 +425,9 @@ bool dm_pp_get_static_clocks(
	return false;
}

void dm_pp_get_funcs_rv(
		struct dc_context *ctx,
		struct pp_smu_funcs_rv *funcs)
{}

/**** end of power component interfaces ****/
+52 −48
Original line number Diff line number Diff line
@@ -1311,12 +1311,16 @@ void dcn_bw_update_from_pplib(struct dc *dc)

void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
{
	struct dm_pp_wm_sets_with_clock_ranges_soc15 clk_ranges = {0};
	struct pp_smu_funcs_rv *pp = dc->res_pool->pp_smu;
	struct pp_smu_wm_range_sets ranges = {0};
	int max_fclk_khz, nom_fclk_khz, min_fclk_khz, max_dcfclk_khz,
		nom_dcfclk_khz, mid_fclk_khz, min_dcfclk_khz, socclk_khz;
	const int overdrive = 5000000; /* 5 GHz to cover Overdrive */
	unsigned factor = (ddr4_dram_factor_single_Channel * dc->dcn_soc->number_of_channels);

	if (!pp->set_wm_ranges)
		return;

	kernel_fpu_begin();
	max_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 * 1000000 / factor;
	nom_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 * 1000000 / factor;
@@ -1336,55 +1340,55 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
	/* SOCCLK does not affect anytihng but writeback for DCN so for now we dont
	 * care what the value is, hence min to overdrive level
	 */
	clk_ranges.num_wm_dmif_sets = 4;
	clk_ranges.num_wm_mcif_sets = 4;
	clk_ranges.wm_dmif_clocks_ranges[0].wm_set_id = WM_SET_A;
	clk_ranges.wm_dmif_clocks_ranges[0].wm_min_dcfclk_clk_in_khz = min_dcfclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[0].wm_max_dcfclk_clk_in_khz = max_dcfclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[0].wm_min_memg_clk_in_khz = min_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[0].wm_max_mem_clk_in_khz = min_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[0].wm_set_id = WM_SET_A;
	clk_ranges.wm_mcif_clocks_ranges[0].wm_min_socclk_clk_in_khz = socclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[0].wm_max_socclk_clk_in_khz = overdrive;
	clk_ranges.wm_mcif_clocks_ranges[0].wm_min_memg_clk_in_khz = min_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[0].wm_max_mem_clk_in_khz = min_fclk_khz;

	clk_ranges.wm_dmif_clocks_ranges[1].wm_set_id = WM_SET_B;
	clk_ranges.wm_dmif_clocks_ranges[1].wm_min_dcfclk_clk_in_khz = min_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[1].wm_max_dcfclk_clk_in_khz = max_dcfclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[1].wm_min_memg_clk_in_khz = mid_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[1].wm_max_mem_clk_in_khz = mid_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[1].wm_set_id = WM_SET_B;
	clk_ranges.wm_mcif_clocks_ranges[1].wm_min_socclk_clk_in_khz = socclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[1].wm_max_socclk_clk_in_khz = overdrive;
	clk_ranges.wm_mcif_clocks_ranges[1].wm_min_memg_clk_in_khz = mid_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[1].wm_max_mem_clk_in_khz = mid_fclk_khz;


	clk_ranges.wm_dmif_clocks_ranges[2].wm_set_id = WM_SET_C;
	clk_ranges.wm_dmif_clocks_ranges[2].wm_min_dcfclk_clk_in_khz = min_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[2].wm_max_dcfclk_clk_in_khz = max_dcfclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[2].wm_min_memg_clk_in_khz = nom_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[2].wm_max_mem_clk_in_khz = nom_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[2].wm_set_id = WM_SET_C;
	clk_ranges.wm_mcif_clocks_ranges[2].wm_min_socclk_clk_in_khz = socclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[2].wm_max_socclk_clk_in_khz = overdrive;
	clk_ranges.wm_mcif_clocks_ranges[2].wm_min_memg_clk_in_khz = nom_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[2].wm_max_mem_clk_in_khz = nom_fclk_khz;

	clk_ranges.wm_dmif_clocks_ranges[3].wm_set_id = WM_SET_D;
	clk_ranges.wm_dmif_clocks_ranges[3].wm_min_dcfclk_clk_in_khz = min_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[3].wm_max_dcfclk_clk_in_khz = max_dcfclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[3].wm_min_memg_clk_in_khz = max_fclk_khz;
	clk_ranges.wm_dmif_clocks_ranges[3].wm_max_mem_clk_in_khz = max_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[3].wm_set_id = WM_SET_D;
	clk_ranges.wm_mcif_clocks_ranges[3].wm_min_socclk_clk_in_khz = socclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[3].wm_max_socclk_clk_in_khz = overdrive;
	clk_ranges.wm_mcif_clocks_ranges[3].wm_min_memg_clk_in_khz = max_fclk_khz;
	clk_ranges.wm_mcif_clocks_ranges[3].wm_max_mem_clk_in_khz = max_fclk_khz;
	ranges.num_reader_wm_sets = WM_COUNT;
	ranges.num_writer_wm_sets = WM_COUNT;
	ranges.reader_wm_sets[0].wm_inst = WM_A;
	ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz;
	ranges.reader_wm_sets[0].max_drain_clk_khz = max_dcfclk_khz;
	ranges.reader_wm_sets[0].min_fill_clk_khz = min_fclk_khz;
	ranges.reader_wm_sets[0].max_fill_clk_khz = min_fclk_khz;
	ranges.writer_wm_sets[0].wm_inst = WM_A;
	ranges.writer_wm_sets[0].min_fill_clk_khz = socclk_khz;
	ranges.writer_wm_sets[0].max_fill_clk_khz = overdrive;
	ranges.writer_wm_sets[0].min_drain_clk_khz = min_fclk_khz;
	ranges.writer_wm_sets[0].max_drain_clk_khz = min_fclk_khz;

	ranges.reader_wm_sets[1].wm_inst = WM_B;
	ranges.reader_wm_sets[1].min_drain_clk_khz = min_fclk_khz;
	ranges.reader_wm_sets[1].max_drain_clk_khz = max_dcfclk_khz;
	ranges.reader_wm_sets[1].min_fill_clk_khz = mid_fclk_khz;
	ranges.reader_wm_sets[1].max_fill_clk_khz = mid_fclk_khz;
	ranges.writer_wm_sets[1].wm_inst = WM_B;
	ranges.writer_wm_sets[1].min_fill_clk_khz = socclk_khz;
	ranges.writer_wm_sets[1].max_fill_clk_khz = overdrive;
	ranges.writer_wm_sets[1].min_drain_clk_khz = mid_fclk_khz;
	ranges.writer_wm_sets[1].max_drain_clk_khz = mid_fclk_khz;


	ranges.reader_wm_sets[2].wm_inst = WM_C;
	ranges.reader_wm_sets[2].min_drain_clk_khz = min_fclk_khz;
	ranges.reader_wm_sets[2].max_drain_clk_khz = max_dcfclk_khz;
	ranges.reader_wm_sets[2].min_fill_clk_khz = nom_fclk_khz;
	ranges.reader_wm_sets[2].max_fill_clk_khz = nom_fclk_khz;
	ranges.writer_wm_sets[2].wm_inst = WM_C;
	ranges.writer_wm_sets[2].min_fill_clk_khz = socclk_khz;
	ranges.writer_wm_sets[2].max_fill_clk_khz = overdrive;
	ranges.writer_wm_sets[2].min_drain_clk_khz = nom_fclk_khz;
	ranges.writer_wm_sets[2].max_drain_clk_khz = nom_fclk_khz;

	ranges.reader_wm_sets[3].wm_inst = WM_D;
	ranges.reader_wm_sets[3].min_drain_clk_khz = min_fclk_khz;
	ranges.reader_wm_sets[3].max_drain_clk_khz = max_dcfclk_khz;
	ranges.reader_wm_sets[3].min_fill_clk_khz = max_fclk_khz;
	ranges.reader_wm_sets[3].max_fill_clk_khz = max_fclk_khz;
	ranges.writer_wm_sets[3].wm_inst = WM_D;
	ranges.writer_wm_sets[3].min_fill_clk_khz = socclk_khz;
	ranges.writer_wm_sets[3].max_fill_clk_khz = overdrive;
	ranges.writer_wm_sets[3].min_drain_clk_khz = max_fclk_khz;
	ranges.writer_wm_sets[3].max_drain_clk_khz = max_fclk_khz;

	/* Notify PP Lib/SMU which Watermarks to use for which clock ranges */
	dm_pp_notify_wm_clock_changes_soc15(dc->ctx, &clk_ranges);
	pp->set_wm_ranges(&pp->pp_smu, &ranges);
}

void dcn_bw_sync_calcs_and_dml(struct dc *dc)
+18 −1
Original line number Diff line number Diff line
@@ -678,6 +678,17 @@ void dcn10_clock_source_destroy(struct clock_source **clk_src)
	*clk_src = NULL;
}

static struct pp_smu_funcs_rv *dcn10_pp_smu_create(struct dc_context *ctx)
{
	struct pp_smu_funcs_rv *pp_smu = dm_alloc(sizeof(*pp_smu));

	if (!pp_smu)
		return pp_smu;

	dm_pp_get_funcs_rv(ctx, pp_smu);
	return pp_smu;
}

static void destruct(struct dcn10_resource_pool *pool)
{
	unsigned int i;
@@ -751,6 +762,8 @@ static void destruct(struct dcn10_resource_pool *pool)

	if (pool->base.display_clock != NULL)
		dce_disp_clk_destroy(&pool->base.display_clock);

	dm_free(pool->base.pp_smu);
}

static struct mem_input *dcn10_mem_input_create(
@@ -1347,11 +1360,15 @@ static bool construct(
		}
	}

	pool->base.pp_smu = dcn10_pp_smu_create(ctx);

	if (!dc->debug.disable_pplib_clock_request)
		dcn_bw_update_from_pplib(dc);
	dcn_bw_sync_calcs_and_dml(dc);
	if (!dc->debug.disable_pplib_wm_range)
	if (!dc->debug.disable_pplib_wm_range) {
		dc->res_pool = &pool->base;
		dcn_bw_notify_pplib_of_wm_ranges(dc);
	}

	{
	#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+131 −0
Original line number Diff line number Diff line
/*
 * Copyright 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: AMD
 *
 */

#ifndef DM_PP_SMU_IF__H
#define DM_PP_SMU_IF__H

/*
 * interface to PPLIB/SMU to setup clocks and pstate requirements on SoC
 */


struct pp_smu {
	struct dc_context *ctx;
};

enum wm_set_id {
	WM_A,
	WM_B,
	WM_C,
	WM_D,
	WM_COUNT,
};

struct pp_smu_wm_set_range {
	enum wm_set_id wm_inst;
	uint32_t min_fill_clk_khz;
	uint32_t max_fill_clk_khz;
	uint32_t min_drain_clk_khz;
	uint32_t max_drain_clk_khz;
};

struct pp_smu_wm_range_sets {
	uint32_t num_reader_wm_sets;
	struct pp_smu_wm_set_range reader_wm_sets[WM_COUNT];

	uint32_t num_writer_wm_sets;
	struct pp_smu_wm_set_range writer_wm_sets[WM_COUNT];
};

struct pp_smu_display_requirement_rv {
	/* PPSMC_MSG_SetDisplayCount: count
	 *  0 triggers S0i2 optimization
	 */
	unsigned int display_count;

	/* PPSMC_MSG_SetHardMinFclkByFreq: khz
	 *  FCLK will vary with DPM, but never below requested hard min
	 */
	unsigned int hard_min_fclk_khz;

	/* PPSMC_MSG_SetHardMinDcefclkByFreq: khz
	 *  fixed clock at requested freq, either from FCH bypass or DFS
	 */
	unsigned int hard_min_dcefclk_khz;

	/* PPSMC_MSG_SetMinDeepSleepDcefclk: mhz
	 *  when DF is in cstate, dcf clock is further divided down
	 *  to just above given frequency
	 */
	unsigned int min_deep_sleep_dcefclk_mhz;
};

struct pp_smu_funcs_rv {
	struct pp_smu pp_smu;

	void (*set_display_requirement)(struct pp_smu *pp,
			struct pp_smu_display_requirement_rv *req);

	/* which SMU message?  are reader and writer WM separate SMU msg? */
	void (*set_wm_ranges)(struct pp_smu *pp,
			struct pp_smu_wm_range_sets *ranges);

};

#if 0
struct pp_smu_funcs_rv {

	/* PPSMC_MSG_SetDisplayCount
	 *  0 triggers S0i2 optimization
	 */
	void (*set_display_count)(struct pp_smu *pp, int count);

	/* PPSMC_MSG_SetHardMinFclkByFreq
	 *  FCLK will vary with DPM, but never below requested hard min
	 */
	void (*set_hard_min_fclk_by_freq)(struct pp_smu *pp, int khz);

	/* PPSMC_MSG_SetHardMinDcefclkByFreq
	 *  fixed clock at requested freq, either from FCH bypass or DFS
	 */
	void (*set_hard_min_dcefclk_by_freq)(struct pp_smu *pp, int khz);

	/* PPSMC_MSG_SetMinDeepSleepDcefclk
	 *  when DF is in cstate, dcf clock is further divided down
	 *  to just above given frequency
	 */
	void (*set_min_deep_sleep_dcefclk)(struct pp_smu *pp, int mhz);

	/* todo: aesthetic
	 * watermark range table
	 */

	/* todo: functional/feature
	 * PPSMC_MSG_SetHardMinSocclkByFreq: required to support DWB
	 */
};
#endif

#endif /* DM_PP_SMU_IF__H */
+2 −3
Original line number Diff line number Diff line
@@ -339,9 +339,8 @@ bool dm_pp_notify_wm_clock_changes(
	const struct dc_context *ctx,
	struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges);

bool dm_pp_notify_wm_clock_changes_soc15(
	const struct dc_context *ctx,
	struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges);
void dm_pp_get_funcs_rv(struct dc_context *ctx,
		struct pp_smu_funcs_rv *funcs);

/* DAL calls this function to notify PP about completion of Mode Set.
 * For PP it means that current DCE clocks are those which were returned
Loading