Commit 81927e28 authored by Jude Shih's avatar Jude Shih Committed by Alex Deucher
Browse files

drm/amd/display: Support for DMUB AUX



[WHY]
To process AUX transactions with DMUB using inbox1 and outbox1 mail boxes.

[How]
1) Added inbox1 command DMUB_CMD__DP_AUX_ACCESS to issue AUX commands
   to DMUB in dc_process_dmub_aux_transfer_async(). DMUB processes AUX cmd
   with DCN and sends reply back in an outbox1 message triggering an
   outbox1 interrupt to driver.
2) In existing driver implementation, AUX commands are processed
   synchronously by configuring DCN reg. But in DMUB AUX, driver sends an
   inbox1 message and waits for a conditional variable (CV) which will be
   signaled by outbox1 ISR.
3) DM will retrieve Outbox1 message and send back reply to upper layer
   and complete the AUX command

Signed-off-by: default avatarJude Shih <shenshih@amd.com>
Reviewed-by: default avatarHanghong Ma <Hanghong.Ma@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarWayne Lin <Wayne.Lin@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 7f63d8a1
Loading
Loading
Loading
Loading
+146 −47
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include "dc/inc/hw/abm.h"
#include "dc/dc_dmub_srv.h"
#include "dc/dc_edid_parser.h"
#include "dc/dc_stat.h"
#include "amdgpu_dm_trace.h"

#include "vid.h"
@@ -59,6 +60,7 @@

#include "ivsrcid/ivsrcid_vislands30.h"

#include "i2caux_interface.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -620,6 +622,58 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
#endif
#endif

/**
 * dm_dmub_outbox1_low_irq() - Handles Outbox interrupt
 * @interrupt_params: used for determining the Outbox instance
 *
 * Handles the Outbox Interrupt
 * event handler.
 */
#define DMUB_TRACE_MAX_READ 64
static void dm_dmub_outbox1_low_irq(void *interrupt_params)
{
	struct dmub_notification notify;
	struct common_irq_params *irq_params = interrupt_params;
	struct amdgpu_device *adev = irq_params->adev;
	struct amdgpu_display_manager *dm = &adev->dm;
	struct dmcub_trace_buf_entry entry = { 0 };
	uint32_t count = 0;

	if (dc_enable_dmub_notifications(adev->dm.dc)) {
		if (irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) {
			do {
				dc_stat_get_dmub_notification(adev->dm.dc, &notify);
			} while (notify.pending_notification);

			if (adev->dm.dmub_notify)
				memcpy(adev->dm.dmub_notify, &notify, sizeof(struct dmub_notification));
			if (notify.type == DMUB_NOTIFICATION_AUX_REPLY)
				complete(&adev->dm.dmub_aux_transfer_done);
			// TODO : HPD Implementation

		} else {
			DRM_ERROR("DM: Failed to receive correct outbox IRQ !");
		}
	}


	do {
		if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) {
			trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count,
							entry.param0, entry.param1);

			DRM_DEBUG_DRIVER("trace_code:%u, tick_count:%u, param0:%u, param1:%u\n",
				 entry.trace_code, entry.tick_count, entry.param0, entry.param1);
		} else
			break;

		count++;

	} while (count <= DMUB_TRACE_MAX_READ);

	ASSERT(count <= DMUB_TRACE_MAX_READ);
}

static int dm_set_clockgating_state(void *handle,
		  enum amd_clockgating_state state)
{
@@ -938,32 +992,6 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
}

#if defined(CONFIG_DRM_AMD_DC_DCN)
#define DMUB_TRACE_MAX_READ 64
static void dm_dmub_trace_high_irq(void *interrupt_params)
{
	struct common_irq_params *irq_params = interrupt_params;
	struct amdgpu_device *adev = irq_params->adev;
	struct amdgpu_display_manager *dm = &adev->dm;
	struct dmcub_trace_buf_entry entry = { 0 };
	uint32_t count = 0;

	do {
		if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) {
			trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count,
							entry.param0, entry.param1);

			DRM_DEBUG_DRIVER("trace_code:%u, tick_count:%u, param0:%u, param1:%u\n",
				 entry.trace_code, entry.tick_count, entry.param0, entry.param1);
		} else
			break;

		count++;

	} while (count <= DMUB_TRACE_MAX_READ);

	ASSERT(count <= DMUB_TRACE_MAX_READ);
}

