Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'drm-fixes-2024-12-06' of https://gitlab.freedesktop.org/drm/kernel

Pull more drm fixes from Simona Vetter:
"Due to mailing list unreliability we missed the amdgpu pull, hence
part two with that now included:

- amdgu: mostly display fixes + jpeg vcn 1.0, sriov, dcn4.0 resume
fixes

- amdkfd fixes"

* tag 'drm-fixes-2024-12-06' of https://gitlab.freedesktop.org/drm/kernel:
drm/amdgpu: rework resume handling for display (v2)
drm/amd/pm: fix and simplify workload handling
Revert "drm/amd/pm: correct the workload setting"
drm/amdgpu: fix sriov reinit late orders
drm/amdgpu: Fix ISP hw init issue
drm/amd/display: Add hblank borrowing support
drm/amd/display: Limit VTotal range to max hw cap minus fp
drm/amd/display: Correct prefetch calculation
drm/amd/display: Add option to retrieve detile buffer size
drm/amd/display: Add a left edge pixel if in YCbCr422 or YCbCr420 and odm
drm/amdkfd: hard-code cacheline for gc943,gc944
drm/amdkfd: add MEC version that supports no PCIe atomics for GFX12
drm/amd/display: Fix programming backlight on OLED panels
drm/amd: Sanity check the ACPI EDID
drm/amdgpu/hdp7.0: do a posting read when flushing HDP
drm/amdgpu/hdp6.0: do a posting read when flushing HDP
drm/amdgpu/hdp5.2: do a posting read when flushing HDP
drm/amdgpu/hdp5.0: do a posting read when flushing HDP
drm/amdgpu/hdp4.0: do a posting read when flushing HDP
drm/amdgpu/jpeg1.0: fix idle work handler

