Commit c44120df authored by Ovidiu Bunea's avatar Ovidiu Bunea Committed by Alex Deucher
Browse files

drm/amd/display: Add DMUB IPS command support for IPS residency tools



[why & how]
Add DMUB IPS CMD interface for driver and
DMU to communicate for IPS residency tools.

Reviewed-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: default avatarOvidiu Bunea <Ovidiu.Bunea@amd.com>
Signed-off-by: default avatarFangzhi Zuo <jerry.zuo@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent c233ec19
Loading
Loading
Loading
Loading
+35 −67
Original line number Diff line number Diff line
@@ -1904,85 +1904,53 @@ void dc_dmub_srv_fams2_passthrough_flip(
	}
}

bool dc_dmub_srv_ips_residency_cntl(struct dc_dmub_srv *dc_dmub_srv, bool start_measurement)

bool dc_dmub_srv_ips_residency_cntl(const struct dc_context *ctx, uint8_t panel_inst, bool start_measurement)
{
	bool result;
	union dmub_rb_cmd cmd;

	if (!dc_dmub_srv || !dc_dmub_srv->dmub)
		return false;
	memset(&cmd, 0, sizeof(cmd));

	result = dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__IPS_RESIDENCY,
					   start_measurement, NULL, DM_DMUB_WAIT_TYPE_WAIT);
	cmd.ips_residency_cntl.header.type = DMUB_CMD__IPS;
	cmd.ips_residency_cntl.header.sub_type = DMUB_CMD__IPS_RESIDENCY_CNTL;
	cmd.ips_residency_cntl.header.payload_bytes = sizeof(struct dmub_cmd_ips_residency_cntl_data);

	return result;
	// only panel_inst=0 is supported at the moment
	cmd.ips_residency_cntl.cntl_data.panel_inst = panel_inst;
	cmd.ips_residency_cntl.cntl_data.start_measurement = start_measurement;

	if (!dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		return false;

	return true;
}

void dc_dmub_srv_ips_query_residency_info(struct dc_dmub_srv *dc_dmub_srv, struct ips_residency_info *output)
bool dc_dmub_srv_ips_query_residency_info(const struct dc_context *ctx, uint8_t panel_inst, struct dmub_ips_residency_info *driver_info,
					  enum ips_residency_mode ips_mode)
{
	uint32_t i;
	enum dmub_gpint_command command_code;
	union dmub_rb_cmd cmd;
	uint32_t bytes = sizeof(struct dmub_ips_residency_info);

	if (!dc_dmub_srv || !dc_dmub_srv->dmub)
		return;
	dmub_flush_buffer_mem(&ctx->dmub_srv->dmub->scratch_mem_fb);
	memset(&cmd, 0, sizeof(cmd));

	switch (output->ips_mode) {
	case DMUB_IPS_MODE_IPS1_MAX:
		command_code = DMUB_GPINT__GET_IPS1_HISTOGRAM_COUNTER;
		break;
	case DMUB_IPS_MODE_IPS2:
		command_code = DMUB_GPINT__GET_IPS2_HISTOGRAM_COUNTER;
		break;
	case DMUB_IPS_MODE_IPS1_RCG:
		command_code = DMUB_GPINT__GET_IPS1_RCG_HISTOGRAM_COUNTER;
		break;
	case DMUB_IPS_MODE_IPS1_ONO2_ON:
		command_code = DMUB_GPINT__GET_IPS1_ONO2_ON_HISTOGRAM_COUNTER;
		break;
	default:
		command_code = DMUB_GPINT__INVALID_COMMAND;
		break;
	}
	cmd.ips_query_residency_info.header.type = DMUB_CMD__IPS;
	cmd.ips_query_residency_info.header.sub_type = DMUB_CMD__IPS_QUERY_RESIDENCY_INFO;
	cmd.ips_query_residency_info.header.payload_bytes = sizeof(struct dmub_cmd_ips_query_residency_info_data);

	if (command_code == DMUB_GPINT__INVALID_COMMAND)
		return;
	cmd.ips_query_residency_info.info_data.dest.quad_part = ctx->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
	cmd.ips_query_residency_info.info_data.size = bytes;
	cmd.ips_query_residency_info.info_data.panel_inst = panel_inst;
	cmd.ips_query_residency_info.info_data.ips_mode = (uint32_t)ips_mode;

	for (i = 0; i < GPINT_RETRY_NUM; i++) {
		// false could mean GPINT timeout, in which case we should retry
		if (dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_PERCENT,
					      (uint16_t)(output->ips_mode), &output->residency_percent,
					      DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
			break;
		udelay(100);
	}

	if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_ENTRY_COUNTER,
				      (uint16_t)(output->ips_mode),
				       &output->entry_counter, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		output->entry_counter = 0;

	if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_DURATION_US_LO,
				      (uint16_t)(output->ips_mode),
				       &output->total_active_time_us[0], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		output->total_active_time_us[0] = 0;
	if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_DURATION_US_HI,
				      (uint16_t)(output->ips_mode),
				       &output->total_active_time_us[1], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		output->total_active_time_us[1] = 0;

	if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_INACTIVE_RESIDENCY_DURATION_US_LO,
				      (uint16_t)(output->ips_mode),
				       &output->total_inactive_time_us[0], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		output->total_inactive_time_us[0] = 0;
	if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_INACTIVE_RESIDENCY_DURATION_US_HI,
				      (uint16_t)(output->ips_mode),
				       &output->total_inactive_time_us[1], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		output->total_inactive_time_us[1] = 0;

	// NUM_IPS_HISTOGRAM_BUCKETS = 16
	for (i = 0; i < 16; i++)
		if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, command_code, i, &output->histogram[i],
					       DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
			output->histogram[i] = 0;
	if (!dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) ||
					  cmd.ips_query_residency_info.header.ret_status == 0)
		return false;

	// copy the result to the output since ret_status != 0 means the command returned data
	memcpy(driver_info, ctx->dmub_srv->dmub->scratch_mem_fb.cpu_addr, bytes);

	return true;
}

bool dmub_lsdma_init(struct dc_dmub_srv *dc_dmub_srv)
+27 −39
Original line number Diff line number Diff line
@@ -210,45 +210,6 @@ void dc_dmub_srv_fams2_passthrough_flip(
		struct dc_surface_update *srf_updates,
		int surface_count);

/**
 * struct ips_residency_info - struct containing info from dmub_ips_residency_stats
 *
 * @ips_mode: The mode of IPS that the follow stats appertain to
 * @residency_percent: The percentage of time spent in given IPS mode in millipercent
 * @entry_counter: The number of entries made in to this IPS state
 * @total_active_time_us: uint32_t array of length 2 representing time in the given IPS mode
 *                        in microseconds. Index 0 is lower 32 bits, index 1 is upper 32 bits.
 * @total_inactive_time_us: uint32_t array of length 2 representing time outside the given IPS mode
 *                          in microseconds. Index 0 is lower 32 bits, index 1 is upper 32 bits.
 * @histogram: Histogram of given IPS state durations - bucket definitions in dmub_ips.c
 */
struct ips_residency_info {
	enum dmub_ips_mode ips_mode;
	unsigned int residency_percent;
	unsigned int entry_counter;
	unsigned int total_active_time_us[2];
	unsigned int total_inactive_time_us[2];
	unsigned int histogram[16];
};

/**
 * bool dc_dmub_srv_ips_residency_cntl() - Controls IPS residency measurement status
 *
 * @dc_dmub_srv: The DC DMUB service pointer
 * @start_measurement: Describes whether to start or stop measurement
 *
 * Return: true if GPINT was sent successfully, false otherwise
 */
bool dc_dmub_srv_ips_residency_cntl(struct dc_dmub_srv *dc_dmub_srv, bool start_measurement);

/**
 * bool dc_dmub_srv_ips_query_residency_info() - Queries DMCUB for residency info
 *
 * @dc_dmub_srv: The DC DMUB service pointer
 * @output: Output struct to copy the the residency info to
 */
void dc_dmub_srv_ips_query_residency_info(struct dc_dmub_srv *dc_dmub_srv, struct ips_residency_info *output);

bool dmub_lsdma_init(struct dc_dmub_srv *dc_dmub_srv);
bool dmub_lsdma_send_linear_copy_packet(
	struct dc_dmub_srv *dc_dmub_srv,
@@ -303,4 +264,31 @@ bool dmub_lsdma_send_tiled_to_tiled_copy_command(
	struct lsdma_send_tiled_to_tiled_copy_command_params params);
bool dmub_lsdma_send_poll_reg_write_command(struct dc_dmub_srv *dc_dmub_srv, uint32_t reg_addr, uint32_t reg_data);

/**
 * struct ips_residency_info - struct containing info from dmub_ips_residency_stats
 *
 * @ips_mode: The mode of IPS that the follow stats appertain to
 * @residency_percent: The percentage of time spent in given IPS mode in millipercent
 * @entry_counter: The number of entries made in to this IPS state
 * @total_active_time_us: uint32_t array of length 2 representing time in the given IPS mode
 *                        in microseconds. Index 0 is lower 32 bits, index 1 is upper 32 bits.
 * @total_inactive_time_us: uint32_t array of length 2 representing time outside the given IPS mode
 *                          in microseconds. Index 0 is lower 32 bits, index 1 is upper 32 bits.
 * @histogram: Histogram of given IPS state durations - bucket definitions in dmub_ips.c
 */
struct ips_residency_info {
	enum ips_residency_mode ips_mode;
	unsigned int residency_percent;
	unsigned int entry_counter;
	unsigned int total_active_time_us[2];
	unsigned int total_inactive_time_us[2];
	unsigned int histogram[16];
};

bool dc_dmub_srv_ips_residency_cntl(const struct dc_context *ctx, uint8_t panel_inst, bool start_measurement);

bool dc_dmub_srv_ips_query_residency_info(const struct dc_context *ctx, uint8_t panel_inst,
					  struct dmub_ips_residency_info *driver_info,
					  enum ips_residency_mode ips_mode);

#endif /* _DMUB_DC_SRV_H_ */
+0 −8
Original line number Diff line number Diff line
@@ -607,14 +607,6 @@ struct dmub_notification {
	};
};

