diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
14 files changed, 836 insertions, 222 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 73cb88121382..6196de6cebbf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -151,6 +151,9 @@ MODULE_FIRMWARE(FIRMWARE_DCN_35_DMUB); #define FIRMWARE_DCN_351_DMUB "amdgpu/dcn_3_5_1_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_DCN_351_DMUB); +#define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin" +MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB); + /* Number of bytes in PSP header for firmware. */ #define PSP_HEADER_BYTES 0x100 @@ -594,12 +597,14 @@ static void dm_crtc_high_irq(void *interrupt_params) if (!acrtc) return; - if (acrtc->wb_pending) { - if (acrtc->wb_conn) { - spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); + if (acrtc->wb_conn) { + spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); + + if (acrtc->wb_pending) { job = list_first_entry_or_null(&acrtc->wb_conn->job_queue, struct drm_writeback_job, list_entry); + acrtc->wb_pending = false; spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); if (job) { @@ -617,8 +622,7 @@ static void dm_crtc_high_irq(void *interrupt_params) acrtc->dm_irq_params.stream, 0); } } else - DRM_ERROR("%s: no amdgpu_crtc wb_conn\n", __func__); - acrtc->wb_pending = false; + spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); } vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); @@ -1203,6 +1207,9 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) memset(fb_info->fb[DMUB_WINDOW_6_FW_STATE].cpu_addr, 0, fb_info->fb[DMUB_WINDOW_6_FW_STATE].size); + memset(fb_info->fb[DMUB_WINDOW_SHARED_STATE].cpu_addr, 0, + fb_info->fb[DMUB_WINDOW_SHARED_STATE].size); + /* Initialize hardware. */ memset(&hw_params, 0, sizeof(hw_params)); hw_params.fb_base = adev->gmc.fb_start; @@ -1223,6 +1230,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) case IP_VERSION(3, 1, 4): case IP_VERSION(3, 5, 0): case IP_VERSION(3, 5, 1): + case IP_VERSION(4, 0, 1): hw_params.dpia_supported = true; hw_params.disable_dpia = adev->dm.dc->debug.dpia_debug.bits.disable_dpia; break; @@ -1619,6 +1627,117 @@ static void retrieve_dmi_info(struct amdgpu_display_manager *dm) } } +void* +dm_allocate_gpu_mem( + struct amdgpu_device *adev, + enum dc_gpu_mem_alloc_type type, + size_t size, + long long *addr) +{ + struct dal_allocation *da; + u32 domain = (type == DC_MEM_ALLOC_TYPE_GART) ? + AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM; + int ret; + + da = kzalloc(sizeof(struct dal_allocation), GFP_KERNEL); + if (!da) + return NULL; + + ret = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, + domain, &da->bo, + &da->gpu_addr, &da->cpu_ptr); + + *addr = da->gpu_addr; + + if (ret) { + kfree(da); + return NULL; + } + + /* add da to list in dm */ + list_add(&da->list, &adev->dm.da_list); + + return da->cpu_ptr; +} + +static enum dmub_status +dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev, + enum dmub_gpint_command command_code, + uint16_t param, + uint32_t timeout_us) +{ + union dmub_gpint_data_register reg, test; + uint32_t i; + + /* Assume that VBIOS DMUB is ready to take commands */ + + reg.bits.status = 1; + reg.bits.command_code = command_code; + reg.bits.param = param; + + cgs_write_register(adev->dm.cgs_device, 0x34c0 + 0x01f8, reg.all); + + for (i = 0; i < timeout_us; ++i) { + udelay(1); + + /* Check if our GPINT got acked */ + reg.bits.status = 0; + test = (union dmub_gpint_data_register) + cgs_read_register(adev->dm.cgs_device, 0x34c0 + 0x01f8); + + if (test.all == reg.all) + return DMUB_STATUS_OK; + } + + return DMUB_STATUS_TIMEOUT; +} + +static struct dml2_soc_bb *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev) +{ + struct dml2_soc_bb *bb; + long long addr; + int i = 0; + uint16_t chunk; + enum dmub_gpint_command send_addrs[] = { + DMUB_GPINT__SET_BB_ADDR_WORD0, + DMUB_GPINT__SET_BB_ADDR_WORD1, + DMUB_GPINT__SET_BB_ADDR_WORD2, + DMUB_GPINT__SET_BB_ADDR_WORD3, + }; + enum dmub_status ret; + + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(4, 0, 1): + break; + default: + return NULL; + } + + bb = dm_allocate_gpu_mem(adev, + DC_MEM_ALLOC_TYPE_GART, + sizeof(struct dml2_soc_bb), + &addr); + if (!bb) + return NULL; + + for (i = 0; i < 4; i++) { + /* Extract 16-bit chunk */ + chunk = ((uint64_t) addr >> (i * 16)) & 0xFFFF; + /* Send the chunk */ + ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000); + if (ret != DMUB_STATUS_OK) + /* No need to free bb here since it shall be done unconditionally <elsewhere> */ + return NULL; + } + + /* Now ask DMUB to copy the bb */ + ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000); + if (ret != DMUB_STATUS_OK) + return NULL; + + return bb; +} + static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; @@ -1654,13 +1773,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.driver = adev; - adev->dm.cgs_device = amdgpu_cgs_create_device(adev); - - if (!adev->dm.cgs_device) { - DRM_ERROR("amdgpu: failed to create cgs device.\n"); - goto error; - } - + /* cgs_device was created in dm_sw_init() */ init_data.cgs_device = adev->dm.cgs_device; init_data.dce_environment = DCE_ENV_PRODUCTION_DRV; @@ -1736,7 +1849,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_dc_debug_mask & DC_DISABLE_IPS) init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL; else - init_data.flags.disable_ips = DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF; + init_data.flags.disable_ips = DMUB_IPS_ENABLE; init_data.flags.disable_ips_in_vpb = 0; @@ -1744,10 +1857,13 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) init_data.num_virtual_links = 1; - INIT_LIST_HEAD(&adev->dm.da_list); - retrieve_dmi_info(&adev->dm); + if (adev->dm.bb_from_dmub) + init_data.bb_from_dmub = adev->dm.bb_from_dmub; + else + init_data.bb_from_dmub = NULL; + /* Display Core create. */ adev->dm.dc = dc_create(&init_data); @@ -1781,8 +1897,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_dc_debug_mask & DC_FORCE_SUBVP_MCLK_SWITCH) adev->dm.dc->debug.force_subvp_mclk_switch = true; - if (amdgpu_dc_debug_mask & DC_ENABLE_DML2) + if (amdgpu_dc_debug_mask & DC_ENABLE_DML2) { adev->dm.dc->debug.using_dml2 = true; + adev->dm.dc->debug.using_dml21 = true; + } adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm; @@ -1832,6 +1950,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) DRM_ERROR("amdgpu: failed to initialize vblank_workqueue.\n"); } + if (adev->dm.dc->caps.ips_support && adev->dm.dc->config.disable_ips == DMUB_IPS_ENABLE) + adev->dm.idle_workqueue = idle_create_workqueue(adev); + if (adev->dm.dc->caps.max_links > 0 && adev->family >= AMDGPU_FAMILY_RV) { adev->dm.hdcp_workqueue = hdcp_create_workqueue(adev, &init_params.cp_psp, adev->dm.dc); @@ -1929,6 +2050,16 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) adev->dm.vblank_control_workqueue = NULL; } + if (adev->dm.idle_workqueue) { + if (adev->dm.idle_workqueue->running) { + adev->dm.idle_workqueue->enable = false; + flush_work(&adev->dm.idle_workqueue->work); + } + + kfree(adev->dm.idle_workqueue); + adev->dm.idle_workqueue = NULL; + } + amdgpu_dm_destroy_drm_device(&adev->dm); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) @@ -2059,6 +2190,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) case IP_VERSION(3, 2, 1): case IP_VERSION(3, 5, 0): case IP_VERSION(3, 5, 1): + case IP_VERSION(4, 0, 1): return 0; default: break; @@ -2182,6 +2314,10 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) case IP_VERSION(3, 5, 1): dmub_asic = DMUB_ASIC_DCN35; break; + case IP_VERSION(4, 0, 1): + dmub_asic = DMUB_ASIC_DCN401; + break; + default: /* ASIC doesn't support DMUB. */ return 0; @@ -2285,6 +2421,8 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) return -EINVAL; } + adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev); + return 0; } @@ -2293,6 +2431,16 @@ static int dm_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; + adev->dm.cgs_device = amdgpu_cgs_create_device(adev); + + if (!adev->dm.cgs_device) { + DRM_ERROR("amdgpu: failed to create cgs device.\n"); + return -EINVAL; + } + + /* Moved from dm init since we need to use allocations for storing bounding box data */ + INIT_LIST_HEAD(&adev->dm.da_list); + r = dm_dmub_sw_init(adev); if (r) return r; @@ -2304,6 +2452,9 @@ static int dm_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + kfree(adev->dm.bb_from_dmub); + adev->dm.bb_from_dmub = NULL; + kfree(adev->dm.dmub_fb_info); adev->dm.dmub_fb_info = NULL; @@ -2335,13 +2486,13 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) aconnector = to_amdgpu_dm_connector(connector); if (aconnector->dc_link->type == dc_connection_mst_branch && aconnector->mst_mgr.aux) { - DRM_DEBUG_DRIVER("DM_MST: starting TM on aconnector: %p [id: %d]\n", + drm_dbg_kms(dev, "DM_MST: starting TM on aconnector: %p [id: %d]\n", aconnector, aconnector->base.base.id); ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true); if (ret < 0) { - DRM_ERROR("DM_MST: Failed to start MST\n"); + drm_err(dev, "DM_MST: Failed to start MST\n"); aconnector->dc_link->type = dc_connection_single; ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, @@ -2418,7 +2569,6 @@ static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr) ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, DP_MST_EN | - DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); if (ret < 0) { drm_dbg_kms(mgr->dev, "mst write failed - undocked during suspend?\n"); @@ -2567,8 +2717,12 @@ static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev) static int dm_hw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int r; + /* Create DAL display manager */ - amdgpu_dm_init(adev); + r = amdgpu_dm_init(adev); + if (r) + return r; amdgpu_dm_hpd_init(adev); return 0; @@ -2943,6 +3097,7 @@ static int dm_resume(void *handle) commit_params.streams = dc_state->streams; commit_params.stream_count = dc_state->stream_count; + dc_exit_ips_for_hw_access(dm->dc); WARN_ON(!dc_commit_streams(dm->dc, &commit_params)); dm_gpureset_commit_state(dm->cached_dc_state, dm); @@ -3015,6 +3170,7 @@ static int dm_resume(void *handle) emulated_link_detect(aconnector->dc_link); } else { mutex_lock(&dm->dc_lock); + dc_exit_ips_for_hw_access(dm->dc); dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); mutex_unlock(&dm->dc_lock); } @@ -3267,15 +3423,15 @@ void amdgpu_dm_update_connector_after_detect( * We got a DP short pulse (Link Loss, DP CTS, etc...). * Do nothing!! */ - DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: dc_sink didn't change.\n", - aconnector->connector_id); + drm_dbg_kms(dev, "DCHPD: connector_id=%d: dc_sink didn't change.\n", + aconnector->connector_id); if (sink) dc_sink_release(sink); return; } - DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: Old sink=%p New sink=%p\n", - aconnector->connector_id, aconnector->dc_sink, sink); + drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n", + aconnector->connector_id, aconnector->dc_sink, sink); mutex_lock(&dev->mode_config.mutex); @@ -3351,6 +3507,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector) enum dc_connection_type new_connection_type = dc_connection_none; struct amdgpu_device *adev = drm_to_adev(dev); struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); + struct dc *dc = aconnector->dc_link->ctx->dc; bool ret = false; if (adev->dm.disable_hpd_irq) @@ -3385,6 +3542,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector) drm_kms_helper_connector_hotplug_event(connector); } else { mutex_lock(&adev->dm.dc_lock); + dc_exit_ips_for_hw_access(dc); ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); mutex_unlock(&adev->dm.dc_lock); if (ret) { @@ -3444,6 +3602,7 @@ static void handle_hpd_rx_irq(void *param) bool has_left_work = false; int idx = dc_link->link_index; struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx]; + struct dc *dc = aconnector->dc_link->ctx->dc; memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); @@ -3533,6 +3692,7 @@ out: bool ret = false; mutex_lock(&adev->dm.dc_lock); + dc_exit_ips_for_hw_access(dc); ret = dc_link_detect(dc_link, DETECT_REASON_HPDRX); mutex_unlock(&adev->dm.dc_lock); @@ -3561,7 +3721,7 @@ out: mutex_unlock(&aconnector->hpd_lock); } -static void register_hpd_handlers(struct amdgpu_device *adev) +static int register_hpd_handlers(struct amdgpu_device *adev) { struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; @@ -3573,11 +3733,17 @@ static void register_hpd_handlers(struct amdgpu_device *adev) int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; if (dc_is_dmub_outbox_supported(adev->dm.dc)) { - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, dmub_hpd_callback, true)) + if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, + dmub_hpd_callback, true)) { DRM_ERROR("amdgpu: fail to register dmub hpd callback"); + return -EINVAL; + } - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, dmub_hpd_callback, true)) + if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, + dmub_hpd_callback, true)) { DRM_ERROR("amdgpu: fail to register dmub hpd callback"); + return -EINVAL; + } } list_for_each_entry(connector, @@ -3593,9 +3759,16 @@ static void register_hpd_handlers(struct amdgpu_device *adev) int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; int_params.irq_source = dc_link->irq_source_hpd; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - handle_hpd_irq, - (void *) aconnector); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_HPD1 || + int_params.irq_source > DC_IRQ_SOURCE_HPD6) { + DRM_ERROR("Failed to register hpd irq!\n"); + return -EINVAL; + } + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + handle_hpd_irq, (void *) aconnector)) + return -ENOMEM; } if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) { @@ -3604,11 +3777,19 @@ static void register_hpd_handlers(struct amdgpu_device *adev) int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; int_params.irq_source = dc_link->irq_source_hpd_rx; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - handle_hpd_rx_irq, - (void *) aconnector); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_HPD1RX || + int_params.irq_source > DC_IRQ_SOURCE_HPD6RX) { + DRM_ERROR("Failed to register hpd rx irq!\n"); + return -EINVAL; + } + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + handle_hpd_rx_irq, (void *) aconnector)) + return -ENOMEM; } } + return 0; } #if defined(CONFIG_DRM_AMD_DC_SI) @@ -3649,13 +3830,21 @@ static int dce60_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i + 1, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || + int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { + DRM_ERROR("Failed to register vblank irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_crtc_high_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_crtc_high_irq, c_irq_params)) + return -ENOMEM; } /* Use GRPH_PFLIP interrupt */ @@ -3671,14 +3860,21 @@ static int dce60_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || + int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { + DRM_ERROR("Failed to register pflip irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_pflip_high_irq, c_irq_params); - + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_pflip_high_irq, c_irq_params)) + return -ENOMEM; } /* HPD */ @@ -3689,9 +3885,9 @@ static int dce60_register_irq_handlers(struct amdgpu_device *adev) return r; } - register_hpd_handlers(adev); + r = register_hpd_handlers(adev); - return 0; + return r; } #endif @@ -3735,13 +3931,21 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || + int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { + DRM_ERROR("Failed to register vblank irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_crtc_high_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_crtc_high_irq, c_irq_params)) + return -ENOMEM; } /* Use VUPDATE interrupt */ @@ -3756,13 +3960,21 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VUPDATE1 || + int_params.irq_source > DC_IRQ_SOURCE_VUPDATE6) { + DRM_ERROR("Failed to register vupdate irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_vupdate_high_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_vupdate_high_irq, c_irq_params)) + return -ENOMEM; } /* Use GRPH_PFLIP interrupt */ @@ -3778,14 +3990,21 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || + int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { + DRM_ERROR("Failed to register pflip irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_pflip_high_irq, c_irq_params); - + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_pflip_high_irq, c_irq_params)) + return -ENOMEM; } /* HPD */ @@ -3796,9 +4015,9 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) return r; } - register_hpd_handlers(adev); + r = register_hpd_handlers(adev); - return 0; + return r; } /* Register IRQ sources and initialize IRQ callbacks */ @@ -3850,13 +4069,21 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || + int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { + DRM_ERROR("Failed to register vblank irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt( - adev, &int_params, dm_crtc_high_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_crtc_high_irq, c_irq_params)) + return -ENOMEM; } /* Use otg vertical line interrupt */ @@ -3874,9 +4101,11 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0); - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID) { - DRM_ERROR("Failed to register vline0 irq %d!\n", vrtl_int_srcid[i]); - break; + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 || + int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) { + DRM_ERROR("Failed to register vline0 irq!\n"); + return -EINVAL; } c_irq_params = &adev->dm.vline0_params[int_params.irq_source @@ -3885,8 +4114,10 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_dcn_vertical_interrupt0_high_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_dcn_vertical_interrupt0_high_irq, + c_irq_params)) + return -ENOMEM; } #endif @@ -3909,13 +4140,21 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VUPDATE1 || + int_params.irq_source > DC_IRQ_SOURCE_VUPDATE6) { + DRM_ERROR("Failed to register vupdate irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_vupdate_high_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_vupdate_high_irq, c_irq_params)) + return -ENOMEM; } /* Use GRPH_PFLIP interrupt */ @@ -3932,14 +4171,21 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) int_params.irq_source = dc_interrupt_to_irq_source(dc, i, 0); + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || + int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { + DRM_ERROR("Failed to register pflip irq!\n"); + return -EINVAL; + } + c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_pflip_high_irq, c_irq_params); - + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_pflip_high_irq, c_irq_params)) + return -ENOMEM; } /* HPD */ @@ -3950,9 +4196,9 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) return r; } - register_hpd_handlers(adev); + r = register_hpd_handlers(adev); - return 0; + return r; } /* Register Outbox IRQ sources and initialize IRQ callbacks */ static int register_outbox_irq_handlers(struct amdgpu_device *adev) @@ -3983,8 +4229,9 @@ static int register_outbox_irq_handlers(struct amdgpu_device *adev) c_irq_params->adev = adev; c_irq_params->irq_src = int_params.irq_source; - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_dmub_outbox1_low_irq, c_irq_params); + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_dmub_outbox1_low_irq, c_irq_params)) + return -ENOMEM; } return 0; @@ -4119,8 +4366,11 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) } #ifdef AMD_PRIVATE_COLOR - if (amdgpu_dm_create_color_properties(adev)) + if (amdgpu_dm_create_color_properties(adev)) { + dc_state_release(state->context); + kfree(state); return -ENOMEM; + } #endif r = amdgpu_dm_audio_init(adev); @@ -4456,7 +4706,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* There is one primary plane per CRTC */ primary_planes = dm->dc->caps.max_streams; - ASSERT(primary_planes <= AMDGPU_MAX_PLANES); + if (primary_planes > AMDGPU_MAX_PLANES) { + DRM_ERROR("DM: Plane nums out of 6 planes\n"); + return -EINVAL; + } /* * Initialize primary planes, implicit planes for legacy IOCTLS. @@ -4523,6 +4776,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case IP_VERSION(2, 1, 0): case IP_VERSION(3, 5, 0): case IP_VERSION(3, 5, 1): + case IP_VERSION(4, 0, 1): if (register_outbox_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; @@ -4545,6 +4799,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case IP_VERSION(3, 2, 1): case IP_VERSION(3, 5, 0): case IP_VERSION(3, 5, 1): + case IP_VERSION(4, 0, 1): psr_feature_enabled = true; break; default: @@ -4556,32 +4811,35 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* Determine whether to enable Replay support by default. */ if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(3, 1, 4): - case IP_VERSION(3, 1, 5): - case IP_VERSION(3, 1, 6): - case IP_VERSION(3, 2, 0): - case IP_VERSION(3, 2, 1): - case IP_VERSION(3, 5, 0): - case IP_VERSION(3, 5, 1): - replay_feature_enabled = true; - break; +/* + * Disabled by default due to https://gitlab.freedesktop.org/drm/amd/-/issues/3344 + * case IP_VERSION(3, 1, 4): + * case IP_VERSION(3, 1, 5): + * case IP_VERSION(3, 1, 6): + * case IP_VERSION(3, 2, 0): + * case IP_VERSION(3, 2, 1): + * case IP_VERSION(3, 5, 0): + * case IP_VERSION(3, 5, 1): + * replay_feature_enabled = true; + * break; + */ default: replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK; break; } } + if (link_cnt > MAX_LINKS) { + DRM_ERROR( + "KMS: Cannot support more than %d display indexes\n", + MAX_LINKS); + goto fail; + } + /* loops over all connectors on the board */ for (i = 0; i < link_cnt; i++) { struct dc_link *link = NULL; - if (i > AMDGPU_DM_MAX_DISPLAY_INDEX) { - DRM_ERROR( - "KMS: Cannot support more than %d display indexes\n", - AMDGPU_DM_MAX_DISPLAY_INDEX); - continue; - } - link = dc_get_link_at_index(dm->dc, i); if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) { @@ -4636,6 +4894,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) bool ret = false; mutex_lock(&dm->dc_lock); + dc_exit_ips_for_hw_access(dm->dc); ret = dc_link_detect(link, DETECT_REASON_BOOT); mutex_unlock(&dm->dc_lock); @@ -4716,6 +4975,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case IP_VERSION(3, 2, 1): case IP_VERSION(3, 5, 0): case IP_VERSION(3, 5, 1): + case IP_VERSION(4, 0, 1): if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; @@ -4852,6 +5112,9 @@ static int dm_init_microcode(struct amdgpu_device *adev) case IP_VERSION(3, 5, 1): fw_name_dmub = FIRMWARE_DCN_351_DMUB; break; + case IP_VERSION(4, 0, 1): + fw_name_dmub = FIRMWARE_DCN_401_DMUB; + break; default: /* ASIC doesn't support DMUB. */ return 0; @@ -4976,6 +5239,7 @@ static int dm_early_init(void *handle) case IP_VERSION(3, 2, 1): case IP_VERSION(3, 5, 0): case IP_VERSION(3, 5, 1): + case IP_VERSION(4, 0, 1): adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; adev->mode_info.num_dig = 4; @@ -6023,6 +6287,7 @@ static bool is_freesync_video_mode(const struct drm_display_mode *mode, return true; } +#if defined(CONFIG_DRM_AMD_DC_FP) static void update_dsc_caps(struct amdgpu_dm_connector *aconnector, struct dc_sink *sink, struct dc_stream_state *stream, struct dsc_dec_dpcd_caps *dsc_caps) @@ -6041,7 +6306,6 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector, } } - static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector, struct dc_sink *sink, struct dc_stream_state *stream, struct dsc_dec_dpcd_caps *dsc_caps, @@ -6105,7 +6369,6 @@ static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector, } } - static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, struct dc_sink *sink, struct dc_stream_state *stream, struct dsc_dec_dpcd_caps *dsc_caps) @@ -6183,6 +6446,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; } +#endif static struct dc_stream_state * create_stream_for_sink(struct drm_connector *connector, @@ -6204,8 +6468,9 @@ create_stream_for_sink(struct drm_connector *connector, int mode_refresh; int preferred_refresh = 0; enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; +#if defined(CONFIG_DRM_AMD_DC_FP) struct dsc_dec_dpcd_caps dsc_caps; - +#endif struct dc_link *link = NULL; struct dc_sink *sink = NULL; @@ -6321,10 +6586,12 @@ create_stream_for_sink(struct drm_connector *connector, stream->timing = *aconnector->timing_requested; } +#if defined(CONFIG_DRM_AMD_DC_FP) /* SST DSC determination policy */ update_dsc_caps(aconnector, sink, stream, &dsc_caps); if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported) apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); +#endif update_stream_scaling_settings(&mode, dm_state, stream); @@ -6548,12 +6815,34 @@ static const struct attribute_group amdgpu_group = { .attrs = amdgpu_attrs }; +static bool +amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector) +{ + if (amdgpu_dm_abm_level >= 0) + return false; + + if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) + return false; + + /* check for OLED panels */ + if (amdgpu_dm_connector->bl_idx >= 0) { + struct drm_device *drm = amdgpu_dm_connector->base.dev; + struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm; + struct amdgpu_dm_backlight_caps *caps; + + caps = &dm->backlight_caps[amdgpu_dm_connector->bl_idx]; + if (caps->aux_support) + return false; + } + + return true; +} + static void amdgpu_dm_connector_unregister(struct drm_connector *connector) { struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && - amdgpu_dm_abm_level < 0) + if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group); drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux); @@ -6660,8 +6949,7 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector) to_amdgpu_dm_connector(connector); int r; - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && - amdgpu_dm_abm_level < 0) { + if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) { r = sysfs_create_group(&connector->kdev->kobj, &amdgpu_group); if (r) @@ -8343,6 +8631,77 @@ static inline uint32_t get_mem_type(struct drm_framebuffer *fb) return abo->tbo.resource ? abo->tbo.resource->mem_type : 0; } +static void amdgpu_dm_update_cursor(struct drm_plane *plane, + struct drm_plane_state *old_plane_state, + struct dc_stream_update *update) +{ + struct amdgpu_device *adev = drm_to_adev(plane->dev); + struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb); + struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc; + struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL; + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + uint64_t address = afb ? afb->address : 0; + struct dc_cursor_position position = {0}; + struct dc_cursor_attributes attributes; + int ret; + + if (!plane->state->fb && !old_plane_state->fb) + return; + + drm_dbg_atomic(plane->dev, "crtc_id=%d with size %d to %d\n", + amdgpu_crtc->crtc_id, plane->state->crtc_w, + plane->state->crtc_h); + + ret = amdgpu_dm_plane_get_cursor_position(plane, crtc, &position); + if (ret) + return; + + if (!position.enable) { + /* turn off cursor */ + if (crtc_state && crtc_state->stream) { + dc_stream_set_cursor_position(crtc_state->stream, + &position); + update->cursor_position = &crtc_state->stream->cursor_position; + } + return; + } + + amdgpu_crtc->cursor_width = plane->state->crtc_w; + amdgpu_crtc->cursor_height = plane->state->crtc_h; + + memset(&attributes, 0, sizeof(attributes)); + attributes.address.high_part = upper_32_bits(address); + attributes.address.low_part = lower_32_bits(address); + attributes.width = plane->state->crtc_w; + attributes.height = plane->state->crtc_h; + attributes.color_format = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA; + attributes.rotation_angle = 0; + attributes.attribute_flags.value = 0; + + /* Enable cursor degamma ROM on DCN3+ for implicit sRGB degamma in DRM + * legacy gamma setup. + */ + if (crtc_state->cm_is_degamma_srgb && + adev->dm.dc->caps.color.dpp.gamma_corr) + attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1; + + attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; + + if (crtc_state->stream) { + if (!dc_stream_set_cursor_attributes(crtc_state->stream, + &attributes)) + DRM_ERROR("DC failed to set cursor attributes\n"); + + update->cursor_attributes = &crtc_state->stream->cursor_attributes; + + if (!dc_stream_set_cursor_position(crtc_state->stream, + &position)) + DRM_ERROR("DC failed to set cursor position\n"); + + update->cursor_position = &crtc_state->stream->cursor_position; + } +} + static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_device *dev, struct amdgpu_display_manager *dm, @@ -8366,6 +8725,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bool cursor_update = false; bool pflip_present = false; bool dirty_rects_changed = false; + bool updated_planes_and_streams = false; struct { struct dc_surface_update surface_updates[MAX_SURFACES]; struct dc_plane_info plane_infos[MAX_SURFACES]; @@ -8402,8 +8762,11 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, /* Cursor plane is handled after stream updates */ if (plane->type == DRM_PLANE_TYPE_CURSOR) { if ((fb && crtc == pcrtc) || - (old_plane_state->fb && old_plane_state->crtc == pcrtc)) + (old_plane_state->fb && old_plane_state->crtc == pcrtc)) { cursor_update = true; + if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0) + amdgpu_dm_update_cursor(plane, old_plane_state, &bundle->stream_update); + } continue; } @@ -8602,15 +8965,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->stream_update.vrr_infopacket = &acrtc_state->stream->vrr_infopacket; } - } else if (cursor_update && acrtc_state->active_planes > 0 && - acrtc_attach->base.state->event) { - drm_crtc_vblank_get(pcrtc); - + } else if (cursor_update && acrtc_state->active_planes > 0) { spin_lock_irqsave(&pcrtc->dev->event_lock, flags); - - acrtc_attach->event = acrtc_attach->base.state->event; - acrtc_attach->base.state->event = NULL; - + if (acrtc_attach->base.state->event) { + drm_crtc_vblank_get(pcrtc); + acrtc_attach->event = acrtc_attach->base.state->event; + acrtc_attach->base.state->event = NULL; + } spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); } @@ -8676,6 +9037,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, acrtc_state->stream, &bundle->stream_update, bundle->surface_updates); + updated_planes_and_streams = true; /** * Enable or disable the interrupts on the backend. @@ -8753,7 +9115,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, * This avoids redundant programming in the case where we're going * to be disabling a single plane - those pipes are being disabled. */ - if (acrtc_state->active_planes) + if (acrtc_state->active_planes && + (!updated_planes_and_streams || amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0)) amdgpu_dm_commit_cursors(state); cleanup: @@ -8942,7 +9305,8 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, memset(&position, 0, sizeof(position)); mutex_lock(&dm->dc_lock); - dc_stream_set_cursor_position(dm_old_crtc_state->stream, &position); + dc_exit_ips_for_hw_access(dm->dc); + dc_stream_program_cursor_position(dm_old_crtc_state->stream, &position); mutex_unlock(&dm->dc_lock); } @@ -8958,7 +9322,9 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, if (amdgpu_dm_crtc_modeset_required(new_crtc_state, dm_new_crtc_state->stream, dm_old_crtc_state->stream)) { - DRM_DEBUG_ATOMIC("Atomic commit: SET crtc id %d: [%p]\n", acrtc->crtc_id, acrtc); + drm_dbg_atomic(dev, + "Atomic commit: SET crtc id %d: [%p]\n", + acrtc->crtc_id, acrtc); if (!dm_new_crtc_state->stream) { /* @@ -8976,8 +9342,9 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, * have a sink to keep the pipe running so that * hw state is consistent with the sw state */ - DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n", - __func__, acrtc->base.base.id); + drm_dbg_atomic(dev, + "Failed to create new stream for crtc %d\n", + acrtc->base.base.id); continue; } @@ -8991,7 +9358,9 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, crtc->hwmode = new_crtc_state->mode; mode_set_reset_required = true; } else if (modereset_required(new_crtc_state)) { - DRM_DEBUG_ATOMIC("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc); + drm_dbg_atomic(dev, + "Atomic commit: RESET. crtc id %d:[%p]\n", + acrtc->crtc_id, acrtc); /* i.e. reset mode */ if (dm_old_crtc_state->stream) remove_stream(adev, acrtc, dm_old_crtc_state->stream); @@ -9011,6 +9380,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, dm_enable_per_frame_crtc_master_sync(dc_state); mutex_lock(&dm->dc_lock); + dc_exit_ips_for_hw_access(dm->dc); WARN_ON(!dc_commit_streams(dm->dc, ¶ms)); /* Allow idle optimization when vblank count is 0 for display off */ @@ -9166,9 +9536,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) trace_amdgpu_dm_atomic_commit_tail_begin(state); - if (dm->dc->caps.ips_support && dm->dc->idle_optimizations_allowed) - dc_allow_idle_optimizations(dm->dc, false); - drm_atomic_helper_update_legacy_modeset_state(dev, state); drm_dp_mst_atomic_wait_for_dependencies(state); @@ -9379,6 +9746,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) mutex_lock(&dm->dc_lock); + dc_exit_ips_for_hw_access(dm->dc); dc_update_planes_and_stream(dm->dc, dummy_updates, status->plane_count, @@ -9449,7 +9817,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) #endif if (amdgpu_dm_crtc_configure_crc_source( crtc, dm_new_crtc_state, cur_crc_src)) - DRM_DEBUG_DRIVER("Failed to configure crc source"); + drm_dbg_atomic(dev, "Failed to configure crc source"); } } #endif @@ -10621,7 +10989,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = drm_atomic_helper_check_modeset(dev, state); if (ret) { - DRM_DEBUG_DRIVER("drm_atomic_helper_check_modeset() failed\n"); + drm_dbg_atomic(dev, "drm_atomic_helper_check_modeset() failed\n"); goto fail; } @@ -10636,7 +11004,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, new_crtc_state = drm_atomic_get_crtc_state(state, new_con_state->crtc); if (IS_ERR(new_crtc_state)) { - DRM_DEBUG_DRIVER("drm_atomic_get_crtc_state() failed\n"); + drm_dbg_atomic(dev, "drm_atomic_get_crtc_state() failed\n"); ret = PTR_ERR(new_crtc_state); goto fail; } @@ -10651,7 +11019,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { ret = add_affected_mst_dsc_crtcs(state, crtc); if (ret) { - DRM_DEBUG_DRIVER("add_affected_mst_dsc_crtcs() failed\n"); + drm_dbg_atomic(dev, "add_affected_mst_dsc_crtcs() failed\n"); goto fail; } } @@ -10668,7 +11036,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = amdgpu_dm_verify_lut_sizes(new_crtc_state); if (ret) { - DRM_DEBUG_DRIVER("amdgpu_dm_verify_lut_sizes() failed\n"); + drm_dbg_atomic(dev, "amdgpu_dm_verify_lut_sizes() failed\n"); goto fail; } @@ -10677,13 +11045,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) { - DRM_DEBUG_DRIVER("drm_atomic_add_affected_connectors() failed\n"); + drm_dbg_atomic(dev, "drm_atomic_add_affected_connectors() failed\n"); goto fail; } ret = drm_atomic_add_affected_planes(state, crtc); if (ret) { - DRM_DEBUG_DRIVER("drm_atomic_add_affected_planes() failed\n"); + drm_dbg_atomic(dev, "drm_atomic_add_affected_planes() failed\n"); goto fail; } @@ -10722,7 +11090,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (IS_ERR(new_plane_state)) { ret = PTR_ERR(new_plane_state); - DRM_DEBUG_DRIVER("new_plane_state is BAD\n"); + drm_dbg_atomic(dev, "new_plane_state is BAD\n"); goto fail; } } @@ -10754,7 +11122,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, &lock_and_validation_needed, &is_top_most_overlay); if (ret) { - DRM_DEBUG_DRIVER("dm_update_plane_state() failed\n"); + drm_dbg_atomic(dev, "dm_update_plane_state() failed\n"); goto fail; } } @@ -10767,7 +11135,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, false, &lock_and_validation_needed); if (ret) { - DRM_DEBUG_DRIVER("DISABLE: dm_update_crtc_state() failed\n"); + drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed\n"); goto fail; } } @@ -10780,7 +11148,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, true, &lock_and_validation_needed); if (ret) { - DRM_DEBUG_DRIVER("ENABLE: dm_update_crtc_state() failed\n"); + drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed\n"); goto fail; } } @@ -10794,35 +11162,37 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, &lock_and_validation_needed, &is_top_most_overlay); if (ret) { - DRM_DEBUG_DRIVER("dm_update_plane_state() failed\n"); + drm_dbg_atomic(dev, "dm_update_plane_state() failed\n"); goto fail; } } +#if defined(CONFIG_DRM_AMD_DC_FP) if (dc_resource_is_dsc_encoding_supported(dc)) { ret = pre_validate_dsc(state, &dm_state, vars); if (ret != 0) goto fail; } +#endif /* Run this here since we want to validate the streams we created */ ret = drm_atomic_helper_check_planes(dev, state); if (ret) { - DRM_DEBUG_DRIVER("drm_atomic_helper_check_planes() failed\n"); + drm_dbg_atomic(dev, "drm_atomic_helper_check_planes() failed\n"); goto fail; } for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); if (dm_new_crtc_state->mpo_requested) - DRM_DEBUG_DRIVER("MPO enablement requested on crtc:[%p]\n", crtc); + drm_dbg_atomic(dev, "MPO enablement requested on crtc:[%p]\n", crtc); } /* Check cursor planes scaling */ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { ret = dm_check_crtc_cursor(state, crtc, new_crtc_state); if (ret) { - DRM_DEBUG_DRIVER("dm_check_crtc_cursor() failed\n"); + drm_dbg_atomic(dev, "dm_check_crtc_cursor() failed\n"); goto fail; } } @@ -10905,28 +11275,30 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (lock_and_validation_needed) { ret = dm_atomic_get_state(state, &dm_state); if (ret) { - DRM_DEBUG_DRIVER("dm_atomic_get_state() failed\n"); + drm_dbg_atomic(dev, "dm_atomic_get_state() failed\n"); goto fail; } ret = do_aquire_global_lock(dev, state); if (ret) { - DRM_DEBUG_DRIVER("do_aquire_global_lock() failed\n"); + drm_dbg_atomic(dev, "do_aquire_global_lock() failed\n"); goto fail; } +#if defined(CONFIG_DRM_AMD_DC_FP) if (dc_resource_is_dsc_encoding_supported(dc)) { ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); if (ret) { - DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); + drm_dbg_atomic(dev, "compute_mst_dsc_configs_for_state() failed\n"); ret = -EINVAL; goto fail; } } +#endif ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars); if (ret) { - DRM_DEBUG_DRIVER("dm_update_mst_vcpi_slots_for_dsc() failed\n"); + drm_dbg_atomic(dev, "dm_update_mst_vcpi_slots_for_dsc() failed\n"); goto fail; } @@ -10938,12 +11310,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, */ ret = drm_dp_mst_atomic_check(state); if (ret) { - DRM_DEBUG_DRIVER("drm_dp_mst_atomic_check() failed\n"); + drm_dbg_atomic(dev, "drm_dp_mst_atomic_check() failed\n"); goto fail; } status = dc_validate_global_state(dc, dm_state->context, true); if (status != DC_OK) { - DRM_DEBUG_DRIVER("DC global validation failure: %s (%d)", + drm_dbg_atomic(dev, "DC global validation failure: %s (%d)", dc_status_to_str(status), status); ret = -EINVAL; goto fail; @@ -11021,11 +11393,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, fail: if (ret == -EDEADLK) - DRM_DEBUG_DRIVER("Atomic check stopped to avoid deadlock.\n"); + drm_dbg_atomic(dev, "Atomic check stopped to avoid deadlock.\n"); else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS) - DRM_DEBUG_DRIVER("Atomic check stopped due to signal.\n"); + drm_dbg_atomic(dev, "Atomic check stopped due to signal.\n"); else - DRM_DEBUG_DRIVER("Atomic check failed with err: %d\n", ret); + drm_dbg_atomic(dev, "Atomic check failed with err: %d\n", ret); trace_amdgpu_dm_atomic_check_finish(state, ret); @@ -11289,7 +11661,6 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, amdgpu_dm_connector->min_vfreq = 0; amdgpu_dm_connector->max_vfreq = 0; - amdgpu_dm_connector->pixel_clock_mhz = 0; connector->display_info.monitor_range.min_vfreq = 0; connector->display_info.monitor_range.max_vfreq = 0; freesync_capable = false; @@ -11353,8 +11724,6 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, connector->display_info.monitor_range.min_vfreq; amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq; - amdgpu_dm_connector->pixel_clock_mhz = - range->pixel_clock_mhz * 10; break; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 09519b7abf67..94fc4c15d2db 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -137,6 +137,13 @@ struct vblank_control_work { bool enable; }; +struct idle_workqueue { + struct work_struct work; + struct amdgpu_display_manager *dm; + bool enable; + bool running; +}; + /** * struct amdgpu_dm_backlight_caps - Information about backlight * @@ -487,6 +494,7 @@ struct amdgpu_display_manager { * Deferred work for vblank control events. */ struct workqueue_struct *vblank_control_workqueue; + struct idle_workqueue *idle_workqueue; struct drm_atomic_state *cached_state; struct dc_state *cached_dc_state; @@ -570,6 +578,11 @@ struct amdgpu_display_manager { * Guards access to DPIA AUX */ struct mutex dpia_aux_lock; + + /* + * Bounding box data read from dmub during early initialization for DCN4+ + */ + struct dml2_soc_bb *bb_from_dmub; }; enum dsc_clock_force_state { @@ -678,7 +691,6 @@ struct amdgpu_dm_connector { * value is set to zero when there is no FreeSync support. */ int max_vfreq ; - int pixel_clock_mhz; /* Audio instance - protected by audio_lock. */ int audio_inst; @@ -956,4 +968,10 @@ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, struct drm_crtc *crtc); int convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth); +struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev); + +void *dm_allocate_gpu_mem(struct amdgpu_device *adev, + enum dc_gpu_mem_alloc_type type, + size_t size, + long long *addr); #endif /* __AMDGPU_DM_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index e23a0a276e33..83ea0afddda7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -35,6 +35,9 @@ #include "amdgpu_dm_trace.h" #include "amdgpu_dm_debugfs.h" +#define HPD_DETECTION_PERIOD_uS 5000000 +#define HPD_DETECTION_TIME_uS 1000 + void amdgpu_dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc) { struct drm_crtc *crtc = &acrtc->base; @@ -146,11 +149,65 @@ static void amdgpu_dm_crtc_set_panel_sr_feature( struct amdgpu_dm_connector *aconn = (struct amdgpu_dm_connector *) vblank_work->stream->dm_stream_context; - if (!aconn->disallow_edp_enter_psr) + if (!aconn->disallow_edp_enter_psr) { + struct amdgpu_display_manager *dm = vblank_work->dm; + amdgpu_dm_psr_enable(vblank_work->stream); + if (dm->idle_workqueue && + dm->dc->idle_optimizations_allowed && + dm->idle_workqueue->enable && + !dm->idle_workqueue->running) + schedule_work(&dm->idle_workqueue->work); + } } } +static void amdgpu_dm_idle_worker(struct work_struct *work) +{ + struct idle_workqueue *idle_work; + + idle_work = container_of(work, struct idle_workqueue, work); + idle_work->dm->idle_workqueue->running = true; + fsleep(HPD_DETECTION_PERIOD_uS); + mutex_lock(&idle_work->dm->dc_lock); + while (idle_work->enable) { + if (!idle_work->dm->dc->idle_optimizations_allowed) + break; + + dc_allow_idle_optimizations(idle_work->dm->dc, false); + + mutex_unlock(&idle_work->dm->dc_lock); + fsleep(HPD_DETECTION_TIME_uS); + mutex_lock(&idle_work->dm->dc_lock); + + if (!amdgpu_dm_psr_is_active_allowed(idle_work->dm)) + break; + + dc_allow_idle_optimizations(idle_work->dm->dc, true); + mutex_unlock(&idle_work->dm->dc_lock); + fsleep(HPD_DETECTION_PERIOD_uS); + mutex_lock(&idle_work->dm->dc_lock); + } + mutex_unlock(&idle_work->dm->dc_lock); + idle_work->dm->idle_workqueue->running = false; +} + +struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev) +{ + struct idle_workqueue *idle_work; + + idle_work = kzalloc(sizeof(*idle_work), GFP_KERNEL); + if (ZERO_OR_NULL_PTR(idle_work)) + return NULL; + + idle_work->dm = &adev->dm; + idle_work->enable = false; + idle_work->running = false; + INIT_WORK(&idle_work->work, amdgpu_dm_idle_worker); + + return idle_work; +} + static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) { struct vblank_control_work *vblank_work = diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index fdbeef9720c9..27d5c6077630 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -30,6 +30,7 @@ #include "amdgpu.h" #include "amdgpu_dm.h" #include "amdgpu_dm_debugfs.h" +#include "amdgpu_dm_replay.h" #include "dm_helpers.h" #include "dmub/dmub_srv.h" #include "resource.h" @@ -960,6 +961,57 @@ static int dmub_fw_state_show(struct seq_file *m, void *data) return seq_write(m, state_base, state_size); } +/* replay_capability_show() - show eDP panel replay capability + * + * The read function: replay_capability_show + * Shows if sink and driver has Replay capability or not. + * + * cat /sys/kernel/debug/dri/0/eDP-X/replay_capability + * + * Expected output: + * "Sink support: no\n" - if panel doesn't support Replay + * "Sink support: yes\n" - if panel supports Replay + * "Driver support: no\n" - if driver doesn't support Replay + * "Driver support: yes\n" - if driver supports Replay + */ +static int replay_capability_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct dc_link *link = aconnector->dc_link; + bool sink_support_replay = false; + bool driver_support_replay = false; + + if (!link) + return -ENODEV; + + if (link->type == dc_connection_none) + return -ENODEV; + + if (!(link->connector_signal & SIGNAL_TYPE_EDP)) + return -ENODEV; + + /* If Replay is already set to support, skip the checks */ + if (link->replay_settings.config.replay_supported) { + sink_support_replay = true; + driver_support_replay = true; + } else if ((amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { + sink_support_replay = amdgpu_dm_link_supports_replay(link, aconnector); + } else { + struct dc *dc = link->ctx->dc; + + sink_support_replay = amdgpu_dm_link_supports_replay(link, aconnector); + if (dc->ctx->dmub_srv && dc->ctx->dmub_srv->dmub) + driver_support_replay = + (bool)dc->ctx->dmub_srv->dmub->feature_caps.replay_supported; + } + + seq_printf(m, "Sink support: %s\n", str_yes_no(sink_support_replay)); + seq_printf(m, "Driver support: %s\n", str_yes_no(driver_support_replay)); + + return 0; +} + /* psr_capability_show() - show eDP panel PSR capability * * The read function: sink_psr_capability_show @@ -1495,7 +1547,9 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -1596,7 +1650,9 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -1681,7 +1737,9 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -1780,7 +1838,9 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -1865,7 +1925,9 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -1964,7 +2026,9 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2045,7 +2109,9 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2141,7 +2207,9 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2220,7 +2288,9 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2276,7 +2346,9 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2347,7 +2419,9 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2418,7 +2492,9 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && - pipe_ctx->stream->link == aconnector->dc_link) + pipe_ctx->stream->link == aconnector->dc_link && + pipe_ctx->stream->sink && + pipe_ctx->stream->sink == aconnector->dc_sink) break; } @@ -2595,6 +2671,49 @@ unlock: } /* + * IPS status. Read only. + * + * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_ips_status + */ +static int ips_status_show(struct seq_file *m, void *unused) +{ + struct amdgpu_device *adev = m->private; + struct dc *dc = adev->dm.dc; + struct dc_dmub_srv *dc_dmub_srv; + + seq_printf(m, "IPS config: %d\n", dc->config.disable_ips); + seq_printf(m, "Idle optimization: %d\n", dc->idle_optimizations_allowed); + + if (adev->dm.idle_workqueue) { + seq_printf(m, "Idle workqueue - enabled: %d\n", adev->dm.idle_workqueue->enable); + seq_printf(m, "Idle workqueue - running: %d\n", adev->dm.idle_workqueue->running); + } + + dc_dmub_srv = dc->ctx->dmub_srv; + if (dc_dmub_srv && dc_dmub_srv->dmub) { + uint32_t rcg_count, ips1_count, ips2_count; + volatile const struct dmub_shared_state_ips_fw *ips_fw = + &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_FW].data.ips_fw; + rcg_count = ips_fw->rcg_entry_count; + ips1_count = ips_fw->ips1_entry_count; + ips2_count = ips_fw->ips2_entry_count; + seq_printf(m, "entry counts: rcg=%u ips1=%u ips2=%u\n", + rcg_count, + ips1_count, + ips2_count); + rcg_count = ips_fw->rcg_exit_count; + ips1_count = ips_fw->ips1_exit_count; + ips2_count = ips_fw->ips2_exit_count; + seq_printf(m, "exit counts: rcg=%u ips1=%u ips2=%u", + rcg_count, + ips1_count, + ips2_count); + seq_puts(m, "\n"); + } + return 0; +} + +/* * Backlight at this moment. Read only. * As written to display, taking ABM and backlight lut into account. * Ranges from 0x0 to 0x10000 (= 100% PWM) @@ -2744,6 +2863,7 @@ DEFINE_SHOW_ATTRIBUTE(dp_lttpr_status); DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability); DEFINE_SHOW_ATTRIBUTE(internal_display); DEFINE_SHOW_ATTRIBUTE(odm_combine_segments); +DEFINE_SHOW_ATTRIBUTE(replay_capability); DEFINE_SHOW_ATTRIBUTE(psr_capability); DEFINE_SHOW_ATTRIBUTE(dp_is_mst_connector); DEFINE_SHOW_ATTRIBUTE(dp_mst_progress_status); @@ -2914,6 +3034,22 @@ DEFINE_DEBUGFS_ATTRIBUTE(force_yuv420_output_fops, force_yuv420_output_get, force_yuv420_output_set, "%llu\n"); /* + * Read Replay state + */ +static int replay_get_state(void *data, u64 *val) +{ + struct amdgpu_dm_connector *connector = data; + struct dc_link *link = connector->dc_link; + uint64_t state = REPLAY_STATE_INVALID; + + dc_link_get_replay_state(link, &state); + + *val = state; + + return 0; +} + +/* * Read PSR state */ static int psr_get(void *data, u64 *val) @@ -3131,6 +3267,8 @@ static int dmcub_trace_event_state_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(dmcub_trace_event_state_fops, dmcub_trace_event_state_get, dmcub_trace_event_state_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(replay_state_fops, replay_get_state, NULL, "%llu\n"); + DEFINE_DEBUGFS_ATTRIBUTE(psr_fops, psr_get, NULL, "%llu\n"); DEFINE_DEBUGFS_ATTRIBUTE(psr_residency_fops, psr_read_residency, NULL, "%llu\n"); @@ -3145,6 +3283,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(disallow_edp_enter_psr_fops, DEFINE_SHOW_ATTRIBUTE(current_backlight); DEFINE_SHOW_ATTRIBUTE(target_backlight); +DEFINE_SHOW_ATTRIBUTE(ips_status); static const struct { char *name; @@ -3304,6 +3443,9 @@ void connector_debugfs_init(struct amdgpu_dm_connector *connector) } } if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) { + debugfs_create_file("replay_capability", 0444, dir, connector, + &replay_capability_fops); + debugfs_create_file("replay_state", 0444, dir, connector, &replay_state_fops); debugfs_create_file_unsafe("psr_capability", 0444, dir, connector, &psr_capability_fops); debugfs_create_file_unsafe("psr_state", 0444, dir, connector, &psr_fops); debugfs_create_file_unsafe("psr_residency", 0444, dir, @@ -4031,4 +4173,7 @@ void dtn_debugfs_init(struct amdgpu_device *adev) debugfs_create_file_unsafe("amdgpu_dm_disable_hpd", 0644, root, adev, &disable_hpd_ops); + if (adev->dm.dc->caps.ips_support) + debugfs_create_file_unsafe("amdgpu_dm_ips_status", 0644, root, adev, + &ips_status_fops); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index c27063305a13..2648d2b5be3e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -69,6 +69,7 @@ static void apply_edid_quirks(struct edid *edid, struct dc_edid_caps *edid_caps) case drm_edid_encode_panel_id('A', 'U', 'O', 0xE69B): case drm_edid_encode_panel_id('B', 'O', 'E', 0x092A): case drm_edid_encode_panel_id('L', 'G', 'D', 0x06D1): + case drm_edid_encode_panel_id('M', 'S', 'F', 0x1003): DRM_DEBUG_DRIVER("Clearing DPCD 0x317 on monitor with panel id %X\n", panel_id); edid_caps->panel_patch.remove_sink_ext_caps = true; break; @@ -363,7 +364,7 @@ void dm_helpers_dp_mst_send_payload_allocation( mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); - ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); + ret = drm_dp_add_payload_part2(mst_mgr, new_payload); if (ret) { amdgpu_dm_set_mst_status(&aconnector->mst_status, @@ -1044,30 +1045,8 @@ void *dm_helpers_allocate_gpu_mem( long long *addr) { struct amdgpu_device *adev = ctx->driver_context; - struct dal_allocation *da; - u32 domain = (type == DC_MEM_ALLOC_TYPE_GART) ? - AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM; - int ret; - - da = kzalloc(sizeof(struct dal_allocation), GFP_KERNEL); - if (!da) - return NULL; - ret = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, - domain, &da->bo, - &da->gpu_addr, &da->cpu_ptr); - - *addr = da->gpu_addr; - - if (ret) { - kfree(da); - return NULL; - } - - /* add da to list in dm */ - list_add(&da->list, &adev->dm.da_list); - - return da->cpu_ptr; + return dm_allocate_gpu_mem(adev, type, size, addr); } void dm_helpers_free_gpu_mem( @@ -1261,7 +1240,10 @@ void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz) void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable) { - /* TODO: add periodic detection implementation */ + struct amdgpu_device *adev = ctx->driver_context; + + if (adev->dm.idle_workqueue) + adev->dm.idle_workqueue->enable = enable; } void dm_helpers_dp_mst_update_branch_bandwidth( diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 0b03e659fdf3..ac60f688660a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -210,6 +210,7 @@ bool needs_dsc_aux_workaround(struct dc_link *link) return false; } +#if defined(CONFIG_DRM_AMD_DC_FP) static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port) { u8 branch_vendor_data[4] = { 0 }; // Vendor data 0x50C ~ 0x50F @@ -269,6 +270,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto return true; } +#endif static bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector) { @@ -402,9 +404,11 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) amdgpu_dm_update_freesync_caps( connector, aconnector->edid); +#if defined(CONFIG_DRM_AMD_DC_FP) if (!validate_dsc_caps_on_connector(aconnector)) memset(&aconnector->dc_sink->dsc_caps, 0, sizeof(aconnector->dc_sink->dsc_caps)); +#endif if (!retrieve_downstream_port_device(aconnector)) memset(&aconnector->mst_downstream_port_present, @@ -613,6 +617,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, &connector->base, dev->mode_config.tile_property, 0); + connector->colorspace_property = master->base.colorspace_property; + if (connector->colorspace_property) + drm_connector_attach_colorspace_property(connector); drm_connector_set_path_property(connector, pathprop); @@ -791,6 +798,7 @@ struct dsc_mst_fairness_params { struct amdgpu_dm_connector *aconnector; }; +#if defined(CONFIG_DRM_AMD_DC_FP) static int kbps_to_peak_pbn(int kbps) { u64 peak_kbps = kbps; @@ -1204,8 +1212,10 @@ static bool is_dsc_need_re_compute( if (dc_link->type != dc_connection_mst_branch) return false; - if (!(dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT || - dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT)) + /* add a check for older MST DSC with no virtual DPCDs */ + if (needs_dsc_aux_workaround(dc_link) && + (!(dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT || + dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT))) return false; for (i = 0; i < MAX_PIPES; i++) @@ -1225,7 +1235,15 @@ static bool is_dsc_need_re_compute( continue; aconnector = (struct amdgpu_dm_connector *) stream->dm_stream_context; - if (!aconnector) + if (!aconnector || !aconnector->dsc_aux) + continue; + + /* + * check if cached virtual MST DSC caps are available and DSC is supported + * as per specifications in their Virtual DPCD registers. + */ + if (!(aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported || + aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT)) continue; stream_on_link[new_stream_on_link_num] = aconnector; @@ -1581,13 +1599,16 @@ static bool is_dsc_common_config_possible(struct dc_stream_state *stream, return bw_range->max_target_bpp_x16 && bw_range->min_target_bpp_x16; } +#endif enum dc_status dm_dp_mst_is_port_support_mode( struct amdgpu_dm_connector *aconnector, struct dc_stream_state *stream) { - int pbn, branch_max_throughput_mps = 0; + int branch_max_throughput_mps = 0; +#if defined(CONFIG_DRM_AMD_DC_FP) struct dc_link_settings cur_link_settings; + int pbn; unsigned int end_to_end_bw_in_kbps = 0; unsigned int upper_link_bw_in_kbps = 0, down_link_bw_in_kbps = 0; struct dc_dsc_bw_range bw_range = {0}; @@ -1665,7 +1686,6 @@ enum dc_status dm_dp_mst_is_port_support_mode( return DC_FAIL_BANDWIDTH_VALIDATE; } } - /* check is mst dsc output bandwidth branch_overall_throughput_0_mps */ switch (stream->timing.pixel_encoding) { case PIXEL_ENCODING_RGB: @@ -1681,6 +1701,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( default: break; } +#endif if (branch_max_throughput_mps != 0 && ((stream->timing.pix_clk_100hz / 10) > branch_max_throughput_mps * 1000)) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 8a4c40b4c27e..a64f20fcddaa 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -647,6 +647,18 @@ static void amdgpu_dm_plane_add_gfx11_modifiers(struct amdgpu_device *adev, AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D)); } +static void amdgpu_dm_plane_add_gfx12_modifiers(struct amdgpu_device *adev, + uint64_t **mods, uint64_t *size, uint64_t *capacity) +{ + uint64_t mod_64K_2D = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX12) | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX12_64K_2D); + + /* 64K without DCC */ + amdgpu_dm_plane_add_modifier(mods, size, capacity, mod_64K_2D); + amdgpu_dm_plane_add_modifier(mods, size, capacity, DRM_FORMAT_MOD_LINEAR); +} + static int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods) { uint64_t size = 0, capacity = 128; @@ -684,6 +696,9 @@ static int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *adev, unsig case AMDGPU_FAMILY_GC_11_5_0: amdgpu_dm_plane_add_gfx11_modifiers(adev, mods, &size, &capacity); break; + case AMDGPU_FAMILY_GC_12_0_0: + amdgpu_dm_plane_add_gfx12_modifiers(adev, mods, &size, &capacity); + break; } amdgpu_dm_plane_add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR); @@ -1182,8 +1197,8 @@ static int amdgpu_dm_plane_atomic_async_check(struct drm_plane *plane, return 0; } -static int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc, - struct dc_cursor_position *position) +int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc, + struct dc_cursor_position *position) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int x, y; @@ -1254,7 +1269,7 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane, /* turn off cursor */ if (crtc_state && crtc_state->stream) { mutex_lock(&adev->dm.dc_lock); - dc_stream_set_cursor_position(crtc_state->stream, + dc_stream_program_cursor_position(crtc_state->stream, &position); mutex_unlock(&adev->dm.dc_lock); } @@ -1284,11 +1299,11 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane, if (crtc_state->stream) { mutex_lock(&adev->dm.dc_lock); - if (!dc_stream_set_cursor_attributes(crtc_state->stream, + if (!dc_stream_program_cursor_attributes(crtc_state->stream, &attributes)) DRM_ERROR("DC failed to set cursor attributes\n"); - if (!dc_stream_set_cursor_position(crtc_state->stream, + if (!dc_stream_program_cursor_position(crtc_state->stream, &position)) DRM_ERROR("DC failed to set cursor position\n"); mutex_unlock(&adev->dm.dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h index b51a6b57bd9b..6498359bff6f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h @@ -29,6 +29,9 @@ #include "dc.h" +int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc, + struct dc_cursor_position *position); + void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane, struct drm_plane_state *old_plane_state); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index bfa090432ce2..633ab1c16dc6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -223,3 +223,31 @@ bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm) return dc_set_psr_allow_active(dm->dc, false); } +/* + * amdgpu_dm_psr_is_active_allowed() - check if psr is allowed on any stream + * @dm: pointer to amdgpu_display_manager + * + * Return: true if allowed + */ + +bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm) +{ + unsigned int i; + bool allow_active = false; + + for (i = 0; i < dm->dc->current_state->stream_count ; i++) { + struct dc_link *link; + struct dc_stream_state *stream = dm->dc->current_state->streams[i]; + + link = stream->link; + if (!link) + continue; + if (link->psr_settings.psr_feature_enabled && + link->psr_settings.psr_allow_active) { + allow_active = true; + break; + } + } + + return allow_active; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h index 1fdfd183c0d9..cd2d45c2b5ef 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h @@ -36,5 +36,6 @@ void amdgpu_dm_psr_enable(struct dc_stream_state *stream); bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream); bool amdgpu_dm_psr_disable(struct dc_stream_state *stream); bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm); +bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm); #endif /* AMDGPU_DM_AMDGPU_DM_PSR_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index 738a58eebba7..41f07f13a7b5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -24,6 +24,7 @@ */ #include "amdgpu_dm_replay.h" +#include "dc_dmub_srv.h" #include "dc.h" #include "dm_helpers.h" #include "amdgpu_dm.h" @@ -32,12 +33,12 @@ #include "dc/inc/link.h" /* - * link_supports_replay() - check if the link supports replay + * amdgpu_dm_link_supports_replay() - check if the link supports replay * @link: link * @aconnector: aconnector * */ -static bool link_supports_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) +bool amdgpu_dm_link_supports_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) { struct dm_connector_state *state = to_dm_connector_state(aconnector->base.state); struct dpcd_caps *dpcd_caps = &link->dpcd_caps; @@ -78,6 +79,7 @@ bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector { struct replay_config pr_config = { 0 }; union replay_debug_flags *debug_flags = NULL; + struct dc *dc = link->ctx->dc; // If Replay is already set to support, return true to skip checks if (link->replay_settings.config.replay_supported) @@ -89,7 +91,11 @@ bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector if (link->panel_config.psr.disallow_replay) return false; - if (!link_supports_replay(link, aconnector)) + if (!amdgpu_dm_link_supports_replay(link, aconnector)) + return false; + + if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub || + !dc->ctx->dmub_srv->dmub->feature_caps.replay_supported) return false; // Mark Replay is supported in pr_config diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h index f0d30eb47312..8126bdb1eb6b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h @@ -38,7 +38,7 @@ enum replay_enable_option { pr_enable_option_full_screen_video_coasting = 0x40000, }; - +bool amdgpu_dm_link_supports_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector); bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool enable); bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector); bool amdgpu_dm_link_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h index 133af994a08c..4686d4b0cbad 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h @@ -87,7 +87,7 @@ TRACE_EVENT(amdgpu_dc_performance, __entry->writes = write_count; __entry->read_delta = read_count - *last_read; __entry->write_delta = write_count - *last_write; - __assign_str(func, func); + __assign_str(func); __entry->line = line; *last_read = read_count; *last_write = write_count; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 4ae4720535a5..e46f8ce41d87 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -26,16 +26,7 @@ #include "dc_trace.h" -#if defined(CONFIG_X86) -#include <asm/fpu/api.h> -#elif defined(CONFIG_PPC64) -#include <asm/switch_to.h> -#include <asm/cputable.h> -#elif defined(CONFIG_ARM64) -#include <asm/neon.h> -#elif defined(CONFIG_LOONGARCH) -#include <asm/fpu.h> -#endif +#include <linux/fpu.h> /** * DOC: DC FPU manipulation overview @@ -87,20 +78,9 @@ void dc_fpu_begin(const char *function_name, const int line) WARN_ON_ONCE(!in_task()); preempt_disable(); depth = __this_cpu_inc_return(fpu_recursion_depth); - if (depth == 1) { -#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) + BUG_ON(!kernel_fpu_available()); kernel_fpu_begin(); -#elif defined(CONFIG_PPC64) - if (cpu_has_feature(CPU_FTR_VSX_COMP)) - enable_kernel_vsx(); - else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) - enable_kernel_altivec(); - else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) - enable_kernel_fp(); -#elif defined(CONFIG_ARM64) - kernel_neon_begin(); -#endif } TRACE_DCN_FPU(true, function_name, line, depth); @@ -122,18 +102,7 @@ void dc_fpu_end(const char *function_name, const int line) depth = __this_cpu_dec_return(fpu_recursion_depth); if (depth == 0) { -#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) kernel_fpu_end(); -#elif defined(CONFIG_PPC64) - if (cpu_has_feature(CPU_FTR_VSX_COMP)) - disable_kernel_vsx(); - else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) - disable_kernel_altivec(); - else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) - disable_kernel_fp(); -#elif defined(CONFIG_ARM64) - kernel_neon_end(); -#endif } else { WARN_ON_ONCE(depth < 0); } |