static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
{
	uint64_t pt_base;
@@ -1220,6 +1248,16 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
	adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work();
#endif
	if (dc_enable_dmub_notifications(adev->dm.dc)) {
		init_completion(&adev->dm.dmub_aux_transfer_done);
		adev->dm.dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_KERNEL);
		if (!adev->dm.dmub_notify) {
			DRM_INFO("amdgpu: fail to allocate adev->dm.dmub_notify");
			goto error;
		}
		amdgpu_dm_outbox_init(adev);
	}

	if (amdgpu_dm_initialize_drm_device(adev)) {
		DRM_ERROR(
		"amdgpu: failed to initialize sw for display support.\n");
@@ -1293,6 +1331,11 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
		adev->dm.dc->ctx->dmub_srv = NULL;
	}

	if (dc_enable_dmub_notifications(adev->dm.dc)) {
		kfree(adev->dm.dmub_notify);
		adev->dm.dmub_notify = NULL;
	}

	if (adev->dm.dmub_bo)
		amdgpu_bo_free_kernel(&adev->dm.dmub_bo,
				      &adev->dm.dmub_bo_gpu_addr,
@@ -3152,38 +3195,51 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)

	}

	if (dc->ctx->dmub_srv) {
		i = DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT;
		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->dmub_trace_irq);
	/* HPD */
	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
			&adev->hpd_irq);
	if (r) {
		DRM_ERROR("Failed to add hpd irq id!\n");
		return r;
	}

	register_hpd_handlers(adev);

	return 0;
}
/* Register Outbox IRQ sources and initialize IRQ callbacks */
static int register_outbox_irq_handlers(struct amdgpu_device *adev)
{
	struct dc *dc = adev->dm.dc;
	struct common_irq_params *c_irq_params;
	struct dc_interrupt_params int_params = {0};
	int r, i;

	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;

	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT,
			&adev->dmub_outbox_irq);
	if (r) {
			DRM_ERROR("Failed to add dmub trace irq id!\n");
		DRM_ERROR("Failed to add outbox irq id!\n");
		return r;
	}

		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
	if (dc->ctx->dmub_srv) {
		i = DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT;
		int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
		int_params.irq_source =
		dc_interrupt_to_irq_source(dc, i, 0);

		c_irq_params = &adev->dm.dmub_trace_params[0];
		c_irq_params = &adev->dm.dmub_outbox_params[0];

		c_irq_params->adev = adev;
		c_irq_params->irq_src = int_params.irq_source;

		amdgpu_dm_irq_register_interrupt(adev, &int_params,
				dm_dmub_trace_high_irq, c_irq_params);
	}

	/* HPD */
	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
			&adev->hpd_irq);
	if (r) {
		DRM_ERROR("Failed to add hpd irq id!\n");
		return r;
				dm_dmub_outbox1_low_irq, c_irq_params);
	}

	register_hpd_handlers(adev);

	return 0;
}
#endif
@@ -3662,6 +3718,22 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
			goto fail;
		}

	/* Use Outbox interrupt */
	switch (adev->asic_type) {
#if defined(CONFIG_DRM_AMD_DC_DCN3_0)
	case CHIP_SIENNA_CICHLID:
	case CHIP_NAVY_FLOUNDER:
#endif
	case CHIP_RENOIR:
		if (register_outbox_irq_handlers(dm->adev)) {
			DRM_ERROR("DM: Failed to initialize IRQ\n");
			goto fail;
		}
		break;
	default:
		DRM_DEBUG_KMS("Unsupported ASIC type for outbox: 0x%X\n", adev->asic_type);
	}

	/* loops over all connectors on the board */
	for (i = 0; i < link_cnt; i++) {
		struct dc_link *link = NULL;
@@ -10707,3 +10779,30 @@ uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address,

	return value;
}

int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int linkIndex,
				struct aux_payload *payload, enum aux_return_code_type *operation_result)
{
	struct amdgpu_device *adev = ctx->driver_context;
	int ret = 0;

	dc_process_dmub_aux_transfer_async(ctx->dc, linkIndex, payload);
	ret = wait_for_completion_interruptible_timeout(&adev->dm.dmub_aux_transfer_done, 10*HZ);
	if (ret == 0) {
		*operation_result = AUX_RET_ERROR_TIMEOUT;
		return -1;
	}
	*operation_result = (enum aux_return_code_type)adev->dm.dmub_notify->result;

	if (adev->dm.dmub_notify->result == AUX_RET_SUCCESS) {
		(*payload->reply) = adev->dm.dmub_notify->aux_reply.command;

		// For read case, Copy data to payload
		if (!payload->write && adev->dm.dmub_notify->aux_reply.length &&
		(*payload->reply == AUX_TRANSACTION_REPLY_AUX_ACK))
			memcpy(payload->data, adev->dm.dmub_notify->aux_reply.data,
			adev->dm.dmub_notify->aux_reply.length);
	}

	return adev->dm.dmub_notify->aux_reply.length;
}
+11 −0
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@
#include "irq_types.h"
#include "signal_types.h"
#include "amdgpu_dm_crc.h"
struct aux_payload;
enum aux_return_code_type;

/* Forward declarations */
struct amdgpu_device;
@@ -63,6 +65,7 @@ struct dc;
struct amdgpu_bo;
struct dmub_srv;
struct dc_plane_state;
struct dmub_notification;

struct common_irq_params {
	struct amdgpu_device *adev;
@@ -180,6 +183,8 @@ struct amdgpu_display_manager {
	 */
	struct dmub_srv *dmub_srv;

	struct dmub_notification *dmub_notify;

	/**
	 * @dmub_fb_info:
	 *
@@ -351,6 +356,9 @@ struct amdgpu_display_manager {
	struct common_irq_params
	dmub_trace_params[1];

	struct common_irq_params
	dmub_outbox_params[1];

	spinlock_t irq_handler_list_table_lock;

	struct backlight_device *backlight_dev;
@@ -423,6 +431,7 @@ struct amdgpu_display_manager {
	 * DAL fb memory allocation list, for communication with SMU.
	 */
	struct list_head da_list;
	struct completion dmub_aux_transfer_done;
};

enum dsc_clock_force_state {
@@ -605,4 +614,6 @@ void amdgpu_dm_update_connector_after_detect(

extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;

int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int linkIndex,
					struct aux_payload *payload, enum aux_return_code_type *operation_result);
#endif /* __AMDGPU_DM_H__ */
+10 −3
Original line number Diff line number Diff line
@@ -640,7 +640,14 @@ enum dc_edid_status dm_helpers_read_local_edid(

	return edid_status;
}

int dm_helper_dmub_aux_transfer_sync(
		struct dc_context *ctx,
		const struct dc_link *link,
		struct aux_payload *payload,
		enum aux_return_code_type *operation_result)
{
	return amdgpu_dm_process_dmub_aux_transfer_sync(ctx, link->link_index, payload, operation_result);
}
void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks)
{
	/* TODO: something */
@@ -698,12 +705,12 @@ void dm_helpers_free_gpu_mem(
	}
}

bool dm_helpers_dmub_outbox0_interrupt_control(struct dc_context *ctx, bool enable)
bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
{
	enum dc_irq_source irq_source;
	bool ret;

	irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX0;
	irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;

	ret = dc_interrupt_set(ctx->dc, irq_source, enable);

+26 −1
Original line number Diff line number Diff line
@@ -769,6 +769,18 @@ static int amdgpu_dm_set_vline0_irq_state(struct amdgpu_device *adev,
		__func__);
}

static int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *adev,
					struct amdgpu_irq_src *source,
					unsigned int crtc_id,
					enum amdgpu_interrupt_state state)
{
	enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
	bool st = (state == AMDGPU_IRQ_STATE_ENABLE);

	dc_interrupt_set(adev->dm.dc, irq_source, st);
	return 0;
}

static int amdgpu_dm_set_vupdate_irq_state(struct amdgpu_device *adev,
					   struct amdgpu_irq_src *source,
					   unsigned int crtc_id,
@@ -805,6 +817,11 @@ static const struct amdgpu_irq_src_funcs dm_vline0_irq_funcs = {
	.process = amdgpu_dm_irq_handler,
};

static const struct amdgpu_irq_src_funcs dm_dmub_outbox_irq_funcs = {
	.set = amdgpu_dm_set_dmub_outbox_irq_state,
	.process = amdgpu_dm_irq_handler,
};

static const struct amdgpu_irq_src_funcs dm_vupdate_irq_funcs = {
	.set = amdgpu_dm_set_vupdate_irq_state,
	.process = amdgpu_dm_irq_handler,
@@ -827,13 +844,15 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = {

void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
{

	adev->crtc_irq.num_types = adev->mode_info.num_crtc;
	adev->crtc_irq.funcs = &dm_crtc_irq_funcs;

	adev->vline0_irq.num_types = adev->mode_info.num_crtc;
	adev->vline0_irq.funcs = &dm_vline0_irq_funcs;

	adev->dmub_outbox_irq.num_types = 1;
	adev->dmub_outbox_irq.funcs = &dm_dmub_outbox_irq_funcs;

	adev->vupdate_irq.num_types = adev->mode_info.num_crtc;
	adev->vupdate_irq.funcs = &dm_vupdate_irq_funcs;

@@ -846,6 +865,12 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
	adev->hpd_irq.num_types = adev->mode_info.num_hpd;
	adev->hpd_irq.funcs = &dm_hpd_irq_funcs;
}
void amdgpu_dm_outbox_init(struct amdgpu_device *adev)
{
	dc_interrupt_set(adev->dm.dc,
		DC_IRQ_SOURCE_DMCUB_OUTBOX,
		true);
}

/**
 * amdgpu_dm_hpd_init - hpd setup callback.
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,

void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev);

void amdgpu_dm_outbox_init(struct amdgpu_device *adev);
void amdgpu_dm_hpd_init(struct amdgpu_device *adev);
void amdgpu_dm_hpd_fini(struct amdgpu_device *adev);

Loading