/* enum dmub_ips_mode - IPS mode identifier */
enum dmub_ips_mode {
	DMUB_IPS_MODE_IPS1_MAX		= 0,
	DMUB_IPS_MODE_IPS2,
	DMUB_IPS_MODE_IPS1_RCG,
	DMUB_IPS_MODE_IPS1_ONO2_ON
};

/**
 * DMUB firmware version helper macro - useful for checking if the version
 * of a firmware to know if feature or functionality is supported or present.
+70 −0
Original line number Diff line number Diff line
@@ -795,6 +795,17 @@ enum dmub_ips_rcg_disable_type {
#define DMUB_IPS1_COMMIT_MASK 0x00000004
#define DMUB_IPS2_COMMIT_MASK 0x00000008

enum dmub_ips_comand_type {
	/**
	 * Start/stop IPS residency measurements for a given IPS mode
	 */
	DMUB_CMD__IPS_RESIDENCY_CNTL = 0,
	/**
	 * Query IPS residency information for a given IPS mode
	 */
	DMUB_CMD__IPS_QUERY_RESIDENCY_INFO = 1,
};

/**
 * union dmub_fw_boot_options - Boot option definitions for SCRATCH14
 */
@@ -1546,6 +1557,11 @@ enum dmub_cmd_type {
	 */
	DMUB_CMD__LSDMA = 90,

	/**
	 * Command type use for all IPS commands.
	 */
	DMUB_CMD__IPS = 91,

	DMUB_CMD__VBIOS = 128,
};

@@ -5856,6 +5872,56 @@ struct dmub_rb_cmd_assr_enable {
	uint32_t reserved[3];
};

/**
 * Current definition of "ips_mode" from driver
 */
enum ips_residency_mode {
	IPS_RESIDENCY__IPS1_MAX,
	IPS_RESIDENCY__IPS2,
	IPS_RESIDENCY__IPS1_RCG,
	IPS_RESIDENCY__IPS1_ONO2_ON,
};

#define NUM_IPS_HISTOGRAM_BUCKETS 16

/**
 * IPS residency statistics to be sent to driver - subset of struct dmub_ips_residency_stats
 */
struct dmub_ips_residency_info {
	uint32_t residency_millipercent;
	uint32_t entry_counter;
	uint32_t histogram[NUM_IPS_HISTOGRAM_BUCKETS];
	uint64_t total_time_us;
	uint64_t total_inactive_time_us;
};

/**
 * Data passed from driver to FW in a DMUB_CMD__IPS_RESIDENCY_CNTL command.
 */
struct dmub_cmd_ips_residency_cntl_data {
	uint8_t panel_inst;
	uint8_t start_measurement;
	uint8_t padding[2]; // align to 4-byte boundary
};

struct dmub_rb_cmd_ips_residency_cntl {
	struct dmub_cmd_header header;
	struct dmub_cmd_ips_residency_cntl_data cntl_data;
};

struct dmub_cmd_ips_query_residency_info_data {
	union dmub_addr dest;
	uint32_t size;
	uint32_t ips_mode;
	uint8_t panel_inst;
	uint8_t padding[3]; // align to 4-byte boundary
};

struct dmub_rb_cmd_ips_query_residency_info {
	struct dmub_cmd_header header;
	struct dmub_cmd_ips_query_residency_info_data info_data;
};

/**
 * union dmub_rb_cmd - DMUB inbox command.
 */
@@ -6177,6 +6243,10 @@ union dmub_rb_cmd {
	 * Definition of a DMUB_CMD__LSDMA command.
	 */
	struct dmub_rb_cmd_lsdma lsdma;

	struct dmub_rb_cmd_ips_residency_cntl ips_residency_cntl;

	struct dmub_rb_cmd_ips_query_residency_info ips_query_residency_info;
};

/**