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

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
......@@ -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;
}
......@@ -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__ */
......@@ -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);
......
......@@ -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.
......
......@@ -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);
......
......@@ -54,7 +54,7 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI
include $(AMD_DC)
DISPLAY_CORE = dc.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \
dc_link_enc_cfg.o
......
......@@ -658,6 +658,9 @@ int dc_link_aux_transfer_raw(struct ddc_service *ddc,
struct aux_payload *payload,
enum aux_return_code_type *operation_result)
{
if (dc_enable_dmub_notifications(ddc->ctx->dc))
return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
else
return dce_aux_transfer_raw(ddc, payload, operation_result);
}
......
......@@ -180,5 +180,5 @@ bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_bu
void dc_dmub_trace_event_control(struct dc *dc, bool enable)
{
dm_helpers_dmub_outbox0_interrupt_control(dc->ctx, enable);
dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable);
}
......@@ -595,6 +595,25 @@ int dce_aux_transfer_raw(struct ddc_service *ddc,
return res;
}
int dce_aux_transfer_dmub_raw(struct ddc_service *ddc,
struct aux_payload *payload,
enum aux_return_code_type *operation_result)
{
struct ddc *ddc_pin = ddc->ddc_pin;
if (ddc_pin != NULL) {
struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
/* XXX: Workaround to configure ddc channels for aux transactions */
if (!acquire(aux_engine, ddc_pin)) {
*operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
return -1;
}
release_engine(aux_engine);
}
return dm_helper_dmub_aux_transfer_sync(ddc->ctx, ddc->link, payload, operation_result);
}
#define AUX_MAX_RETRIES 7
#define AUX_MAX_DEFER_RETRIES 7
#define AUX_MAX_I2C_DEFER_RETRIES 7
......
......@@ -304,6 +304,9 @@ int dce_aux_transfer_raw(struct ddc_service *ddc,
struct aux_payload *cmd,
enum aux_return_code_type *operation_result);
int dce_aux_transfer_dmub_raw(struct ddc_service *ddc,
struct aux_payload *payload,
enum aux_return_code_type *operation_result);
bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
struct aux_payload *cmd);
......
......@@ -34,6 +34,8 @@
#include "dc.h"
struct dp_mst_stream_allocation_table;
struct aux_payload;
enum aux_return_code_type;
/*
* Allocate memory accessible by the GPU
......@@ -158,6 +160,11 @@ void dm_set_dcn_clocks(
struct dc_context *ctx,
struct dc_clocks *clks);
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);
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);
#endif /* __DM_HELPERS__ */
......@@ -58,8 +58,8 @@ enum dc_irq_source to_dal_irq_source_dcn21(
return DC_IRQ_SOURCE_VBLANK5;
case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK6;
case DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT:
return DC_IRQ_SOURCE_DMCUB_OUTBOX0;
case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
return DC_IRQ_SOURCE_DMCUB_OUTBOX;
case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC1_VLINE0;
case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
......@@ -187,7 +187,7 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
.ack = NULL
};
static const struct irq_source_info_funcs dmub_trace_irq_info_funcs = {
static const struct irq_source_info_funcs dmub_outbox_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
......@@ -301,11 +301,11 @@ static const struct irq_source_info_funcs vline0_irq_info_funcs = {
.funcs = &vline0_irq_info_funcs\
}
#define dmub_trace_int_entry()\
[DC_IRQ_SOURCE_DMCUB_OUTBOX0] = {\
IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX0_READY_INT_EN,\
DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX0_READY_INT_ACK),\
.funcs = &dmub_trace_irq_info_funcs\
#define dmub_outbox_int_entry()\
[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX1_READY_INT_ACK),\
.funcs = &dmub_outbox_irq_info_funcs\
}
#define dummy_irq_entry() \
......@@ -426,7 +426,7 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = {
vline0_int_entry(3),
vline0_int_entry(4),
vline0_int_entry(5),
dmub_trace_int_entry(),
dmub_outbox_int_entry(),
};
static const struct irq_service_funcs irq_service_funcs_dcn21 = {
......
......@@ -150,7 +150,7 @@ enum dc_irq_source {
DC_IRQ_SOURCE_DC4_VLINE1,
DC_IRQ_SOURCE_DC5_VLINE1,
DC_IRQ_SOURCE_DC6_VLINE1,
DC_IRQ_DMCUB_OUTBOX1,
DC_IRQ_SOURCE_DMCUB_OUTBOX,
DC_IRQ_SOURCE_DMCUB_OUTBOX0,
DAL_IRQ_SOURCES_NUMBER
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment