diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 193 |
1 files changed, 146 insertions, 47 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index e5efae695559..bdbc577be65c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -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, ¬ify); + } while (notify.pending_notification); + + if (adev->dm.dmub_notify) + memcpy(adev->dm.dmub_notify, ¬ify, 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; + } - 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 @@ -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; +} |