Skip to content

Commit

Permalink
drm/amd/display: Support for DMUB AUX
Browse files Browse the repository at this point in the history
[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: Jude Shih <shenshih@amd.com>
Reviewed-by: Hanghong Ma <Hanghong.Ma@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Wayne Lin <Wayne.Lin@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Jude Shih authored and Alex Deucher committed May 10, 2021
1 parent 7f63d8a commit 81927e2
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 65 deletions.
193 changes: 146 additions & 47 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

if (r) {
DRM_ERROR("Failed to add dmub trace irq id!\n");
return r;
}
register_hpd_handlers(adev);

int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
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 outbox irq id!\n");
return r;
}

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);
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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 changes: 11 additions & 0 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -180,6 +183,8 @@ struct amdgpu_display_manager {
*/
struct dmub_srv *dmub_srv;

struct dmub_notification *dmub_notify;

/**
* @dmub_fb_info:
*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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__ */
13 changes: 10 additions & 3 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

Expand Down
Loading

0 comments on commit 81927e2

Please sign in to comment.