+1062 -646
+64 -26
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
··· 145 145 "LAST", 146 146 }; 147 147 148 - #define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMDGPU_MAX_IP_NUM - 1, 0) 148 + #define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMDGPU_MAX_IP_NUM, 0) 149 149 /* 150 150 * Default init level where all blocks are expected to be initialized. This is 151 151 * the level of initialization expected by default and also after a full reset ··· 3670 3670 continue; 3671 3671 3672 3672 r = block->version->funcs->hw_init(&adev->ip_blocks[i]); 3673 - DRM_INFO("RE-INIT-early: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); 3674 - if (r) 3673 + if (r) { 3674 + dev_err(adev->dev, "RE-INIT-early: %s failed\n", 3675 + block->version->funcs->name); 3675 3676 return r; 3677 + } 3676 3678 block->status.hw = true; 3677 3679 } 3678 3680 } ··· 3684 3682 3685 3683 static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev) 3686 3684 { 3687 - int i, r; 3685 + struct amdgpu_ip_block *block; 3686 + int i, r = 0; 3688 3687 3689 3688 static enum amd_ip_block_type ip_order[] = { 3690 3689 AMD_IP_BLOCK_TYPE_SMC, ··· 3700 3697 }; 3701 3698 3702 3699 for (i = 0; i < ARRAY_SIZE(ip_order); i++) { 3703 - int j; 3704 - struct amdgpu_ip_block *block; 3700 + block = amdgpu_device_ip_get_ip_block(adev, ip_order[i]); 3705 3701 3706 - for (j = 0; j < adev->num_ip_blocks; j++) { 3707 - block = &adev->ip_blocks[j]; 3702 + if (!block) 3703 + continue; 3708 3704 3709 - if (block->version->type != ip_order[i] || 3710 - !block->status.valid || 3711 - block->status.hw) 3712 - continue; 3713 - 3705 + if (block->status.valid && !block->status.hw) { 3714 3706 if (block->version->type == AMD_IP_BLOCK_TYPE_SMC) { 3715 - r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); 3716 - if (r) 3717 - return r; 3707 + r = amdgpu_ip_block_resume(block); 3718 3708 } else { 3719 - r = block->version->funcs->hw_init(&adev->ip_blocks[i]); 3720 - if (r) { 3721 - DRM_ERROR("hw_init of IP block <%s> failed %d\n", 3722 - adev->ip_blocks[i].version->funcs->name, r); 3723 - return r; 3724 - } 3725 - block->status.hw = true; 3709 + r = block->version->funcs->hw_init(block); 3726 3710 } 3711 + 3712 + if (r) { 3713 + dev_err(adev->dev, "RE-INIT-late: %s failed\n", 3714 + block->version->funcs->name); 3715 + break; 3716 + } 3717 + block->status.hw = true; 3727 3718 } 3728 3719 } 3729 3720 3730 - return 0; 3721 + return r; 3731 3722 } 3732 3723 3733 3724 /** ··· 3762 3765 * 3763 3766 * @adev: amdgpu_device pointer 3764 3767 * 3765 - * First resume function for hardware IPs. The list of all the hardware 3768 + * Second resume function for hardware IPs. The list of all the hardware 3766 3769 * IPs that make up the asic is walked and the resume callbacks are run for 3767 3770 * all blocks except COMMON, GMC, and IH. resume puts the hardware into a 3768 3771 * functional state after a suspend and updates the software state as ··· 3780 3783 if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || 3781 3784 adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || 3782 3785 adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH || 3786 + adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE || 3783 3787 adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) 3784 3788 continue; 3785 3789 r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); 3786 3790 if (r) 3787 3791 return r; 3792 + } 3793 + 3794 + return 0; 3795 + } 3796 + 3797 + /** 3798 + * amdgpu_device_ip_resume_phase3 - run resume for hardware IPs 3799 + * 3800 + * @adev: amdgpu_device pointer 3801 + * 3802 + * Third resume function for hardware IPs. The list of all the hardware 3803 + * IPs that make up the asic is walked and the resume callbacks are run for 3804 + * all DCE. resume puts the hardware into a functional state after a suspend 3805 + * and updates the software state as necessary. This function is also used 3806 + * for restoring the GPU after a GPU reset. 3807 + * 3808 + * Returns 0 on success, negative error code on failure. 3809 + */ 3810 + static int amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev) 3811 + { 3812 + int i, r; 3813 + 3814 + for (i = 0; i < adev->num_ip_blocks; i++) { 3815 + if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw) 3816 + continue; 3817 + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) { 3818 + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); 3819 + if (r) 3820 + return r; 3821 + } 3788 3822 } 3789 3823 3790 3824 return 0; ··· 3849 3821 3850 3822 if (adev->mman.buffer_funcs_ring->sched.ready) 3851 3823 amdgpu_ttm_set_buffer_funcs_status(adev, true); 3824 + 3825 + if (r) 3826 + return r; 3827 + 3828 + amdgpu_fence_driver_hw_init(adev); 3829 + 3830 + r = amdgpu_device_ip_resume_phase3(adev); 3852 3831 3853 3832 return r; 3854 3833 } ··· 4937 4902 dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r); 4938 4903 goto exit; 4939 4904 } 4940 - amdgpu_fence_driver_hw_init(adev); 4941 4905 4942 4906 if (!adev->in_s0ix) { 4943 4907 r = amdgpu_amdkfd_resume(adev, adev->in_runpm); ··· 5520 5486 5521 5487 if (tmp_adev->mman.buffer_funcs_ring->sched.ready) 5522 5488 amdgpu_ttm_set_buffer_funcs_status(tmp_adev, true); 5489 + 5490 + r = amdgpu_device_ip_resume_phase3(tmp_adev); 5491 + if (r) 5492 + goto out; 5523 5493 5524 5494 if (vram_lost) 5525 5495 amdgpu_device_fill_reset_magic(tmp_adev);
+8 -4
drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c
··· 40 40 static void hdp_v4_0_flush_hdp(struct amdgpu_device *adev, 41 41 struct amdgpu_ring *ring) 42 42 { 43 - if (!ring || !ring->funcs->emit_wreg) 43 + if (!ring || !ring->funcs->emit_wreg) { 44 44 WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 45 - else 45 + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); 46 + } else { 46 47 amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 48 + } 47 49 } 48 50 49 51 static void hdp_v4_0_invalidate_hdp(struct amdgpu_device *adev, ··· 56 54 amdgpu_ip_version(adev, HDP_HWIP, 0) == IP_VERSION(4, 4, 5)) 57 55 return; 58 56 59 - if (!ring || !ring->funcs->emit_wreg) 57 + if (!ring || !ring->funcs->emit_wreg) { 60 58 WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1); 61 - else 59 + RREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE); 60 + } else { 62 61 amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( 63 62 HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1); 63 + } 64 64 } 65 65 66 66 static void hdp_v4_0_query_ras_error_count(struct amdgpu_device *adev,
+5 -2
drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c
··· 31 31 static void hdp_v5_0_flush_hdp(struct amdgpu_device *adev, 32 32 struct amdgpu_ring *ring) 33 33 { 34 - if (!ring || !ring->funcs->emit_wreg) 34 + if (!ring || !ring->funcs->emit_wreg) { 35 35 WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 36 - else 36 + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); 37 + } else { 37 38 amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 39 + } 38 40 } 39 41 40 42 static void hdp_v5_0_invalidate_hdp(struct amdgpu_device *adev, ··· 44 42 { 45 43 if (!ring || !ring->funcs->emit_wreg) { 46 44 WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1); 45 + RREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE); 47 46 } else { 48 47 amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( 49 48 HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1);
+4 -2
drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c
··· 31 31 static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev, 32 32 struct amdgpu_ring *ring) 33 33 { 34 - if (!ring || !ring->funcs->emit_wreg) 34 + if (!ring || !ring->funcs->emit_wreg) { 35 35 WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 36 36 0); 37 - else 37 + RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); 38 + } else { 38 39 amdgpu_ring_emit_wreg(ring, 39 40 (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 40 41 0); 42 + } 41 43 } 42 44 43 45 static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev,
+4 -2
drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c
··· 34 34 static void hdp_v6_0_flush_hdp(struct amdgpu_device *adev, 35 35 struct amdgpu_ring *ring) 36 36 { 37 - if (!ring || !ring->funcs->emit_wreg) 37 + if (!ring || !ring->funcs->emit_wreg) { 38 38 WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 39 - else 39 + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); 40 + } else { 40 41 amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 42 + } 41 43 } 42 44 43 45 static void hdp_v6_0_update_clock_gating(struct amdgpu_device *adev,
+4 -2
drivers/gpu/drm/amd/amdgpu/hdp_v7_0.c
··· 31 31 static void hdp_v7_0_flush_hdp(struct amdgpu_device *adev, 32 32 struct amdgpu_ring *ring) 33 33 { 34 - if (!ring || !ring->funcs->emit_wreg) 34 + if (!ring || !ring->funcs->emit_wreg) { 35 35 WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 36 - else 36 + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); 37 + } else { 37 38 amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); 39 + } 38 40 } 39 41 40 42 static void hdp_v7_0_update_clock_gating(struct amdgpu_device *adev,
+1 -1
drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c
··· 604 604 static void jpeg_v1_0_ring_begin_use(struct amdgpu_ring *ring) 605 605 { 606 606 struct amdgpu_device *adev = ring->adev; 607 - bool set_clocks = !cancel_delayed_work_sync(&adev->jpeg.idle_work); 607 + bool set_clocks = !cancel_delayed_work_sync(&adev->vcn.idle_work); 608 608 int cnt = 0; 609 609 610 610 mutex_lock(&adev->vcn.vcn1_jpeg1_workaround);
+6
drivers/gpu/drm/amd/amdkfd/kfd_crat.c
··· 1510 1510 if (adev->gfx.config.gc_tcp_size_per_cu) { 1511 1511 pcache_info[i].cache_size = adev->gfx.config.gc_tcp_size_per_cu; 1512 1512 pcache_info[i].cache_level = 1; 1513 + /* Cacheline size not available in IP discovery for gc943,gc944 */ 1514 + pcache_info[i].cache_line_size = 128; 1513 1515 pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | 1514 1516 CRAT_CACHE_FLAGS_DATA_CACHE | 1515 1517 CRAT_CACHE_FLAGS_SIMD_CACHE); ··· 1523 1521 pcache_info[i].cache_size = 1524 1522 adev->gfx.config.gc_l1_instruction_cache_size_per_sqc; 1525 1523 pcache_info[i].cache_level = 1; 1524 + pcache_info[i].cache_line_size = 64; 1526 1525 pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | 1527 1526 CRAT_CACHE_FLAGS_INST_CACHE | 1528 1527 CRAT_CACHE_FLAGS_SIMD_CACHE); ··· 1534 1531 if (adev->gfx.config.gc_l1_data_cache_size_per_sqc) { 1535 1532 pcache_info[i].cache_size = adev->gfx.config.gc_l1_data_cache_size_per_sqc; 1536 1533 pcache_info[i].cache_level = 1; 1534 + pcache_info[i].cache_line_size = 64; 1537 1535 pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | 1538 1536 CRAT_CACHE_FLAGS_DATA_CACHE | 1539 1537 CRAT_CACHE_FLAGS_SIMD_CACHE); ··· 1545 1541 if (adev->gfx.config.gc_tcc_size) { 1546 1542 pcache_info[i].cache_size = adev->gfx.config.gc_tcc_size; 1547 1543 pcache_info[i].cache_level = 2; 1544 + pcache_info[i].cache_line_size = 128; 1548 1545 pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | 1549 1546 CRAT_CACHE_FLAGS_DATA_CACHE | 1550 1547 CRAT_CACHE_FLAGS_SIMD_CACHE); ··· 1556 1551 if (adev->gmc.mall_size) { 1557 1552 pcache_info[i].cache_size = adev->gmc.mall_size / 1024; 1558 1553 pcache_info[i].cache_level = 3; 1554 + pcache_info[i].cache_line_size = 64; 1559 1555 pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | 1560 1556 CRAT_CACHE_FLAGS_DATA_CACHE | 1561 1557 CRAT_CACHE_FLAGS_SIMD_CACHE);
+3
drivers/gpu/drm/amd/amdkfd/kfd_device.c
··· 235 235 */ 236 236 kfd->device_info.needs_pci_atomics = true; 237 237 kfd->device_info.no_atomic_fw_version = kfd->adev->gfx.rs64_enable ? 509 : 0; 238 + } else if (gc_version < IP_VERSION(13, 0, 0)) { 239 + kfd->device_info.needs_pci_atomics = true; 240 + kfd->device_info.no_atomic_fw_version = 2090; 238 241 } else { 239 242 kfd->device_info.needs_pci_atomics = true; 240 243 }
+2
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 3481 3481 caps->aux_support = false; 3482 3482 else if (amdgpu_backlight == 1) 3483 3483 caps->aux_support = true; 3484 + if (caps->aux_support) 3485 + aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; 3484 3486 3485 3487 luminance_range = &conn_base->display_info.luminance_range; 3486 3488
+10 -3
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
··· 907 907 struct drm_connector *connector = data; 908 908 struct acpi_device *acpidev = ACPI_COMPANION(connector->dev->dev); 909 909 unsigned char start = block * EDID_LENGTH; 910 - void *edid; 910 + struct edid *edid; 911 911 int r; 912 912 913 913 if (!acpidev) 914 914 return -ENODEV; 915 915 916 916 /* fetch the entire edid from BIOS */ 917 - r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, &edid); 917 + r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, (void *)&edid); 918 918 if (r < 0) { 919 919 drm_dbg(connector->dev, "Failed to get EDID from ACPI: %d\n", r); 920 920 return r; ··· 924 924 goto cleanup; 925 925 } 926 926 927 - memcpy(buf, edid + start, len); 927 + /* sanity check */ 928 + if (edid->revision < 4 || !(edid->input & DRM_EDID_INPUT_DIGITAL) || 929 + (edid->input & DRM_EDID_DIGITAL_TYPE_MASK) == DRM_EDID_DIGITAL_TYPE_UNDEF) { 930 + r = -EINVAL; 931 + goto cleanup; 932 + } 933 + 934 + memcpy(buf, (void *)edid + start, len); 928 935 r = 0; 929 936 930 937 cleanup:
+18
drivers/gpu/drm/amd/display/dc/core/dc.c
··· 6109 6109 profile.power_level = dc->res_pool->funcs->get_power_profile(context); 6110 6110 return profile; 6111 6111 } 6112 + 6113 + /* 6114 + ********************************************************************************** 6115 + * dc_get_det_buffer_size_from_state() - extracts detile buffer size from dc state 6116 + * 6117 + * Called when DM wants to log detile buffer size from dc_state 6118 + * 6119 + ********************************************************************************** 6120 + */ 6121 + unsigned int dc_get_det_buffer_size_from_state(const struct dc_state *context) 6122 + { 6123 + struct dc *dc = context->clk_mgr->ctx->dc; 6124 + 6125 + if (dc->res_pool->funcs->get_det_buffer_size) 6126 + return dc->res_pool->funcs->get_det_buffer_size(context); 6127 + else 6128 + return 0; 6129 + }
+41 -1
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
··· 2094 2094 count = resource_get_odm_slice_count(otg_master); 2095 2095 h_active = timing->h_addressable + 2096 2096 timing->h_border_left + 2097 - timing->h_border_right; 2097 + timing->h_border_right + 2098 + otg_master->hblank_borrow; 2098 2099 width = h_active / count; 2099 2100 2100 2101 if (otg_master->stream_res.tg) ··· 4028 4027 } 4029 4028 4030 4029 /** 4030 + * decide_hblank_borrow - Decides the horizontal blanking borrow value for a given pipe context. 4031 + * @pipe_ctx: Pointer to the pipe context structure. 4032 + * 4033 + * This function calculates the horizontal blanking borrow value for a given pipe context based on the 4034 + * display stream compression (DSC) configuration. If the horizontal active pixels (hactive) are less 4035 + * than the total width of the DSC slices, it sets the hblank_borrow value to the difference. If the 4036 + * total horizontal timing minus the hblank_borrow value is less than 32, it resets the hblank_borrow 4037 + * value to 0. 4038 + */ 4039 + static void decide_hblank_borrow(struct pipe_ctx *pipe_ctx) 4040 + { 4041 + uint32_t hactive; 4042 + uint32_t ceil_slice_width; 4043 + struct dc_stream_state *stream = NULL; 4044 + 4045 + if (!pipe_ctx) 4046 + return; 4047 + 4048 + stream = pipe_ctx->stream; 4049 + 4050 + if (stream->timing.flags.DSC) { 4051 + hactive = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; 4052 + 4053 + /* Assume if determined slices does not divide Hactive evenly, Hborrow is needed for padding*/ 4054 + if (hactive % stream->timing.dsc_cfg.num_slices_h != 0) { 4055 + ceil_slice_width = (hactive / stream->timing.dsc_cfg.num_slices_h) + 1; 4056 + pipe_ctx->hblank_borrow = ceil_slice_width * stream->timing.dsc_cfg.num_slices_h - hactive; 4057 + 4058 + if (stream->timing.h_total - hactive - pipe_ctx->hblank_borrow < 32) 4059 + pipe_ctx->hblank_borrow = 0; 4060 + } 4061 + } 4062 + } 4063 + 4064 + /** 4031 4065 * dc_validate_global_state() - Determine if hardware can support a given state 4032 4066 * 4033 4067 * @dc: dc struct for this driver ··· 4099 4063 4100 4064 if (pipe_ctx->stream != stream) 4101 4065 continue; 4066 + 4067 + /* Decide whether hblank borrow is needed and save it in pipe_ctx */ 4068 + if (dc->debug.enable_hblank_borrow) 4069 + decide_hblank_borrow(pipe_ctx); 4102 4070 4103 4071 if (dc->res_pool->funcs->patch_unknown_plane_state && 4104 4072 pipe_ctx->plane_state &&
+4
drivers/gpu/drm/amd/display/dc/dc.h
··· 290 290 uint16_t subvp_vertical_int_margin_us; 291 291 bool seamless_odm; 292 292 uint32_t max_v_total; 293 + bool vtotal_limited_by_fp2; 293 294 uint32_t max_disp_clock_khz_at_vmin; 294 295 uint8_t subvp_drr_vblank_start_margin_us; 295 296 bool cursor_not_scaled; ··· 1069 1068 unsigned int scale_to_sharpness_policy; 1070 1069 bool skip_full_updated_if_possible; 1071 1070 unsigned int enable_oled_edp_power_up_opt; 1071 + bool enable_hblank_borrow; 1072 1072 }; 1073 1073 1074 1074 ··· 2551 2549 }; 2552 2550 2553 2551 struct dc_power_profile dc_get_power_profile_for_dc_state(const struct dc_state *context); 2552 + 2553 + unsigned int dc_get_det_buffer_size_from_state(const struct dc_state *context); 2554 2554 2555 2555 /* DSC Interfaces */ 2556 2556 #include "dc_dsc.h"
+1 -1
drivers/gpu/drm/amd/display/dc/dc_spl_translate.c
··· 120 120 spl_in->odm_slice_index = resource_get_odm_slice_index(pipe_ctx); 121 121 // Make spl input basic out info output_size width point to stream h active 122 122 spl_in->basic_out.output_size.width = 123 - stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; 123 + stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + pipe_ctx->hblank_borrow; 124 124 // Make spl input basic out info output_size height point to v active 125 125 spl_in->basic_out.output_size.height = 126 126 stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
+1
drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c
··· 1222 1222 s->dst_y_prefetch_oto = s->Tvm_oto_lines + 2 * s->Tr0_oto_lines + s->Lsw_oto; 1223 1223 1224 1224 s->dst_y_prefetch_equ = p->VStartup - (*p->TSetup + dml_max(p->TWait + p->TCalc, *p->Tdmdl)) / s->LineTime - (*p->DSTYAfterScaler + (dml_float_t) *p->DSTXAfterScaler / (dml_float_t)p->myPipe->HTotal); 1225 + s->dst_y_prefetch_equ = dml_min(s->dst_y_prefetch_equ, 63.75); // limit to the reg limit of U6.2 for DST_Y_PREFETCH 1225 1226 1226 1227 #ifdef __DML_VBA_DEBUG__ 1227 1228 dml_print("DML::%s: HTotal = %u\n", __func__, p->myPipe->HTotal);
+44 -4
drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c
··· 339 339 // } 340 340 } 341 341 342 + static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stream) 343 + { 344 + unsigned int max_hw_v_total = stream->ctx->dc->caps.max_v_total; 345 + 346 + if (stream->ctx->dc->caps.vtotal_limited_by_fp2) { 347 + max_hw_v_total -= stream->timing.v_front_porch + 1; 348 + } 349 + 350 + return max_hw_v_total; 351 + } 352 + 342 353 static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cfg *timing, 343 354 struct dc_stream_state *stream, 344 355 struct dml2_context *dml_ctx) 345 356 { 346 - unsigned int hblank_start, vblank_start; 357 + unsigned int hblank_start, vblank_start, min_hardware_refresh_in_uhz; 347 358 348 359 timing->h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; 349 360 timing->v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; ··· 382 371 - stream->timing.v_border_top - stream->timing.v_border_bottom; 383 372 384 373 timing->drr_config.enabled = stream->ignore_msa_timing_param; 385 - timing->drr_config.min_refresh_uhz = stream->timing.min_refresh_in_uhz; 386 374 timing->drr_config.drr_active_variable = stream->vrr_active_variable; 387 375 timing->drr_config.drr_active_fixed = stream->vrr_active_fixed; 388 376 timing->drr_config.disallowed = !stream->allow_freesync; 377 + 378 + /* limit min refresh rate to DC cap */ 379 + min_hardware_refresh_in_uhz = stream->timing.min_refresh_in_uhz; 380 + if (stream->ctx->dc->caps.max_v_total != 0) { 381 + min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL), 382 + (stream->timing.h_total * (long long)calc_max_hardware_v_total(stream))); 383 + } 384 + 385 + if (stream->timing.min_refresh_in_uhz > min_hardware_refresh_in_uhz) { 386 + timing->drr_config.min_refresh_uhz = stream->timing.min_refresh_in_uhz; 387 + } else { 388 + timing->drr_config.min_refresh_uhz = min_hardware_refresh_in_uhz; 389 + } 389 390 390 391 if (dml_ctx->config.callbacks.get_max_flickerless_instant_vtotal_increase && 391 392 stream->ctx->dc->config.enable_fpo_flicker_detection == 1) ··· 443 420 } 444 421 445 422 timing->vblank_nom = timing->v_total - timing->v_active; 423 + } 424 + 425 + /** 426 + * adjust_dml21_hblank_timing_config_from_pipe_ctx - Adjusts the horizontal blanking timing configuration 427 + * based on the pipe context. 428 + * @timing: Pointer to the dml2_timing_cfg structure to be adjusted. 429 + * @pipe: Pointer to the pipe_ctx structure containing the horizontal blanking borrow value. 430 + * 431 + * This function modifies the horizontal active and blank end timings by adding and subtracting 432 + * the horizontal blanking borrow value from the pipe context, respectively. 433 + */ 434 + static void adjust_dml21_hblank_timing_config_from_pipe_ctx(struct dml2_timing_cfg *timing, struct pipe_ctx *pipe) 435 + { 436 + timing->h_active += pipe->hblank_borrow; 437 + timing->h_blank_end -= pipe->hblank_borrow; 446 438 } 447 439 448 440 static void populate_dml21_output_config_from_stream_state(struct dml2_link_output_cfg *output, ··· 747 709 temp_pipe->plane_state = pipe->plane_state; 748 710 temp_pipe->plane_res.scl_data.taps = pipe->plane_res.scl_data.taps; 749 711 temp_pipe->stream_res = pipe->stream_res; 712 + temp_pipe->hblank_borrow = pipe->hblank_borrow; 750 713 dml_ctx->config.callbacks.build_scaling_params(temp_pipe); 751 714 break; 752 715 } ··· 1012 973 1013 974 ASSERT(disp_cfg_stream_location >= 0 && disp_cfg_stream_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__); 1014 975 populate_dml21_timing_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, context->streams[stream_index], dml_ctx); 976 + adjust_dml21_hblank_timing_config_from_pipe_ctx(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, &context->res_ctx.pipe_ctx[stream_index]); 1015 977 populate_dml21_output_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].output, context->streams[stream_index], &context->res_ctx.pipe_ctx[stream_index]); 1016 978 populate_dml21_stream_overrides_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location], context->streams[stream_index]); 1017 979 ··· 1151 1111 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 1152 1112 union dml2_global_sync_programming *global_sync = &stream_programming->global_sync; 1153 1113 1154 - hactive = timing->h_addressable + timing->h_border_left + timing->h_border_right; 1114 + hactive = timing->h_addressable + timing->h_border_left + timing->h_border_right + pipe_ctx->hblank_borrow; 1155 1115 vactive = timing->v_addressable + timing->v_border_bottom + timing->v_border_top; 1156 1116 hblank_start = pipe_ctx->stream->timing.h_total - pipe_ctx->stream->timing.h_front_porch; 1157 1117 vblank_start = pipe_ctx->stream->timing.v_total - pipe_ctx->stream->timing.v_front_porch; 1158 1118 1159 - hblank_end = hblank_start - timing->h_addressable - timing->h_border_left - timing->h_border_right; 1119 + hblank_end = hblank_start - timing->h_addressable - timing->h_border_left - timing->h_border_right - pipe_ctx->hblank_borrow; 1160 1120 vblank_end = vblank_start - timing->v_addressable - timing->v_border_top - timing->v_border_bottom; 1161 1121 1162 1122 if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
+2 -1
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
··· 1049 1049 } 1050 1050 1051 1051 /* Enable DSC hw block */ 1052 - dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; 1052 + dsc_cfg.pic_width = (stream->timing.h_addressable + pipe_ctx->hblank_borrow + 1053 + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; 1053 1054 dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; 1054 1055 dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; 1055 1056 dsc_cfg.color_depth = stream->timing.display_color_depth;
+6 -1
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
··· 820 820 int opp_cnt = 1; 821 821 int opp_inst[MAX_PIPES] = {0}; 822 822 struct pipe_ctx *opp_heads[MAX_PIPES] = {0}; 823 + struct dc_crtc_timing patched_crtc_timing = stream->timing; 823 824 bool manual_mode; 824 825 unsigned int tmds_div = PIXEL_RATE_DIV_NA; 825 826 unsigned int unused_div = PIXEL_RATE_DIV_NA; ··· 875 874 if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal))) 876 875 dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx); 877 876 877 + /* if we are borrowing from hblank, h_addressable needs to be adjusted */ 878 + if (dc->debug.enable_hblank_borrow) 879 + patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->hblank_borrow; 880 + 878 881 pipe_ctx->stream_res.tg->funcs->program_timing( 879 882 pipe_ctx->stream_res.tg, 880 - &stream->timing, 883 + &patched_crtc_timing, 881 884 pipe_ctx->pipe_dlg_param.vready_offset, 882 885 pipe_ctx->pipe_dlg_param.vstartup_start, 883 886 pipe_ctx->pipe_dlg_param.vupdate_offset,
+3
drivers/gpu/drm/amd/display/dc/inc/core_types.h
··· 219 219 * Get indicator of power from a context that went through full validation 220 220 */ 221 221 int (*get_power_profile)(const struct dc_state *context); 222 + unsigned int (*get_det_buffer_size)(const struct dc_state *context); 222 223 }; 223 224 224 225 struct audio_support{ ··· 478 477 /* subvp_index: only valid if the pipe is a SUBVP_MAIN*/ 479 478 uint8_t subvp_index; 480 479 struct pixel_rate_divider pixel_rate_divider; 480 + /* pixels borrowed from hblank to hactive */ 481 + uint8_t hblank_borrow; 481 482 }; 482 483 483 484 /* Data used for dynamic link encoder assignment.
+23
drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
··· 1510 1510 1511 1511 if (prev_odm_pipe->plane_state) { 1512 1512 struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data; 1513 + struct output_pixel_processor *opp = next_odm_pipe->stream_res.opp; 1513 1514 int new_width; 1514 1515 1515 1516 /* HACTIVE halved for odm combine */ ··· 1544 1543 sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( 1545 1544 sd->ratios.horz_c, sd->h_active - sd->recout.x)); 1546 1545 sd->recout.x = 0; 1546 + 1547 + /* 1548 + * When odm is used in YcbCr422 or 420 colour space, a split screen 1549 + * will be seen with the previous calculations since the extra left 1550 + * edge pixel is accounted for in fmt but not in viewport. 1551 + * 1552 + * Below are calculations which fix the split by fixing the calculations 1553 + * if there is an extra left edge pixel. 1554 + */ 1555 + if (opp && opp->funcs->opp_get_left_edge_extra_pixel_count 1556 + && opp->funcs->opp_get_left_edge_extra_pixel_count( 1557 + opp, next_odm_pipe->stream->timing.pixel_encoding, 1558 + resource_is_pipe_type(next_odm_pipe, OTG_MASTER)) == 1) { 1559 + sd->h_active += 1; 1560 + sd->recout.width += 1; 1561 + sd->viewport.x -= dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); 1562 + sd->viewport_c.x -= dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); 1563 + sd->viewport_c.width += dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); 1564 + sd->viewport.width += dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); 1565 + } 1547 1566 } 1567 + 1548 1568 if (!next_odm_pipe->top_pipe) 1549 1569 next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; 1550 1570 else ··· 2154 2132 ASSERT(0); 2155 2133 } 2156 2134 } 2135 + 2157 2136 /* Actual dsc count per stream dsc validation*/ 2158 2137 if (!dcn20_validate_dsc(dc, context)) { 2159 2138 context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] =
+1
drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
··· 2353 2353 2354 2354 dc->caps.dp_hdmi21_pcon_support = true; 2355 2355 dc->caps.max_v_total = (1 << 15) - 1; 2356 + dc->caps.vtotal_limited_by_fp2 = true; 2356 2357 2357 2358 /* read VBIOS LTTPR caps */ 2358 2359 {
+1
drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c
··· 1233 1233 dc->caps.extended_aux_timeout_support = true; 1234 1234 dc->caps.dmcub_support = true; 1235 1235 dc->caps.max_v_total = (1 << 15) - 1; 1236 + dc->caps.vtotal_limited_by_fp2 = true; 1236 1237 1237 1238 /* Color pipeline capabilities */ 1238 1239 dc->caps.color.dpp.dcn_arch = 1;
+1
drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c
··· 1178 1178 dc->caps.extended_aux_timeout_support = true; 1179 1179 dc->caps.dmcub_support = true; 1180 1180 dc->caps.max_v_total = (1 << 15) - 1; 1181 + dc->caps.vtotal_limited_by_fp2 = true; 1181 1182 1182 1183 /* Color pipeline capabilities */ 1183 1184 dc->caps.color.dpp.dcn_arch = 1;
+7
drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
··· 1720 1720 return pipe_cnt; 1721 1721 } 1722 1722 1723 + unsigned int dcn31_get_det_buffer_size( 1724 + const struct dc_state *context) 1725 + { 1726 + return context->bw_ctx.dml.ip.det_buffer_size_kbytes; 1727 + } 1728 + 1723 1729 void dcn31_calculate_wm_and_dlg( 1724 1730 struct dc *dc, struct dc_state *context, 1725 1731 display_e2e_pipe_params_st *pipes, ··· 1848 1842 .update_bw_bounding_box = dcn31_update_bw_bounding_box, 1849 1843 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, 1850 1844 .get_panel_config_defaults = dcn31_get_panel_config_defaults, 1845 + .get_det_buffer_size = dcn31_get_det_buffer_size, 1851 1846 }; 1852 1847 1853 1848 static struct clock_source *dcn30_clock_source_create(
+3
drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h
··· 63 63 const struct dc_init_data *init_data, 64 64 struct dc *dc); 65 65 66 + unsigned int dcn31_get_det_buffer_size( 67 + const struct dc_state *context); 68 + 66 69 /*temp: B0 specific before switch to dcn313 headers*/ 67 70 #ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL 68 71 #define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e
+1
drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
··· 1777 1777 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, 1778 1778 .get_panel_config_defaults = dcn314_get_panel_config_defaults, 1779 1779 .get_preferred_eng_id_dpia = dcn314_get_preferred_eng_id_dpia, 1780 + .get_det_buffer_size = dcn31_get_det_buffer_size, 1780 1781 }; 1781 1782 1782 1783 static struct clock_source *dcn30_clock_source_create(
+1
drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
··· 1845 1845 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, 1846 1846 .get_panel_config_defaults = dcn315_get_panel_config_defaults, 1847 1847 .get_power_profile = dcn315_get_power_profile, 1848 + .get_det_buffer_size = dcn31_get_det_buffer_size, 1848 1849 }; 1849 1850 1850 1851 static bool dcn315_resource_construct(
+1
drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
··· 1719 1719 .update_bw_bounding_box = dcn316_update_bw_bounding_box, 1720 1720 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, 1721 1721 .get_panel_config_defaults = dcn316_get_panel_config_defaults, 1722 + .get_det_buffer_size = dcn31_get_det_buffer_size, 1722 1723 }; 1723 1724 1724 1725 static bool dcn316_resource_construct(
+2
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
··· 2189 2189 dc->caps.dmcub_support = true; 2190 2190 dc->caps.seamless_odm = true; 2191 2191 dc->caps.max_v_total = (1 << 15) - 1; 2192 + dc->caps.vtotal_limited_by_fp2 = true; 2192 2193 2193 2194 /* Color pipeline capabilities */ 2194 2195 dc->caps.color.dpp.dcn_arch = 1; ··· 2804 2803 free_pipe->plane_res.xfm = pool->transforms[free_pipe_idx]; 2805 2804 free_pipe->plane_res.dpp = pool->dpps[free_pipe_idx]; 2806 2805 free_pipe->plane_res.mpcc_inst = pool->dpps[free_pipe_idx]->inst; 2806 + free_pipe->hblank_borrow = otg_master->hblank_borrow; 2807 2807 if (free_pipe->stream->timing.flags.DSC == 1) { 2808 2808 dcn20_acquire_dsc(free_pipe->stream->ctx->dc, 2809 2809 &new_ctx->res_ctx,
+1
drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
··· 1742 1742 dc->caps.extended_aux_timeout_support = true; 1743 1743 dc->caps.dmcub_support = true; 1744 1744 dc->caps.max_v_total = (1 << 15) - 1; 1745 + dc->caps.vtotal_limited_by_fp2 = true; 1745 1746 1746 1747 /* Color pipeline capabilities */ 1747 1748 dc->caps.color.dpp.dcn_arch = 1;
+2
drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
··· 1778 1778 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, 1779 1779 .get_panel_config_defaults = dcn35_get_panel_config_defaults, 1780 1780 .get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia, 1781 + .get_det_buffer_size = dcn31_get_det_buffer_size, 1781 1782 }; 1782 1783 1783 1784 static bool dcn35_resource_construct( ··· 1850 1849 dc->caps.zstate_support = true; 1851 1850 dc->caps.ips_support = true; 1852 1851 dc->caps.max_v_total = (1 << 15) - 1; 1852 + dc->caps.vtotal_limited_by_fp2 = true; 1853 1853 1854 1854 /* Color pipeline capabilities */ 1855 1855 dc->caps.color.dpp.dcn_arch = 1;
+2
drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
··· 1757 1757 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, 1758 1758 .get_panel_config_defaults = dcn35_get_panel_config_defaults, 1759 1759 .get_preferred_eng_id_dpia = dcn351_get_preferred_eng_id_dpia, 1760 + .get_det_buffer_size = dcn31_get_det_buffer_size, 1760 1761 }; 1761 1762 1762 1763 static bool dcn351_resource_construct( ··· 1829 1828 dc->caps.zstate_support = true; 1830 1829 dc->caps.ips_support = true; 1831 1830 dc->caps.max_v_total = (1 << 15) - 1; 1831 + dc->caps.vtotal_limited_by_fp2 = true; 1832 1832 1833 1833 /* Color pipeline capabilities */ 1834 1834 dc->caps.color.dpp.dcn_arch = 1;
+1
drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
··· 1864 1864 dc->caps.extended_aux_timeout_support = true; 1865 1865 dc->caps.dmcub_support = true; 1866 1866 dc->caps.max_v_total = (1 << 15) - 1; 1867 + dc->caps.vtotal_limited_by_fp2 = true; 1867 1868 1868 1869 if (ASICREV_IS_GC_12_0_1_A0(dc->ctx->asic_id.hw_internal_rev)) 1869 1870 dc->caps.dcc_plane_width_limit = 7680;
+12 -1
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
··· 122 122 return duration_in_us; 123 123 } 124 124 125 + static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stream) 126 + { 127 + unsigned int max_hw_v_total = stream->ctx->dc->caps.max_v_total; 128 + 129 + if (stream->ctx->dc->caps.vtotal_limited_by_fp2) { 130 + max_hw_v_total -= stream->timing.v_front_porch + 1; 131 + } 132 + 133 + return max_hw_v_total; 134 + } 135 + 125 136 unsigned int mod_freesync_calc_v_total_from_refresh( 126 137 const struct dc_stream_state *stream, 127 138 unsigned int refresh_in_uhz) ··· 1027 1016 1028 1017 if (stream->ctx->dc->caps.max_v_total != 0 && stream->timing.h_total != 0) { 1029 1018 min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL), 1030 - (stream->timing.h_total * (long long)stream->ctx->dc->caps.max_v_total)); 1019 + (stream->timing.h_total * (long long)calc_max_hardware_v_total(stream))); 1031 1020 } 1032 1021 /* Limit minimum refresh rate to what can be supported by hardware */ 1033 1022 min_refresh_in_uhz = min_hardware_refresh_in_uhz > in_config->min_refresh_in_uhz ?
+5 -1
drivers/gpu/drm/amd/pm/amdgpu_pm.c
··· 1361 1361 * create a custom set of heuristics, write a string of numbers to the file 1362 1362 * starting with the number of the custom profile along with a setting 1363 1363 * for each heuristic parameter. Due to differences across asic families 1364 - * the heuristic parameters vary from family to family. 1364 + * the heuristic parameters vary from family to family. Additionally, 1365 + * you can apply the custom heuristics to different clock domains. Each 1366 + * clock domain is considered a distinct operation so if you modify the 1367 + * gfxclk heuristics and then the memclk heuristics, the all of the 1368 + * custom heuristics will be retained until you switch to another profile. 1365 1369 * 1366 1370 */ 1367 1371
+91 -76
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
··· 72 72 static int smu_set_fan_speed_rpm(void *handle, uint32_t speed); 73 73 static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled); 74 74 static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state); 75 + static void smu_power_profile_mode_get(struct smu_context *smu, 76 + enum PP_SMC_POWER_PROFILE profile_mode); 77 + static void smu_power_profile_mode_put(struct smu_context *smu, 78 + enum PP_SMC_POWER_PROFILE profile_mode); 75 79 76 80 static int smu_sys_get_pp_feature_mask(void *handle, 77 81 char *buf) ··· 1263 1259 INIT_WORK(&smu->interrupt_work, smu_interrupt_work_fn); 1264 1260 atomic64_set(&smu->throttle_int_counter, 0); 1265 1261 smu->watermarks_bitmap = 0; 1266 - smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; 1267 - smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; 1268 - smu->user_dpm_profile.user_workload_mask = 0; 1269 1262 1270 1263 atomic_set(&smu->smu_power.power_gate.vcn_gated, 1); 1271 1264 atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1); 1272 1265 atomic_set(&smu->smu_power.power_gate.vpe_gated, 1); 1273 1266 atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1); 1274 1267 1275 - smu->workload_priority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0; 1276 - smu->workload_priority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1; 1277 - smu->workload_priority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2; 1278 - smu->workload_priority[PP_SMC_POWER_PROFILE_VIDEO] = 3; 1279 - smu->workload_priority[PP_SMC_POWER_PROFILE_VR] = 4; 1280 - smu->workload_priority[PP_SMC_POWER_PROFILE_COMPUTE] = 5; 1281 - smu->workload_priority[PP_SMC_POWER_PROFILE_CUSTOM] = 6; 1282 - 1283 1268 if (smu->is_apu || 1284 - !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) { 1285 - smu->driver_workload_mask = 1286 - 1 << smu->workload_priority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT]; 1287 - } else { 1288 - smu->driver_workload_mask = 1289 - 1 << smu->workload_priority[PP_SMC_POWER_PROFILE_FULLSCREEN3D]; 1290 - smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D; 1291 - } 1269 + !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) 1270 + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; 1271 + else 1272 + smu->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D; 1273 + smu_power_profile_mode_get(smu, smu->power_profile_mode); 1292 1274 1293 - smu->workload_mask = smu->driver_workload_mask | 1294 - smu->user_dpm_profile.user_workload_mask; 1295 - smu->workload_setting[0] = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; 1296 - smu->workload_setting[1] = PP_SMC_POWER_PROFILE_FULLSCREEN3D; 1297 - smu->workload_setting[2] = PP_SMC_POWER_PROFILE_POWERSAVING; 1298 - smu->workload_setting[3] = PP_SMC_POWER_PROFILE_VIDEO; 1299 - smu->workload_setting[4] = PP_SMC_POWER_PROFILE_VR; 1300 - smu->workload_setting[5] = PP_SMC_POWER_PROFILE_COMPUTE; 1301 - smu->workload_setting[6] = PP_SMC_POWER_PROFILE_CUSTOM; 1302 1275 smu->display_config = &adev->pm.pm_display_cfg; 1303 1276 1304 1277 smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; ··· 1326 1345 if (ret) { 1327 1346 dev_err(adev->dev, "Failed to sw fini smc table!\n"); 1328 1347 return ret; 1348 + } 1349 + 1350 + if (smu->custom_profile_params) { 1351 + kfree(smu->custom_profile_params); 1352 + smu->custom_profile_params = NULL; 1329 1353 } 1330 1354 1331 1355 smu_fini_microcode(smu); ··· 2117 2131 if (!ret) 2118 2132 adev->gfx.gfx_off_entrycount = count; 2119 2133 2134 + /* clear this on suspend so it will get reprogrammed on resume */ 2135 + smu->workload_mask = 0; 2136 + 2120 2137 return 0; 2121 2138 } 2122 2139 ··· 2232 2243 } 2233 2244 2234 2245 static int smu_bump_power_profile_mode(struct smu_context *smu, 2235 - long *param, 2236 - uint32_t param_size) 2246 + long *custom_params, 2247 + u32 custom_params_max_idx) 2237 2248 { 2238 - int ret = 0; 2249 + u32 workload_mask = 0; 2250 + int i, ret = 0; 2251 + 2252 + for (i = 0; i < PP_SMC_POWER_PROFILE_COUNT; i++) { 2253 + if (smu->workload_refcount[i]) 2254 + workload_mask |= 1 << i; 2255 + } 2256 + 2257 + if (smu->workload_mask == workload_mask) 2258 + return 0; 2239 2259 2240 2260 if (smu->ppt_funcs->set_power_profile_mode) 2241 - ret = smu->ppt_funcs->set_power_profile_mode(smu, param, param_size); 2261 + ret = smu->ppt_funcs->set_power_profile_mode(smu, workload_mask, 2262 + custom_params, 2263 + custom_params_max_idx); 2264 + 2265 + if (!ret) 2266 + smu->workload_mask = workload_mask; 2242 2267 2243 2268 return ret; 2244 2269 } 2245 2270 2271 + static void smu_power_profile_mode_get(struct smu_context *smu, 2272 + enum PP_SMC_POWER_PROFILE profile_mode) 2273 + { 2274 + smu->workload_refcount[profile_mode]++; 2275 + } 2276 + 2277 + static void smu_power_profile_mode_put(struct smu_context *smu, 2278 + enum PP_SMC_POWER_PROFILE profile_mode) 2279 + { 2280 + if (smu->workload_refcount[profile_mode]) 2281 + smu->workload_refcount[profile_mode]--; 2282 + } 2283 + 2246 2284 static int smu_adjust_power_state_dynamic(struct smu_context *smu, 2247 2285 enum amd_dpm_forced_level level, 2248 - bool skip_display_settings, 2249 - bool init) 2286 + bool skip_display_settings) 2250 2287 { 2251 2288 int ret = 0; 2252 - int index = 0; 2253 - long workload[1]; 2254 2289 struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); 2255 2290 2256 2291 if (!skip_display_settings) { ··· 2311 2298 } 2312 2299 2313 2300 if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && 2314 - smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { 2315 - index = fls(smu->workload_mask); 2316 - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; 2317 - workload[0] = smu->workload_setting[index]; 2318 - 2319 - if (init || smu->power_profile_mode != workload[0]) 2320 - smu_bump_power_profile_mode(smu, workload, 0); 2321 - } 2301 + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) 2302 + smu_bump_power_profile_mode(smu, NULL, 0); 2322 2303 2323 2304 return ret; 2324 2305 } ··· 2331 2324 ret = smu_pre_display_config_changed(smu); 2332 2325 if (ret) 2333 2326 return ret; 2334 - ret = smu_adjust_power_state_dynamic(smu, level, false, false); 2327 + ret = smu_adjust_power_state_dynamic(smu, level, false); 2335 2328 break; 2336 2329 case AMD_PP_TASK_COMPLETE_INIT: 2337 - ret = smu_adjust_power_state_dynamic(smu, level, true, true); 2330 + ret = smu_adjust_power_state_dynamic(smu, level, true); 2338 2331 break; 2339 2332 case AMD_PP_TASK_READJUST_POWER_STATE: 2340 - ret = smu_adjust_power_state_dynamic(smu, level, true, false); 2333 + ret = smu_adjust_power_state_dynamic(smu, level, true); 2341 2334 break; 2342 2335 default: 2343 2336 break; ··· 2359 2352 2360 2353 static int smu_switch_power_profile(void *handle, 2361 2354 enum PP_SMC_POWER_PROFILE type, 2362 - bool en) 2355 + bool enable) 2363 2356 { 2364 2357 struct smu_context *smu = handle; 2365 2358 struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); 2366 - long workload[1]; 2367 - uint32_t index; 2359 + int ret; 2368 2360 2369 2361 if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) 2370 2362 return -EOPNOTSUPP; ··· 2371 2365 if (!(type < PP_SMC_POWER_PROFILE_CUSTOM)) 2372 2366 return -EINVAL; 2373 2367 2374 - if (!en) { 2375 - smu->driver_workload_mask &= ~(1 << smu->workload_priority[type]); 2376 - index = fls(smu->workload_mask); 2377 - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; 2378 - workload[0] = smu->workload_setting[index]; 2379 - } else { 2380 - smu->driver_workload_mask |= (1 << smu->workload_priority[type]); 2381 - index = fls(smu->workload_mask); 2382 - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; 2383 - workload[0] = smu->workload_setting[index]; 2384 - } 2385 - 2386 - smu->workload_mask = smu->driver_workload_mask | 2387 - smu->user_dpm_profile.user_workload_mask; 2388 - 2389 2368 if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && 2390 - smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) 2391 - smu_bump_power_profile_mode(smu, workload, 0); 2369 + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { 2370 + if (enable) 2371 + smu_power_profile_mode_get(smu, type); 2372 + else 2373 + smu_power_profile_mode_put(smu, type); 2374 + ret = smu_bump_power_profile_mode(smu, NULL, 0); 2375 + if (ret) { 2376 + if (enable) 2377 + smu_power_profile_mode_put(smu, type); 2378 + else 2379 + smu_power_profile_mode_get(smu, type); 2380 + return ret; 2381 + } 2382 + } 2392 2383 2393 2384 return 0; 2394 2385 } ··· 3077 3074 uint32_t param_size) 3078 3075 { 3079 3076 struct smu_context *smu = handle; 3080 - int ret; 3077 + bool custom = false; 3078 + int ret = 0; 3081 3079 3082 3080 if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled || 3083 3081 !smu->ppt_funcs->set_power_profile_mode) 3084 3082 return -EOPNOTSUPP; 3085 3083 3086 - if (smu->user_dpm_profile.user_workload_mask & 3087 - (1 << smu->workload_priority[param[param_size]])) 3088 - return 0; 3084 + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) { 3085 + custom = true; 3086 + /* clear frontend mask so custom changes propogate */ 3087 + smu->workload_mask = 0; 3088 + } 3089 3089 3090 - smu->user_dpm_profile.user_workload_mask = 3091 - (1 << smu->workload_priority[param[param_size]]); 3092 - smu->workload_mask = smu->user_dpm_profile.user_workload_mask | 3093 - smu->driver_workload_mask; 3094 - ret = smu_bump_power_profile_mode(smu, param, param_size); 3090 + if ((param[param_size] != smu->power_profile_mode) || custom) { 3091 + /* clear the old user preference */ 3092 + smu_power_profile_mode_put(smu, smu->power_profile_mode); 3093 + /* set the new user preference */ 3094 + smu_power_profile_mode_get(smu, param[param_size]); 3095 + ret = smu_bump_power_profile_mode(smu, 3096 + custom ? param : NULL, 3097 + custom ? param_size : 0); 3098 + if (ret) 3099 + smu_power_profile_mode_put(smu, param[param_size]); 3100 + else 3101 + /* store the user's preference */ 3102 + smu->power_profile_mode = param[param_size]; 3103 + } 3095 3104 3096 3105 return ret; 3097 3106 }
+10 -7
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
··· 240 240 /* user clock state information */ 241 241 uint32_t clk_mask[SMU_CLK_COUNT]; 242 242 uint32_t clk_dependency; 243 - uint32_t user_workload_mask; 244 243 }; 245 244 246 245 #define SMU_TABLE_INIT(tables, table_id, s, a, d) \ ··· 556 557 uint32_t hard_min_uclk_req_from_dal; 557 558 bool disable_uclk_switch; 558 559 560 + /* asic agnostic workload mask */ 559 561 uint32_t workload_mask; 560 - uint32_t driver_workload_mask; 561 - uint32_t workload_priority[WORKLOAD_POLICY_MAX]; 562 - uint32_t workload_setting[WORKLOAD_POLICY_MAX]; 562 + /* default/user workload preference */ 563 563 uint32_t power_profile_mode; 564 - uint32_t default_power_profile_mode; 564 + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT]; 565 + /* backend specific custom workload settings */ 566 + long *custom_profile_params; 565 567 bool pm_enabled; 566 568 bool is_apu; 567 569 ··· 733 733 * @set_power_profile_mode: Set a power profile mode. Also used to 734 734 * create/set custom power profile modes. 735 735 * &input: Power profile mode parameters. 736 - * &size: Size of &input. 736 + * &workload_mask: mask of workloads to enable 737 + * &custom_params: custom profile parameters 738 + * &custom_params_max_idx: max valid idx into custom_params 737 739 */ 738 - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size); 740 + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask, 741 + long *custom_params, u32 custom_params_max_idx); 739 742 740 743 /** 741 744 * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
+106 -83
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
··· 1445 1445 return size; 1446 1446 } 1447 1447 1448 - static int arcturus_set_power_profile_mode(struct smu_context *smu, 1449 - long *input, 1450 - uint32_t size) 1448 + #define ARCTURUS_CUSTOM_PARAMS_COUNT 10 1449 + #define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2 1450 + #define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long)) 1451 + 1452 + static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu, 1453 + long *input) 1451 1454 { 1452 1455 DpmActivityMonitorCoeffInt_t activity_monitor; 1453 - int workload_type = 0; 1454 - uint32_t profile_mode = input[size]; 1455 - int ret = 0; 1456 + int ret, idx; 1456 1457 1457 - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { 1458 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); 1459 - return -EINVAL; 1460 - } 1461 - 1462 - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) && 1463 - (smu->smc_fw_version >= 0x360d00)) { 1464 - if (size != 10) 1465 - return -EINVAL; 1466 - 1467 - ret = smu_cmn_update_table(smu, 1468 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1469 - WORKLOAD_PPLIB_CUSTOM_BIT, 1470 - (void *)(&activity_monitor), 1471 - false); 1472 - if (ret) { 1473 - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 1474 - return ret; 1475 - } 1476 - 1477 - switch (input[0]) { 1478 - case 0: /* Gfxclk */ 1479 - activity_monitor.Gfx_FPS = input[1]; 1480 - activity_monitor.Gfx_UseRlcBusy = input[2]; 1481 - activity_monitor.Gfx_MinActiveFreqType = input[3]; 1482 - activity_monitor.Gfx_MinActiveFreq = input[4]; 1483 - activity_monitor.Gfx_BoosterFreqType = input[5]; 1484 - activity_monitor.Gfx_BoosterFreq = input[6]; 1485 - activity_monitor.Gfx_PD_Data_limit_c = input[7]; 1486 - activity_monitor.Gfx_PD_Data_error_coeff = input[8]; 1487 - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; 1488 - break; 1489 - case 1: /* Uclk */ 1490 - activity_monitor.Mem_FPS = input[1]; 1491 - activity_monitor.Mem_UseRlcBusy = input[2]; 1492 - activity_monitor.Mem_MinActiveFreqType = input[3]; 1493 - activity_monitor.Mem_MinActiveFreq = input[4]; 1494 - activity_monitor.Mem_BoosterFreqType = input[5]; 1495 - activity_monitor.Mem_BoosterFreq = input[6]; 1496 - activity_monitor.Mem_PD_Data_limit_c = input[7]; 1497 - activity_monitor.Mem_PD_Data_error_coeff = input[8]; 1498 - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; 1499 - break; 1500 - default: 1501 - return -EINVAL; 1502 - } 1503 - 1504 - ret = smu_cmn_update_table(smu, 1505 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1506 - WORKLOAD_PPLIB_CUSTOM_BIT, 1507 - (void *)(&activity_monitor), 1508 - true); 1509 - if (ret) { 1510 - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 1511 - return ret; 1512 - } 1513 - } 1514 - 1515 - /* 1516 - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT 1517 - * Not all profile modes are supported on arcturus. 1518 - */ 1519 - workload_type = smu_cmn_to_asic_specific_index(smu, 1520 - CMN2ASIC_MAPPING_WORKLOAD, 1521 - profile_mode); 1522 - if (workload_type < 0) { 1523 - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode); 1524 - return -EINVAL; 1525 - } 1526 - 1527 - ret = smu_cmn_send_smc_msg_with_param(smu, 1528 - SMU_MSG_SetWorkloadMask, 1529 - smu->workload_mask, 1530 - NULL); 1458 + ret = smu_cmn_update_table(smu, 1459 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1460 + WORKLOAD_PPLIB_CUSTOM_BIT, 1461 + (void *)(&activity_monitor), 1462 + false); 1531 1463 if (ret) { 1532 - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type); 1464 + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 1533 1465 return ret; 1534 1466 } 1535 1467 1536 - smu_cmn_assign_power_profile(smu); 1468 + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT; 1469 + if (input[idx]) { 1470 + /* Gfxclk */ 1471 + activity_monitor.Gfx_FPS = input[idx + 1]; 1472 + activity_monitor.Gfx_UseRlcBusy = input[idx + 2]; 1473 + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3]; 1474 + activity_monitor.Gfx_MinActiveFreq = input[idx + 4]; 1475 + activity_monitor.Gfx_BoosterFreqType = input[idx + 5]; 1476 + activity_monitor.Gfx_BoosterFreq = input[idx + 6]; 1477 + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7]; 1478 + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8]; 1479 + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9]; 1480 + } 1481 + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT; 1482 + if (input[idx]) { 1483 + /* Uclk */ 1484 + activity_monitor.Mem_FPS = input[idx + 1]; 1485 + activity_monitor.Mem_UseRlcBusy = input[idx + 2]; 1486 + activity_monitor.Mem_MinActiveFreqType = input[idx + 3]; 1487 + activity_monitor.Mem_MinActiveFreq = input[idx + 4]; 1488 + activity_monitor.Mem_BoosterFreqType = input[idx + 5]; 1489 + activity_monitor.Mem_BoosterFreq = input[idx + 6]; 1490 + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7]; 1491 + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8]; 1492 + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9]; 1493 + } 1537 1494 1538 - return 0; 1495 + ret = smu_cmn_update_table(smu, 1496 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1497 + WORKLOAD_PPLIB_CUSTOM_BIT, 1498 + (void *)(&activity_monitor), 1499 + true); 1500 + if (ret) { 1501 + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 1502 + return ret; 1503 + } 1504 + 1505 + return ret; 1506 + } 1507 + 1508 + static int arcturus_set_power_profile_mode(struct smu_context *smu, 1509 + u32 workload_mask, 1510 + long *custom_params, 1511 + u32 custom_params_max_idx) 1512 + { 1513 + u32 backend_workload_mask = 0; 1514 + int ret, idx = -1, i; 1515 + 1516 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 1517 + &backend_workload_mask); 1518 + 1519 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { 1520 + if (smu->smc_fw_version < 0x360d00) 1521 + return -EINVAL; 1522 + if (!smu->custom_profile_params) { 1523 + smu->custom_profile_params = 1524 + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL); 1525 + if (!smu->custom_profile_params) 1526 + return -ENOMEM; 1527 + } 1528 + if (custom_params && custom_params_max_idx) { 1529 + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT) 1530 + return -EINVAL; 1531 + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT) 1532 + return -EINVAL; 1533 + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT; 1534 + smu->custom_profile_params[idx] = 1; 1535 + for (i = 1; i < custom_params_max_idx; i++) 1536 + smu->custom_profile_params[idx + i] = custom_params[i]; 1537 + } 1538 + ret = arcturus_set_power_profile_mode_coeff(smu, 1539 + smu->custom_profile_params); 1540 + if (ret) { 1541 + if (idx != -1) 1542 + smu->custom_profile_params[idx] = 0; 1543 + return ret; 1544 + } 1545 + } else if (smu->custom_profile_params) { 1546 + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE); 1547 + } 1548 + 1549 + ret = smu_cmn_send_smc_msg_with_param(smu, 1550 + SMU_MSG_SetWorkloadMask, 1551 + backend_workload_mask, 1552 + NULL); 1553 + if (ret) { 1554 + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", 1555 + workload_mask); 1556 + if (idx != -1) 1557 + smu->custom_profile_params[idx] = 0; 1558 + return ret; 1559 + } 1560 + 1561 + return ret; 1539 1562 } 1540 1563 1541 1564 static int arcturus_set_performance_level(struct smu_context *smu,
+107 -75
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
··· 2006 2006 return size; 2007 2007 } 2008 2008 2009 - static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) 2009 + #define NAVI10_CUSTOM_PARAMS_COUNT 10 2010 + #define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3 2011 + #define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long)) 2012 + 2013 + static int navi10_set_power_profile_mode_coeff(struct smu_context *smu, 2014 + long *input) 2010 2015 { 2011 2016 DpmActivityMonitorCoeffInt_t activity_monitor; 2012 - int workload_type, ret = 0; 2017 + int ret, idx; 2013 2018 2014 - smu->power_profile_mode = input[size]; 2015 - 2016 - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { 2017 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); 2018 - return -EINVAL; 2019 + ret = smu_cmn_update_table(smu, 2020 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2021 + (void *)(&activity_monitor), false); 2022 + if (ret) { 2023 + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 2024 + return ret; 2019 2025 } 2020 2026 2021 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { 2022 - if (size != 10) 2023 - return -EINVAL; 2024 - 2025 - ret = smu_cmn_update_table(smu, 2026 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2027 - (void *)(&activity_monitor), false); 2028 - if (ret) { 2029 - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 2030 - return ret; 2031 - } 2032 - 2033 - switch (input[0]) { 2034 - case 0: /* Gfxclk */ 2035 - activity_monitor.Gfx_FPS = input[1]; 2036 - activity_monitor.Gfx_MinFreqStep = input[2]; 2037 - activity_monitor.Gfx_MinActiveFreqType = input[3]; 2038 - activity_monitor.Gfx_MinActiveFreq = input[4]; 2039 - activity_monitor.Gfx_BoosterFreqType = input[5]; 2040 - activity_monitor.Gfx_BoosterFreq = input[6]; 2041 - activity_monitor.Gfx_PD_Data_limit_c = input[7]; 2042 - activity_monitor.Gfx_PD_Data_error_coeff = input[8]; 2043 - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; 2044 - break; 2045 - case 1: /* Socclk */ 2046 - activity_monitor.Soc_FPS = input[1]; 2047 - activity_monitor.Soc_MinFreqStep = input[2]; 2048 - activity_monitor.Soc_MinActiveFreqType = input[3]; 2049 - activity_monitor.Soc_MinActiveFreq = input[4]; 2050 - activity_monitor.Soc_BoosterFreqType = input[5]; 2051 - activity_monitor.Soc_BoosterFreq = input[6]; 2052 - activity_monitor.Soc_PD_Data_limit_c = input[7]; 2053 - activity_monitor.Soc_PD_Data_error_coeff = input[8]; 2054 - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9]; 2055 - break; 2056 - case 2: /* Memclk */ 2057 - activity_monitor.Mem_FPS = input[1]; 2058 - activity_monitor.Mem_MinFreqStep = input[2]; 2059 - activity_monitor.Mem_MinActiveFreqType = input[3]; 2060 - activity_monitor.Mem_MinActiveFreq = input[4]; 2061 - activity_monitor.Mem_BoosterFreqType = input[5]; 2062 - activity_monitor.Mem_BoosterFreq = input[6]; 2063 - activity_monitor.Mem_PD_Data_limit_c = input[7]; 2064 - activity_monitor.Mem_PD_Data_error_coeff = input[8]; 2065 - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; 2066 - break; 2067 - default: 2068 - return -EINVAL; 2069 - } 2070 - 2071 - ret = smu_cmn_update_table(smu, 2072 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2073 - (void *)(&activity_monitor), true); 2074 - if (ret) { 2075 - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 2076 - return ret; 2077 - } 2027 + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT; 2028 + if (input[idx]) { 2029 + /* Gfxclk */ 2030 + activity_monitor.Gfx_FPS = input[idx + 1]; 2031 + activity_monitor.Gfx_MinFreqStep = input[idx + 2]; 2032 + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3]; 2033 + activity_monitor.Gfx_MinActiveFreq = input[idx + 4]; 2034 + activity_monitor.Gfx_BoosterFreqType = input[idx + 5]; 2035 + activity_monitor.Gfx_BoosterFreq = input[idx + 6]; 2036 + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7]; 2037 + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8]; 2038 + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9]; 2039 + } 2040 + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT; 2041 + if (input[idx]) { 2042 + /* Socclk */ 2043 + activity_monitor.Soc_FPS = input[idx + 1]; 2044 + activity_monitor.Soc_MinFreqStep = input[idx + 2]; 2045 + activity_monitor.Soc_MinActiveFreqType = input[idx + 3]; 2046 + activity_monitor.Soc_MinActiveFreq = input[idx + 4]; 2047 + activity_monitor.Soc_BoosterFreqType = input[idx + 5]; 2048 + activity_monitor.Soc_BoosterFreq = input[idx + 6]; 2049 + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7]; 2050 + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8]; 2051 + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9]; 2052 + } 2053 + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT; 2054 + if (input[idx]) { 2055 + /* Memclk */ 2056 + activity_monitor.Mem_FPS = input[idx + 1]; 2057 + activity_monitor.Mem_MinFreqStep = input[idx + 2]; 2058 + activity_monitor.Mem_MinActiveFreqType = input[idx + 3]; 2059 + activity_monitor.Mem_MinActiveFreq = input[idx + 4]; 2060 + activity_monitor.Mem_BoosterFreqType = input[idx + 5]; 2061 + activity_monitor.Mem_BoosterFreq = input[idx + 6]; 2062 + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7]; 2063 + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8]; 2064 + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9]; 2078 2065 } 2079 2066 2080 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 2081 - workload_type = smu_cmn_to_asic_specific_index(smu, 2082 - CMN2ASIC_MAPPING_WORKLOAD, 2083 - smu->power_profile_mode); 2084 - if (workload_type < 0) 2085 - return -EINVAL; 2067 + ret = smu_cmn_update_table(smu, 2068 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2069 + (void *)(&activity_monitor), true); 2070 + if (ret) { 2071 + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 2072 + return ret; 2073 + } 2074 + 2075 + return ret; 2076 + } 2077 + 2078 + static int navi10_set_power_profile_mode(struct smu_context *smu, 2079 + u32 workload_mask, 2080 + long *custom_params, 2081 + u32 custom_params_max_idx) 2082 + { 2083 + u32 backend_workload_mask = 0; 2084 + int ret, idx = -1, i; 2085 + 2086 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 2087 + &backend_workload_mask); 2088 + 2089 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { 2090 + if (!smu->custom_profile_params) { 2091 + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL); 2092 + if (!smu->custom_profile_params) 2093 + return -ENOMEM; 2094 + } 2095 + if (custom_params && custom_params_max_idx) { 2096 + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT) 2097 + return -EINVAL; 2098 + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT) 2099 + return -EINVAL; 2100 + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT; 2101 + smu->custom_profile_params[idx] = 1; 2102 + for (i = 1; i < custom_params_max_idx; i++) 2103 + smu->custom_profile_params[idx + i] = custom_params[i]; 2104 + } 2105 + ret = navi10_set_power_profile_mode_coeff(smu, 2106 + smu->custom_profile_params); 2107 + if (ret) { 2108 + if (idx != -1) 2109 + smu->custom_profile_params[idx] = 0; 2110 + return ret; 2111 + } 2112 + } else if (smu->custom_profile_params) { 2113 + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE); 2114 + } 2086 2115 2087 2116 ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 2088 - smu->workload_mask, NULL); 2089 - if (ret) 2090 - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); 2091 - else 2092 - smu_cmn_assign_power_profile(smu); 2117 + backend_workload_mask, NULL); 2118 + if (ret) { 2119 + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", 2120 + workload_mask); 2121 + if (idx != -1) 2122 + smu->custom_profile_params[idx] = 0; 2123 + return ret; 2124 + } 2093 2125 2094 2126 return ret; 2095 2127 }
+108 -75
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
··· 1708 1708 return size; 1709 1709 } 1710 1710 1711 - static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) 1711 + #define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10 1712 + #define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3 1713 + #define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long)) 1714 + 1715 + static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu, 1716 + long *input) 1712 1717 { 1713 1718 1714 1719 DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; 1715 1720 DpmActivityMonitorCoeffInt_t *activity_monitor = 1716 1721 &(activity_monitor_external.DpmActivityMonitorCoeffInt); 1717 - int workload_type, ret = 0; 1722 + int ret, idx; 1718 1723 1719 - smu->power_profile_mode = input[size]; 1720 - 1721 - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { 1722 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); 1723 - return -EINVAL; 1724 + ret = smu_cmn_update_table(smu, 1725 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 1726 + (void *)(&activity_monitor_external), false); 1727 + if (ret) { 1728 + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 1729 + return ret; 1724 1730 } 1725 1731 1726 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { 1727 - if (size != 10) 1728 - return -EINVAL; 1729 - 1730 - ret = smu_cmn_update_table(smu, 1731 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 1732 - (void *)(&activity_monitor_external), false); 1733 - if (ret) { 1734 - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 1735 - return ret; 1736 - } 1737 - 1738 - switch (input[0]) { 1739 - case 0: /* Gfxclk */ 1740 - activity_monitor->Gfx_FPS = input[1]; 1741 - activity_monitor->Gfx_MinFreqStep = input[2]; 1742 - activity_monitor->Gfx_MinActiveFreqType = input[3]; 1743 - activity_monitor->Gfx_MinActiveFreq = input[4]; 1744 - activity_monitor->Gfx_BoosterFreqType = input[5]; 1745 - activity_monitor->Gfx_BoosterFreq = input[6]; 1746 - activity_monitor->Gfx_PD_Data_limit_c = input[7]; 1747 - activity_monitor->Gfx_PD_Data_error_coeff = input[8]; 1748 - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9]; 1749 - break; 1750 - case 1: /* Socclk */ 1751 - activity_monitor->Fclk_FPS = input[1]; 1752 - activity_monitor->Fclk_MinFreqStep = input[2]; 1753 - activity_monitor->Fclk_MinActiveFreqType = input[3]; 1754 - activity_monitor->Fclk_MinActiveFreq = input[4]; 1755 - activity_monitor->Fclk_BoosterFreqType = input[5]; 1756 - activity_monitor->Fclk_BoosterFreq = input[6]; 1757 - activity_monitor->Fclk_PD_Data_limit_c = input[7]; 1758 - activity_monitor->Fclk_PD_Data_error_coeff = input[8]; 1759 - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9]; 1760 - break; 1761 - case 2: /* Memclk */ 1762 - activity_monitor->Mem_FPS = input[1]; 1763 - activity_monitor->Mem_MinFreqStep = input[2]; 1764 - activity_monitor->Mem_MinActiveFreqType = input[3]; 1765 - activity_monitor->Mem_MinActiveFreq = input[4]; 1766 - activity_monitor->Mem_BoosterFreqType = input[5]; 1767 - activity_monitor->Mem_BoosterFreq = input[6]; 1768 - activity_monitor->Mem_PD_Data_limit_c = input[7]; 1769 - activity_monitor->Mem_PD_Data_error_coeff = input[8]; 1770 - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9]; 1771 - break; 1772 - default: 1773 - return -EINVAL; 1774 - } 1775 - 1776 - ret = smu_cmn_update_table(smu, 1777 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 1778 - (void *)(&activity_monitor_external), true); 1779 - if (ret) { 1780 - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 1781 - return ret; 1782 - } 1732 + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; 1733 + if (input[idx]) { 1734 + /* Gfxclk */ 1735 + activity_monitor->Gfx_FPS = input[idx + 1]; 1736 + activity_monitor->Gfx_MinFreqStep = input[idx + 2]; 1737 + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3]; 1738 + activity_monitor->Gfx_MinActiveFreq = input[idx + 4]; 1739 + activity_monitor->Gfx_BoosterFreqType = input[idx + 5]; 1740 + activity_monitor->Gfx_BoosterFreq = input[idx + 6]; 1741 + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7]; 1742 + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8]; 1743 + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9]; 1744 + } 1745 + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; 1746 + if (input[idx]) { 1747 + /* Socclk */ 1748 + activity_monitor->Fclk_FPS = input[idx + 1]; 1749 + activity_monitor->Fclk_MinFreqStep = input[idx + 2]; 1750 + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3]; 1751 + activity_monitor->Fclk_MinActiveFreq = input[idx + 4]; 1752 + activity_monitor->Fclk_BoosterFreqType = input[idx + 5]; 1753 + activity_monitor->Fclk_BoosterFreq = input[idx + 6]; 1754 + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7]; 1755 + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8]; 1756 + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9]; 1757 + } 1758 + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; 1759 + if (input[idx]) { 1760 + /* Memclk */ 1761 + activity_monitor->Mem_FPS = input[idx + 1]; 1762 + activity_monitor->Mem_MinFreqStep = input[idx + 2]; 1763 + activity_monitor->Mem_MinActiveFreqType = input[idx + 3]; 1764 + activity_monitor->Mem_MinActiveFreq = input[idx + 4]; 1765 + activity_monitor->Mem_BoosterFreqType = input[idx + 5]; 1766 + activity_monitor->Mem_BoosterFreq = input[idx + 6]; 1767 + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7]; 1768 + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8]; 1769 + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9]; 1783 1770 } 1784 1771 1785 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 1786 - workload_type = smu_cmn_to_asic_specific_index(smu, 1787 - CMN2ASIC_MAPPING_WORKLOAD, 1788 - smu->power_profile_mode); 1789 - if (workload_type < 0) 1790 - return -EINVAL; 1772 + ret = smu_cmn_update_table(smu, 1773 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 1774 + (void *)(&activity_monitor_external), true); 1775 + if (ret) { 1776 + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 1777 + return ret; 1778 + } 1779 + 1780 + return ret; 1781 + } 1782 + 1783 + static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, 1784 + u32 workload_mask, 1785 + long *custom_params, 1786 + u32 custom_params_max_idx) 1787 + { 1788 + u32 backend_workload_mask = 0; 1789 + int ret, idx = -1, i; 1790 + 1791 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 1792 + &backend_workload_mask); 1793 + 1794 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { 1795 + if (!smu->custom_profile_params) { 1796 + smu->custom_profile_params = 1797 + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL); 1798 + if (!smu->custom_profile_params) 1799 + return -ENOMEM; 1800 + } 1801 + if (custom_params && custom_params_max_idx) { 1802 + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT) 1803 + return -EINVAL; 1804 + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT) 1805 + return -EINVAL; 1806 + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; 1807 + smu->custom_profile_params[idx] = 1; 1808 + for (i = 1; i < custom_params_max_idx; i++) 1809 + smu->custom_profile_params[idx + i] = custom_params[i]; 1810 + } 1811 + ret = sienna_cichlid_set_power_profile_mode_coeff(smu, 1812 + smu->custom_profile_params); 1813 + if (ret) { 1814 + if (idx != -1) 1815 + smu->custom_profile_params[idx] = 0; 1816 + return ret; 1817 + } 1818 + } else if (smu->custom_profile_params) { 1819 + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE); 1820 + } 1791 1821 1792 1822 ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 1793 - smu->workload_mask, NULL); 1794 - if (ret) 1795 - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); 1796 - else 1797 - smu_cmn_assign_power_profile(smu); 1823 + backend_workload_mask, NULL); 1824 + if (ret) { 1825 + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", 1826 + workload_mask); 1827 + if (idx != -1) 1828 + smu->custom_profile_params[idx] = 0; 1829 + return ret; 1830 + } 1798 1831 1799 1832 return ret; 1800 1833 }
+13 -28
drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
··· 1056 1056 return size; 1057 1057 } 1058 1058 1059 - static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) 1059 + static int vangogh_set_power_profile_mode(struct smu_context *smu, 1060 + u32 workload_mask, 1061 + long *custom_params, 1062 + u32 custom_params_max_idx) 1060 1063 { 1061 - int workload_type, ret; 1062 - uint32_t profile_mode = input[size]; 1064 + u32 backend_workload_mask = 0; 1065 + int ret; 1063 1066 1064 - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { 1065 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); 1066 - return -EINVAL; 1067 - } 1068 - 1069 - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT || 1070 - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) 1071 - return 0; 1072 - 1073 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 1074 - workload_type = smu_cmn_to_asic_specific_index(smu, 1075 - CMN2ASIC_MAPPING_WORKLOAD, 1076 - profile_mode); 1077 - if (workload_type < 0) { 1078 - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n", 1079 - profile_mode); 1080 - return -EINVAL; 1081 - } 1067 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 1068 + &backend_workload_mask); 1082 1069 1083 1070 ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify, 1084 - smu->workload_mask, 1085 - NULL); 1071 + backend_workload_mask, 1072 + NULL); 1086 1073 if (ret) { 1087 - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", 1088 - workload_type); 1074 + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n", 1075 + workload_mask); 1089 1076 return ret; 1090 1077 } 1091 1078 1092 - smu_cmn_assign_power_profile(smu); 1093 - 1094 - return 0; 1079 + return ret; 1095 1080 } 1096 1081 1097 1082 static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
+13 -30
drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
··· 864 864 return ret; 865 865 } 866 866 867 - static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) 867 + static int renoir_set_power_profile_mode(struct smu_context *smu, 868 + u32 workload_mask, 869 + long *custom_params, 870 + u32 custom_params_max_idx) 868 871 { 869 - int workload_type, ret; 870 - uint32_t profile_mode = input[size]; 872 + int ret; 873 + u32 backend_workload_mask = 0; 871 874 872 - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { 873 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); 874 - return -EINVAL; 875 - } 876 - 877 - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT || 878 - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) 879 - return 0; 880 - 881 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 882 - workload_type = smu_cmn_to_asic_specific_index(smu, 883 - CMN2ASIC_MAPPING_WORKLOAD, 884 - profile_mode); 885 - if (workload_type < 0) { 886 - /* 887 - * TODO: If some case need switch to powersave/default power mode 888 - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving. 889 - */ 890 - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode); 891 - return -EINVAL; 892 - } 875 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 876 + &backend_workload_mask); 893 877 894 878 ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify, 895 - smu->workload_mask, 896 - NULL); 879 + backend_workload_mask, 880 + NULL); 897 881 if (ret) { 898 - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type); 882 + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n", 883 + workload_mask); 899 884 return ret; 900 885 } 901 886 902 - smu_cmn_assign_power_profile(smu); 903 - 904 - return 0; 887 + return ret; 905 888 } 906 889 907 890 static int renoir_set_peak_clock_by_device(struct smu_context *smu)
+97 -80
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
··· 2571 2571 return size; 2572 2572 } 2573 2573 2574 - static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, 2575 - long *input, 2576 - uint32_t size) 2574 + #define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9 2575 + #define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2 2576 + #define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long)) 2577 + 2578 + static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu, 2579 + long *input) 2577 2580 { 2578 2581 DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; 2579 2582 DpmActivityMonitorCoeffInt_t *activity_monitor = 2580 2583 &(activity_monitor_external.DpmActivityMonitorCoeffInt); 2581 - int workload_type, ret = 0; 2582 - u32 workload_mask; 2584 + int ret, idx; 2583 2585 2584 - smu->power_profile_mode = input[size]; 2585 - 2586 - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { 2587 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); 2588 - return -EINVAL; 2586 + ret = smu_cmn_update_table(smu, 2587 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, 2588 + WORKLOAD_PPLIB_CUSTOM_BIT, 2589 + (void *)(&activity_monitor_external), 2590 + false); 2591 + if (ret) { 2592 + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 2593 + return ret; 2589 2594 } 2590 2595 2591 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { 2592 - if (size != 9) 2593 - return -EINVAL; 2594 - 2595 - ret = smu_cmn_update_table(smu, 2596 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, 2597 - WORKLOAD_PPLIB_CUSTOM_BIT, 2598 - (void *)(&activity_monitor_external), 2599 - false); 2600 - if (ret) { 2601 - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 2602 - return ret; 2603 - } 2604 - 2605 - switch (input[0]) { 2606 - case 0: /* Gfxclk */ 2607 - activity_monitor->Gfx_FPS = input[1]; 2608 - activity_monitor->Gfx_MinActiveFreqType = input[2]; 2609 - activity_monitor->Gfx_MinActiveFreq = input[3]; 2610 - activity_monitor->Gfx_BoosterFreqType = input[4]; 2611 - activity_monitor->Gfx_BoosterFreq = input[5]; 2612 - activity_monitor->Gfx_PD_Data_limit_c = input[6]; 2613 - activity_monitor->Gfx_PD_Data_error_coeff = input[7]; 2614 - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8]; 2615 - break; 2616 - case 1: /* Fclk */ 2617 - activity_monitor->Fclk_FPS = input[1]; 2618 - activity_monitor->Fclk_MinActiveFreqType = input[2]; 2619 - activity_monitor->Fclk_MinActiveFreq = input[3]; 2620 - activity_monitor->Fclk_BoosterFreqType = input[4]; 2621 - activity_monitor->Fclk_BoosterFreq = input[5]; 2622 - activity_monitor->Fclk_PD_Data_limit_c = input[6]; 2623 - activity_monitor->Fclk_PD_Data_error_coeff = input[7]; 2624 - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8]; 2625 - break; 2626 - default: 2627 - return -EINVAL; 2628 - } 2629 - 2630 - ret = smu_cmn_update_table(smu, 2631 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, 2632 - WORKLOAD_PPLIB_CUSTOM_BIT, 2633 - (void *)(&activity_monitor_external), 2634 - true); 2635 - if (ret) { 2636 - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 2637 - return ret; 2638 - } 2596 + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT; 2597 + if (input[idx]) { 2598 + /* Gfxclk */ 2599 + activity_monitor->Gfx_FPS = input[idx + 1]; 2600 + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2]; 2601 + activity_monitor->Gfx_MinActiveFreq = input[idx + 3]; 2602 + activity_monitor->Gfx_BoosterFreqType = input[idx + 4]; 2603 + activity_monitor->Gfx_BoosterFreq = input[idx + 5]; 2604 + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6]; 2605 + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7]; 2606 + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8]; 2607 + } 2608 + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT; 2609 + if (input[idx]) { 2610 + /* Fclk */ 2611 + activity_monitor->Fclk_FPS = input[idx + 1]; 2612 + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2]; 2613 + activity_monitor->Fclk_MinActiveFreq = input[idx + 3]; 2614 + activity_monitor->Fclk_BoosterFreqType = input[idx + 4]; 2615 + activity_monitor->Fclk_BoosterFreq = input[idx + 5]; 2616 + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6]; 2617 + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7]; 2618 + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8]; 2639 2619 } 2640 2620 2641 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 2642 - workload_type = smu_cmn_to_asic_specific_index(smu, 2643 - CMN2ASIC_MAPPING_WORKLOAD, 2644 - smu->power_profile_mode); 2621 + ret = smu_cmn_update_table(smu, 2622 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, 2623 + WORKLOAD_PPLIB_CUSTOM_BIT, 2624 + (void *)(&activity_monitor_external), 2625 + true); 2626 + if (ret) { 2627 + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 2628 + return ret; 2629 + } 2645 2630 2646 - if (workload_type < 0) 2647 - return -EINVAL; 2631 + return ret; 2632 + } 2648 2633 2649 - workload_mask = 1 << workload_type; 2634 + static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, 2635 + u32 workload_mask, 2636 + long *custom_params, 2637 + u32 custom_params_max_idx) 2638 + { 2639 + u32 backend_workload_mask = 0; 2640 + int workload_type, ret, idx = -1, i; 2641 + 2642 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 2643 + &backend_workload_mask); 2650 2644 2651 2645 /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */ 2652 2646 if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) && ··· 2652 2658 CMN2ASIC_MAPPING_WORKLOAD, 2653 2659 PP_SMC_POWER_PROFILE_POWERSAVING); 2654 2660 if (workload_type >= 0) 2655 - workload_mask |= 1 << workload_type; 2661 + backend_workload_mask |= 1 << workload_type; 2656 2662 } 2657 2663 2658 - smu->workload_mask |= workload_mask; 2659 - ret = smu_cmn_send_smc_msg_with_param(smu, 2660 - SMU_MSG_SetWorkloadMask, 2661 - smu->workload_mask, 2662 - NULL); 2663 - if (!ret) { 2664 - smu_cmn_assign_power_profile(smu); 2665 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) { 2666 - workload_type = smu_cmn_to_asic_specific_index(smu, 2667 - CMN2ASIC_MAPPING_WORKLOAD, 2668 - PP_SMC_POWER_PROFILE_FULLSCREEN3D); 2669 - smu->power_profile_mode = smu->workload_mask & (1 << workload_type) 2670 - ? PP_SMC_POWER_PROFILE_FULLSCREEN3D 2671 - : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; 2664 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { 2665 + if (!smu->custom_profile_params) { 2666 + smu->custom_profile_params = 2667 + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL); 2668 + if (!smu->custom_profile_params) 2669 + return -ENOMEM; 2672 2670 } 2671 + if (custom_params && custom_params_max_idx) { 2672 + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT) 2673 + return -EINVAL; 2674 + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT) 2675 + return -EINVAL; 2676 + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT; 2677 + smu->custom_profile_params[idx] = 1; 2678 + for (i = 1; i < custom_params_max_idx; i++) 2679 + smu->custom_profile_params[idx + i] = custom_params[i]; 2680 + } 2681 + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu, 2682 + smu->custom_profile_params); 2683 + if (ret) { 2684 + if (idx != -1) 2685 + smu->custom_profile_params[idx] = 0; 2686 + return ret; 2687 + } 2688 + } else if (smu->custom_profile_params) { 2689 + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE); 2690 + } 2691 + 2692 + ret = smu_cmn_send_smc_msg_with_param(smu, 2693 + SMU_MSG_SetWorkloadMask, 2694 + backend_workload_mask, 2695 + NULL); 2696 + if (ret) { 2697 + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", 2698 + workload_mask); 2699 + if (idx != -1) 2700 + smu->custom_profile_params[idx] = 0; 2701 + return ret; 2673 2702 } 2674 2703 2675 2704 return ret;
+91 -60
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
··· 2530 2530 return result; 2531 2531 } 2532 2532 2533 - static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) 2533 + #define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8 2534 + #define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2 2535 + #define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long)) 2536 + 2537 + static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu, 2538 + long *input) 2534 2539 { 2535 2540 2536 2541 DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; 2537 2542 DpmActivityMonitorCoeffInt_t *activity_monitor = 2538 2543 &(activity_monitor_external.DpmActivityMonitorCoeffInt); 2539 - int workload_type, ret = 0; 2544 + int ret, idx; 2540 2545 2541 - smu->power_profile_mode = input[size]; 2542 - 2543 - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) { 2544 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); 2545 - return -EINVAL; 2546 + ret = smu_cmn_update_table(smu, 2547 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2548 + (void *)(&activity_monitor_external), false); 2549 + if (ret) { 2550 + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 2551 + return ret; 2546 2552 } 2547 2553 2548 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { 2549 - if (size != 8) 2550 - return -EINVAL; 2551 - 2552 - ret = smu_cmn_update_table(smu, 2553 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2554 - (void *)(&activity_monitor_external), false); 2555 - if (ret) { 2556 - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 2557 - return ret; 2558 - } 2559 - 2560 - switch (input[0]) { 2561 - case 0: /* Gfxclk */ 2562 - activity_monitor->Gfx_ActiveHystLimit = input[1]; 2563 - activity_monitor->Gfx_IdleHystLimit = input[2]; 2564 - activity_monitor->Gfx_FPS = input[3]; 2565 - activity_monitor->Gfx_MinActiveFreqType = input[4]; 2566 - activity_monitor->Gfx_BoosterFreqType = input[5]; 2567 - activity_monitor->Gfx_MinActiveFreq = input[6]; 2568 - activity_monitor->Gfx_BoosterFreq = input[7]; 2569 - break; 2570 - case 1: /* Fclk */ 2571 - activity_monitor->Fclk_ActiveHystLimit = input[1]; 2572 - activity_monitor->Fclk_IdleHystLimit = input[2]; 2573 - activity_monitor->Fclk_FPS = input[3]; 2574 - activity_monitor->Fclk_MinActiveFreqType = input[4]; 2575 - activity_monitor->Fclk_BoosterFreqType = input[5]; 2576 - activity_monitor->Fclk_MinActiveFreq = input[6]; 2577 - activity_monitor->Fclk_BoosterFreq = input[7]; 2578 - break; 2579 - default: 2580 - return -EINVAL; 2581 - } 2582 - 2583 - ret = smu_cmn_update_table(smu, 2584 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2585 - (void *)(&activity_monitor_external), true); 2586 - if (ret) { 2587 - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 2588 - return ret; 2589 - } 2554 + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT; 2555 + if (input[idx]) { 2556 + /* Gfxclk */ 2557 + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1]; 2558 + activity_monitor->Gfx_IdleHystLimit = input[idx + 2]; 2559 + activity_monitor->Gfx_FPS = input[idx + 3]; 2560 + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4]; 2561 + activity_monitor->Gfx_BoosterFreqType = input[idx + 5]; 2562 + activity_monitor->Gfx_MinActiveFreq = input[idx + 6]; 2563 + activity_monitor->Gfx_BoosterFreq = input[idx + 7]; 2564 + } 2565 + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT; 2566 + if (input[idx]) { 2567 + /* Fclk */ 2568 + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1]; 2569 + activity_monitor->Fclk_IdleHystLimit = input[idx + 2]; 2570 + activity_monitor->Fclk_FPS = input[idx + 3]; 2571 + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4]; 2572 + activity_monitor->Fclk_BoosterFreqType = input[idx + 5]; 2573 + activity_monitor->Fclk_MinActiveFreq = input[idx + 6]; 2574 + activity_monitor->Fclk_BoosterFreq = input[idx + 7]; 2590 2575 } 2591 2576 2592 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 2593 - workload_type = smu_cmn_to_asic_specific_index(smu, 2594 - CMN2ASIC_MAPPING_WORKLOAD, 2595 - smu->power_profile_mode); 2596 - if (workload_type < 0) 2597 - return -EINVAL; 2577 + ret = smu_cmn_update_table(smu, 2578 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, 2579 + (void *)(&activity_monitor_external), true); 2580 + if (ret) { 2581 + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 2582 + return ret; 2583 + } 2584 + 2585 + return ret; 2586 + } 2587 + 2588 + static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, 2589 + u32 workload_mask, 2590 + long *custom_params, 2591 + u32 custom_params_max_idx) 2592 + { 2593 + u32 backend_workload_mask = 0; 2594 + int ret, idx = -1, i; 2595 + 2596 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 2597 + &backend_workload_mask); 2598 + 2599 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { 2600 + if (!smu->custom_profile_params) { 2601 + smu->custom_profile_params = 2602 + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL); 2603 + if (!smu->custom_profile_params) 2604 + return -ENOMEM; 2605 + } 2606 + if (custom_params && custom_params_max_idx) { 2607 + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT) 2608 + return -EINVAL; 2609 + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT) 2610 + return -EINVAL; 2611 + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT; 2612 + smu->custom_profile_params[idx] = 1; 2613 + for (i = 1; i < custom_params_max_idx; i++) 2614 + smu->custom_profile_params[idx + i] = custom_params[i]; 2615 + } 2616 + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu, 2617 + smu->custom_profile_params); 2618 + if (ret) { 2619 + if (idx != -1) 2620 + smu->custom_profile_params[idx] = 0; 2621 + return ret; 2622 + } 2623 + } else if (smu->custom_profile_params) { 2624 + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE); 2625 + } 2598 2626 2599 2627 ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 2600 - smu->workload_mask, NULL); 2628 + backend_workload_mask, NULL); 2601 2629 2602 - if (ret) 2603 - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); 2604 - else 2605 - smu_cmn_assign_power_profile(smu); 2630 + if (ret) { 2631 + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", 2632 + workload_mask); 2633 + if (idx != -1) 2634 + smu->custom_profile_params[idx] = 0; 2635 + return ret; 2636 + } 2606 2637 2607 2638 return ret; 2608 2639 }
+100 -69
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
··· 1739 1739 return size; 1740 1740 } 1741 1741 1742 - static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu, 1743 - long *input, 1744 - uint32_t size) 1742 + #define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9 1743 + #define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2 1744 + #define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long)) 1745 + 1746 + static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu, 1747 + long *input) 1745 1748 { 1746 1749 DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; 1747 1750 DpmActivityMonitorCoeffInt_t *activity_monitor = 1748 1751 &(activity_monitor_external.DpmActivityMonitorCoeffInt); 1749 - int workload_type, ret = 0; 1750 - uint32_t current_profile_mode = smu->power_profile_mode; 1751 - smu->power_profile_mode = input[size]; 1752 + int ret, idx; 1752 1753 1753 - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { 1754 - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); 1755 - return -EINVAL; 1754 + ret = smu_cmn_update_table(smu, 1755 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1756 + WORKLOAD_PPLIB_CUSTOM_BIT, 1757 + (void *)(&activity_monitor_external), 1758 + false); 1759 + if (ret) { 1760 + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 1761 + return ret; 1756 1762 } 1757 1763 1758 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { 1759 - if (size != 9) 1760 - return -EINVAL; 1761 - 1762 - ret = smu_cmn_update_table(smu, 1763 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1764 - WORKLOAD_PPLIB_CUSTOM_BIT, 1765 - (void *)(&activity_monitor_external), 1766 - false); 1767 - if (ret) { 1768 - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); 1769 - return ret; 1770 - } 1771 - 1772 - switch (input[0]) { 1773 - case 0: /* Gfxclk */ 1774 - activity_monitor->Gfx_FPS = input[1]; 1775 - activity_monitor->Gfx_MinActiveFreqType = input[2]; 1776 - activity_monitor->Gfx_MinActiveFreq = input[3]; 1777 - activity_monitor->Gfx_BoosterFreqType = input[4]; 1778 - activity_monitor->Gfx_BoosterFreq = input[5]; 1779 - activity_monitor->Gfx_PD_Data_limit_c = input[6]; 1780 - activity_monitor->Gfx_PD_Data_error_coeff = input[7]; 1781 - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8]; 1782 - break; 1783 - case 1: /* Fclk */ 1784 - activity_monitor->Fclk_FPS = input[1]; 1785 - activity_monitor->Fclk_MinActiveFreqType = input[2]; 1786 - activity_monitor->Fclk_MinActiveFreq = input[3]; 1787 - activity_monitor->Fclk_BoosterFreqType = input[4]; 1788 - activity_monitor->Fclk_BoosterFreq = input[5]; 1789 - activity_monitor->Fclk_PD_Data_limit_c = input[6]; 1790 - activity_monitor->Fclk_PD_Data_error_coeff = input[7]; 1791 - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8]; 1792 - break; 1793 - default: 1794 - return -EINVAL; 1795 - } 1796 - 1797 - ret = smu_cmn_update_table(smu, 1798 - SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1799 - WORKLOAD_PPLIB_CUSTOM_BIT, 1800 - (void *)(&activity_monitor_external), 1801 - true); 1802 - if (ret) { 1803 - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 1804 - return ret; 1805 - } 1764 + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT; 1765 + if (input[idx]) { 1766 + /* Gfxclk */ 1767 + activity_monitor->Gfx_FPS = input[idx + 1]; 1768 + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2]; 1769 + activity_monitor->Gfx_MinActiveFreq = input[idx + 3]; 1770 + activity_monitor->Gfx_BoosterFreqType = input[idx + 4]; 1771 + activity_monitor->Gfx_BoosterFreq = input[idx + 5]; 1772 + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6]; 1773 + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7]; 1774 + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8]; 1775 + } 1776 + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT; 1777 + if (input[idx]) { 1778 + /* Fclk */ 1779 + activity_monitor->Fclk_FPS = input[idx + 1]; 1780 + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2]; 1781 + activity_monitor->Fclk_MinActiveFreq = input[idx + 3]; 1782 + activity_monitor->Fclk_BoosterFreqType = input[idx + 4]; 1783 + activity_monitor->Fclk_BoosterFreq = input[idx + 5]; 1784 + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6]; 1785 + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7]; 1786 + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8]; 1806 1787 } 1807 1788 1808 - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) 1789 + ret = smu_cmn_update_table(smu, 1790 + SMU_TABLE_ACTIVITY_MONITOR_COEFF, 1791 + WORKLOAD_PPLIB_CUSTOM_BIT, 1792 + (void *)(&activity_monitor_external), 1793 + true); 1794 + if (ret) { 1795 + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); 1796 + return ret; 1797 + } 1798 + 1799 + return ret; 1800 + } 1801 + 1802 + static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu, 1803 + u32 workload_mask, 1804 + long *custom_params, 1805 + u32 custom_params_max_idx) 1806 + { 1807 + u32 backend_workload_mask = 0; 1808 + int ret, idx = -1, i; 1809 + 1810 + smu_cmn_get_backend_workload_mask(smu, workload_mask, 1811 + &backend_workload_mask); 1812 + 1813 + /* disable deep sleep if compute is enabled */ 1814 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE)) 1809 1815 smu_v14_0_deep_sleep_control(smu, false); 1810 - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) 1816 + else 1811 1817 smu_v14_0_deep_sleep_control(smu, true); 1812 1818 1813 - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 1814 - workload_type = smu_cmn_to_asic_specific_index(smu, 1815 - CMN2ASIC_MAPPING_WORKLOAD, 1816 - smu->power_profile_mode); 1817 - if (workload_type < 0) 1818 - return -EINVAL; 1819 + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { 1820 + if (!smu->custom_profile_params) { 1821 + smu->custom_profile_params = 1822 + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL); 1823 + if (!smu->custom_profile_params) 1824 + return -ENOMEM; 1825 + } 1826 + if (custom_params && custom_params_max_idx) { 1827 + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT) 1828 + return -EINVAL; 1829 + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT) 1830 + return -EINVAL; 1831 + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT; 1832 + smu->custom_profile_params[idx] = 1; 1833 + for (i = 1; i < custom_params_max_idx; i++) 1834 + smu->custom_profile_params[idx + i] = custom_params[i]; 1835 + } 1836 + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu, 1837 + smu->custom_profile_params); 1838 + if (ret) { 1839 + if (idx != -1) 1840 + smu->custom_profile_params[idx] = 0; 1841 + return ret; 1842 + } 1843 + } else if (smu->custom_profile_params) { 1844 + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE); 1845 + } 1819 1846 1820 1847 ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 1821 - smu->workload_mask, NULL); 1822 - 1823 - if (!ret) 1824 - smu_cmn_assign_power_profile(smu); 1848 + backend_workload_mask, NULL); 1849 + if (ret) { 1850 + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", 1851 + workload_mask); 1852 + if (idx != -1) 1853 + smu->custom_profile_params[idx] = 0; 1854 + return ret; 1855 + } 1825 1856 1826 1857 return ret; 1827 1858 }
+25 -8
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
··· 1144 1144 return ret; 1145 1145 } 1146 1146 1147 - void smu_cmn_assign_power_profile(struct smu_context *smu) 1148 - { 1149 - uint32_t index; 1150 - index = fls(smu->workload_mask); 1151 - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; 1152 - smu->power_profile_mode = smu->workload_setting[index]; 1153 - } 1154 - 1155 1147 bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) 1156 1148 { 1157 1149 struct pci_dev *p = NULL; ··· 1220 1228 void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy) 1221 1229 { 1222 1230 policy->desc = &xgmi_plpd_policy_desc; 1231 + } 1232 + 1233 + void smu_cmn_get_backend_workload_mask(struct smu_context *smu, 1234 + u32 workload_mask, 1235 + u32 *backend_workload_mask) 1236 + { 1237 + int workload_type; 1238 + u32 profile_mode; 1239 + 1240 + *backend_workload_mask = 0; 1241 + 1242 + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) { 1243 + if (!(workload_mask & (1 << profile_mode))) 1244 + continue; 1245 + 1246 + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ 1247 + workload_type = smu_cmn_to_asic_specific_index(smu, 1248 + CMN2ASIC_MAPPING_WORKLOAD, 1249 + profile_mode); 1250 + 1251 + if (workload_type < 0) 1252 + continue; 1253 + 1254 + *backend_workload_mask |= 1 << workload_type; 1255 + } 1223 1256 }
+4 -2
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
··· 130 130 int smu_cmn_set_mp1_state(struct smu_context *smu, 131 131 enum pp_mp1_state mp1_state); 132 132 133 - void smu_cmn_assign_power_profile(struct smu_context *smu); 134 - 135 133 /* 136 134 * Helper function to make sysfs_emit_at() happy. Align buf to 137 135 * the current page boundary and record the offset. ··· 146 148 bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev); 147 149 void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy); 148 150 void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy); 151 + 152 + void smu_cmn_get_backend_workload_mask(struct smu_context *smu, 153 + u32 workload_mask, 154 + u32 *backend_workload_mask); 149 155 150 156 #endif 151 157 #endif