mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-05 10:04:12 +08:00
Merge tag 'amd-drm-next-5.12-2021-01-08' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-5.12-2021-01-08: amdgpu: - Rework IH ring handling on vega and navi - Rework HDP handling for vega and navi - swSMU documenation updates - Overdrive support for Sienna Cichlid and newer asics - swSMU updates for vangogh - swSMU updates for renoir - Enable FP16 on DCE8-11 - Misc code cleanups and bug fixes radeon: - Fixes for platforms that can't access PCI resources correctly - Misc code cleanups From: Alex Deucher <alexdeucher@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210108221811.3868-1-alexander.deucher@amd.com Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
commit
2ce542e517
@ -71,7 +71,7 @@ amdgpu-y += \
|
||||
vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
|
||||
vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \
|
||||
arct_reg_init.o navi12_reg_init.o mxgpu_nv.o sienna_cichlid_reg_init.o vangogh_reg_init.o \
|
||||
nbio_v7_2.o dimgrey_cavefish_reg_init.o
|
||||
nbio_v7_2.o dimgrey_cavefish_reg_init.o hdp_v4_0.o hdp_v5_0.o
|
||||
|
||||
# add DF block
|
||||
amdgpu-y += \
|
||||
@ -97,6 +97,7 @@ amdgpu-y += \
|
||||
tonga_ih.o \
|
||||
cz_ih.o \
|
||||
vega10_ih.o \
|
||||
vega20_ih.o \
|
||||
navi10_ih.o
|
||||
|
||||
# add PSP block
|
||||
|
@ -88,6 +88,7 @@
|
||||
#include "amdgpu_gfx.h"
|
||||
#include "amdgpu_sdma.h"
|
||||
#include "amdgpu_nbio.h"
|
||||
#include "amdgpu_hdp.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "amdgpu_virt.h"
|
||||
#include "amdgpu_csa.h"
|
||||
@ -106,6 +107,7 @@
|
||||
#include "amdgpu_gfxhub.h"
|
||||
#include "amdgpu_df.h"
|
||||
#include "amdgpu_smuio.h"
|
||||
#include "amdgpu_hdp.h"
|
||||
|
||||
#define MAX_GPU_INSTANCE 16
|
||||
|
||||
@ -607,7 +609,6 @@ struct amdgpu_asic_funcs {
|
||||
/* invalidate hdp read cache */
|
||||
void (*invalidate_hdp)(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring);
|
||||
void (*reset_hdp_ras_error_count)(struct amdgpu_device *adev);
|
||||
/* check if the asic needs a full reset of if soft reset will work */
|
||||
bool (*need_full_reset)(struct amdgpu_device *adev);
|
||||
/* initialize doorbell layout for specific asic*/
|
||||
@ -920,6 +921,9 @@ struct amdgpu_device {
|
||||
/* nbio */
|
||||
struct amdgpu_nbio nbio;
|
||||
|
||||
/* hdp */
|
||||
struct amdgpu_hdp hdp;
|
||||
|
||||
/* smuio */
|
||||
struct amdgpu_smuio smuio;
|
||||
|
||||
@ -1201,8 +1205,10 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
||||
#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
|
||||
#define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
|
||||
#define amdgpu_asic_get_config_memsize(adev) (adev)->asic_funcs->get_config_memsize((adev))
|
||||
#define amdgpu_asic_flush_hdp(adev, r) (adev)->asic_funcs->flush_hdp((adev), (r))
|
||||
#define amdgpu_asic_invalidate_hdp(adev, r) (adev)->asic_funcs->invalidate_hdp((adev), (r))
|
||||
#define amdgpu_asic_flush_hdp(adev, r) \
|
||||
((adev)->asic_funcs->flush_hdp ? (adev)->asic_funcs->flush_hdp((adev), (r)) : (adev)->hdp.funcs->flush_hdp((adev), (r)))
|
||||
#define amdgpu_asic_invalidate_hdp(adev, r) \
|
||||
((adev)->asic_funcs->invalidate_hdp ? (adev)->asic_funcs->invalidate_hdp((adev), (r)) : (adev)->hdp.funcs->invalidate_hdp((adev), (r)))
|
||||
#define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev))
|
||||
#define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev))
|
||||
#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "gc/gc_10_1_0_offset.h"
|
||||
#include "gc/gc_10_1_0_sh_mask.h"
|
||||
#include "navi10_enum.h"
|
||||
#include "athub/athub_2_0_0_offset.h"
|
||||
#include "athub/athub_2_0_0_sh_mask.h"
|
||||
#include "oss/osssys_5_0_0_offset.h"
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "gc/gc_10_3_0_offset.h"
|
||||
#include "gc/gc_10_3_0_sh_mask.h"
|
||||
#include "navi10_enum.h"
|
||||
#include "oss/osssys_5_0_0_offset.h"
|
||||
#include "oss/osssys_5_0_0_sh_mask.h"
|
||||
#include "soc15_common.h"
|
||||
|
@ -155,7 +155,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
|
||||
u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
|
||||
int len;
|
||||
|
||||
if (!adev->asic_funcs->read_bios_from_rom)
|
||||
if (!adev->asic_funcs || !adev->asic_funcs->read_bios_from_rom)
|
||||
return false;
|
||||
|
||||
/* validate VBIOS signature */
|
||||
@ -348,7 +348,8 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return igp_read_bios_from_vram(adev);
|
||||
else
|
||||
return amdgpu_asic_read_disabled_bios(adev);
|
||||
return (!adev->asic_funcs || !adev->asic_funcs->read_disabled_bios) ?
|
||||
false : amdgpu_asic_read_disabled_bios(adev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
@ -2548,11 +2548,11 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
|
||||
if (adev->gmc.xgmi.num_physical_nodes > 1)
|
||||
amdgpu_xgmi_remove_device(adev);
|
||||
|
||||
amdgpu_amdkfd_device_fini(adev);
|
||||
|
||||
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
|
||||
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
|
||||
|
||||
amdgpu_amdkfd_device_fini(adev);
|
||||
|
||||
/* need to disable SMC first */
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.hw)
|
||||
@ -3034,7 +3034,7 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
|
||||
#endif
|
||||
default:
|
||||
if (amdgpu_dc > 0)
|
||||
DRM_INFO("Display Core has been requested via kernel parameter "
|
||||
DRM_INFO_ONCE("Display Core has been requested via kernel parameter "
|
||||
"but isn't supported by ASIC, ignoring\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
#include <linux/pci-p2pdma.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/**
|
||||
* amdgpu_gem_prime_mmap - &drm_driver.gem_prime_mmap implementation
|
||||
@ -151,9 +152,13 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
|
||||
if (attach->dev->driver == adev->dev->driver)
|
||||
return 0;
|
||||
|
||||
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = amdgpu_bo_reserve(bo, false);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We only create shared fences for internal use, but importers
|
||||
@ -165,11 +170,15 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
|
||||
*/
|
||||
r = __dma_resv_make_exclusive(bo->tbo.base.resv);
|
||||
if (r)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
bo->prime_shared_count++;
|
||||
amdgpu_bo_unreserve(bo);
|
||||
return 0;
|
||||
|
||||
out:
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,6 +198,9 @@ static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf,
|
||||
|
||||
if (attach->dev->driver != adev->dev->driver && bo->prime_shared_count)
|
||||
bo->prime_shared_count--;
|
||||
|
||||
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
40
drivers/gpu/drm/amd/amdgpu/amdgpu_hdp.h
Normal file
40
drivers/gpu/drm/amd/amdgpu/amdgpu_hdp.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef __AMDGPU_HDP_H__
|
||||
#define __AMDGPU_HDP_H__
|
||||
|
||||
struct amdgpu_hdp_funcs {
|
||||
void (*flush_hdp)(struct amdgpu_device *adev, struct amdgpu_ring *ring);
|
||||
void (*invalidate_hdp)(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring);
|
||||
void (*reset_ras_error_count)(struct amdgpu_device *adev);
|
||||
void (*update_clock_gating)(struct amdgpu_device *adev, bool enable);
|
||||
void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags);
|
||||
void (*init_registers)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_hdp {
|
||||
const struct amdgpu_hdp_funcs *funcs;
|
||||
};
|
||||
|
||||
#endif /* __AMDGPU_HDP_H__ */
|
@ -205,3 +205,46 @@ restart_ih:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_ih_decode_iv_helper - decode an interrupt vector
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Decodes the interrupt vector at the current rptr
|
||||
* position and also advance the position for for Vega10
|
||||
* and later GPUs.
|
||||
*/
|
||||
void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
/* wptr/rptr are in bytes! */
|
||||
u32 ring_index = ih->rptr >> 2;
|
||||
uint32_t dw[8];
|
||||
|
||||
dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
|
||||
dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
|
||||
dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
|
||||
dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
|
||||
dw[4] = le32_to_cpu(ih->ring[ring_index + 4]);
|
||||
dw[5] = le32_to_cpu(ih->ring[ring_index + 5]);
|
||||
dw[6] = le32_to_cpu(ih->ring[ring_index + 6]);
|
||||
dw[7] = le32_to_cpu(ih->ring[ring_index + 7]);
|
||||
|
||||
entry->client_id = dw[0] & 0xff;
|
||||
entry->src_id = (dw[0] >> 8) & 0xff;
|
||||
entry->ring_id = (dw[0] >> 16) & 0xff;
|
||||
entry->vmid = (dw[0] >> 24) & 0xf;
|
||||
entry->vmid_src = (dw[0] >> 31);
|
||||
entry->timestamp = dw[1] | ((u64)(dw[2] & 0xffff) << 32);
|
||||
entry->timestamp_src = dw[2] >> 31;
|
||||
entry->pasid = dw[3] & 0xffff;
|
||||
entry->pasid_src = dw[3] >> 31;
|
||||
entry->src_data[0] = dw[4];
|
||||
entry->src_data[1] = dw[5];
|
||||
entry->src_data[2] = dw[6];
|
||||
entry->src_data[3] = dw[7];
|
||||
|
||||
/* wptr/rptr are in bytes! */
|
||||
ih->rptr += 32;
|
||||
}
|
||||
|
@ -30,6 +30,18 @@
|
||||
struct amdgpu_device;
|
||||
struct amdgpu_iv_entry;
|
||||
|
||||
struct amdgpu_ih_regs {
|
||||
uint32_t ih_rb_base;
|
||||
uint32_t ih_rb_base_hi;
|
||||
uint32_t ih_rb_cntl;
|
||||
uint32_t ih_rb_wptr;
|
||||
uint32_t ih_rb_rptr;
|
||||
uint32_t ih_doorbell_rptr;
|
||||
uint32_t ih_rb_wptr_addr_lo;
|
||||
uint32_t ih_rb_wptr_addr_hi;
|
||||
uint32_t psp_reg_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* R6xx+ IH ring
|
||||
*/
|
||||
@ -53,6 +65,7 @@ struct amdgpu_ih_ring {
|
||||
bool enabled;
|
||||
unsigned rptr;
|
||||
atomic_t lock;
|
||||
struct amdgpu_ih_regs ih_regs;
|
||||
};
|
||||
|
||||
/* provided by the ih block */
|
||||
@ -75,5 +88,7 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
|
||||
void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
|
||||
unsigned int num_dw);
|
||||
int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
|
||||
|
||||
void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
struct amdgpu_iv_entry *entry);
|
||||
#endif
|
||||
|
@ -444,7 +444,8 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
|
||||
} else if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
|
||||
DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
|
||||
|
||||
} else if (adev->irq.virq[src_id]) {
|
||||
} else if ((client_id == AMDGPU_IRQ_CLIENTID_LEGACY) &&
|
||||
adev->irq.virq[src_id]) {
|
||||
generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
|
||||
|
||||
} else if (!adev->irq.client[client_id].sources) {
|
||||
|
@ -57,7 +57,6 @@ struct amdgpu_nbio_funcs {
|
||||
u32 (*get_pcie_port_data_offset)(struct amdgpu_device *adev);
|
||||
u32 (*get_rev_id)(struct amdgpu_device *adev);
|
||||
void (*mc_access_enable)(struct amdgpu_device *adev, bool enable);
|
||||
void (*hdp_flush)(struct amdgpu_device *adev, struct amdgpu_ring *ring);
|
||||
u32 (*get_memsize)(struct amdgpu_device *adev);
|
||||
void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance,
|
||||
bool use_doorbell, int doorbell_index, int doorbell_size);
|
||||
|
@ -249,7 +249,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
|
||||
{
|
||||
int ret;
|
||||
int index;
|
||||
int timeout = 2000;
|
||||
int timeout = 20000;
|
||||
bool ras_intr = false;
|
||||
bool skip_unsupport = false;
|
||||
|
||||
@ -282,7 +282,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
|
||||
ras_intr = amdgpu_ras_intr_triggered();
|
||||
if (ras_intr)
|
||||
break;
|
||||
msleep(1);
|
||||
usleep_range(10, 100);
|
||||
amdgpu_asic_invalidate_hdp(psp->adev, NULL);
|
||||
}
|
||||
|
||||
@ -563,7 +563,7 @@ static int psp_asd_load(struct psp_context *psp)
|
||||
* add workaround to bypass it for sriov now.
|
||||
* TODO: add version check to make it common
|
||||
*/
|
||||
if (amdgpu_sriov_vf(psp->adev) || !psp->asd_fw)
|
||||
if (amdgpu_sriov_vf(psp->adev) || !psp->asd_ucode_size)
|
||||
return 0;
|
||||
|
||||
cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
|
||||
@ -1315,8 +1315,12 @@ static int psp_hdcp_terminate(struct psp_context *psp)
|
||||
if (amdgpu_sriov_vf(psp->adev))
|
||||
return 0;
|
||||
|
||||
if (!psp->hdcp_context.hdcp_initialized)
|
||||
return 0;
|
||||
if (!psp->hdcp_context.hdcp_initialized) {
|
||||
if (psp->hdcp_context.hdcp_shared_buf)
|
||||
goto out;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = psp_hdcp_unload(psp);
|
||||
if (ret)
|
||||
@ -1324,6 +1328,7 @@ static int psp_hdcp_terminate(struct psp_context *psp)
|
||||
|
||||
psp->hdcp_context.hdcp_initialized = false;
|
||||
|
||||
out:
|
||||
/* free hdcp shared memory */
|
||||
amdgpu_bo_free_kernel(&psp->hdcp_context.hdcp_shared_bo,
|
||||
&psp->hdcp_context.hdcp_shared_mc_addr,
|
||||
@ -1462,8 +1467,12 @@ static int psp_dtm_terminate(struct psp_context *psp)
|
||||
if (amdgpu_sriov_vf(psp->adev))
|
||||
return 0;
|
||||
|
||||
if (!psp->dtm_context.dtm_initialized)
|
||||
return 0;
|
||||
if (!psp->dtm_context.dtm_initialized) {
|
||||
if (psp->dtm_context.dtm_shared_buf)
|
||||
goto out;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = psp_dtm_unload(psp);
|
||||
if (ret)
|
||||
@ -1471,6 +1480,7 @@ static int psp_dtm_terminate(struct psp_context *psp)
|
||||
|
||||
psp->dtm_context.dtm_initialized = false;
|
||||
|
||||
out:
|
||||
/* free hdcp shared memory */
|
||||
amdgpu_bo_free_kernel(&psp->dtm_context.dtm_shared_bo,
|
||||
&psp->dtm_context.dtm_shared_mc_addr,
|
||||
@ -2589,11 +2599,10 @@ static int parse_ta_bin_descriptor(struct psp_context *psp,
|
||||
|
||||
switch (desc->fw_type) {
|
||||
case TA_FW_TYPE_PSP_ASD:
|
||||
psp->asd_fw_version = le32_to_cpu(desc->fw_version);
|
||||
psp->asd_fw_version = le32_to_cpu(desc->fw_version);
|
||||
psp->asd_feature_version = le32_to_cpu(desc->fw_version);
|
||||
psp->asd_ucode_size = le32_to_cpu(desc->size_bytes);
|
||||
psp->asd_ucode_size = le32_to_cpu(desc->size_bytes);
|
||||
psp->asd_start_addr = ucode_start_addr;
|
||||
psp->asd_fw = psp->ta_fw;
|
||||
break;
|
||||
case TA_FW_TYPE_PSP_XGMI:
|
||||
psp->ta_xgmi_ucode_version = le32_to_cpu(desc->fw_version);
|
||||
|
@ -1518,7 +1518,7 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev,
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct ras_err_handler_data *data;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
int ret = 0, status;
|
||||
|
||||
if (!con || !con->eh_data || !bps || !count)
|
||||
return -EINVAL;
|
||||
@ -1543,12 +1543,12 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev,
|
||||
.size = AMDGPU_GPU_PAGE_SIZE,
|
||||
.flags = AMDGPU_RAS_RETIRE_PAGE_RESERVED,
|
||||
};
|
||||
ret = amdgpu_vram_mgr_query_page_status(
|
||||
status = amdgpu_vram_mgr_query_page_status(
|
||||
ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM),
|
||||
data->bps[i].retired_page);
|
||||
if (ret == -EBUSY)
|
||||
if (status == -EBUSY)
|
||||
(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_PENDING;
|
||||
else if (ret == -ENOENT)
|
||||
else if (status == -ENOENT)
|
||||
(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_FAULT;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define EEPROM_I2C_TARGET_ADDR_VEGA20 0xA0
|
||||
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS 0xA8
|
||||
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0xA0
|
||||
#define EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID 0xA0
|
||||
|
||||
/*
|
||||
* The 2 macros bellow represent the actual size in bytes that
|
||||
@ -62,7 +63,8 @@
|
||||
static bool __is_ras_eeprom_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
if ((adev->asic_type == CHIP_VEGA20) ||
|
||||
(adev->asic_type == CHIP_ARCTURUS))
|
||||
(adev->asic_type == CHIP_ARCTURUS) ||
|
||||
(adev->asic_type == CHIP_SIENNA_CICHLID))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -100,6 +102,10 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
|
||||
case CHIP_ARCTURUS:
|
||||
return __get_eeprom_i2c_addr_arct(adev, i2c_addr);
|
||||
|
||||
case CHIP_SIENNA_CICHLID:
|
||||
*i2c_addr = EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(_AMDGPU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#if !defined(_AMDGPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _AMDGPU_TRACE_H_
|
||||
|
||||
#include <linux/stringify.h>
|
||||
|
@ -1170,7 +1170,7 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
int r, i;
|
||||
|
||||
r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
&bo, NULL, (void **)&msg);
|
||||
if (r)
|
||||
return r;
|
||||
@ -1202,7 +1202,7 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
int r, i;
|
||||
|
||||
r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
&bo, NULL, (void **)&msg);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "athub/athub_2_0_0_offset.h"
|
||||
#include "athub/athub_2_0_0_sh_mask.h"
|
||||
#include "athub/athub_2_0_0_default.h"
|
||||
#include "navi10_enum.h"
|
||||
|
||||
#include "soc15_common.h"
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include "athub/athub_2_1_0_offset.h"
|
||||
#include "athub/athub_2_1_0_sh_mask.h"
|
||||
#include "navi10_enum.h"
|
||||
|
||||
#include "soc15_common.h"
|
||||
|
||||
|
@ -194,19 +194,30 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev,
|
||||
|
||||
wptr = le32_to_cpu(*ih->wptr_cpu);
|
||||
|
||||
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 16). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
|
||||
ih->rptr = (wptr + 16) & ih->ptr_mask;
|
||||
tmp = RREG32(mmIH_RB_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32(mmIH_RB_CNTL, tmp);
|
||||
}
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
/* Double check that the overflow wasn't already cleared. */
|
||||
wptr = RREG32(mmIH_RB_WPTR);
|
||||
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 16). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
|
||||
ih->rptr = (wptr + 16) & ih->ptr_mask;
|
||||
tmp = RREG32(mmIH_RB_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32(mmIH_RB_CNTL, tmp);
|
||||
|
||||
|
||||
out:
|
||||
return (wptr & ih->ptr_mask);
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ static int dce_virtual_get_modes(struct drm_connector *connector)
|
||||
static const struct mode_size {
|
||||
int w;
|
||||
int h;
|
||||
} common_modes[21] = {
|
||||
} common_modes[] = {
|
||||
{ 640, 480},
|
||||
{ 720, 480},
|
||||
{ 800, 600},
|
||||
@ -312,13 +312,14 @@ static int dce_virtual_get_modes(struct drm_connector *connector)
|
||||
{1600, 1200},
|
||||
{1920, 1080},
|
||||
{1920, 1200},
|
||||
{2560, 1440},
|
||||
{4096, 3112},
|
||||
{3656, 2664},
|
||||
{3840, 2160},
|
||||
{4096, 2160},
|
||||
};
|
||||
|
||||
for (i = 0; i < 21; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
|
||||
mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
}
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "smuio/smuio_11_0_0_offset.h"
|
||||
#include "smuio/smuio_11_0_0_sh_mask.h"
|
||||
#include "navi10_enum.h"
|
||||
#include "hdp/hdp_5_0_0_offset.h"
|
||||
#include "ivsrcid/gfx/irqsrcs_gfx_10_1.h"
|
||||
|
||||
#include "soc15.h"
|
||||
@ -5691,7 +5690,7 @@ static int gfx_v10_0_cp_gfx_load_pfp_microcode(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
if (amdgpu_emu_mode == 1)
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
tmp = RREG32_SOC15(GC, 0, mmCP_PFP_IC_BASE_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, CP_PFP_IC_BASE_CNTL, VMID, 0);
|
||||
@ -5769,7 +5768,7 @@ static int gfx_v10_0_cp_gfx_load_ce_microcode(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
if (amdgpu_emu_mode == 1)
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
tmp = RREG32_SOC15(GC, 0, mmCP_CE_IC_BASE_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, CP_CE_IC_BASE_CNTL, VMID, 0);
|
||||
@ -5846,7 +5845,7 @@ static int gfx_v10_0_cp_gfx_load_me_microcode(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
if (amdgpu_emu_mode == 1)
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
tmp = RREG32_SOC15(GC, 0, mmCP_ME_IC_BASE_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, CP_ME_IC_BASE_CNTL, VMID, 0);
|
||||
@ -6215,7 +6214,7 @@ static int gfx_v10_0_cp_compute_load_microcode(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
if (amdgpu_emu_mode == 1)
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
tmp = RREG32_SOC15(GC, 0, mmCP_CPC_IC_BASE_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "gc/gc_9_0_sh_mask.h"
|
||||
|
||||
#include "vega10_enum.h"
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
|
||||
#include "soc15_common.h"
|
||||
#include "clearstate_gfx9.h"
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include "gmc_v10_0.h"
|
||||
#include "umc_v8_7.h"
|
||||
|
||||
#include "hdp/hdp_5_0_0_offset.h"
|
||||
#include "hdp/hdp_5_0_0_sh_mask.h"
|
||||
#include "athub/athub_2_0_0_sh_mask.h"
|
||||
#include "athub/athub_2_0_0_offset.h"
|
||||
#include "dcn/dcn_2_0_0_offset.h"
|
||||
@ -312,7 +310,7 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
int r;
|
||||
|
||||
/* flush hdp cache */
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
/* For SRIOV run time, driver shouldn't access the register through MMIO
|
||||
* Directly use kiq to do the vm invalidation instead
|
||||
@ -995,7 +993,6 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev)
|
||||
{
|
||||
int r;
|
||||
bool value;
|
||||
u32 tmp;
|
||||
|
||||
if (adev->gart.bo == NULL) {
|
||||
dev_err(adev->dev, "No VRAM object for PCIE GART.\n");
|
||||
@ -1014,15 +1011,10 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_MISC_CNTL);
|
||||
tmp |= HDP_MISC_CNTL__FLUSH_INVALIDATE_CACHE_MASK;
|
||||
WREG32_SOC15(HDP, 0, mmHDP_MISC_CNTL, tmp);
|
||||
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL);
|
||||
WREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL, tmp);
|
||||
adev->hdp.funcs->init_registers(adev);
|
||||
|
||||
/* Flush HDP after it is initialized */
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
value = (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) ?
|
||||
false : true;
|
||||
|
@ -31,8 +31,6 @@
|
||||
#include "amdgpu_atomfirmware.h"
|
||||
#include "amdgpu_gem.h"
|
||||
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
#include "hdp/hdp_4_0_sh_mask.h"
|
||||
#include "gc/gc_9_0_sh_mask.h"
|
||||
#include "dce/dce_12_0_offset.h"
|
||||
#include "dce/dce_12_0_sh_mask.h"
|
||||
@ -283,20 +281,6 @@ static const char *mmhub_client_ids_arcturus[][2] = {
|
||||
[224+15][1] = "SDMA7",
|
||||
};
|
||||
|
||||
static const u32 golden_settings_vega10_hdp[] =
|
||||
{
|
||||
0xf64, 0x0fffffff, 0x00000000,
|
||||
0xf65, 0x0fffffff, 0x00000000,
|
||||
0xf66, 0x0fffffff, 0x00000000,
|
||||
0xf67, 0x0fffffff, 0x00000000,
|
||||
0xf68, 0x0fffffff, 0x00000000,
|
||||
0xf6a, 0x0fffffff, 0x00000000,
|
||||
0xf6b, 0x0fffffff, 0x00000000,
|
||||
0xf6c, 0x0fffffff, 0x00000000,
|
||||
0xf6d, 0x0fffffff, 0x00000000,
|
||||
0xf6e, 0x0fffffff, 0x00000000,
|
||||
};
|
||||
|
||||
static const struct soc15_reg_golden golden_settings_mmhub_1_0_0[] =
|
||||
{
|
||||
SOC15_REG_GOLDEN_VALUE(MMHUB, 0, mmDAGB1_WRCLI2, 0x00000007, 0xfe5fe0fa),
|
||||
@ -1571,7 +1555,6 @@ static int gmc_v9_0_hw_init(void *handle)
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
bool value;
|
||||
int r, i;
|
||||
u32 tmp;
|
||||
|
||||
/* The sequence of these two function calls matters.*/
|
||||
gmc_v9_0_init_golden_registers(adev);
|
||||
@ -1583,31 +1566,13 @@ static int gmc_v9_0_hw_init(void *handle)
|
||||
WREG32_FIELD15(DCE, 0, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 0);
|
||||
}
|
||||
|
||||
amdgpu_device_program_register_sequence(adev,
|
||||
golden_settings_vega10_hdp,
|
||||
ARRAY_SIZE(golden_settings_vega10_hdp));
|
||||
|
||||
if (adev->mmhub.funcs->update_power_gating)
|
||||
adev->mmhub.funcs->update_power_gating(adev, true);
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_ARCTURUS:
|
||||
WREG32_FIELD15(HDP, 0, HDP_MMHUB_CNTL, HDP_MMHUB_GCC, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
WREG32_FIELD15(HDP, 0, HDP_MISC_CNTL, FLUSH_INVALIDATE_CACHE, 1);
|
||||
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL);
|
||||
WREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL, tmp);
|
||||
|
||||
WREG32_SOC15(HDP, 0, mmHDP_NONSURFACE_BASE, (adev->gmc.vram_start >> 8));
|
||||
WREG32_SOC15(HDP, 0, mmHDP_NONSURFACE_BASE_HI, (adev->gmc.vram_start >> 40));
|
||||
adev->hdp.funcs->init_registers(adev);
|
||||
|
||||
/* After HDP is initialized, flush HDP.*/
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
|
||||
if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS)
|
||||
value = false;
|
||||
|
137
drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c
Normal file
137
drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_atombios.h"
|
||||
#include "hdp_v4_0.h"
|
||||
#include "amdgpu_ras.h"
|
||||
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
#include "hdp/hdp_4_0_sh_mask.h"
|
||||
#include <uapi/linux/kfd_ioctl.h>
|
||||
|
||||
/* for Vega20 register name change */
|
||||
#define mmHDP_MEM_POWER_CTRL 0x00d4
|
||||
#define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK 0x00000001L
|
||||
#define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK 0x00000002L
|
||||
#define HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK 0x00010000L
|
||||
#define HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK 0x00020000L
|
||||
#define mmHDP_MEM_POWER_CTRL_BASE_IDX 0
|
||||
|
||||
static void hdp_v4_0_flush_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
}
|
||||
|
||||
static void hdp_v4_0_invalidate_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET(
|
||||
HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1);
|
||||
}
|
||||
|
||||
static void hdp_v4_0_reset_ras_error_count(struct amdgpu_device *adev)
|
||||
{
|
||||
if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__HDP))
|
||||
return;
|
||||
/*read back hdp ras counter to reset it to 0 */
|
||||
RREG32_SOC15(HDP, 0, mmHDP_EDC_CNT);
|
||||
}
|
||||
|
||||
static void hdp_v4_0_update_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t def, data;
|
||||
|
||||
if (adev->asic_type == CHIP_VEGA10 ||
|
||||
adev->asic_type == CHIP_VEGA12 ||
|
||||
adev->asic_type == CHIP_RAVEN) {
|
||||
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS));
|
||||
|
||||
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
||||
data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK;
|
||||
else
|
||||
data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK;
|
||||
|
||||
if (def != data)
|
||||
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS), data);
|
||||
} else {
|
||||
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL));
|
||||
|
||||
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
||||
data |= HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK;
|
||||
else
|
||||
data &= ~(HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK);
|
||||
|
||||
if (def != data)
|
||||
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void hdp_v4_0_get_clockgating_state(struct amdgpu_device *adev,
|
||||
u32 *flags)
|
||||
{
|
||||
int data;
|
||||
|
||||
/* AMD_CG_SUPPORT_HDP_LS */
|
||||
data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS));
|
||||
if (data & HDP_MEM_POWER_LS__LS_ENABLE_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_LS;
|
||||
}
|
||||
|
||||
static void hdp_v4_0_init_registers(struct amdgpu_device *adev)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_ARCTURUS:
|
||||
WREG32_FIELD15(HDP, 0, HDP_MMHUB_CNTL, HDP_MMHUB_GCC, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
WREG32_FIELD15(HDP, 0, HDP_MISC_CNTL, FLUSH_INVALIDATE_CACHE, 1);
|
||||
|
||||
WREG32_SOC15(HDP, 0, mmHDP_NONSURFACE_BASE, (adev->gmc.vram_start >> 8));
|
||||
WREG32_SOC15(HDP, 0, mmHDP_NONSURFACE_BASE_HI, (adev->gmc.vram_start >> 40));
|
||||
}
|
||||
|
||||
const struct amdgpu_hdp_funcs hdp_v4_0_funcs = {
|
||||
.flush_hdp = hdp_v4_0_flush_hdp,
|
||||
.invalidate_hdp = hdp_v4_0_invalidate_hdp,
|
||||
.reset_ras_error_count = hdp_v4_0_reset_ras_error_count,
|
||||
.update_clock_gating = hdp_v4_0_update_clock_gating,
|
||||
.get_clock_gating_state = hdp_v4_0_get_clockgating_state,
|
||||
.init_registers = hdp_v4_0_init_registers,
|
||||
};
|
31
drivers/gpu/drm/amd/amdgpu/hdp_v4_0.h
Normal file
31
drivers/gpu/drm/amd/amdgpu/hdp_v4_0.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HDP_V4_0_H__
|
||||
#define __HDP_V4_0_H__
|
||||
|
||||
#include "soc15_common.h"
|
||||
|
||||
extern const struct amdgpu_hdp_funcs hdp_v4_0_funcs;
|
||||
|
||||
#endif
|
212
drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c
Normal file
212
drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_atombios.h"
|
||||
#include "hdp_v5_0.h"
|
||||
|
||||
#include "hdp/hdp_5_0_0_offset.h"
|
||||
#include "hdp/hdp_5_0_0_sh_mask.h"
|
||||
#include <uapi/linux/kfd_ioctl.h>
|
||||
|
||||
static void hdp_v5_0_flush_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
}
|
||||
|
||||
static void hdp_v5_0_invalidate_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg) {
|
||||
WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1);
|
||||
} else {
|
||||
amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET(
|
||||
HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void hdp_v5_0_update_mem_power_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t hdp_clk_cntl, hdp_clk_cntl1;
|
||||
uint32_t hdp_mem_pwr_cntl;
|
||||
|
||||
if (!(adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS |
|
||||
AMD_CG_SUPPORT_HDP_DS |
|
||||
AMD_CG_SUPPORT_HDP_SD)))
|
||||
return;
|
||||
|
||||
hdp_clk_cntl = hdp_clk_cntl1 = RREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL);
|
||||
hdp_mem_pwr_cntl = RREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL);
|
||||
|
||||
/* Before doing clock/power mode switch,
|
||||
* forced on IPH & RC clock */
|
||||
hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
|
||||
IPH_MEM_CLK_SOFT_OVERRIDE, 1);
|
||||
hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
|
||||
RC_MEM_CLK_SOFT_OVERRIDE, 1);
|
||||
WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl);
|
||||
|
||||
/* HDP 5.0 doesn't support dynamic power mode switch,
|
||||
* disable clock and power gating before any changing */
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_CTRL_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_LS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_DS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_SD_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_CTRL_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_LS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_DS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_SD_EN, 0);
|
||||
WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
|
||||
|
||||
/* only one clock gating mode (LS/DS/SD) can be enabled */
|
||||
if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_LS_EN, enable);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_LS_EN, enable);
|
||||
} else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_DS_EN, enable);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_DS_EN, enable);
|
||||
} else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_SD_EN, enable);
|
||||
/* RC should not use shut down mode, fallback to ds */
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_DS_EN, enable);
|
||||
}
|
||||
|
||||
/* confirmed that IPH_MEM_POWER_CTRL_EN and RC_MEM_POWER_CTRL_EN have to
|
||||
* be set for SRAM LS/DS/SD */
|
||||
if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS |
|
||||
AMD_CG_SUPPORT_HDP_SD)) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_CTRL_EN, 1);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_CTRL_EN, 1);
|
||||
}
|
||||
|
||||
WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
|
||||
|
||||
/* restore IPH & RC clock override after clock/power mode changing */
|
||||
WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl1);
|
||||
}
|
||||
|
||||
static void hdp_v5_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t hdp_clk_cntl;
|
||||
|
||||
if (!(adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG))
|
||||
return;
|
||||
|
||||
hdp_clk_cntl = RREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL);
|
||||
|
||||
if (enable) {
|
||||
hdp_clk_cntl &=
|
||||
~(uint32_t)
|
||||
(HDP_CLK_CNTL__IPH_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK);
|
||||
} else {
|
||||
hdp_clk_cntl |= HDP_CLK_CNTL__IPH_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK;
|
||||
}
|
||||
|
||||
WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl);
|
||||
}
|
||||
|
||||
static void hdp_v5_0_update_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
hdp_v5_0_update_mem_power_gating(adev, enable);
|
||||
hdp_v5_0_update_medium_grain_clock_gating(adev, enable);
|
||||
}
|
||||
|
||||
static void hdp_v5_0_get_clockgating_state(struct amdgpu_device *adev,
|
||||
u32 *flags)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
/* AMD_CG_SUPPORT_HDP_MGCG */
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL);
|
||||
if (!(tmp & (HDP_CLK_CNTL__IPH_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK)))
|
||||
*flags |= AMD_CG_SUPPORT_HDP_MGCG;
|
||||
|
||||
/* AMD_CG_SUPPORT_HDP_LS/DS/SD */
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL);
|
||||
if (tmp & HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_LS;
|
||||
else if (tmp & HDP_MEM_POWER_CTRL__IPH_MEM_POWER_DS_EN_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_DS;
|
||||
else if (tmp & HDP_MEM_POWER_CTRL__IPH_MEM_POWER_SD_EN_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_SD;
|
||||
}
|
||||
|
||||
static void hdp_v5_0_init_registers(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_MISC_CNTL);
|
||||
tmp |= HDP_MISC_CNTL__FLUSH_INVALIDATE_CACHE_MASK;
|
||||
WREG32_SOC15(HDP, 0, mmHDP_MISC_CNTL, tmp);
|
||||
}
|
||||
|
||||
const struct amdgpu_hdp_funcs hdp_v5_0_funcs = {
|
||||
.flush_hdp = hdp_v5_0_flush_hdp,
|
||||
.invalidate_hdp = hdp_v5_0_invalidate_hdp,
|
||||
.update_clock_gating = hdp_v5_0_update_clock_gating,
|
||||
.get_clock_gating_state = hdp_v5_0_get_clockgating_state,
|
||||
.init_registers = hdp_v5_0_init_registers,
|
||||
};
|
31
drivers/gpu/drm/amd/amdgpu/hdp_v5_0.h
Normal file
31
drivers/gpu/drm/amd/amdgpu/hdp_v5_0.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HDP_V5_0_H__
|
||||
#define __HDP_V5_0_H__
|
||||
|
||||
#include "soc15_common.h"
|
||||
|
||||
extern const struct amdgpu_hdp_funcs hdp_v5_0_funcs;
|
||||
|
||||
#endif
|
@ -194,19 +194,29 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev,
|
||||
|
||||
wptr = le32_to_cpu(*ih->wptr_cpu);
|
||||
|
||||
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 16). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
|
||||
ih->rptr = (wptr + 16) & ih->ptr_mask;
|
||||
tmp = RREG32(mmIH_RB_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32(mmIH_RB_CNTL, tmp);
|
||||
}
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
/* Double check that the overflow wasn't already cleared. */
|
||||
wptr = RREG32(mmIH_RB_WPTR);
|
||||
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 16). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
|
||||
ih->rptr = (wptr + 16) & ih->ptr_mask;
|
||||
tmp = RREG32(mmIH_RB_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32(mmIH_RB_CNTL, tmp);
|
||||
|
||||
|
||||
out:
|
||||
return (wptr & ih->ptr_mask);
|
||||
}
|
||||
|
||||
|
@ -310,7 +310,7 @@ static void mmhub_v2_3_setup_vmid_config(struct amdgpu_device *adev)
|
||||
/* Send no-retry XNACK on fault to suppress VM fault storm. */
|
||||
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
|
||||
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
|
||||
!amdgpu_noretry);
|
||||
!adev->gmc.noretry);
|
||||
WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_CNTL,
|
||||
i * hub->ctx_distance, tmp);
|
||||
WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,
|
||||
|
@ -39,6 +39,53 @@
|
||||
|
||||
static void navi10_ih_set_interrupt_funcs(struct amdgpu_device *adev);
|
||||
|
||||
/**
|
||||
* navi10_ih_init_register_offset - Initialize register offset for ih rings
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Initialize register offset ih rings (NAVI10).
|
||||
*/
|
||||
static void navi10_ih_init_register_offset(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (adev->irq.ih.ring_size) {
|
||||
ih_regs = &adev->irq.ih.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR);
|
||||
ih_regs->ih_rb_wptr_addr_lo = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO);
|
||||
ih_regs->ih_rb_wptr_addr_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL;
|
||||
}
|
||||
|
||||
if (adev->irq.ih1.ring_size) {
|
||||
ih_regs = &adev->irq.ih1.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING1);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING1);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING1;
|
||||
}
|
||||
|
||||
if (adev->irq.ih2.ring_size) {
|
||||
ih_regs = &adev->irq.ih2.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING2);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING2);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* force_update_wptr_for_self_int - Force update the wptr for self interrupt
|
||||
*
|
||||
@ -82,133 +129,66 @@ force_update_wptr_for_self_int(struct amdgpu_device *adev,
|
||||
}
|
||||
|
||||
/**
|
||||
* navi10_ih_enable_interrupts - Enable the interrupt ring buffer
|
||||
* navi10_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: amdgpu_ih_ring pointet
|
||||
* @enable: true - enable the interrupts, false - disable the interrupts
|
||||
*
|
||||
* Enable the interrupt ring buffer (NAVI10).
|
||||
* Toggle the interrupt ring buffer (NAVI10)
|
||||
*/
|
||||
static void navi10_ih_enable_interrupts(struct amdgpu_device *adev)
|
||||
static int navi10_ih_toggle_ring_interrupts(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
bool enable)
|
||||
{
|
||||
u32 ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
uint32_t tmp;
|
||||
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) {
|
||||
DRM_ERROR("PSP program IH_RB_CNTL failed!\n");
|
||||
return;
|
||||
}
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
tmp = RREG32(ih_regs->ih_rb_cntl);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
|
||||
/* enable_intr field is only valid in ring0 */
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0));
|
||||
WREG32(ih_regs->ih_rb_cntl, tmp);
|
||||
|
||||
if (enable) {
|
||||
ih->enabled = true;
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32(ih_regs->ih_rb_rptr, 0);
|
||||
WREG32(ih_regs->ih_rb_wptr, 0);
|
||||
ih->enabled = false;
|
||||
ih->rptr = 0;
|
||||
}
|
||||
|
||||
adev->irq.ih.enabled = true;
|
||||
|
||||
if (adev->irq.ih1.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
|
||||
RB_ENABLE, 1);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
|
||||
}
|
||||
adev->irq.ih1.enabled = true;
|
||||
}
|
||||
|
||||
if (adev->irq.ih2.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
|
||||
RB_ENABLE, 1);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
|
||||
}
|
||||
adev->irq.ih2.enabled = true;
|
||||
}
|
||||
|
||||
if (adev->irq.ih_soft.ring_size)
|
||||
adev->irq.ih_soft.enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* navi10_ih_disable_interrupts - Disable the interrupt ring buffer
|
||||
* navi10_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @enable: enable or disable interrupt ring buffers
|
||||
*
|
||||
* Disable the interrupt ring buffer (NAVI10).
|
||||
* Toggle all the available interrupt ring buffers (NAVI10).
|
||||
*/
|
||||
static void navi10_ih_disable_interrupts(struct amdgpu_device *adev)
|
||||
static int navi10_ih_toggle_interrupts(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
u32 ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
|
||||
int i;
|
||||
int r;
|
||||
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) {
|
||||
DRM_ERROR("PSP program IH_RB_CNTL failed!\n");
|
||||
return;
|
||||
for (i = 0; i < ARRAY_SIZE(ih); i++) {
|
||||
if (ih[i]->ring_size) {
|
||||
r = navi10_ih_toggle_ring_interrupts(adev, ih[i], enable);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
|
||||
adev->irq.ih.enabled = false;
|
||||
adev->irq.ih.rptr = 0;
|
||||
|
||||
if (adev->irq.ih1.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
|
||||
RB_ENABLE, 0);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
|
||||
}
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
|
||||
adev->irq.ih1.enabled = false;
|
||||
adev->irq.ih1.rptr = 0;
|
||||
}
|
||||
|
||||
if (adev->irq.ih2.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
|
||||
RB_ENABLE, 0);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
|
||||
}
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
|
||||
adev->irq.ih2.enabled = false;
|
||||
adev->irq.ih2.rptr = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
|
||||
@ -253,22 +233,49 @@ static uint32_t navi10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
|
||||
return ih_doorbell_rtpr;
|
||||
}
|
||||
|
||||
static void navi10_ih_reroute_ih(struct amdgpu_device *adev)
|
||||
/**
|
||||
* navi10_ih_enable_ring - enable an ih ring buffer
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: amdgpu_ih_ring pointer
|
||||
*
|
||||
* Enable an ih ring buffer (NAVI10)
|
||||
*/
|
||||
static int navi10_ih_enable_ring(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
uint32_t tmp;
|
||||
|
||||
/* Reroute to IH ring 1 for VMC */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12);
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
/* Reroute IH ring 1 for UMC */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B);
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
|
||||
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
|
||||
WREG32(ih_regs->ih_rb_base, ih->gpu_addr >> 8);
|
||||
WREG32(ih_regs->ih_rb_base_hi, (ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
tmp = RREG32(ih_regs->ih_rb_cntl);
|
||||
tmp = navi10_ih_rb_cntl(ih, tmp);
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RPTR_REARM, !!adev->irq.msi_enabled);
|
||||
if (ih == &adev->irq.ih1) {
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 0);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_FULL_DRAIN_ENABLE, 1);
|
||||
}
|
||||
WREG32(ih_regs->ih_rb_cntl, tmp);
|
||||
|
||||
if (ih == &adev->irq.ih) {
|
||||
/* set the ih ring 0 writeback address whether it's enabled or not */
|
||||
WREG32(ih_regs->ih_rb_wptr_addr_lo, lower_32_bits(ih->wptr_addr));
|
||||
WREG32(ih_regs->ih_rb_wptr_addr_hi, upper_32_bits(ih->wptr_addr) & 0xFFFF);
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32(ih_regs->ih_rb_wptr, 0);
|
||||
WREG32(ih_regs->ih_rb_rptr, 0);
|
||||
|
||||
WREG32(ih_regs->ih_doorbell_rptr, navi10_ih_doorbell_rptr(ih));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -284,36 +291,21 @@ static void navi10_ih_reroute_ih(struct amdgpu_device *adev)
|
||||
*/
|
||||
static int navi10_ih_irq_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ih_ring *ih = &adev->irq.ih;
|
||||
u32 ih_rb_cntl, ih_chicken;
|
||||
struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
|
||||
u32 ih_chicken;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* disable irqs */
|
||||
navi10_ih_disable_interrupts(adev);
|
||||
ret = navi10_ih_toggle_interrupts(adev, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adev->nbio.funcs->ih_control(adev);
|
||||
|
||||
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, ih->gpu_addr >> 8);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, (ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM,
|
||||
!!adev->irq.msi_enabled);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) {
|
||||
DRM_ERROR("PSP program IH_RB_CNTL failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
|
||||
}
|
||||
if (adev->irq.ih1.ring_size)
|
||||
navi10_ih_reroute_ih(adev);
|
||||
|
||||
if (unlikely(adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT)) {
|
||||
if (ih->use_bus_addr) {
|
||||
if (ih[0]->use_bus_addr) {
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_SIENNA_CICHLID:
|
||||
case CHIP_NAVY_FLOUNDER:
|
||||
@ -334,77 +326,17 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
/* set the writeback address whether it's enabled or not */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO,
|
||||
lower_32_bits(ih->wptr_addr));
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI,
|
||||
upper_32_bits(ih->wptr_addr) & 0xFFFF);
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
|
||||
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR,
|
||||
navi10_ih_doorbell_rptr(ih));
|
||||
|
||||
adev->nbio.funcs->ih_doorbell_range(adev, ih->use_doorbell,
|
||||
ih->doorbell_index);
|
||||
|
||||
ih = &adev->irq.ih1;
|
||||
if (ih->ring_size) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING1, ih->gpu_addr >> 8);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING1,
|
||||
(ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
WPTR_OVERFLOW_ENABLE, 0);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
RB_FULL_DRAIN_ENABLE, 1);
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
|
||||
for (i = 0; i < ARRAY_SIZE(ih); i++) {
|
||||
if (ih[i]->ring_size) {
|
||||
ret = navi10_ih_enable_ring(adev, ih[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
|
||||
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1,
|
||||
navi10_ih_doorbell_rptr(ih));
|
||||
}
|
||||
|
||||
ih = &adev->irq.ih2;
|
||||
if (ih->ring_size) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING2, ih->gpu_addr >> 8);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING2,
|
||||
(ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl);
|
||||
|
||||
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
|
||||
}
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
|
||||
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2,
|
||||
navi10_ih_doorbell_rptr(ih));
|
||||
}
|
||||
|
||||
/* update doorbell range for ih ring 0*/
|
||||
adev->nbio.funcs->ih_doorbell_range(adev, ih[0]->use_doorbell,
|
||||
ih[0]->doorbell_index);
|
||||
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL,
|
||||
@ -418,10 +350,15 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)
|
||||
pci_set_master(adev->pdev);
|
||||
|
||||
/* enable interrupts */
|
||||
navi10_ih_enable_interrupts(adev);
|
||||
ret = navi10_ih_toggle_interrupts(adev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* enable wptr force update for self int */
|
||||
force_update_wptr_for_self_int(adev, 0, 8, true);
|
||||
|
||||
if (adev->irq.ih_soft.ring_size)
|
||||
adev->irq.ih_soft.enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -435,7 +372,7 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)
|
||||
static void navi10_ih_irq_disable(struct amdgpu_device *adev)
|
||||
{
|
||||
force_update_wptr_for_self_int(adev, 0, 8, false);
|
||||
navi10_ih_disable_interrupts(adev);
|
||||
navi10_ih_toggle_interrupts(adev, false);
|
||||
|
||||
/* Wait and acknowledge irq */
|
||||
mdelay(1);
|
||||
@ -455,23 +392,16 @@ static void navi10_ih_irq_disable(struct amdgpu_device *adev)
|
||||
static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
u32 wptr, reg, tmp;
|
||||
u32 wptr, tmp;
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
wptr = le32_to_cpu(*ih->wptr_cpu);
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
if (ih == &adev->irq.ih)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
|
||||
else if (ih == &adev->irq.ih1)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
|
||||
else if (ih == &adev->irq.ih2)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
|
||||
else
|
||||
BUG();
|
||||
|
||||
wptr = RREG32_NO_KIQ(reg);
|
||||
wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
@ -486,67 +416,13 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
|
||||
wptr, ih->rptr, tmp);
|
||||
ih->rptr = tmp;
|
||||
|
||||
if (ih == &adev->irq.ih)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
else if (ih == &adev->irq.ih1)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
else if (ih == &adev->irq.ih2)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
else
|
||||
BUG();
|
||||
|
||||
tmp = RREG32_NO_KIQ(reg);
|
||||
tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32_NO_KIQ(reg, tmp);
|
||||
WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
|
||||
out:
|
||||
return (wptr & ih->ptr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* navi10_ih_decode_iv - decode an interrupt vector
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: IH ring buffer to decode
|
||||
* @entry: IV entry to place decoded information into
|
||||
*
|
||||
* Decodes the interrupt vector at the current rptr
|
||||
* position and also advance the position.
|
||||
*/
|
||||
static void navi10_ih_decode_iv(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
/* wptr/rptr are in bytes! */
|
||||
u32 ring_index = ih->rptr >> 2;
|
||||
uint32_t dw[8];
|
||||
|
||||
dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
|
||||
dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
|
||||
dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
|
||||
dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
|
||||
dw[4] = le32_to_cpu(ih->ring[ring_index + 4]);
|
||||
dw[5] = le32_to_cpu(ih->ring[ring_index + 5]);
|
||||
dw[6] = le32_to_cpu(ih->ring[ring_index + 6]);
|
||||
dw[7] = le32_to_cpu(ih->ring[ring_index + 7]);
|
||||
|
||||
entry->client_id = dw[0] & 0xff;
|
||||
entry->src_id = (dw[0] >> 8) & 0xff;
|
||||
entry->ring_id = (dw[0] >> 16) & 0xff;
|
||||
entry->vmid = (dw[0] >> 24) & 0xf;
|
||||
entry->vmid_src = (dw[0] >> 31);
|
||||
entry->timestamp = dw[1] | ((u64)(dw[2] & 0xffff) << 32);
|
||||
entry->timestamp_src = dw[2] >> 31;
|
||||
entry->pasid = dw[3] & 0xffff;
|
||||
entry->pasid_src = dw[3] >> 31;
|
||||
entry->src_data[0] = dw[4];
|
||||
entry->src_data[1] = dw[5];
|
||||
entry->src_data[2] = dw[6];
|
||||
entry->src_data[3] = dw[7];
|
||||
|
||||
/* wptr/rptr are in bytes! */
|
||||
ih->rptr += 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* navi10_ih_irq_rearm - rearm IRQ if lost
|
||||
*
|
||||
@ -557,22 +433,15 @@ static void navi10_ih_decode_iv(struct amdgpu_device *adev,
|
||||
static void navi10_ih_irq_rearm(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
uint32_t reg_rptr = 0;
|
||||
uint32_t v = 0;
|
||||
uint32_t i = 0;
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (ih == &adev->irq.ih)
|
||||
reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
|
||||
else if (ih == &adev->irq.ih1)
|
||||
reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
|
||||
else if (ih == &adev->irq.ih2)
|
||||
reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
|
||||
else
|
||||
return;
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
/* Rearm IRQ / re-write doorbell if doorbell write is lost */
|
||||
for (i = 0; i < MAX_REARM_RETRY; i++) {
|
||||
v = RREG32_NO_KIQ(reg_rptr);
|
||||
v = RREG32_NO_KIQ(ih_regs->ih_rb_rptr);
|
||||
if ((v < ih->ring_size) && (v != ih->rptr))
|
||||
WDOORBELL32(ih->doorbell_index, ih->rptr);
|
||||
else
|
||||
@ -591,6 +460,8 @@ static void navi10_ih_irq_rearm(struct amdgpu_device *adev,
|
||||
static void navi10_ih_set_rptr(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (ih->use_doorbell) {
|
||||
/* XXX check if swapping is necessary on BE */
|
||||
*ih->rptr_cpu = ih->rptr;
|
||||
@ -598,12 +469,9 @@ static void navi10_ih_set_rptr(struct amdgpu_device *adev,
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
navi10_ih_irq_rearm(adev, ih);
|
||||
} else if (ih == &adev->irq.ih) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr);
|
||||
} else if (ih == &adev->irq.ih1) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, ih->rptr);
|
||||
} else if (ih == &adev->irq.ih2) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, ih->rptr);
|
||||
} else {
|
||||
ih_regs = &ih->ih_regs;
|
||||
WREG32(ih_regs->ih_rb_rptr, ih->rptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,23 +553,8 @@ static int navi10_ih_sw_init(void *handle)
|
||||
adev->irq.ih1.ring_size = 0;
|
||||
adev->irq.ih2.ring_size = 0;
|
||||
|
||||
if (adev->asic_type < CHIP_NAVI10) {
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih1.use_doorbell = true;
|
||||
adev->irq.ih1.doorbell_index =
|
||||
(adev->doorbell_index.ih + 1) << 1;
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih2.use_doorbell = true;
|
||||
adev->irq.ih2.doorbell_index =
|
||||
(adev->doorbell_index.ih + 2) << 1;
|
||||
}
|
||||
/* initialize ih control registers offset */
|
||||
navi10_ih_init_register_offset(adev);
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
|
||||
if (r)
|
||||
@ -717,6 +570,7 @@ static int navi10_ih_sw_fini(void *handle)
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih_soft);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih2);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih);
|
||||
@ -848,7 +702,7 @@ static const struct amd_ip_funcs navi10_ih_ip_funcs = {
|
||||
|
||||
static const struct amdgpu_ih_funcs navi10_ih_funcs = {
|
||||
.get_wptr = navi10_ih_get_wptr,
|
||||
.decode_iv = navi10_ih_decode_iv,
|
||||
.decode_iv = amdgpu_ih_decode_iv_helper,
|
||||
.set_rptr = navi10_ih_set_rptr
|
||||
};
|
||||
|
||||
|
@ -80,15 +80,6 @@ static void nbio_v2_3_mc_access_enable(struct amdgpu_device *adev, bool enable)
|
||||
WREG32_SOC15(NBIO, 0, mmBIF_FB_EN, 0);
|
||||
}
|
||||
|
||||
static void nbio_v2_3_hdp_flush(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
}
|
||||
|
||||
static u32 nbio_v2_3_get_memsize(struct amdgpu_device *adev)
|
||||
{
|
||||
return RREG32_SOC15(NBIO, 0, mmRCC_DEV0_EPF0_RCC_CONFIG_MEMSIZE);
|
||||
@ -366,7 +357,6 @@ const struct amdgpu_nbio_funcs nbio_v2_3_funcs = {
|
||||
.get_pcie_data_offset = nbio_v2_3_get_pcie_data_offset,
|
||||
.get_rev_id = nbio_v2_3_get_rev_id,
|
||||
.mc_access_enable = nbio_v2_3_mc_access_enable,
|
||||
.hdp_flush = nbio_v2_3_hdp_flush,
|
||||
.get_memsize = nbio_v2_3_get_memsize,
|
||||
.sdma_doorbell_range = nbio_v2_3_sdma_doorbell_range,
|
||||
.vcn_doorbell_range = nbio_v2_3_vcn_doorbell_range,
|
||||
|
@ -29,6 +29,15 @@
|
||||
#include "nbio/nbio_6_1_sh_mask.h"
|
||||
#include "nbio/nbio_6_1_smn.h"
|
||||
#include "vega10_enum.h"
|
||||
#include <uapi/linux/kfd_ioctl.h>
|
||||
|
||||
static void nbio_v6_1_remap_hdp_registers(struct amdgpu_device *adev)
|
||||
{
|
||||
WREG32_SOC15(NBIO, 0, mmREMAP_HDP_MEM_FLUSH_CNTL,
|
||||
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL);
|
||||
WREG32_SOC15(NBIO, 0, mmREMAP_HDP_REG_FLUSH_CNTL,
|
||||
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL);
|
||||
}
|
||||
|
||||
static u32 nbio_v6_1_get_rev_id(struct amdgpu_device *adev)
|
||||
{
|
||||
@ -50,18 +59,6 @@ static void nbio_v6_1_mc_access_enable(struct amdgpu_device *adev, bool enable)
|
||||
WREG32_SOC15(NBIO, 0, mmBIF_FB_EN, 0);
|
||||
}
|
||||
|
||||
static void nbio_v6_1_hdp_flush(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_SOC15_NO_KIQ(NBIO, 0,
|
||||
mmBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL,
|
||||
0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET(
|
||||
NBIO, 0, mmBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL), 0);
|
||||
}
|
||||
|
||||
static u32 nbio_v6_1_get_memsize(struct amdgpu_device *adev)
|
||||
{
|
||||
return RREG32_SOC15(NBIO, 0, mmRCC_PF_0_0_RCC_CONFIG_MEMSIZE);
|
||||
@ -266,7 +263,6 @@ const struct amdgpu_nbio_funcs nbio_v6_1_funcs = {
|
||||
.get_pcie_data_offset = nbio_v6_1_get_pcie_data_offset,
|
||||
.get_rev_id = nbio_v6_1_get_rev_id,
|
||||
.mc_access_enable = nbio_v6_1_mc_access_enable,
|
||||
.hdp_flush = nbio_v6_1_hdp_flush,
|
||||
.get_memsize = nbio_v6_1_get_memsize,
|
||||
.sdma_doorbell_range = nbio_v6_1_sdma_doorbell_range,
|
||||
.enable_doorbell_aperture = nbio_v6_1_enable_doorbell_aperture,
|
||||
@ -277,4 +273,5 @@ const struct amdgpu_nbio_funcs nbio_v6_1_funcs = {
|
||||
.get_clockgating_state = nbio_v6_1_get_clockgating_state,
|
||||
.ih_control = nbio_v6_1_ih_control,
|
||||
.init_registers = nbio_v6_1_init_registers,
|
||||
.remap_hdp_registers = nbio_v6_1_remap_hdp_registers,
|
||||
};
|
||||
|
@ -60,15 +60,6 @@ static void nbio_v7_0_mc_access_enable(struct amdgpu_device *adev, bool enable)
|
||||
WREG32_SOC15(NBIO, 0, mmBIF_FB_EN, 0);
|
||||
}
|
||||
|
||||
static void nbio_v7_0_hdp_flush(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
}
|
||||
|
||||
static u32 nbio_v7_0_get_memsize(struct amdgpu_device *adev)
|
||||
{
|
||||
return RREG32_SOC15(NBIO, 0, mmRCC_CONFIG_MEMSIZE);
|
||||
@ -292,7 +283,6 @@ const struct amdgpu_nbio_funcs nbio_v7_0_funcs = {
|
||||
.get_pcie_data_offset = nbio_v7_0_get_pcie_data_offset,
|
||||
.get_rev_id = nbio_v7_0_get_rev_id,
|
||||
.mc_access_enable = nbio_v7_0_mc_access_enable,
|
||||
.hdp_flush = nbio_v7_0_hdp_flush,
|
||||
.get_memsize = nbio_v7_0_get_memsize,
|
||||
.sdma_doorbell_range = nbio_v7_0_sdma_doorbell_range,
|
||||
.vcn_doorbell_range = nbio_v7_0_vcn_doorbell_range,
|
||||
|
@ -56,15 +56,6 @@ static void nbio_v7_2_mc_access_enable(struct amdgpu_device *adev, bool enable)
|
||||
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN, 0);
|
||||
}
|
||||
|
||||
static void nbio_v7_2_hdp_flush(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
}
|
||||
|
||||
static u32 nbio_v7_2_get_memsize(struct amdgpu_device *adev)
|
||||
{
|
||||
return RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF0_0_RCC_CONFIG_MEMSIZE);
|
||||
@ -325,7 +316,6 @@ const struct amdgpu_nbio_funcs nbio_v7_2_funcs = {
|
||||
.get_pcie_port_data_offset = nbio_v7_2_get_pcie_port_data_offset,
|
||||
.get_rev_id = nbio_v7_2_get_rev_id,
|
||||
.mc_access_enable = nbio_v7_2_mc_access_enable,
|
||||
.hdp_flush = nbio_v7_2_hdp_flush,
|
||||
.get_memsize = nbio_v7_2_get_memsize,
|
||||
.sdma_doorbell_range = nbio_v7_2_sdma_doorbell_range,
|
||||
.vcn_doorbell_range = nbio_v7_2_vcn_doorbell_range,
|
||||
|
@ -82,15 +82,6 @@ static void nbio_v7_4_mc_access_enable(struct amdgpu_device *adev, bool enable)
|
||||
WREG32_SOC15(NBIO, 0, mmBIF_FB_EN, 0);
|
||||
}
|
||||
|
||||
static void nbio_v7_4_hdp_flush(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0);
|
||||
}
|
||||
|
||||
static u32 nbio_v7_4_get_memsize(struct amdgpu_device *adev)
|
||||
{
|
||||
return RREG32_SOC15(NBIO, 0, mmRCC_CONFIG_MEMSIZE);
|
||||
@ -541,7 +532,6 @@ const struct amdgpu_nbio_funcs nbio_v7_4_funcs = {
|
||||
.get_pcie_data_offset = nbio_v7_4_get_pcie_data_offset,
|
||||
.get_rev_id = nbio_v7_4_get_rev_id,
|
||||
.mc_access_enable = nbio_v7_4_mc_access_enable,
|
||||
.hdp_flush = nbio_v7_4_hdp_flush,
|
||||
.get_memsize = nbio_v7_4_get_memsize,
|
||||
.sdma_doorbell_range = nbio_v7_4_sdma_doorbell_range,
|
||||
.vcn_doorbell_range = nbio_v7_4_vcn_doorbell_range,
|
||||
|
@ -38,8 +38,6 @@
|
||||
|
||||
#include "gc/gc_10_1_0_offset.h"
|
||||
#include "gc/gc_10_1_0_sh_mask.h"
|
||||
#include "hdp/hdp_5_0_0_offset.h"
|
||||
#include "hdp/hdp_5_0_0_sh_mask.h"
|
||||
#include "smuio/smuio_11_0_0_offset.h"
|
||||
#include "mp/mp_11_0_offset.h"
|
||||
|
||||
@ -50,6 +48,7 @@
|
||||
#include "mmhub_v2_0.h"
|
||||
#include "nbio_v2_3.h"
|
||||
#include "nbio_v7_2.h"
|
||||
#include "hdp_v5_0.h"
|
||||
#include "nv.h"
|
||||
#include "navi10_ih.h"
|
||||
#include "gfx_v10_0.h"
|
||||
@ -514,6 +513,7 @@ int nv_set_ip_blocks(struct amdgpu_device *adev)
|
||||
adev->nbio.funcs = &nbio_v2_3_funcs;
|
||||
adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg;
|
||||
}
|
||||
adev->hdp.funcs = &hdp_v5_0_funcs;
|
||||
|
||||
if (adev->asic_type == CHIP_SIENNA_CICHLID)
|
||||
adev->gmc.xgmi.supported = true;
|
||||
@ -669,22 +669,6 @@ static uint32_t nv_get_rev_id(struct amdgpu_device *adev)
|
||||
return adev->nbio.funcs->get_rev_id(adev);
|
||||
}
|
||||
|
||||
static void nv_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring)
|
||||
{
|
||||
adev->nbio.funcs->hdp_flush(adev, ring);
|
||||
}
|
||||
|
||||
static void nv_invalidate_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg) {
|
||||
WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1);
|
||||
} else {
|
||||
amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET(
|
||||
HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1);
|
||||
}
|
||||
}
|
||||
|
||||
static bool nv_need_full_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
return true;
|
||||
@ -788,8 +772,6 @@ static const struct amdgpu_asic_funcs nv_asic_funcs =
|
||||
.set_uvd_clocks = &nv_set_uvd_clocks,
|
||||
.set_vce_clocks = &nv_set_vce_clocks,
|
||||
.get_config_memsize = &nv_get_config_memsize,
|
||||
.flush_hdp = &nv_flush_hdp,
|
||||
.invalidate_hdp = &nv_invalidate_hdp,
|
||||
.init_doorbell_index = &nv_init_doorbell_index,
|
||||
.need_full_reset = &nv_need_full_reset,
|
||||
.need_reset_on_init = &nv_need_reset_on_init,
|
||||
@ -1080,120 +1062,6 @@ static int nv_common_soft_reset(void *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nv_update_hdp_mem_power_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t hdp_clk_cntl, hdp_clk_cntl1;
|
||||
uint32_t hdp_mem_pwr_cntl;
|
||||
|
||||
if (!(adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS |
|
||||
AMD_CG_SUPPORT_HDP_DS |
|
||||
AMD_CG_SUPPORT_HDP_SD)))
|
||||
return;
|
||||
|
||||
hdp_clk_cntl = hdp_clk_cntl1 = RREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL);
|
||||
hdp_mem_pwr_cntl = RREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL);
|
||||
|
||||
/* Before doing clock/power mode switch,
|
||||
* forced on IPH & RC clock */
|
||||
hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
|
||||
IPH_MEM_CLK_SOFT_OVERRIDE, 1);
|
||||
hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
|
||||
RC_MEM_CLK_SOFT_OVERRIDE, 1);
|
||||
WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl);
|
||||
|
||||
/* HDP 5.0 doesn't support dynamic power mode switch,
|
||||
* disable clock and power gating before any changing */
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_CTRL_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_LS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_DS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_SD_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_CTRL_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_LS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_DS_EN, 0);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_SD_EN, 0);
|
||||
WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
|
||||
|
||||
/* only one clock gating mode (LS/DS/SD) can be enabled */
|
||||
if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_LS_EN, enable);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_LS_EN, enable);
|
||||
} else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_DS_EN, enable);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_DS_EN, enable);
|
||||
} else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_SD_EN, enable);
|
||||
/* RC should not use shut down mode, fallback to ds */
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
|
||||
HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_DS_EN, enable);
|
||||
}
|
||||
|
||||
/* confirmed that IPH_MEM_POWER_CTRL_EN and RC_MEM_POWER_CTRL_EN have to
|
||||
* be set for SRAM LS/DS/SD */
|
||||
if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS |
|
||||
AMD_CG_SUPPORT_HDP_SD)) {
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
IPH_MEM_POWER_CTRL_EN, 1);
|
||||
hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
|
||||
RC_MEM_POWER_CTRL_EN, 1);
|
||||
}
|
||||
|
||||
WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
|
||||
|
||||
/* restore IPH & RC clock override after clock/power mode changing */
|
||||
WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl1);
|
||||
}
|
||||
|
||||
static void nv_update_hdp_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t hdp_clk_cntl;
|
||||
|
||||
if (!(adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG))
|
||||
return;
|
||||
|
||||
hdp_clk_cntl = RREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL);
|
||||
|
||||
if (enable) {
|
||||
hdp_clk_cntl &=
|
||||
~(uint32_t)
|
||||
(HDP_CLK_CNTL__IPH_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK);
|
||||
} else {
|
||||
hdp_clk_cntl |= HDP_CLK_CNTL__IPH_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK;
|
||||
}
|
||||
|
||||
WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl);
|
||||
}
|
||||
|
||||
static int nv_common_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
@ -1213,9 +1081,7 @@ static int nv_common_set_clockgating_state(void *handle,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
adev->nbio.funcs->update_medium_grain_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
nv_update_hdp_mem_power_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
nv_update_hdp_clock_gating(adev,
|
||||
adev->hdp.funcs->update_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
break;
|
||||
default:
|
||||
@ -1234,31 +1100,13 @@ static int nv_common_set_powergating_state(void *handle,
|
||||
static void nv_common_get_clockgating_state(void *handle, u32 *flags)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
uint32_t tmp;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
*flags = 0;
|
||||
|
||||
adev->nbio.funcs->get_clockgating_state(adev, flags);
|
||||
|
||||
/* AMD_CG_SUPPORT_HDP_MGCG */
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL);
|
||||
if (!(tmp & (HDP_CLK_CNTL__IPH_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
|
||||
HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK)))
|
||||
*flags |= AMD_CG_SUPPORT_HDP_MGCG;
|
||||
|
||||
/* AMD_CG_SUPPORT_HDP_LS/DS/SD */
|
||||
tmp = RREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL);
|
||||
if (tmp & HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_LS;
|
||||
else if (tmp & HDP_MEM_POWER_CTRL__IPH_MEM_POWER_DS_EN_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_DS;
|
||||
else if (tmp & HDP_MEM_POWER_CTRL__IPH_MEM_POWER_SD_EN_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_SD;
|
||||
adev->hdp.funcs->get_clock_gating_state(adev, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ enum psp_gfx_crtl_cmd_id
|
||||
GFX_CTRL_CMD_ID_DISABLE_INT = 0x00060000, /* disable PSP-to-Gfx interrupt */
|
||||
GFX_CTRL_CMD_ID_MODE1_RST = 0x00070000, /* trigger the Mode 1 reset */
|
||||
GFX_CTRL_CMD_ID_GBR_IH_SET = 0x00080000, /* set Gbr IH_RB_CNTL registers */
|
||||
GFX_CTRL_CMD_ID_CONSUME_CMD = 0x000A0000, /* send interrupt to psp for updating write pointer of vf */
|
||||
GFX_CTRL_CMD_ID_CONSUME_CMD = 0x00090000, /* send interrupt to psp for updating write pointer of vf */
|
||||
GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING = 0x000C0000, /* destroy GPCOM ring */
|
||||
|
||||
GFX_CTRL_CMD_ID_MAX = 0x000F0000, /* max command ID */
|
||||
|
@ -392,37 +392,6 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void psp_v11_0_reroute_ih(struct psp_context *psp)
|
||||
{
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
uint32_t tmp;
|
||||
|
||||
/* Change IH ring for VMC */
|
||||
tmp = REG_SET_FIELD(0, IH_CLIENT_CFG_DATA, CREDIT_RETURN_ADDR, 0x1244b);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
|
||||
|
||||
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, 3);
|
||||
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, tmp);
|
||||
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, GFX_CTRL_CMD_ID_GBR_IH_SET);
|
||||
|
||||
mdelay(20);
|
||||
psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
|
||||
0x80000000, 0x8000FFFF, false);
|
||||
|
||||
/* Change IH ring for UMC */
|
||||
tmp = REG_SET_FIELD(0, IH_CLIENT_CFG_DATA, CREDIT_RETURN_ADDR, 0x1216b);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
|
||||
|
||||
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, 4);
|
||||
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, tmp);
|
||||
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, GFX_CTRL_CMD_ID_GBR_IH_SET);
|
||||
|
||||
mdelay(20);
|
||||
psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
|
||||
0x80000000, 0x8000FFFF, false);
|
||||
}
|
||||
|
||||
static int psp_v11_0_ring_init(struct psp_context *psp,
|
||||
enum psp_ring_type ring_type)
|
||||
{
|
||||
@ -430,11 +399,6 @@ static int psp_v11_0_ring_init(struct psp_context *psp,
|
||||
struct psp_ring *ring;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
if ((!amdgpu_sriov_vf(adev)) &&
|
||||
!(adev->asic_type >= CHIP_SIENNA_CICHLID &&
|
||||
adev->asic_type <= CHIP_DIMGREY_CAVEFISH))
|
||||
psp_v11_0_reroute_ih(psp);
|
||||
|
||||
ring = &psp->km_ring;
|
||||
|
||||
ring->ring_type = ring_type;
|
||||
@ -726,7 +690,7 @@ static int psp_v11_0_memory_training(struct psp_context *psp, uint32_t ops)
|
||||
}
|
||||
|
||||
memcpy_toio(adev->mman.aper_base_kaddr, buf, sz);
|
||||
adev->nbio.funcs->hdp_flush(adev, NULL);
|
||||
adev->hdp.funcs->flush_hdp(adev, NULL);
|
||||
vfree(buf);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "sdma6/sdma6_4_2_2_sh_mask.h"
|
||||
#include "sdma7/sdma7_4_2_2_offset.h"
|
||||
#include "sdma7/sdma7_4_2_2_sh_mask.h"
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
#include "sdma0/sdma0_4_1_default.h"
|
||||
|
||||
#include "soc15_common.h"
|
||||
|
@ -32,7 +32,6 @@
|
||||
|
||||
#include "gc/gc_10_1_0_offset.h"
|
||||
#include "gc/gc_10_1_0_sh_mask.h"
|
||||
#include "hdp/hdp_5_0_0_offset.h"
|
||||
#include "ivsrcid/sdma0/irqsrcs_sdma0_5_0.h"
|
||||
#include "ivsrcid/sdma1/irqsrcs_sdma1_5_0.h"
|
||||
|
||||
|
@ -119,15 +119,7 @@ static int sdma_v5_2_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst)
|
||||
|
||||
static void sdma_v5_2_destroy_inst_ctx(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->sdma.num_instances; i++) {
|
||||
release_firmware(adev->sdma.instance[i].fw);
|
||||
adev->sdma.instance[i].fw = NULL;
|
||||
|
||||
if (adev->asic_type == CHIP_SIENNA_CICHLID)
|
||||
break;
|
||||
}
|
||||
release_firmware(adev->sdma.instance[0].fw);
|
||||
|
||||
memset((void *)adev->sdma.instance, 0,
|
||||
sizeof(struct amdgpu_sdma_instance) * AMDGPU_MAX_SDMA_INSTANCES);
|
||||
@ -185,23 +177,10 @@ static int sdma_v5_2_init_microcode(struct amdgpu_device *adev)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
for (i = 1; i < adev->sdma.num_instances; i++) {
|
||||
if (adev->asic_type >= CHIP_SIENNA_CICHLID &&
|
||||
adev->asic_type <= CHIP_DIMGREY_CAVEFISH) {
|
||||
memcpy((void *)&adev->sdma.instance[i],
|
||||
(void *)&adev->sdma.instance[0],
|
||||
sizeof(struct amdgpu_sdma_instance));
|
||||
} else {
|
||||
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma%d.bin", chip_name, i);
|
||||
err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = sdma_v5_2_init_inst_ctx(&adev->sdma.instance[i]);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
for (i = 1; i < adev->sdma.num_instances; i++)
|
||||
memcpy((void *)&adev->sdma.instance[i],
|
||||
(void *)&adev->sdma.instance[0],
|
||||
sizeof(struct amdgpu_sdma_instance));
|
||||
|
||||
DRM_DEBUG("psp_load == '%s'\n",
|
||||
adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false");
|
||||
|
@ -40,8 +40,6 @@
|
||||
#include "gc/gc_9_0_sh_mask.h"
|
||||
#include "sdma0/sdma0_4_0_offset.h"
|
||||
#include "sdma1/sdma1_4_0_offset.h"
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
#include "hdp/hdp_4_0_sh_mask.h"
|
||||
#include "nbio/nbio_7_0_default.h"
|
||||
#include "nbio/nbio_7_0_offset.h"
|
||||
#include "nbio/nbio_7_0_sh_mask.h"
|
||||
@ -59,7 +57,9 @@
|
||||
#include "nbio_v6_1.h"
|
||||
#include "nbio_v7_0.h"
|
||||
#include "nbio_v7_4.h"
|
||||
#include "hdp_v4_0.h"
|
||||
#include "vega10_ih.h"
|
||||
#include "vega20_ih.h"
|
||||
#include "navi10_ih.h"
|
||||
#include "sdma_v4_0.h"
|
||||
#include "uvd_v7_0.h"
|
||||
@ -83,14 +83,6 @@
|
||||
#define mmMP0_MISC_LIGHT_SLEEP_CTRL 0x01ba
|
||||
#define mmMP0_MISC_LIGHT_SLEEP_CTRL_BASE_IDX 0
|
||||
|
||||
/* for Vega20 register name change */
|
||||
#define mmHDP_MEM_POWER_CTRL 0x00d4
|
||||
#define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK 0x00000001L
|
||||
#define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK 0x00000002L
|
||||
#define HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK 0x00010000L
|
||||
#define HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK 0x00020000L
|
||||
#define mmHDP_MEM_POWER_CTRL_BASE_IDX 0
|
||||
|
||||
/*
|
||||
* Indirect registers accessor
|
||||
*/
|
||||
@ -699,6 +691,7 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
|
||||
adev->nbio.funcs = &nbio_v6_1_funcs;
|
||||
adev->nbio.hdp_flush_reg = &nbio_v6_1_hdp_flush_reg;
|
||||
}
|
||||
adev->hdp.funcs = &hdp_v4_0_funcs;
|
||||
|
||||
if (adev->asic_type == CHIP_VEGA20 || adev->asic_type == CHIP_ARCTURUS)
|
||||
adev->df.funcs = &df_v3_6_funcs;
|
||||
@ -729,12 +722,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
|
||||
amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block);
|
||||
}
|
||||
if (adev->asic_type == CHIP_VEGA20)
|
||||
amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block);
|
||||
else
|
||||
amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
|
||||
} else {
|
||||
if (adev->asic_type == CHIP_VEGA20)
|
||||
amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block);
|
||||
else
|
||||
amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
|
||||
if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) {
|
||||
@ -787,9 +780,9 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP))
|
||||
amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block);
|
||||
} else {
|
||||
amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block);
|
||||
if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP))
|
||||
amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block);
|
||||
}
|
||||
@ -834,35 +827,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void soc15_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring)
|
||||
{
|
||||
adev->nbio.funcs->hdp_flush(adev, ring);
|
||||
}
|
||||
|
||||
static void soc15_invalidate_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1);
|
||||
else
|
||||
amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET(
|
||||
HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1);
|
||||
}
|
||||
|
||||
static bool soc15_need_full_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
/* change this when we implement soft reset */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vega20_reset_hdp_ras_error_count(struct amdgpu_device *adev)
|
||||
{
|
||||
if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__HDP))
|
||||
return;
|
||||
/*read back hdp ras counter to reset it to 0 */
|
||||
RREG32_SOC15(HDP, 0, mmHDP_EDC_CNT);
|
||||
}
|
||||
|
||||
static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
|
||||
uint64_t *count1)
|
||||
{
|
||||
@ -1011,8 +981,6 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs =
|
||||
.set_uvd_clocks = &soc15_set_uvd_clocks,
|
||||
.set_vce_clocks = &soc15_set_vce_clocks,
|
||||
.get_config_memsize = &soc15_get_config_memsize,
|
||||
.flush_hdp = &soc15_flush_hdp,
|
||||
.invalidate_hdp = &soc15_invalidate_hdp,
|
||||
.need_full_reset = &soc15_need_full_reset,
|
||||
.init_doorbell_index = &vega10_doorbell_index_init,
|
||||
.get_pcie_usage = &soc15_get_pcie_usage,
|
||||
@ -1034,9 +1002,6 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs =
|
||||
.set_uvd_clocks = &soc15_set_uvd_clocks,
|
||||
.set_vce_clocks = &soc15_set_vce_clocks,
|
||||
.get_config_memsize = &soc15_get_config_memsize,
|
||||
.flush_hdp = &soc15_flush_hdp,
|
||||
.invalidate_hdp = &soc15_invalidate_hdp,
|
||||
.reset_hdp_ras_error_count = &vega20_reset_hdp_ras_error_count,
|
||||
.need_full_reset = &soc15_need_full_reset,
|
||||
.init_doorbell_index = &vega20_doorbell_index_init,
|
||||
.get_pcie_usage = &vega20_get_pcie_usage,
|
||||
@ -1293,9 +1258,8 @@ static int soc15_common_late_init(void *handle)
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
xgpu_ai_mailbox_get_irq(adev);
|
||||
|
||||
if (adev->asic_funcs &&
|
||||
adev->asic_funcs->reset_hdp_ras_error_count)
|
||||
adev->asic_funcs->reset_hdp_ras_error_count(adev);
|
||||
if (adev->hdp.funcs->reset_ras_error_count)
|
||||
adev->hdp.funcs->reset_ras_error_count(adev);
|
||||
|
||||
if (adev->nbio.funcs->ras_late_init)
|
||||
r = adev->nbio.funcs->ras_late_init(adev);
|
||||
@ -1421,41 +1385,6 @@ static int soc15_common_soft_reset(void *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void soc15_update_hdp_light_sleep(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
uint32_t def, data;
|
||||
|
||||
if (adev->asic_type == CHIP_VEGA20 ||
|
||||
adev->asic_type == CHIP_ARCTURUS ||
|
||||
adev->asic_type == CHIP_RENOIR) {
|
||||
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL));
|
||||
|
||||
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
||||
data |= HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK;
|
||||
else
|
||||
data &= ~(HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK |
|
||||
HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK);
|
||||
|
||||
if (def != data)
|
||||
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL), data);
|
||||
} else {
|
||||
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS));
|
||||
|
||||
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
||||
data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK;
|
||||
else
|
||||
data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK;
|
||||
|
||||
if (def != data)
|
||||
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void soc15_update_drm_clock_gating(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
uint32_t def, data;
|
||||
@ -1516,7 +1445,7 @@ static int soc15_common_set_clockgating_state(void *handle,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
adev->nbio.funcs->update_medium_grain_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
soc15_update_hdp_light_sleep(adev,
|
||||
adev->hdp.funcs->update_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
soc15_update_drm_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
@ -1533,7 +1462,7 @@ static int soc15_common_set_clockgating_state(void *handle,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
adev->nbio.funcs->update_medium_grain_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
soc15_update_hdp_light_sleep(adev,
|
||||
adev->hdp.funcs->update_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
soc15_update_drm_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
@ -1541,7 +1470,7 @@ static int soc15_common_set_clockgating_state(void *handle,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
break;
|
||||
case CHIP_ARCTURUS:
|
||||
soc15_update_hdp_light_sleep(adev,
|
||||
adev->hdp.funcs->update_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
break;
|
||||
default:
|
||||
@ -1560,10 +1489,7 @@ static void soc15_common_get_clockgating_state(void *handle, u32 *flags)
|
||||
|
||||
adev->nbio.funcs->get_clockgating_state(adev, flags);
|
||||
|
||||
/* AMD_CG_SUPPORT_HDP_LS */
|
||||
data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS));
|
||||
if (data & HDP_MEM_POWER_LS__LS_ENABLE_MASK)
|
||||
*flags |= AMD_CG_SUPPORT_HDP_LS;
|
||||
adev->hdp.funcs->get_clock_gating_state(adev, flags);
|
||||
|
||||
/* AMD_CG_SUPPORT_DRM_MGCG */
|
||||
data = RREG32(SOC15_REG_OFFSET(MP0, 0, mmMP0_MISC_CGTT_CTRL0));
|
||||
|
@ -196,19 +196,30 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev,
|
||||
|
||||
wptr = le32_to_cpu(*ih->wptr_cpu);
|
||||
|
||||
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 16). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
|
||||
ih->rptr = (wptr + 16) & ih->ptr_mask;
|
||||
tmp = RREG32(mmIH_RB_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32(mmIH_RB_CNTL, tmp);
|
||||
}
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
/* Double check that the overflow wasn't already cleared. */
|
||||
wptr = RREG32(mmIH_RB_WPTR);
|
||||
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 16). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
|
||||
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
|
||||
ih->rptr = (wptr + 16) & ih->ptr_mask;
|
||||
tmp = RREG32(mmIH_RB_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32(mmIH_RB_CNTL, tmp);
|
||||
|
||||
out:
|
||||
return (wptr & ih->ptr_mask);
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include "vce/vce_4_0_default.h"
|
||||
#include "vce/vce_4_0_sh_mask.h"
|
||||
#include "nbif/nbif_6_1_offset.h"
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
#include "mmhub/mmhub_1_0_offset.h"
|
||||
#include "mmhub/mmhub_1_0_sh_mask.h"
|
||||
#include "ivsrcid/uvd/irqsrcs_uvd_7_0.h"
|
||||
|
@ -32,7 +32,6 @@
|
||||
|
||||
#include "vcn/vcn_1_0_offset.h"
|
||||
#include "vcn/vcn_1_0_sh_mask.h"
|
||||
#include "hdp/hdp_4_0_offset.h"
|
||||
#include "mmhub/mmhub_9_1_offset.h"
|
||||
#include "mmhub/mmhub_9_1_sh_mask.h"
|
||||
|
||||
|
@ -38,132 +38,120 @@
|
||||
static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev);
|
||||
|
||||
/**
|
||||
* vega10_ih_enable_interrupts - Enable the interrupt ring buffer
|
||||
* vega10_ih_init_register_offset - Initialize register offset for ih rings
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Enable the interrupt ring buffer (VEGA10).
|
||||
* Initialize register offset ih rings (VEGA10).
|
||||
*/
|
||||
static void vega10_ih_enable_interrupts(struct amdgpu_device *adev)
|
||||
static void vega10_ih_init_register_offset(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) {
|
||||
DRM_ERROR("PSP program IH_RB_CNTL failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
|
||||
if (adev->irq.ih.ring_size) {
|
||||
ih_regs = &adev->irq.ih.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR);
|
||||
ih_regs->ih_rb_wptr_addr_lo = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO);
|
||||
ih_regs->ih_rb_wptr_addr_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL;
|
||||
}
|
||||
adev->irq.ih.enabled = true;
|
||||
|
||||
if (adev->irq.ih1.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
|
||||
RB_ENABLE, 1);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
|
||||
}
|
||||
adev->irq.ih1.enabled = true;
|
||||
ih_regs = &adev->irq.ih1.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING1);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING1);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING1;
|
||||
}
|
||||
|
||||
if (adev->irq.ih2.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
|
||||
RB_ENABLE, 1);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
|
||||
}
|
||||
adev->irq.ih2.enabled = true;
|
||||
ih_regs = &adev->irq.ih2.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING2);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING2);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING2;
|
||||
}
|
||||
|
||||
if (adev->irq.ih_soft.ring_size)
|
||||
adev->irq.ih_soft.enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega10_ih_disable_interrupts - Disable the interrupt ring buffer
|
||||
* vega10_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: amdgpu_ih_ring pointet
|
||||
* @enable: true - enable the interrupts, false - disable the interrupts
|
||||
*
|
||||
* Disable the interrupt ring buffer (VEGA10).
|
||||
* Toggle the interrupt ring buffer (VEGA10)
|
||||
*/
|
||||
static void vega10_ih_disable_interrupts(struct amdgpu_device *adev)
|
||||
static int vega10_ih_toggle_ring_interrupts(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
bool enable)
|
||||
{
|
||||
u32 ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
uint32_t tmp;
|
||||
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0);
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
tmp = RREG32(ih_regs->ih_rb_cntl);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
|
||||
/* enable_intr field is only valid in ring0 */
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0));
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) {
|
||||
DRM_ERROR("PSP program IH_RB_CNTL failed!\n");
|
||||
return;
|
||||
if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
|
||||
dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
|
||||
WREG32(ih_regs->ih_rb_cntl, tmp);
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
|
||||
adev->irq.ih.enabled = false;
|
||||
adev->irq.ih.rptr = 0;
|
||||
|
||||
if (adev->irq.ih1.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
|
||||
RB_ENABLE, 0);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
|
||||
}
|
||||
if (enable) {
|
||||
ih->enabled = true;
|
||||
} else {
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
|
||||
adev->irq.ih1.enabled = false;
|
||||
adev->irq.ih1.rptr = 0;
|
||||
WREG32(ih_regs->ih_rb_rptr, 0);
|
||||
WREG32(ih_regs->ih_rb_wptr, 0);
|
||||
ih->enabled = false;
|
||||
ih->rptr = 0;
|
||||
}
|
||||
|
||||
if (adev->irq.ih2.ring_size) {
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
|
||||
RB_ENABLE, 0);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega10_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @enable: enable or disable interrupt ring buffers
|
||||
*
|
||||
* Toggle all the available interrupt ring buffers (VEGA10).
|
||||
*/
|
||||
static int vega10_ih_toggle_interrupts(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
|
||||
int i;
|
||||
int r;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ih); i++) {
|
||||
if (ih[i]->ring_size) {
|
||||
r = vega10_ih_toggle_ring_interrupts(adev, ih[i], enable);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
|
||||
adev->irq.ih2.enabled = false;
|
||||
adev->irq.ih2.rptr = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t vega10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
|
||||
@ -208,6 +196,58 @@ static uint32_t vega10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
|
||||
return ih_doorbell_rtpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega10_ih_enable_ring - enable an ih ring buffer
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: amdgpu_ih_ring pointer
|
||||
*
|
||||
* Enable an ih ring buffer (VEGA10)
|
||||
*/
|
||||
static int vega10_ih_enable_ring(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
uint32_t tmp;
|
||||
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
|
||||
WREG32(ih_regs->ih_rb_base, ih->gpu_addr >> 8);
|
||||
WREG32(ih_regs->ih_rb_base_hi, (ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
tmp = RREG32(ih_regs->ih_rb_cntl);
|
||||
tmp = vega10_ih_rb_cntl(ih, tmp);
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RPTR_REARM, !!adev->irq.msi_enabled);
|
||||
if (ih == &adev->irq.ih1) {
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 0);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_FULL_DRAIN_ENABLE, 1);
|
||||
}
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
|
||||
dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32(ih_regs->ih_rb_cntl, tmp);
|
||||
}
|
||||
|
||||
if (ih == &adev->irq.ih) {
|
||||
/* set the ih ring 0 writeback address whether it's enabled or not */
|
||||
WREG32(ih_regs->ih_rb_wptr_addr_lo, lower_32_bits(ih->wptr_addr));
|
||||
WREG32(ih_regs->ih_rb_wptr_addr_hi, upper_32_bits(ih->wptr_addr) & 0xFFFF);
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32(ih_regs->ih_rb_wptr, 0);
|
||||
WREG32(ih_regs->ih_rb_rptr, 0);
|
||||
|
||||
WREG32(ih_regs->ih_doorbell_rptr, vega10_ih_doorbell_rptr(ih));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega10_ih_irq_init - init and enable the interrupt ring
|
||||
*
|
||||
@ -221,116 +261,34 @@ static uint32_t vega10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
|
||||
*/
|
||||
static int vega10_ih_irq_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ih_ring *ih;
|
||||
u32 ih_rb_cntl, ih_chicken;
|
||||
int ret = 0;
|
||||
struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
|
||||
u32 ih_chicken;
|
||||
int ret;
|
||||
int i;
|
||||
u32 tmp;
|
||||
|
||||
/* disable irqs */
|
||||
vega10_ih_disable_interrupts(adev);
|
||||
ret = vega10_ih_toggle_interrupts(adev, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adev->nbio.funcs->ih_control(adev);
|
||||
|
||||
ih = &adev->irq.ih;
|
||||
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, ih->gpu_addr >> 8);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, (ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM,
|
||||
!!adev->irq.msi_enabled);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) {
|
||||
DRM_ERROR("PSP program IH_RB_CNTL failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
|
||||
}
|
||||
|
||||
if ((adev->asic_type == CHIP_ARCTURUS &&
|
||||
adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) ||
|
||||
adev->asic_type == CHIP_RENOIR) {
|
||||
if (adev->asic_type == CHIP_RENOIR) {
|
||||
ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN);
|
||||
if (adev->irq.ih.use_bus_addr) {
|
||||
ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
|
||||
MC_SPACE_GPA_ENABLE, 1);
|
||||
} else {
|
||||
ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
|
||||
MC_SPACE_FBPA_ENABLE, 1);
|
||||
}
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN, ih_chicken);
|
||||
}
|
||||
|
||||
/* set the writeback address whether it's enabled or not */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO,
|
||||
lower_32_bits(ih->wptr_addr));
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI,
|
||||
upper_32_bits(ih->wptr_addr) & 0xFFFF);
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
|
||||
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR,
|
||||
vega10_ih_doorbell_rptr(ih));
|
||||
|
||||
ih = &adev->irq.ih1;
|
||||
if (ih->ring_size) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING1, ih->gpu_addr >> 8);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING1,
|
||||
(ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
WPTR_OVERFLOW_ENABLE, 0);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
RB_FULL_DRAIN_ENABLE, 1);
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
|
||||
for (i = 0; i < ARRAY_SIZE(ih); i++) {
|
||||
if (ih[i]->ring_size) {
|
||||
ret = vega10_ih_enable_ring(adev, ih[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
|
||||
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1,
|
||||
vega10_ih_doorbell_rptr(ih));
|
||||
}
|
||||
|
||||
ih = &adev->irq.ih2;
|
||||
if (ih->ring_size) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING2, ih->gpu_addr >> 8);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING2,
|
||||
(ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl);
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2,
|
||||
ih_rb_cntl)) {
|
||||
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
|
||||
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2,
|
||||
vega10_ih_doorbell_rptr(ih));
|
||||
}
|
||||
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);
|
||||
@ -345,9 +303,14 @@ static int vega10_ih_irq_init(struct amdgpu_device *adev)
|
||||
pci_set_master(adev->pdev);
|
||||
|
||||
/* enable interrupts */
|
||||
vega10_ih_enable_interrupts(adev);
|
||||
ret = vega10_ih_toggle_interrupts(adev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
if (adev->irq.ih_soft.ring_size)
|
||||
adev->irq.ih_soft.enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -359,7 +322,7 @@ static int vega10_ih_irq_init(struct amdgpu_device *adev)
|
||||
*/
|
||||
static void vega10_ih_irq_disable(struct amdgpu_device *adev)
|
||||
{
|
||||
vega10_ih_disable_interrupts(adev);
|
||||
vega10_ih_toggle_interrupts(adev, false);
|
||||
|
||||
/* Wait and acknowledge irq */
|
||||
mdelay(1);
|
||||
@ -379,25 +342,17 @@ static void vega10_ih_irq_disable(struct amdgpu_device *adev)
|
||||
static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
u32 wptr, reg, tmp;
|
||||
u32 wptr, tmp;
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
wptr = le32_to_cpu(*ih->wptr_cpu);
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
/* Double check that the overflow wasn't already cleared. */
|
||||
|
||||
if (ih == &adev->irq.ih)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
|
||||
else if (ih == &adev->irq.ih1)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
|
||||
else if (ih == &adev->irq.ih2)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
|
||||
else
|
||||
BUG();
|
||||
|
||||
wptr = RREG32_NO_KIQ(reg);
|
||||
wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
@ -413,68 +368,14 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
|
||||
wptr, ih->rptr, tmp);
|
||||
ih->rptr = tmp;
|
||||
|
||||
if (ih == &adev->irq.ih)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
else if (ih == &adev->irq.ih1)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
else if (ih == &adev->irq.ih2)
|
||||
reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
else
|
||||
BUG();
|
||||
|
||||
tmp = RREG32_NO_KIQ(reg);
|
||||
tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32_NO_KIQ(reg, tmp);
|
||||
WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
|
||||
|
||||
out:
|
||||
return (wptr & ih->ptr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* vega10_ih_decode_iv - decode an interrupt vector
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: IH ring buffer to decode
|
||||
* @entry: IV entry to place decoded information into
|
||||
*
|
||||
* Decodes the interrupt vector at the current rptr
|
||||
* position and also advance the position.
|
||||
*/
|
||||
static void vega10_ih_decode_iv(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
/* wptr/rptr are in bytes! */
|
||||
u32 ring_index = ih->rptr >> 2;
|
||||
uint32_t dw[8];
|
||||
|
||||
dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
|
||||
dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
|
||||
dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
|
||||
dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
|
||||
dw[4] = le32_to_cpu(ih->ring[ring_index + 4]);
|
||||
dw[5] = le32_to_cpu(ih->ring[ring_index + 5]);
|
||||
dw[6] = le32_to_cpu(ih->ring[ring_index + 6]);
|
||||
dw[7] = le32_to_cpu(ih->ring[ring_index + 7]);
|
||||
|
||||
entry->client_id = dw[0] & 0xff;
|
||||
entry->src_id = (dw[0] >> 8) & 0xff;
|
||||
entry->ring_id = (dw[0] >> 16) & 0xff;
|
||||
entry->vmid = (dw[0] >> 24) & 0xf;
|
||||
entry->vmid_src = (dw[0] >> 31);
|
||||
entry->timestamp = dw[1] | ((u64)(dw[2] & 0xffff) << 32);
|
||||
entry->timestamp_src = dw[2] >> 31;
|
||||
entry->pasid = dw[3] & 0xffff;
|
||||
entry->pasid_src = dw[3] >> 31;
|
||||
entry->src_data[0] = dw[4];
|
||||
entry->src_data[1] = dw[5];
|
||||
entry->src_data[2] = dw[6];
|
||||
entry->src_data[3] = dw[7];
|
||||
|
||||
/* wptr/rptr are in bytes! */
|
||||
ih->rptr += 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega10_ih_irq_rearm - rearm IRQ if lost
|
||||
*
|
||||
@ -485,22 +386,14 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev,
|
||||
static void vega10_ih_irq_rearm(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
uint32_t reg_rptr = 0;
|
||||
uint32_t v = 0;
|
||||
uint32_t i = 0;
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (ih == &adev->irq.ih)
|
||||
reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
|
||||
else if (ih == &adev->irq.ih1)
|
||||
reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
|
||||
else if (ih == &adev->irq.ih2)
|
||||
reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
|
||||
else
|
||||
return;
|
||||
|
||||
ih_regs = &ih->ih_regs;
|
||||
/* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
|
||||
for (i = 0; i < MAX_REARM_RETRY; i++) {
|
||||
v = RREG32_NO_KIQ(reg_rptr);
|
||||
v = RREG32_NO_KIQ(ih_regs->ih_rb_rptr);
|
||||
if ((v < ih->ring_size) && (v != ih->rptr))
|
||||
WDOORBELL32(ih->doorbell_index, ih->rptr);
|
||||
else
|
||||
@ -519,6 +412,8 @@ static void vega10_ih_irq_rearm(struct amdgpu_device *adev,
|
||||
static void vega10_ih_set_rptr(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (ih->use_doorbell) {
|
||||
/* XXX check if swapping is necessary on BE */
|
||||
*ih->rptr_cpu = ih->rptr;
|
||||
@ -526,12 +421,9 @@ static void vega10_ih_set_rptr(struct amdgpu_device *adev,
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
vega10_ih_irq_rearm(adev, ih);
|
||||
} else if (ih == &adev->irq.ih) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr);
|
||||
} else if (ih == &adev->irq.ih1) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, ih->rptr);
|
||||
} else if (ih == &adev->irq.ih2) {
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, ih->rptr);
|
||||
} else {
|
||||
ih_regs = &ih->ih_regs;
|
||||
WREG32(ih_regs->ih_rb_rptr, ih->rptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -600,19 +492,23 @@ static int vega10_ih_sw_init(void *handle)
|
||||
adev->irq.ih.use_doorbell = true;
|
||||
adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih1.use_doorbell = true;
|
||||
adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1;
|
||||
adev->irq.ih1.use_doorbell = true;
|
||||
adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1;
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih2.use_doorbell = true;
|
||||
adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1;
|
||||
adev->irq.ih2.use_doorbell = true;
|
||||
adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1;
|
||||
}
|
||||
/* initialize ih control registers offset */
|
||||
vega10_ih_init_register_offset(adev);
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
|
||||
if (r)
|
||||
@ -628,6 +524,7 @@ static int vega10_ih_sw_fini(void *handle)
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih_soft);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih2);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih);
|
||||
@ -698,15 +595,11 @@ static void vega10_ih_update_clockgating_state(struct amdgpu_device *adev,
|
||||
def = data = RREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL);
|
||||
field_val = enable ? 0 : 1;
|
||||
/**
|
||||
* Vega10 does not have IH_RETRY_INT_CAM_MEM_CLK_SOFT_OVERRIDE
|
||||
* and IH_BUFFER_MEM_CLK_SOFT_OVERRIDE field.
|
||||
* Vega10/12 and RAVEN don't have IH_BUFFER_MEM_CLK_SOFT_OVERRIDE field.
|
||||
*/
|
||||
if (adev->asic_type > CHIP_VEGA10) {
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
IH_RETRY_INT_CAM_MEM_CLK_SOFT_OVERRIDE, field_val);
|
||||
if (adev->asic_type == CHIP_RENOIR)
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
IH_BUFFER_MEM_CLK_SOFT_OVERRIDE, field_val);
|
||||
}
|
||||
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
DBUS_MUX_CLK_SOFT_OVERRIDE, field_val);
|
||||
@ -759,7 +652,7 @@ const struct amd_ip_funcs vega10_ih_ip_funcs = {
|
||||
|
||||
static const struct amdgpu_ih_funcs vega10_ih_funcs = {
|
||||
.get_wptr = vega10_ih_get_wptr,
|
||||
.decode_iv = vega10_ih_decode_iv,
|
||||
.decode_iv = amdgpu_ih_decode_iv_helper,
|
||||
.set_rptr = vega10_ih_set_rptr
|
||||
};
|
||||
|
||||
|
700
drivers/gpu/drm/amd/amdgpu/vega20_ih.c
Normal file
700
drivers/gpu/drm/amd/amdgpu/vega20_ih.c
Normal file
@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_ih.h"
|
||||
#include "soc15.h"
|
||||
|
||||
#include "oss/osssys_4_2_0_offset.h"
|
||||
#include "oss/osssys_4_2_0_sh_mask.h"
|
||||
|
||||
#include "soc15_common.h"
|
||||
#include "vega20_ih.h"
|
||||
|
||||
#define MAX_REARM_RETRY 10
|
||||
|
||||
static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev);
|
||||
|
||||
/**
|
||||
* vega20_ih_init_register_offset - Initialize register offset for ih rings
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Initialize register offset ih rings (VEGA20).
|
||||
*/
|
||||
static void vega20_ih_init_register_offset(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (adev->irq.ih.ring_size) {
|
||||
ih_regs = &adev->irq.ih.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR);
|
||||
ih_regs->ih_rb_wptr_addr_lo = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO);
|
||||
ih_regs->ih_rb_wptr_addr_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL;
|
||||
}
|
||||
|
||||
if (adev->irq.ih1.ring_size) {
|
||||
ih_regs = &adev->irq.ih1.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING1);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING1);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING1;
|
||||
}
|
||||
|
||||
if (adev->irq.ih2.ring_size) {
|
||||
ih_regs = &adev->irq.ih2.ih_regs;
|
||||
ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING2);
|
||||
ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING2);
|
||||
ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
|
||||
ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
|
||||
ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
|
||||
ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2);
|
||||
ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: amdgpu_ih_ring pointet
|
||||
* @enable: true - enable the interrupts, false - disable the interrupts
|
||||
*
|
||||
* Toggle the interrupt ring buffer (VEGA20)
|
||||
*/
|
||||
static int vega20_ih_toggle_ring_interrupts(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
bool enable)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
uint32_t tmp;
|
||||
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
tmp = RREG32(ih_regs->ih_rb_cntl);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
|
||||
/* enable_intr field is only valid in ring0 */
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0));
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
|
||||
dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32(ih_regs->ih_rb_cntl, tmp);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ih->enabled = true;
|
||||
} else {
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32(ih_regs->ih_rb_rptr, 0);
|
||||
WREG32(ih_regs->ih_rb_wptr, 0);
|
||||
ih->enabled = false;
|
||||
ih->rptr = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @enable: enable or disable interrupt ring buffers
|
||||
*
|
||||
* Toggle all the available interrupt ring buffers (VEGA20).
|
||||
*/
|
||||
static int vega20_ih_toggle_interrupts(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
|
||||
int i;
|
||||
int r;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ih); i++) {
|
||||
if (ih[i]->ring_size) {
|
||||
r = vega20_ih_toggle_ring_interrupts(adev, ih[i], enable);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t vega20_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
|
||||
{
|
||||
int rb_bufsz = order_base_2(ih->ring_size / 4);
|
||||
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
MC_SPACE, ih->use_bus_addr ? 1 : 4);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
WPTR_OVERFLOW_CLEAR, 1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
WPTR_OVERFLOW_ENABLE, 1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
|
||||
/* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register
|
||||
* value is written to memory
|
||||
*/
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
|
||||
WPTR_WRITEBACK_ENABLE, 1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0);
|
||||
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
|
||||
|
||||
return ih_rb_cntl;
|
||||
}
|
||||
|
||||
static uint32_t vega20_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
u32 ih_doorbell_rtpr = 0;
|
||||
|
||||
if (ih->use_doorbell) {
|
||||
ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
|
||||
IH_DOORBELL_RPTR, OFFSET,
|
||||
ih->doorbell_index);
|
||||
ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
|
||||
IH_DOORBELL_RPTR,
|
||||
ENABLE, 1);
|
||||
} else {
|
||||
ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
|
||||
IH_DOORBELL_RPTR,
|
||||
ENABLE, 0);
|
||||
}
|
||||
return ih_doorbell_rtpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_enable_ring - enable an ih ring buffer
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: amdgpu_ih_ring pointer
|
||||
*
|
||||
* Enable an ih ring buffer (VEGA20)
|
||||
*/
|
||||
static int vega20_ih_enable_ring(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
uint32_t tmp;
|
||||
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
|
||||
WREG32(ih_regs->ih_rb_base, ih->gpu_addr >> 8);
|
||||
WREG32(ih_regs->ih_rb_base_hi, (ih->gpu_addr >> 40) & 0xff);
|
||||
|
||||
tmp = RREG32(ih_regs->ih_rb_cntl);
|
||||
tmp = vega20_ih_rb_cntl(ih, tmp);
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RPTR_REARM, !!adev->irq.msi_enabled);
|
||||
if (ih == &adev->irq.ih1) {
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 0);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_FULL_DRAIN_ENABLE, 1);
|
||||
}
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
|
||||
dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
WREG32(ih_regs->ih_rb_cntl, tmp);
|
||||
}
|
||||
|
||||
if (ih == &adev->irq.ih) {
|
||||
/* set the ih ring 0 writeback address whether it's enabled or not */
|
||||
WREG32(ih_regs->ih_rb_wptr_addr_lo, lower_32_bits(ih->wptr_addr));
|
||||
WREG32(ih_regs->ih_rb_wptr_addr_hi, upper_32_bits(ih->wptr_addr) & 0xFFFF);
|
||||
}
|
||||
|
||||
/* set rptr, wptr to 0 */
|
||||
WREG32(ih_regs->ih_rb_wptr, 0);
|
||||
WREG32(ih_regs->ih_rb_rptr, 0);
|
||||
|
||||
WREG32(ih_regs->ih_doorbell_rptr, vega20_ih_doorbell_rptr(ih));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_reroute_ih - reroute VMC/UTCL2 ih to an ih ring
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Reroute VMC and UMC interrupts on primary ih ring to
|
||||
* ih ring 1 so they won't lose when bunches of page faults
|
||||
* interrupts overwhelms the interrupt handler(VEGA20)
|
||||
*/
|
||||
static void vega20_ih_reroute_ih(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
/* vega20 ih reroute will go through psp
|
||||
* this function is only used for arcturus
|
||||
*/
|
||||
if (adev->asic_type == CHIP_ARCTURUS) {
|
||||
/* Reroute to IH ring 1 for VMC */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12);
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
|
||||
|
||||
/* Reroute IH ring 1 for UTCL2 */
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B);
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
|
||||
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_irq_init - init and enable the interrupt ring
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Allocate a ring buffer for the interrupt controller,
|
||||
* enable the RLC, disable interrupts, enable the IH
|
||||
* ring buffer and enable it (VI).
|
||||
* Called at device load and reume.
|
||||
* Returns 0 for success, errors for failure.
|
||||
*/
|
||||
static int vega20_ih_irq_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
|
||||
u32 ih_chicken;
|
||||
int ret;
|
||||
int i;
|
||||
u32 tmp;
|
||||
|
||||
/* disable irqs */
|
||||
ret = vega20_ih_toggle_interrupts(adev, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adev->nbio.funcs->ih_control(adev);
|
||||
|
||||
if (adev->asic_type == CHIP_ARCTURUS &&
|
||||
adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
|
||||
ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN);
|
||||
if (adev->irq.ih.use_bus_addr) {
|
||||
ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
|
||||
MC_SPACE_GPA_ENABLE, 1);
|
||||
}
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN, ih_chicken);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ih); i++) {
|
||||
if (ih[i]->ring_size) {
|
||||
if (i == 1)
|
||||
vega20_ih_reroute_ih(adev);
|
||||
ret = vega20_ih_enable_ring(adev, ih[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL,
|
||||
CLIENT18_IS_STORM_CLIENT, 1);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL, tmp);
|
||||
|
||||
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_INT_FLOOD_CNTL);
|
||||
tmp = REG_SET_FIELD(tmp, IH_INT_FLOOD_CNTL, FLOOD_CNTL_ENABLE, 1);
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_INT_FLOOD_CNTL, tmp);
|
||||
|
||||
pci_set_master(adev->pdev);
|
||||
|
||||
/* enable interrupts */
|
||||
ret = vega20_ih_toggle_interrupts(adev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adev->irq.ih_soft.ring_size)
|
||||
adev->irq.ih_soft.enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_irq_disable - disable interrupts
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Disable interrupts on the hw (VEGA20).
|
||||
*/
|
||||
static void vega20_ih_irq_disable(struct amdgpu_device *adev)
|
||||
{
|
||||
vega20_ih_toggle_interrupts(adev, false);
|
||||
|
||||
/* Wait and acknowledge irq */
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_get_wptr - get the IH ring buffer wptr
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Get the IH ring buffer wptr from either the register
|
||||
* or the writeback memory buffer (VEGA20). Also check for
|
||||
* ring buffer overflow and deal with it.
|
||||
* Returns the value of the wptr.
|
||||
*/
|
||||
static u32 vega20_ih_get_wptr(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
u32 wptr, tmp;
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
wptr = le32_to_cpu(*ih->wptr_cpu);
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
/* Double check that the overflow wasn't already cleared. */
|
||||
wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
|
||||
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
|
||||
goto out;
|
||||
|
||||
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
|
||||
|
||||
/* When a ring buffer overflow happen start parsing interrupt
|
||||
* from the last not overwritten vector (wptr + 32). Hopefully
|
||||
* this should allow us to catchup.
|
||||
*/
|
||||
tmp = (wptr + 32) & ih->ptr_mask;
|
||||
dev_warn(adev->dev, "IH ring buffer overflow "
|
||||
"(0x%08X, 0x%08X, 0x%08X)\n",
|
||||
wptr, ih->rptr, tmp);
|
||||
ih->rptr = tmp;
|
||||
|
||||
tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
|
||||
|
||||
out:
|
||||
return (wptr & ih->ptr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_irq_rearm - rearm IRQ if lost
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
*/
|
||||
static void vega20_ih_irq_rearm(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
uint32_t v = 0;
|
||||
uint32_t i = 0;
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
ih_regs = &ih->ih_regs;
|
||||
|
||||
/* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
|
||||
for (i = 0; i < MAX_REARM_RETRY; i++) {
|
||||
v = RREG32_NO_KIQ(ih_regs->ih_rb_rptr);
|
||||
if ((v < ih->ring_size) && (v != ih->rptr))
|
||||
WDOORBELL32(ih->doorbell_index, ih->rptr);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_set_rptr - set the IH ring buffer rptr
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Set the IH ring buffer rptr.
|
||||
*/
|
||||
static void vega20_ih_set_rptr(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
struct amdgpu_ih_regs *ih_regs;
|
||||
|
||||
if (ih->use_doorbell) {
|
||||
/* XXX check if swapping is necessary on BE */
|
||||
*ih->rptr_cpu = ih->rptr;
|
||||
WDOORBELL32(ih->doorbell_index, ih->rptr);
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
vega20_ih_irq_rearm(adev, ih);
|
||||
} else {
|
||||
ih_regs = &ih->ih_regs;
|
||||
WREG32(ih_regs->ih_rb_rptr, ih->rptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vega20_ih_self_irq - dispatch work for ring 1 and 2
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @source: irq source
|
||||
* @entry: IV with WPTR update
|
||||
*
|
||||
* Update the WPTR from the IV and schedule work to handle the entries.
|
||||
*/
|
||||
static int vega20_ih_self_irq(struct amdgpu_device *adev,
|
||||
struct amdgpu_irq_src *source,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
uint32_t wptr = cpu_to_le32(entry->src_data[0]);
|
||||
|
||||
switch (entry->ring_id) {
|
||||
case 1:
|
||||
*adev->irq.ih1.wptr_cpu = wptr;
|
||||
schedule_work(&adev->irq.ih1_work);
|
||||
break;
|
||||
case 2:
|
||||
*adev->irq.ih2.wptr_cpu = wptr;
|
||||
schedule_work(&adev->irq.ih2_work);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct amdgpu_irq_src_funcs vega20_ih_self_irq_funcs = {
|
||||
.process = vega20_ih_self_irq,
|
||||
};
|
||||
|
||||
static void vega20_ih_set_self_irq_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
adev->irq.self_irq.num_types = 0;
|
||||
adev->irq.self_irq.funcs = &vega20_ih_self_irq_funcs;
|
||||
}
|
||||
|
||||
static int vega20_ih_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
vega20_ih_set_interrupt_funcs(adev);
|
||||
vega20_ih_set_self_irq_funcs(adev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vega20_ih_sw_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
int r;
|
||||
|
||||
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0,
|
||||
&adev->irq.self_irq);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih.use_doorbell = true;
|
||||
adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih1.use_doorbell = true;
|
||||
adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1;
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->irq.ih2.use_doorbell = true;
|
||||
adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1;
|
||||
|
||||
/* initialize ih control registers offset */
|
||||
vega20_ih_init_register_offset(adev);
|
||||
|
||||
r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_irq_init(adev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vega20_ih_sw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih_soft);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih2);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
|
||||
amdgpu_ih_ring_fini(adev, &adev->irq.ih);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vega20_ih_hw_init(void *handle)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
r = vega20_ih_irq_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vega20_ih_hw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
vega20_ih_irq_disable(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vega20_ih_suspend(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
return vega20_ih_hw_fini(adev);
|
||||
}
|
||||
|
||||
static int vega20_ih_resume(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
return vega20_ih_hw_init(adev);
|
||||
}
|
||||
|
||||
static bool vega20_ih_is_idle(void *handle)
|
||||
{
|
||||
/* todo */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int vega20_ih_wait_for_idle(void *handle)
|
||||
{
|
||||
/* todo */
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int vega20_ih_soft_reset(void *handle)
|
||||
{
|
||||
/* todo */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vega20_ih_update_clockgating_state(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t data, def, field_val;
|
||||
|
||||
if (adev->cg_flags & AMD_CG_SUPPORT_IH_CG) {
|
||||
def = data = RREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL);
|
||||
field_val = enable ? 0 : 1;
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
IH_RETRY_INT_CAM_MEM_CLK_SOFT_OVERRIDE, field_val);
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
IH_BUFFER_MEM_CLK_SOFT_OVERRIDE, field_val);
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
DBUS_MUX_CLK_SOFT_OVERRIDE, field_val);
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
OSSSYS_SHARE_CLK_SOFT_OVERRIDE, field_val);
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
LIMIT_SMN_CLK_SOFT_OVERRIDE, field_val);
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
DYN_CLK_SOFT_OVERRIDE, field_val);
|
||||
data = REG_SET_FIELD(data, IH_CLK_CTRL,
|
||||
REG_CLK_SOFT_OVERRIDE, field_val);
|
||||
if (def != data)
|
||||
WREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL, data);
|
||||
}
|
||||
}
|
||||
|
||||
static int vega20_ih_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
vega20_ih_update_clockgating_state(adev,
|
||||
state == AMD_CG_STATE_GATE);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int vega20_ih_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs vega20_ih_ip_funcs = {
|
||||
.name = "vega20_ih",
|
||||
.early_init = vega20_ih_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = vega20_ih_sw_init,
|
||||
.sw_fini = vega20_ih_sw_fini,
|
||||
.hw_init = vega20_ih_hw_init,
|
||||
.hw_fini = vega20_ih_hw_fini,
|
||||
.suspend = vega20_ih_suspend,
|
||||
.resume = vega20_ih_resume,
|
||||
.is_idle = vega20_ih_is_idle,
|
||||
.wait_for_idle = vega20_ih_wait_for_idle,
|
||||
.soft_reset = vega20_ih_soft_reset,
|
||||
.set_clockgating_state = vega20_ih_set_clockgating_state,
|
||||
.set_powergating_state = vega20_ih_set_powergating_state,
|
||||
};
|
||||
|
||||
static const struct amdgpu_ih_funcs vega20_ih_funcs = {
|
||||
.get_wptr = vega20_ih_get_wptr,
|
||||
.decode_iv = amdgpu_ih_decode_iv_helper,
|
||||
.set_rptr = vega20_ih_set_rptr
|
||||
};
|
||||
|
||||
static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
adev->irq.ih_funcs = &vega20_ih_funcs;
|
||||
}
|
||||
|
||||
const struct amdgpu_ip_block_version vega20_ih_ip_block =
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_IH,
|
||||
.major = 4,
|
||||
.minor = 2,
|
||||
.rev = 0,
|
||||
.funcs = &vega20_ih_ip_funcs,
|
||||
};
|
30
drivers/gpu/drm/amd/amdgpu/vega20_ih.h
Normal file
30
drivers/gpu/drm/amd/amdgpu/vega20_ih.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VEGA20_IH_H__
|
||||
#define __VEGA20_IH_H__
|
||||
|
||||
extern const struct amd_ip_funcs vega20_ih_ip_funcs;
|
||||
extern const struct amdgpu_ip_block_version vega20_ih_ip_block;
|
||||
|
||||
#endif
|
@ -44,6 +44,25 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev,
|
||||
client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
|
||||
pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
|
||||
|
||||
/* Only handle clients we care about */
|
||||
if (client_id != SOC15_IH_CLIENTID_GRBM_CP &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA0 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA1 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA2 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA3 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA4 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA5 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA6 &&
|
||||
client_id != SOC15_IH_CLIENTID_SDMA7 &&
|
||||
client_id != SOC15_IH_CLIENTID_VMC &&
|
||||
client_id != SOC15_IH_CLIENTID_VMC1 &&
|
||||
client_id != SOC15_IH_CLIENTID_UTCL2 &&
|
||||
client_id != SOC15_IH_CLIENTID_SE0SH &&
|
||||
client_id != SOC15_IH_CLIENTID_SE1SH &&
|
||||
client_id != SOC15_IH_CLIENTID_SE2SH &&
|
||||
client_id != SOC15_IH_CLIENTID_SE3SH)
|
||||
return false;
|
||||
|
||||
/* This is a known issue for gfx9. Under non HWS, pasid is not set
|
||||
* in the interrupt payload, so we need to find out the pasid on our
|
||||
* own.
|
||||
@ -96,17 +115,30 @@ static void event_interrupt_wq_v9(struct kfd_dev *dev,
|
||||
vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry);
|
||||
context_id = SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry);
|
||||
|
||||
if (source_id == SOC15_INTSRC_CP_END_OF_PIPE)
|
||||
kfd_signal_event_interrupt(pasid, context_id, 32);
|
||||
else if (source_id == SOC15_INTSRC_SDMA_TRAP)
|
||||
kfd_signal_event_interrupt(pasid, context_id & 0xfffffff, 28);
|
||||
else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG)
|
||||
kfd_signal_event_interrupt(pasid, context_id & 0xffffff, 24);
|
||||
else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE)
|
||||
kfd_signal_hw_exception_event(pasid);
|
||||
else if (client_id == SOC15_IH_CLIENTID_VMC ||
|
||||
client_id == SOC15_IH_CLIENTID_VMC1 ||
|
||||
client_id == SOC15_IH_CLIENTID_UTCL2) {
|
||||
if (client_id == SOC15_IH_CLIENTID_GRBM_CP ||
|
||||
client_id == SOC15_IH_CLIENTID_SE0SH ||
|
||||
client_id == SOC15_IH_CLIENTID_SE1SH ||
|
||||
client_id == SOC15_IH_CLIENTID_SE2SH ||
|
||||
client_id == SOC15_IH_CLIENTID_SE3SH) {
|
||||
if (source_id == SOC15_INTSRC_CP_END_OF_PIPE)
|
||||
kfd_signal_event_interrupt(pasid, context_id, 32);
|
||||
else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG)
|
||||
kfd_signal_event_interrupt(pasid, context_id & 0xffffff, 24);
|
||||
else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE)
|
||||
kfd_signal_hw_exception_event(pasid);
|
||||
} else if (client_id == SOC15_IH_CLIENTID_SDMA0 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA1 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA2 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA3 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA4 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA5 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA6 ||
|
||||
client_id == SOC15_IH_CLIENTID_SDMA7) {
|
||||
if (source_id == SOC15_INTSRC_SDMA_TRAP)
|
||||
kfd_signal_event_interrupt(pasid, context_id & 0xfffffff, 28);
|
||||
} else if (client_id == SOC15_IH_CLIENTID_VMC ||
|
||||
client_id == SOC15_IH_CLIENTID_VMC1 ||
|
||||
client_id == SOC15_IH_CLIENTID_UTCL2) {
|
||||
struct kfd_vm_fault_info info = {0};
|
||||
uint16_t ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry);
|
||||
|
||||
|
@ -6,7 +6,7 @@ config DRM_AMD_DC
|
||||
bool "AMD DC - Enable new display engine"
|
||||
default y
|
||||
select SND_HDA_COMPONENT if SND_HDA_CORE
|
||||
select DRM_AMD_DC_DCN if (X86 || PPC64 || (ARM64 && KERNEL_MODE_NEON)) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
|
||||
select DRM_AMD_DC_DCN if (X86 || PPC64) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
|
||||
help
|
||||
Choose this option if you want to use the new display engine
|
||||
support for AMDGPU. This adds required support for Vega and
|
||||
|
@ -60,7 +60,6 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pci.h>
|
||||
@ -2386,8 +2385,7 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
|
||||
drm_connector_update_edid_property(connector,
|
||||
aconnector->edid);
|
||||
aconnector->num_modes = drm_add_edid_modes(connector, aconnector->edid);
|
||||
drm_connector_list_update(connector);
|
||||
drm_add_edid_modes(connector, aconnector->edid);
|
||||
|
||||
if (aconnector->dc_link->aux_mode)
|
||||
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
|
||||
@ -3760,10 +3758,53 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
|
||||
};
|
||||
|
||||
|
||||
static void get_min_max_dc_plane_scaling(struct drm_device *dev,
|
||||
struct drm_framebuffer *fb,
|
||||
int *min_downscale, int *max_upscale)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct dc *dc = adev->dm.dc;
|
||||
/* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
|
||||
struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
|
||||
|
||||
switch (fb->format->format) {
|
||||
case DRM_FORMAT_P010:
|
||||
case DRM_FORMAT_NV12:
|
||||
case DRM_FORMAT_NV21:
|
||||
*max_upscale = plane_cap->max_upscale_factor.nv12;
|
||||
*min_downscale = plane_cap->max_downscale_factor.nv12;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_XRGB16161616F:
|
||||
case DRM_FORMAT_ARGB16161616F:
|
||||
case DRM_FORMAT_XBGR16161616F:
|
||||
case DRM_FORMAT_ABGR16161616F:
|
||||
*max_upscale = plane_cap->max_upscale_factor.fp16;
|
||||
*min_downscale = plane_cap->max_downscale_factor.fp16;
|
||||
break;
|
||||
|
||||
default:
|
||||
*max_upscale = plane_cap->max_upscale_factor.argb8888;
|
||||
*min_downscale = plane_cap->max_downscale_factor.argb8888;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* A factor of 1 in the plane_cap means to not allow scaling, ie. use a
|
||||
* scaling factor of 1.0 == 1000 units.
|
||||
*/
|
||||
if (*max_upscale == 1)
|
||||
*max_upscale = 1000;
|
||||
|
||||
if (*min_downscale == 1)
|
||||
*min_downscale = 1000;
|
||||
}
|
||||
|
||||
|
||||
static int fill_dc_scaling_info(const struct drm_plane_state *state,
|
||||
struct dc_scaling_info *scaling_info)
|
||||
{
|
||||
int scale_w, scale_h;
|
||||
int scale_w, scale_h, min_downscale, max_upscale;
|
||||
|
||||
memset(scaling_info, 0, sizeof(*scaling_info));
|
||||
|
||||
@ -3795,17 +3836,25 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state,
|
||||
/* DRM doesn't specify clipping on destination output. */
|
||||
scaling_info->clip_rect = scaling_info->dst_rect;
|
||||
|
||||
/* TODO: Validate scaling per-format with DC plane caps */
|
||||
/* Validate scaling per-format with DC plane caps */
|
||||
if (state->plane && state->plane->dev && state->fb) {
|
||||
get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
|
||||
&min_downscale, &max_upscale);
|
||||
} else {
|
||||
min_downscale = 250;
|
||||
max_upscale = 16000;
|
||||
}
|
||||
|
||||
scale_w = scaling_info->dst_rect.width * 1000 /
|
||||
scaling_info->src_rect.width;
|
||||
|
||||
if (scale_w < 250 || scale_w > 16000)
|
||||
if (scale_w < min_downscale || scale_w > max_upscale)
|
||||
return -EINVAL;
|
||||
|
||||
scale_h = scaling_info->dst_rect.height * 1000 /
|
||||
scaling_info->src_rect.height;
|
||||
|
||||
if (scale_h < 250 || scale_h > 16000)
|
||||
if (scale_h < min_downscale || scale_h > max_upscale)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
@ -5414,6 +5463,7 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
|
||||
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
|
||||
struct amdgpu_device *adev = drm_to_adev(crtc->dev);
|
||||
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
|
||||
struct amdgpu_display_manager *dm = &adev->dm;
|
||||
int rc = 0;
|
||||
|
||||
if (enable) {
|
||||
@ -5429,7 +5479,27 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
|
||||
return rc;
|
||||
|
||||
irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
|
||||
return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
|
||||
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
|
||||
return -EBUSY;
|
||||
|
||||
mutex_lock(&dm->dc_lock);
|
||||
|
||||
if (enable)
|
||||
dm->active_vblank_irq_count++;
|
||||
else
|
||||
dm->active_vblank_irq_count--;
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
dc_allow_idle_optimizations(
|
||||
adev->dm.dc, dm->active_vblank_irq_count == 0 ? true : false);
|
||||
|
||||
DRM_DEBUG_DRIVER("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0);
|
||||
#endif
|
||||
|
||||
mutex_unlock(&dm->dc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dm_enable_vblank(struct drm_crtc *crtc)
|
||||
@ -6424,12 +6494,26 @@ static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
|
||||
static int dm_plane_helper_check_state(struct drm_plane_state *state,
|
||||
struct drm_crtc_state *new_crtc_state)
|
||||
{
|
||||
int max_downscale = 0;
|
||||
int max_upscale = INT_MAX;
|
||||
struct drm_framebuffer *fb = state->fb;
|
||||
int min_downscale, max_upscale;
|
||||
int min_scale = 0;
|
||||
int max_scale = INT_MAX;
|
||||
|
||||
/* Plane enabled? Get min/max allowed scaling factors from plane caps. */
|
||||
if (fb && state->crtc) {
|
||||
get_min_max_dc_plane_scaling(state->crtc->dev, fb,
|
||||
&min_downscale, &max_upscale);
|
||||
/*
|
||||
* Convert to drm convention: 16.16 fixed point, instead of dc's
|
||||
* 1.0 == 1000. Also drm scaling is src/dst instead of dc's
|
||||
* dst/src, so min_scale = 1.0 / max_upscale, etc.
|
||||
*/
|
||||
min_scale = (1000 << 16) / max_upscale;
|
||||
max_scale = (1000 << 16) / min_downscale;
|
||||
}
|
||||
|
||||
/* TODO: These should be checked against DC plane caps */
|
||||
return drm_atomic_helper_check_plane_state(
|
||||
state, new_crtc_state, max_downscale, max_upscale, true, true);
|
||||
state, new_crtc_state, min_scale, max_scale, true, true);
|
||||
}
|
||||
|
||||
static int dm_plane_atomic_check(struct drm_plane *plane,
|
||||
@ -8378,8 +8462,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
|
||||
manage_dm_interrupts(adev, acrtc, true);
|
||||
}
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
if (new_crtc_state->active &&
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS) && new_crtc_state->active &&
|
||||
amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) {
|
||||
/**
|
||||
* Frontend may have changed so reapply the CRC capture
|
||||
@ -8400,7 +8483,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
amdgpu_dm_crtc_configure_crc_source(
|
||||
crtc, dm_new_crtc_state, dm_new_crtc_state->crc_src);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, new_crtc_state, j)
|
||||
|
@ -336,6 +336,13 @@ struct amdgpu_display_manager {
|
||||
*/
|
||||
const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box;
|
||||
|
||||
/**
|
||||
* @active_vblank_irq_count
|
||||
*
|
||||
* number of currently active vblank irqs
|
||||
*/
|
||||
uint32_t active_vblank_irq_count;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
/**
|
||||
* @crc_win_x_start_property:
|
||||
|
@ -46,13 +46,13 @@ static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source
|
||||
}
|
||||
|
||||
/* amdgpu_dm_crc.c */
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
bool amdgpu_dm_crc_window_is_default(struct dm_crtc_state *dm_crtc_state);
|
||||
bool amdgpu_dm_crc_window_changed(struct dm_crtc_state *dm_new_crtc_state,
|
||||
struct dm_crtc_state *dm_old_crtc_state);
|
||||
int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
|
||||
struct dm_crtc_state *dm_crtc_state,
|
||||
enum amdgpu_dm_pipe_crc_source source);
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name);
|
||||
int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc,
|
||||
const char *src_name,
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
@ -23,7 +23,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_dp_mst_helper.h>
|
||||
|
@ -33,10 +33,6 @@ ifdef CONFIG_PPC64
|
||||
calcs_ccflags := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
calcs_rcflags := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -104,13 +104,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
|
||||
endif
|
||||
|
||||
# prevent build errors:
|
||||
# ...: '-mgeneral-regs-only' is incompatible with the use of floating-point types
|
||||
# this file is unused on arm64, just like on ppc64
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
AMD_DAL_CLK_MGR_DCN21 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn21/,$(CLK_MGR_DCN21))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN21)
|
||||
@ -125,13 +118,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn30/dcn30_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
|
||||
endif
|
||||
|
||||
# prevent build errors:
|
||||
# ...: '-mgeneral-regs-only' is incompatible with the use of floating-point types
|
||||
# this file is unused on arm64, just like on ppc64
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/clk_mgr/dcn30/dcn30_clk_mgr.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
AMD_DAL_CLK_MGR_DCN30 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn30/,$(CLK_MGR_DCN30))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN30)
|
||||
@ -146,13 +132,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn301/vg_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
|
||||
endif
|
||||
|
||||
# prevent build errors:
|
||||
# ...: '-mgeneral-regs-only' is incompatible with the use of floating-point types
|
||||
# this file is unused on arm64, just like on ppc64
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/clk_mgr/dcn301/vg_clk_mgr.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
AMD_DAL_CLK_MGR_DCN301 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn301/,$(CLK_MGR_DCN301))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN301)
|
||||
|
@ -964,19 +964,15 @@ struct dc *dc_create(const struct dc_init_data *init_params)
|
||||
struct dc *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
|
||||
unsigned int full_pipe_count;
|
||||
|
||||
if (NULL == dc)
|
||||
goto alloc_fail;
|
||||
if (!dc)
|
||||
return NULL;
|
||||
|
||||
if (init_params->dce_environment == DCE_ENV_VIRTUAL_HW) {
|
||||
if (false == dc_construct_ctx(dc, init_params)) {
|
||||
dc_destruct(dc);
|
||||
goto construct_fail;
|
||||
}
|
||||
if (!dc_construct_ctx(dc, init_params))
|
||||
goto destruct_dc;
|
||||
} else {
|
||||
if (false == dc_construct(dc, init_params)) {
|
||||
dc_destruct(dc);
|
||||
goto construct_fail;
|
||||
}
|
||||
if (!dc_construct(dc, init_params))
|
||||
goto destruct_dc;
|
||||
|
||||
full_pipe_count = dc->res_pool->pipe_count;
|
||||
if (dc->res_pool->underlay_pipe_index != NO_UNDERLAY_PIPE)
|
||||
@ -1007,10 +1003,9 @@ struct dc *dc_create(const struct dc_init_data *init_params)
|
||||
|
||||
return dc;
|
||||
|
||||
construct_fail:
|
||||
destruct_dc:
|
||||
dc_destruct(dc);
|
||||
kfree(dc);
|
||||
|
||||
alloc_fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1493,7 +1488,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context)
|
||||
enum dc_status result = DC_ERROR_UNEXPECTED;
|
||||
int i;
|
||||
|
||||
if (false == context_changed(dc, context))
|
||||
if (!context_changed(dc, context))
|
||||
return DC_OK;
|
||||
|
||||
DC_LOG_DC("%s: %d streams\n",
|
||||
@ -1540,7 +1535,7 @@ bool dc_acquire_release_mpc_3dlut(
|
||||
if (found_pipe_idx) {
|
||||
if (acquire && pool->funcs->acquire_post_bldn_3dlut)
|
||||
ret = pool->funcs->acquire_post_bldn_3dlut(res_ctx, pool, mpcc_id, lut, shaper);
|
||||
else if (acquire == false && pool->funcs->release_post_bldn_3dlut)
|
||||
else if (!acquire && pool->funcs->release_post_bldn_3dlut)
|
||||
ret = pool->funcs->release_post_bldn_3dlut(res_ctx, pool, lut, shaper);
|
||||
}
|
||||
}
|
||||
@ -3143,9 +3138,11 @@ void dc_lock_memory_clock_frequency(struct dc *dc)
|
||||
core_link_enable_stream(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
|
||||
}
|
||||
|
||||
bool dc_is_plane_eligible_for_idle_optimizaitons(struct dc *dc,
|
||||
struct dc_plane_state *plane)
|
||||
bool dc_is_plane_eligible_for_idle_optimizaitons(struct dc *dc, struct dc_plane_state *plane)
|
||||
{
|
||||
if (dc->hwss.does_plane_fit_in_mall && dc->hwss.does_plane_fit_in_mall(dc, plane))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2487,9 +2487,14 @@ enum dc_status dc_link_validate_mode_timing(
|
||||
static struct abm *get_abm_from_stream_res(const struct dc_link *link)
|
||||
{
|
||||
int i;
|
||||
struct dc *dc = link->ctx->dc;
|
||||
struct dc *dc = NULL;
|
||||
struct abm *abm = NULL;
|
||||
|
||||
if (!link || !link->ctx)
|
||||
return NULL;
|
||||
|
||||
dc = link->ctx->dc;
|
||||
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
|
||||
struct dc_stream_state *stream = pipe_ctx.stream;
|
||||
|
@ -171,6 +171,9 @@ struct dc_caps {
|
||||
bool dmcub_support;
|
||||
uint32_t num_of_internal_disp;
|
||||
enum dp_protocol_version max_dp_protocol_version;
|
||||
unsigned int mall_size_per_mem_channel;
|
||||
unsigned int mall_size_total;
|
||||
unsigned int cursor_cache_size;
|
||||
struct dc_plane_cap planes[MAX_PLANES];
|
||||
struct dc_color_caps color;
|
||||
};
|
||||
@ -499,6 +502,7 @@ struct dc_debug_options {
|
||||
bool dmcub_emulation;
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
bool disable_idle_power_optimizations;
|
||||
unsigned int mall_size_override;
|
||||
#endif
|
||||
bool dmub_command_table; /* for testing only */
|
||||
struct dc_bw_validation_profile bw_val_profile;
|
||||
|
@ -71,6 +71,7 @@ struct dc_plane_address {
|
||||
union {
|
||||
struct{
|
||||
PHYSICAL_ADDRESS_LOC addr;
|
||||
PHYSICAL_ADDRESS_LOC cursor_cache_addr;
|
||||
PHYSICAL_ADDRESS_LOC meta_addr;
|
||||
union large_integer dcc_const_color;
|
||||
} grph;
|
||||
|
@ -385,7 +385,7 @@ static const struct dc_plane_cap plane_cap = {
|
||||
.pixel_format_support = {
|
||||
.argb8888 = true,
|
||||
.nv12 = false,
|
||||
.fp16 = false
|
||||
.fp16 = true
|
||||
},
|
||||
|
||||
.max_upscale_factor = {
|
||||
|
@ -410,7 +410,7 @@ static const struct dc_plane_cap plane_cap = {
|
||||
.pixel_format_support = {
|
||||
.argb8888 = true,
|
||||
.nv12 = false,
|
||||
.fp16 = false
|
||||
.fp16 = true
|
||||
},
|
||||
|
||||
.max_upscale_factor = {
|
||||
|
@ -402,7 +402,7 @@ static const struct dc_plane_cap plane_cap = {
|
||||
.pixel_format_support = {
|
||||
.argb8888 = true,
|
||||
.nv12 = false,
|
||||
.fp16 = false
|
||||
.fp16 = true
|
||||
},
|
||||
|
||||
.max_upscale_factor = {
|
||||
|
@ -31,11 +31,4 @@ DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \
|
||||
|
||||
AMD_DAL_DCN10 = $(addprefix $(AMDDALPATH)/dc/dcn10/,$(DCN10))
|
||||
|
||||
# fix:
|
||||
# ...: '-mgeneral-regs-only' is incompatible with the use of floating-point types
|
||||
# aarch64 does not support soft-float, so use hard-float and handle this in code
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn10/dcn10_resource.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_DCN10)
|
||||
|
@ -1534,15 +1534,8 @@ static bool dcn10_resource_construct(
|
||||
memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults));
|
||||
memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults));
|
||||
|
||||
#if defined(CONFIG_ARM64)
|
||||
/* Aarch64 does not support -msoft-float/-mfloat-abi=soft */
|
||||
DC_FP_START();
|
||||
dcn10_resource_construct_fp(dc);
|
||||
DC_FP_END();
|
||||
#else
|
||||
/* Other architectures we build for build this with soft-float */
|
||||
dcn10_resource_construct_fp(dc);
|
||||
#endif
|
||||
|
||||
pool->base.pp_smu = dcn10_pp_smu_create(ctx);
|
||||
|
||||
|
@ -17,10 +17,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -13,10 +13,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -41,11 +41,6 @@ CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mhard-float -maltivec
|
||||
CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mgeneral-regs-only
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -814,6 +814,19 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane)
|
||||
{
|
||||
// add meta size?
|
||||
unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height *
|
||||
(plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
|
||||
unsigned int mall_size = dc->caps.mall_size_total;
|
||||
|
||||
if (dc->debug.mall_size_override)
|
||||
mall_size = 1024 * 1024 * dc->debug.mall_size_override;
|
||||
|
||||
return (surface_size + dc->caps.cursor_cache_size) < mall_size;
|
||||
}
|
||||
|
||||
void dcn30_hardware_release(struct dc *dc)
|
||||
{
|
||||
/* if pstate unsupported, force it supported */
|
||||
|
@ -65,6 +65,8 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx);
|
||||
void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx);
|
||||
|
||||
bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane);
|
||||
|
||||
bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable);
|
||||
|
||||
void dcn30_hardware_release(struct dc *dc);
|
||||
|
@ -91,6 +91,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
|
||||
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
|
||||
.calc_vupdate_position = dcn10_calc_vupdate_position,
|
||||
.apply_idle_power_optimizations = dcn30_apply_idle_power_optimizations,
|
||||
.does_plane_fit_in_mall = dcn30_does_plane_fit_in_mall,
|
||||
.set_backlight_level = dcn21_set_backlight_level,
|
||||
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
|
||||
.hardware_release = dcn30_hardware_release,
|
||||
|
@ -2631,6 +2631,10 @@ static bool dcn30_resource_construct(
|
||||
dc->caps.max_cursor_size = 256;
|
||||
dc->caps.min_horizontal_blanking_period = 80;
|
||||
dc->caps.dmdata_alloc_size = 2048;
|
||||
dc->caps.mall_size_per_mem_channel = 8;
|
||||
/* total size = mall per channel * num channels * 1024 * 1024 */
|
||||
dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576;
|
||||
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
|
||||
|
||||
dc->caps.max_slave_planes = 1;
|
||||
dc->caps.post_blend_color_processing = true;
|
||||
|
@ -21,10 +21,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -20,10 +20,6 @@ ifdef CONFIG_PPC64
|
||||
CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "dce/dce_i2c_hw.h"
|
||||
#include "dce/dce_panel_cntl.h"
|
||||
#include "dce/dmub_abm.h"
|
||||
#include "dce/dmub_psr.h"
|
||||
|
||||
#include "hw_sequencer_private.h"
|
||||
#include "reg_helper.h"
|
||||
@ -238,6 +239,7 @@ static const struct dc_debug_options debug_defaults_diags = {
|
||||
.dwb_fi_phase = -1, // -1 = disable
|
||||
.dmub_command_table = true,
|
||||
.enable_tri_buf = true,
|
||||
.disable_psr = true,
|
||||
};
|
||||
|
||||
enum dcn302_clk_src_array_id {
|
||||
@ -1213,6 +1215,9 @@ static void dcn302_resource_destruct(struct resource_pool *pool)
|
||||
dce_abm_destroy(&pool->multiple_abms[i]);
|
||||
}
|
||||
|
||||
if (pool->psr != NULL)
|
||||
dmub_psr_destroy(&pool->psr);
|
||||
|
||||
if (pool->dccg != NULL)
|
||||
dcn_dccg_destroy(&pool->dccg);
|
||||
}
|
||||
@ -1354,8 +1359,6 @@ static bool dcn302_resource_construct(
|
||||
|
||||
if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
|
||||
dc->debug = debug_defaults_drv;
|
||||
else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)
|
||||
dc->debug = debug_defaults_diags;
|
||||
else
|
||||
dc->debug = debug_defaults_diags;
|
||||
|
||||
@ -1469,6 +1472,14 @@ static bool dcn302_resource_construct(
|
||||
}
|
||||
pool->timing_generator_count = i;
|
||||
|
||||
/* PSR */
|
||||
pool->psr = dmub_psr_create(ctx);
|
||||
if (pool->psr == NULL) {
|
||||
dm_error("DC: failed to create psr!\n");
|
||||
BREAK_TO_DEBUGGER();
|
||||
goto create_fail;
|
||||
}
|
||||
|
||||
/* ABMs */
|
||||
for (i = 0; i < pool->res_cap->num_timing_generator; i++) {
|
||||
pool->multiple_abms[i] = dmub_abm_create(ctx, &abm_regs[i], &abm_shift, &abm_mask);
|
||||
|
@ -33,10 +33,6 @@ ifdef CONFIG_PPC64
|
||||
dml_ccflags := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
dml_rcflags := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -10,10 +10,6 @@ ifdef CONFIG_PPC64
|
||||
dsc_ccflags := -mhard-float -maltivec
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
dsc_rcflags := -mgeneral-regs-only
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
ifeq ($(call cc-ifversion, -lt, 0701, y), y)
|
||||
IS_OLD_GCC = 1
|
||||
|
@ -217,6 +217,8 @@ struct hw_sequencer_funcs {
|
||||
/* Idle Optimization Related */
|
||||
bool (*apply_idle_power_optimizations)(struct dc *dc, bool enable);
|
||||
|
||||
bool (*does_plane_fit_in_mall)(struct dc *dc, struct dc_plane_state *plane);
|
||||
|
||||
bool (*is_abm_supported)(struct dc *dc,
|
||||
struct dc_state *context, struct dc_stream_state *stream);
|
||||
|
||||
|
@ -55,10 +55,6 @@
|
||||
#include <asm/fpu/api.h>
|
||||
#define DC_FP_START() kernel_fpu_begin()
|
||||
#define DC_FP_END() kernel_fpu_end()
|
||||
#elif defined(CONFIG_ARM64)
|
||||
#include <asm/neon.h>
|
||||
#define DC_FP_START() kernel_neon_begin()
|
||||
#define DC_FP_END() kernel_neon_end()
|
||||
#elif defined(CONFIG_PPC64)
|
||||
#include <asm/switch_to.h>
|
||||
#include <asm/cputable.h>
|
||||
|
345
drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h
Normal file
345
drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _osssys_4_2_0_OFFSET_HEADER
|
||||
#define _osssys_4_2_0_OFFSET_HEADER
|
||||
|
||||
|
||||
|
||||
// addressBlock: osssys_osssysdec
|
||||
// base address: 0x4280
|
||||
#define mmIH_VMID_0_LUT 0x0000
|
||||
#define mmIH_VMID_0_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_1_LUT 0x0001
|
||||
#define mmIH_VMID_1_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_2_LUT 0x0002
|
||||
#define mmIH_VMID_2_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_3_LUT 0x0003
|
||||
#define mmIH_VMID_3_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_4_LUT 0x0004
|
||||
#define mmIH_VMID_4_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_5_LUT 0x0005
|
||||
#define mmIH_VMID_5_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_6_LUT 0x0006
|
||||
#define mmIH_VMID_6_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_7_LUT 0x0007
|
||||
#define mmIH_VMID_7_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_8_LUT 0x0008
|
||||
#define mmIH_VMID_8_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_9_LUT 0x0009
|
||||
#define mmIH_VMID_9_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_10_LUT 0x000a
|
||||
#define mmIH_VMID_10_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_11_LUT 0x000b
|
||||
#define mmIH_VMID_11_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_12_LUT 0x000c
|
||||
#define mmIH_VMID_12_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_13_LUT 0x000d
|
||||
#define mmIH_VMID_13_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_14_LUT 0x000e
|
||||
#define mmIH_VMID_14_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_15_LUT 0x000f
|
||||
#define mmIH_VMID_15_LUT_BASE_IDX 0
|
||||
#define mmIH_VMID_0_LUT_MM 0x0010
|
||||
#define mmIH_VMID_0_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_1_LUT_MM 0x0011
|
||||
#define mmIH_VMID_1_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_2_LUT_MM 0x0012
|
||||
#define mmIH_VMID_2_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_3_LUT_MM 0x0013
|
||||
#define mmIH_VMID_3_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_4_LUT_MM 0x0014
|
||||
#define mmIH_VMID_4_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_5_LUT_MM 0x0015
|
||||
#define mmIH_VMID_5_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_6_LUT_MM 0x0016
|
||||
#define mmIH_VMID_6_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_7_LUT_MM 0x0017
|
||||
#define mmIH_VMID_7_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_8_LUT_MM 0x0018
|
||||
#define mmIH_VMID_8_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_9_LUT_MM 0x0019
|
||||
#define mmIH_VMID_9_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_10_LUT_MM 0x001a
|
||||
#define mmIH_VMID_10_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_11_LUT_MM 0x001b
|
||||
#define mmIH_VMID_11_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_12_LUT_MM 0x001c
|
||||
#define mmIH_VMID_12_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_13_LUT_MM 0x001d
|
||||
#define mmIH_VMID_13_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_14_LUT_MM 0x001e
|
||||
#define mmIH_VMID_14_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_VMID_15_LUT_MM 0x001f
|
||||
#define mmIH_VMID_15_LUT_MM_BASE_IDX 0
|
||||
#define mmIH_COOKIE_0 0x0020
|
||||
#define mmIH_COOKIE_0_BASE_IDX 0
|
||||
#define mmIH_COOKIE_1 0x0021
|
||||
#define mmIH_COOKIE_1_BASE_IDX 0
|
||||
#define mmIH_COOKIE_2 0x0022
|
||||
#define mmIH_COOKIE_2_BASE_IDX 0
|
||||
#define mmIH_COOKIE_3 0x0023
|
||||
#define mmIH_COOKIE_3_BASE_IDX 0
|
||||
#define mmIH_COOKIE_4 0x0024
|
||||
#define mmIH_COOKIE_4_BASE_IDX 0
|
||||
#define mmIH_COOKIE_5 0x0025
|
||||
#define mmIH_COOKIE_5_BASE_IDX 0
|
||||
#define mmIH_COOKIE_6 0x0026
|
||||
#define mmIH_COOKIE_6_BASE_IDX 0
|
||||
#define mmIH_COOKIE_7 0x0027
|
||||
#define mmIH_COOKIE_7_BASE_IDX 0
|
||||
#define mmIH_REGISTER_LAST_PART0 0x003f
|
||||
#define mmIH_REGISTER_LAST_PART0_BASE_IDX 0
|
||||
#define mmSEM_REQ_INPUT_0 0x0040
|
||||
#define mmSEM_REQ_INPUT_0_BASE_IDX 0
|
||||
#define mmSEM_REQ_INPUT_1 0x0041
|
||||
#define mmSEM_REQ_INPUT_1_BASE_IDX 0
|
||||
#define mmSEM_REQ_INPUT_2 0x0042
|
||||
#define mmSEM_REQ_INPUT_2_BASE_IDX 0
|
||||
#define mmSEM_REQ_INPUT_3 0x0043
|
||||
#define mmSEM_REQ_INPUT_3_BASE_IDX 0
|
||||
#define mmSEM_REGISTER_LAST_PART0 0x007f
|
||||
#define mmSEM_REGISTER_LAST_PART0_BASE_IDX 0
|
||||
#define mmIH_RB_CNTL 0x0080
|
||||
#define mmIH_RB_CNTL_BASE_IDX 0
|
||||
#define mmIH_RB_BASE 0x0081
|
||||
#define mmIH_RB_BASE_BASE_IDX 0
|
||||
#define mmIH_RB_BASE_HI 0x0082
|
||||
#define mmIH_RB_BASE_HI_BASE_IDX 0
|
||||
#define mmIH_RB_RPTR 0x0083
|
||||
#define mmIH_RB_RPTR_BASE_IDX 0
|
||||
#define mmIH_RB_WPTR 0x0084
|
||||
#define mmIH_RB_WPTR_BASE_IDX 0
|
||||
#define mmIH_RB_WPTR_ADDR_HI 0x0085
|
||||
#define mmIH_RB_WPTR_ADDR_HI_BASE_IDX 0
|
||||
#define mmIH_RB_WPTR_ADDR_LO 0x0086
|
||||
#define mmIH_RB_WPTR_ADDR_LO_BASE_IDX 0
|
||||
#define mmIH_DOORBELL_RPTR 0x0087
|
||||
#define mmIH_DOORBELL_RPTR_BASE_IDX 0
|
||||
#define mmIH_RB_CNTL_RING1 0x008c
|
||||
#define mmIH_RB_CNTL_RING1_BASE_IDX 0
|
||||
#define mmIH_RB_BASE_RING1 0x008d
|
||||
#define mmIH_RB_BASE_RING1_BASE_IDX 0
|
||||
#define mmIH_RB_BASE_HI_RING1 0x008e
|
||||
#define mmIH_RB_BASE_HI_RING1_BASE_IDX 0
|
||||
#define mmIH_RB_RPTR_RING1 0x008f
|
||||
#define mmIH_RB_RPTR_RING1_BASE_IDX 0
|
||||
#define mmIH_RB_WPTR_RING1 0x0090
|
||||
#define mmIH_RB_WPTR_RING1_BASE_IDX 0
|
||||
#define mmIH_DOORBELL_RPTR_RING1 0x0093
|
||||
#define mmIH_DOORBELL_RPTR_RING1_BASE_IDX 0
|
||||
#define mmIH_RB_CNTL_RING2 0x0098
|
||||
#define mmIH_RB_CNTL_RING2_BASE_IDX 0
|
||||
#define mmIH_RB_BASE_RING2 0x0099
|
||||
#define mmIH_RB_BASE_RING2_BASE_IDX 0
|
||||
#define mmIH_RB_BASE_HI_RING2 0x009a
|
||||
#define mmIH_RB_BASE_HI_RING2_BASE_IDX 0
|
||||
#define mmIH_RB_RPTR_RING2 0x009b
|
||||
#define mmIH_RB_RPTR_RING2_BASE_IDX 0
|
||||
#define mmIH_RB_WPTR_RING2 0x009c
|
||||
#define mmIH_RB_WPTR_RING2_BASE_IDX 0
|
||||
#define mmIH_DOORBELL_RPTR_RING2 0x009f
|
||||
#define mmIH_DOORBELL_RPTR_RING2_BASE_IDX 0
|
||||
#define mmIH_VERSION 0x00a5
|
||||
#define mmIH_VERSION_BASE_IDX 0
|
||||
#define mmIH_CNTL 0x00c0
|
||||
#define mmIH_CNTL_BASE_IDX 0
|
||||
#define mmIH_CNTL2 0x00c1
|
||||
#define mmIH_CNTL2_BASE_IDX 0
|
||||
#define mmIH_STATUS 0x00c2
|
||||
#define mmIH_STATUS_BASE_IDX 0
|
||||
#define mmIH_PERFMON_CNTL 0x00c3
|
||||
#define mmIH_PERFMON_CNTL_BASE_IDX 0
|
||||
#define mmIH_PERFCOUNTER0_RESULT 0x00c4
|
||||
#define mmIH_PERFCOUNTER0_RESULT_BASE_IDX 0
|
||||
#define mmIH_PERFCOUNTER1_RESULT 0x00c5
|
||||
#define mmIH_PERFCOUNTER1_RESULT_BASE_IDX 0
|
||||
#define mmIH_DSM_MATCH_VALUE_BIT_31_0 0x00c7
|
||||
#define mmIH_DSM_MATCH_VALUE_BIT_31_0_BASE_IDX 0
|
||||
#define mmIH_DSM_MATCH_VALUE_BIT_63_32 0x00c8
|
||||
#define mmIH_DSM_MATCH_VALUE_BIT_63_32_BASE_IDX 0
|
||||
#define mmIH_DSM_MATCH_VALUE_BIT_95_64 0x00c9
|
||||
#define mmIH_DSM_MATCH_VALUE_BIT_95_64_BASE_IDX 0
|
||||
#define mmIH_DSM_MATCH_FIELD_CONTROL 0x00ca
|
||||
#define mmIH_DSM_MATCH_FIELD_CONTROL_BASE_IDX 0
|
||||
#define mmIH_DSM_MATCH_DATA_CONTROL 0x00cb
|
||||
#define mmIH_DSM_MATCH_DATA_CONTROL_BASE_IDX 0
|
||||
#define mmIH_DSM_MATCH_FCN_ID 0x00cc
|
||||
#define mmIH_DSM_MATCH_FCN_ID_BASE_IDX 0
|
||||
#define mmIH_LIMIT_INT_RATE_CNTL 0x00cd
|
||||
#define mmIH_LIMIT_INT_RATE_CNTL_BASE_IDX 0
|
||||
#define mmIH_VF_RB_STATUS 0x00ce
|
||||
#define mmIH_VF_RB_STATUS_BASE_IDX 0
|
||||
#define mmIH_VF_RB_STATUS2 0x00cf
|
||||
#define mmIH_VF_RB_STATUS2_BASE_IDX 0
|
||||
#define mmIH_VF_RB1_STATUS 0x00d0
|
||||
#define mmIH_VF_RB1_STATUS_BASE_IDX 0
|
||||
#define mmIH_VF_RB1_STATUS2 0x00d1
|
||||
#define mmIH_VF_RB1_STATUS2_BASE_IDX 0
|
||||
#define mmIH_VF_RB2_STATUS 0x00d2
|
||||
#define mmIH_VF_RB2_STATUS_BASE_IDX 0
|
||||
#define mmIH_VF_RB2_STATUS2 0x00d3
|
||||
#define mmIH_VF_RB2_STATUS2_BASE_IDX 0
|
||||
#define mmIH_INT_FLOOD_CNTL 0x00d5
|
||||
#define mmIH_INT_FLOOD_CNTL_BASE_IDX 0
|
||||
#define mmIH_RB0_INT_FLOOD_STATUS 0x00d6
|
||||
#define mmIH_RB0_INT_FLOOD_STATUS_BASE_IDX 0
|
||||
#define mmIH_RB1_INT_FLOOD_STATUS 0x00d7
|
||||
#define mmIH_RB1_INT_FLOOD_STATUS_BASE_IDX 0
|
||||
#define mmIH_RB2_INT_FLOOD_STATUS 0x00d8
|
||||
#define mmIH_RB2_INT_FLOOD_STATUS_BASE_IDX 0
|
||||
#define mmIH_INT_FLOOD_STATUS 0x00d9
|
||||
#define mmIH_INT_FLOOD_STATUS_BASE_IDX 0
|
||||
#define mmIH_STORM_CLIENT_LIST_CNTL 0x00da
|
||||
#define mmIH_STORM_CLIENT_LIST_CNTL_BASE_IDX 0
|
||||
#define mmIH_CLK_CTRL 0x00db
|
||||
#define mmIH_CLK_CTRL_BASE_IDX 0
|
||||
#define mmIH_INT_FLAGS 0x00dc
|
||||
#define mmIH_INT_FLAGS_BASE_IDX 0
|
||||
#define mmIH_LAST_INT_INFO0 0x00dd
|
||||
#define mmIH_LAST_INT_INFO0_BASE_IDX 0
|
||||
#define mmIH_LAST_INT_INFO1 0x00de
|
||||
#define mmIH_LAST_INT_INFO1_BASE_IDX 0
|
||||
#define mmIH_LAST_INT_INFO2 0x00df
|
||||
#define mmIH_LAST_INT_INFO2_BASE_IDX 0
|
||||
#define mmIH_SCRATCH 0x00e0
|
||||
#define mmIH_SCRATCH_BASE_IDX 0
|
||||
#define mmIH_CLIENT_CREDIT_ERROR 0x00e1
|
||||
#define mmIH_CLIENT_CREDIT_ERROR_BASE_IDX 0
|
||||
#define mmIH_GPU_IOV_VIOLATION_LOG 0x00e2
|
||||
#define mmIH_GPU_IOV_VIOLATION_LOG_BASE_IDX 0
|
||||
#define mmIH_COOKIE_REC_VIOLATION_LOG 0x00e3
|
||||
#define mmIH_COOKIE_REC_VIOLATION_LOG_BASE_IDX 0
|
||||
#define mmIH_CREDIT_STATUS 0x00e4
|
||||
#define mmIH_CREDIT_STATUS_BASE_IDX 0
|
||||
#define mmIH_MMHUB_ERROR 0x00e5
|
||||
#define mmIH_MMHUB_ERROR_BASE_IDX 0
|
||||
#define mmIH_MEM_POWER_CTRL 0x00e8
|
||||
#define mmIH_MEM_POWER_CTRL_BASE_IDX 0
|
||||
#define mmIH_REGISTER_LAST_PART2 0x00ff
|
||||
#define mmIH_REGISTER_LAST_PART2_BASE_IDX 0
|
||||
#define mmSEM_CLK_CTRL 0x0100
|
||||
#define mmSEM_CLK_CTRL_BASE_IDX 0
|
||||
#define mmSEM_UTC_CREDIT 0x0101
|
||||
#define mmSEM_UTC_CREDIT_BASE_IDX 0
|
||||
#define mmSEM_UTC_CONFIG 0x0102
|
||||
#define mmSEM_UTC_CONFIG_BASE_IDX 0
|
||||
#define mmSEM_UTCL2_TRAN_EN_LUT 0x0103
|
||||
#define mmSEM_UTCL2_TRAN_EN_LUT_BASE_IDX 0
|
||||
#define mmSEM_MCIF_CONFIG 0x0104
|
||||
#define mmSEM_MCIF_CONFIG_BASE_IDX 0
|
||||
#define mmSEM_PERFMON_CNTL 0x0105
|
||||
#define mmSEM_PERFMON_CNTL_BASE_IDX 0
|
||||
#define mmSEM_PERFCOUNTER0_RESULT 0x0106
|
||||
#define mmSEM_PERFCOUNTER0_RESULT_BASE_IDX 0
|
||||
#define mmSEM_PERFCOUNTER1_RESULT 0x0107
|
||||
#define mmSEM_PERFCOUNTER1_RESULT_BASE_IDX 0
|
||||
#define mmSEM_STATUS 0x0108
|
||||
#define mmSEM_STATUS_BASE_IDX 0
|
||||
#define mmSEM_MAILBOX_CLIENTCONFIG 0x0109
|
||||
#define mmSEM_MAILBOX_CLIENTCONFIG_BASE_IDX 0
|
||||
#define mmSEM_MAILBOX 0x010a
|
||||
#define mmSEM_MAILBOX_BASE_IDX 0
|
||||
#define mmSEM_MAILBOX_CONTROL 0x010b
|
||||
#define mmSEM_MAILBOX_CONTROL_BASE_IDX 0
|
||||
#define mmSEM_CHICKEN_BITS 0x010c
|
||||
#define mmSEM_CHICKEN_BITS_BASE_IDX 0
|
||||
#define mmSEM_MAILBOX_CLIENTCONFIG_EXTRA 0x010d
|
||||
#define mmSEM_MAILBOX_CLIENTCONFIG_EXTRA_BASE_IDX 0
|
||||
#define mmSEM_GPU_IOV_VIOLATION_LOG 0x010e
|
||||
#define mmSEM_GPU_IOV_VIOLATION_LOG_BASE_IDX 0
|
||||
#define mmSEM_OUTSTANDING_THRESHOLD 0x010f
|
||||
#define mmSEM_OUTSTANDING_THRESHOLD_BASE_IDX 0
|
||||
#define mmSEM_MEM_POWER_CTRL 0x0110
|
||||
#define mmSEM_MEM_POWER_CTRL_BASE_IDX 0
|
||||
#define mmSEM_REGISTER_LAST_PART2 0x017f
|
||||
#define mmSEM_REGISTER_LAST_PART2_BASE_IDX 0
|
||||
#define mmIH_ACTIVE_FCN_ID 0x0180
|
||||
#define mmIH_ACTIVE_FCN_ID_BASE_IDX 0
|
||||
#define mmIH_VIRT_RESET_REQ 0x0181
|
||||
#define mmIH_VIRT_RESET_REQ_BASE_IDX 0
|
||||
#define mmIH_CLIENT_CFG 0x0184
|
||||
#define mmIH_CLIENT_CFG_BASE_IDX 0
|
||||
#define mmIH_CLIENT_CFG_INDEX 0x0188
|
||||
#define mmIH_CLIENT_CFG_INDEX_BASE_IDX 0
|
||||
#define mmIH_CLIENT_CFG_DATA 0x0189
|
||||
#define mmIH_CLIENT_CFG_DATA_BASE_IDX 0
|
||||
#define mmIH_CID_REMAP_INDEX 0x018a
|
||||
#define mmIH_CID_REMAP_INDEX_BASE_IDX 0
|
||||
#define mmIH_CID_REMAP_DATA 0x018b
|
||||
#define mmIH_CID_REMAP_DATA_BASE_IDX 0
|
||||
#define mmIH_CHICKEN 0x018c
|
||||
#define mmIH_CHICKEN_BASE_IDX 0
|
||||
#define mmIH_MMHUB_CNTL 0x018d
|
||||
#define mmIH_MMHUB_CNTL_BASE_IDX 0
|
||||
#define mmIH_INT_DROP_CNTL 0x018e
|
||||
#define mmIH_INT_DROP_CNTL_BASE_IDX 0
|
||||
#define mmIH_INT_DROP_MATCH_VALUE0 0x018f
|
||||
#define mmIH_INT_DROP_MATCH_VALUE0_BASE_IDX 0
|
||||
#define mmIH_INT_DROP_MATCH_VALUE1 0x0190
|
||||
#define mmIH_INT_DROP_MATCH_VALUE1_BASE_IDX 0
|
||||
#define mmIH_INT_DROP_MATCH_MASK0 0x0191
|
||||
#define mmIH_INT_DROP_MATCH_MASK0_BASE_IDX 0
|
||||
#define mmIH_INT_DROP_MATCH_MASK1 0x0192
|
||||
#define mmIH_INT_DROP_MATCH_MASK1_BASE_IDX 0
|
||||
#define mmIH_REGISTER_LAST_PART1 0x019f
|
||||
#define mmIH_REGISTER_LAST_PART1_BASE_IDX 0
|
||||
#define mmSEM_ACTIVE_FCN_ID 0x01a0
|
||||
#define mmSEM_ACTIVE_FCN_ID_BASE_IDX 0
|
||||
#define mmSEM_VIRT_RESET_REQ 0x01a1
|
||||
#define mmSEM_VIRT_RESET_REQ_BASE_IDX 0
|
||||
#define mmSEM_RESP_SDMA0 0x01a4
|
||||
#define mmSEM_RESP_SDMA0_BASE_IDX 0
|
||||
#define mmSEM_RESP_SDMA1 0x01a5
|
||||
#define mmSEM_RESP_SDMA1_BASE_IDX 0
|
||||
#define mmSEM_RESP_UVD 0x01a6
|
||||
#define mmSEM_RESP_UVD_BASE_IDX 0
|
||||
#define mmSEM_RESP_VCE_0 0x01a7
|
||||
#define mmSEM_RESP_VCE_0_BASE_IDX 0
|
||||
#define mmSEM_RESP_ACP 0x01a8
|
||||
#define mmSEM_RESP_ACP_BASE_IDX 0
|
||||
#define mmSEM_RESP_ISP 0x01a9
|
||||
#define mmSEM_RESP_ISP_BASE_IDX 0
|
||||
#define mmSEM_RESP_VCE_1 0x01aa
|
||||
#define mmSEM_RESP_VCE_1_BASE_IDX 0
|
||||
#define mmSEM_RESP_VP8 0x01ab
|
||||
#define mmSEM_RESP_VP8_BASE_IDX 0
|
||||
#define mmSEM_RESP_GC 0x01ac
|
||||
#define mmSEM_RESP_GC_BASE_IDX 0
|
||||
#define mmSEM_RESP_UVD_1 0x01ad
|
||||
#define mmSEM_RESP_UVD_1_BASE_IDX 0
|
||||
#define mmSEM_CID_REMAP_INDEX 0x01b0
|
||||
#define mmSEM_CID_REMAP_INDEX_BASE_IDX 0
|
||||
#define mmSEM_CID_REMAP_DATA 0x01b1
|
||||
#define mmSEM_CID_REMAP_DATA_BASE_IDX 0
|
||||
#define mmSEM_ATOMIC_OP_LUT 0x01b2
|
||||
#define mmSEM_ATOMIC_OP_LUT_BASE_IDX 0
|
||||
#define mmSEM_EDC_CONFIG 0x01b3
|
||||
#define mmSEM_EDC_CONFIG_BASE_IDX 0
|
||||
#define mmSEM_CHICKEN_BITS2 0x01b4
|
||||
#define mmSEM_CHICKEN_BITS2_BASE_IDX 0
|
||||
#define mmSEM_MMHUB_CNTL 0x01b5
|
||||
#define mmSEM_MMHUB_CNTL_BASE_IDX 0
|
||||
#define mmSEM_REGISTER_LAST_PART1 0x01bf
|
||||
#define mmSEM_REGISTER_LAST_PART1_BASE_IDX 0
|
||||
|
||||
#endif
|
1300
drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h
Normal file
1300
drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -157,7 +157,8 @@ enum PP_OD_DPM_TABLE_COMMAND {
|
||||
PP_OD_EDIT_MCLK_VDDC_TABLE,
|
||||
PP_OD_EDIT_VDDC_CURVE,
|
||||
PP_OD_RESTORE_DEFAULT_TABLE,
|
||||
PP_OD_COMMIT_DPM_TABLE
|
||||
PP_OD_COMMIT_DPM_TABLE,
|
||||
PP_OD_EDIT_VDDGFX_OFFSET
|
||||
};
|
||||
|
||||
struct pp_states_info {
|
||||
|
@ -730,11 +730,18 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
|
||||
*
|
||||
* - minimum and maximum engine clock labeled OD_SCLK
|
||||
*
|
||||
* - maximum memory clock labeled OD_MCLK
|
||||
* - minimum(not available for Vega20 and Navi1x) and maximum memory
|
||||
* clock labeled OD_MCLK
|
||||
*
|
||||
* - three <frequency, voltage> points labeled OD_VDDC_CURVE.
|
||||
* They can be used to calibrate the sclk voltage curve.
|
||||
*
|
||||
* - voltage offset(in mV) applied on target voltage calculation.
|
||||
* This is available for Sienna Cichlid, Navy Flounder and Dimgrey
|
||||
* Cavefish. For these ASICs, the target voltage calculation can be
|
||||
* illustrated by "voltage = voltage calculated from v/f curve +
|
||||
* overdrive vddgfx offset"
|
||||
*
|
||||
* - a list of valid ranges for sclk, mclk, and voltage curve points
|
||||
* labeled OD_RANGE
|
||||
*
|
||||
@ -755,6 +762,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
|
||||
* 600mV. "vc 2 1000 1000" will update point3 with clock set
|
||||
* as 1000Mhz and voltage 1000mV.
|
||||
*
|
||||
* To update the voltage offset applied for gfxclk/voltage calculation,
|
||||
* enter the new value by writing a string that contains "vo offset".
|
||||
* This is supported by Sienna Cichlid, Navy Flounder and Dimgrey Cavefish.
|
||||
* And the offset can be a positive or negative value.
|
||||
*
|
||||
* - When you have edited all of the states as needed, write "c" (commit)
|
||||
* to the file to commit your changes
|
||||
*
|
||||
@ -795,6 +807,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
|
||||
type = PP_OD_COMMIT_DPM_TABLE;
|
||||
else if (!strncmp(buf, "vc", 2))
|
||||
type = PP_OD_EDIT_VDDC_CURVE;
|
||||
else if (!strncmp(buf, "vo", 2))
|
||||
type = PP_OD_EDIT_VDDGFX_OFFSET;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
@ -802,7 +816,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
|
||||
|
||||
tmp_str = buf_cpy;
|
||||
|
||||
if (type == PP_OD_EDIT_VDDC_CURVE)
|
||||
if ((type == PP_OD_EDIT_VDDC_CURVE) ||
|
||||
(type == PP_OD_EDIT_VDDGFX_OFFSET))
|
||||
tmp_str++;
|
||||
while (isspace(*++tmp_str));
|
||||
|
||||
@ -898,6 +913,7 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
|
||||
size = smu_print_clk_levels(&adev->smu, SMU_OD_SCLK, buf);
|
||||
size += smu_print_clk_levels(&adev->smu, SMU_OD_MCLK, buf+size);
|
||||
size += smu_print_clk_levels(&adev->smu, SMU_OD_VDDC_CURVE, buf+size);
|
||||
size += smu_print_clk_levels(&adev->smu, SMU_OD_VDDGFX_OFFSET, buf+size);
|
||||
size += smu_print_clk_levels(&adev->smu, SMU_OD_RANGE, buf+size);
|
||||
} else if (adev->powerplay.pp_funcs->print_clock_levels) {
|
||||
size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf);
|
||||
@ -1346,6 +1362,138 @@ static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_pp_dpm_vclk(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
ssize_t size;
|
||||
int ret;
|
||||
|
||||
if (amdgpu_in_reset(adev))
|
||||
return -EPERM;
|
||||
|
||||
ret = pm_runtime_get_sync(ddev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
size = smu_print_clk_levels(&adev->smu, SMU_VCLK, buf);
|
||||
else
|
||||
size = snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
pm_runtime_mark_last_busy(ddev->dev);
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_pp_dpm_vclk(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
int ret;
|
||||
uint32_t mask = 0;
|
||||
|
||||
if (amdgpu_in_reset(adev))
|
||||
return -EPERM;
|
||||
|
||||
ret = amdgpu_read_mask(buf, count, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_get_sync(ddev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
ret = smu_force_clk_levels(&adev->smu, SMU_VCLK, mask);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
pm_runtime_mark_last_busy(ddev->dev);
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_pp_dpm_dclk(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
ssize_t size;
|
||||
int ret;
|
||||
|
||||
if (amdgpu_in_reset(adev))
|
||||
return -EPERM;
|
||||
|
||||
ret = pm_runtime_get_sync(ddev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
size = smu_print_clk_levels(&adev->smu, SMU_DCLK, buf);
|
||||
else
|
||||
size = snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
pm_runtime_mark_last_busy(ddev->dev);
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_pp_dpm_dclk(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
int ret;
|
||||
uint32_t mask = 0;
|
||||
|
||||
if (amdgpu_in_reset(adev))
|
||||
return -EPERM;
|
||||
|
||||
ret = amdgpu_read_mask(buf, count, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_get_sync(ddev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
ret = smu_force_clk_levels(&adev->smu, SMU_DCLK, mask);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
pm_runtime_mark_last_busy(ddev->dev);
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -2025,6 +2173,8 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = {
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_mclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_socclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_fclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_vclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_dclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_dcefclk, ATTR_FLAG_BASIC),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_dpm_pcie, ATTR_FLAG_BASIC),
|
||||
AMDGPU_DEVICE_ATTR_RW(pp_sclk_od, ATTR_FLAG_BASIC),
|
||||
@ -2067,7 +2217,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
|
||||
} else if (DEVICE_ATTR_IS(pp_od_clk_voltage)) {
|
||||
*states = ATTR_STATE_UNSUPPORTED;
|
||||
if ((is_support_sw_smu(adev) && adev->smu.od_enabled) ||
|
||||
(!is_support_sw_smu(adev) && hwmgr->od_enabled))
|
||||
(is_support_sw_smu(adev) && adev->smu.fine_grain_enabled) ||
|
||||
(!is_support_sw_smu(adev) && hwmgr->od_enabled))
|
||||
*states = ATTR_STATE_SUPPORTED;
|
||||
} else if (DEVICE_ATTR_IS(mem_busy_percent)) {
|
||||
if (adev->flags & AMD_IS_APU || asic_type == CHIP_VEGA10)
|
||||
@ -2087,6 +2238,12 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
|
||||
} else if (DEVICE_ATTR_IS(gpu_metrics)) {
|
||||
if (asic_type < CHIP_VEGA12)
|
||||
*states = ATTR_STATE_UNSUPPORTED;
|
||||
} else if (DEVICE_ATTR_IS(pp_dpm_vclk)) {
|
||||
if (!(asic_type == CHIP_VANGOGH))
|
||||
*states = ATTR_STATE_UNSUPPORTED;
|
||||
} else if (DEVICE_ATTR_IS(pp_dpm_dclk)) {
|
||||
if (!(asic_type == CHIP_VANGOGH))
|
||||
*states = ATTR_STATE_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (asic_type == CHIP_ARCTURUS) {
|
||||
|
@ -465,124 +465,653 @@ struct smu_context
|
||||
uint32_t gfx_default_soft_max_freq;
|
||||
uint32_t gfx_actual_hard_min_freq;
|
||||
uint32_t gfx_actual_soft_max_freq;
|
||||
|
||||
bool fine_grain_enabled;
|
||||
bool fine_grain_started;
|
||||
};
|
||||
|
||||
struct i2c_adapter;
|
||||
|
||||
/**
|
||||
* struct pptable_funcs - Callbacks used to interact with the SMU.
|
||||
*/
|
||||
struct pptable_funcs {
|
||||
/**
|
||||
* @run_btc: Calibrate voltage/frequency curve to fit the system's
|
||||
* power delivery and voltage margins. Required for adaptive
|
||||
* voltage frequency scaling (AVFS).
|
||||
*/
|
||||
int (*run_btc)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_allowed_feature_mask: Get allowed feature mask.
|
||||
* &feature_mask: Array to store feature mask.
|
||||
* &num: Elements in &feature_mask.
|
||||
*/
|
||||
int (*get_allowed_feature_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num);
|
||||
|
||||
/**
|
||||
* @get_current_power_state: Get the current power state.
|
||||
*
|
||||
* Return: Current power state on success, negative errno on failure.
|
||||
*/
|
||||
enum amd_pm_state_type (*get_current_power_state)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_default_dpm_table: Retrieve the default overdrive settings from
|
||||
* the SMU.
|
||||
*/
|
||||
int (*set_default_dpm_table)(struct smu_context *smu);
|
||||
|
||||
int (*set_power_state)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @populate_umd_state_clk: Populate the UMD power state table with
|
||||
* defaults.
|
||||
*/
|
||||
int (*populate_umd_state_clk)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @print_clk_levels: Print DPM clock levels for a clock domain
|
||||
* to buffer. Star current level.
|
||||
*
|
||||
* Used for sysfs interfaces.
|
||||
*/
|
||||
int (*print_clk_levels)(struct smu_context *smu, enum smu_clk_type clk_type, char *buf);
|
||||
|
||||
/**
|
||||
* @force_clk_levels: Set a range of allowed DPM levels for a clock
|
||||
* domain.
|
||||
* &clk_type: Clock domain.
|
||||
* &mask: Range of allowed DPM levels.
|
||||
*/
|
||||
int (*force_clk_levels)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t mask);
|
||||
|
||||
/**
|
||||
* @od_edit_dpm_table: Edit the custom overdrive DPM table.
|
||||
* &type: Type of edit.
|
||||
* &input: Edit parameters.
|
||||
* &size: Size of &input.
|
||||
*/
|
||||
int (*od_edit_dpm_table)(struct smu_context *smu,
|
||||
enum PP_OD_DPM_TABLE_COMMAND type,
|
||||
long *input, uint32_t size);
|
||||
|
||||
/**
|
||||
* @get_clock_by_type_with_latency: Get the speed and latency of a clock
|
||||
* domain.
|
||||
*/
|
||||
int (*get_clock_by_type_with_latency)(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type,
|
||||
struct
|
||||
pp_clock_levels_with_latency
|
||||
*clocks);
|
||||
/**
|
||||
* @get_clock_by_type_with_voltage: Get the speed and voltage of a clock
|
||||
* domain.
|
||||
*/
|
||||
int (*get_clock_by_type_with_voltage)(struct smu_context *smu,
|
||||
enum amd_pp_clock_type type,
|
||||
struct
|
||||
pp_clock_levels_with_voltage
|
||||
*clocks);
|
||||
|
||||
/**
|
||||
* @get_power_profile_mode: Print all power profile modes to
|
||||
* buffer. Star current mode.
|
||||
*/
|
||||
int (*get_power_profile_mode)(struct smu_context *smu, char *buf);
|
||||
|
||||
/**
|
||||
* @set_power_profile_mode: Set a power profile mode. Also used to
|
||||
* create/set custom power profile modes.
|
||||
* &input: Power profile mode parameters.
|
||||
* &size: Size of &input.
|
||||
*/
|
||||
int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
|
||||
|
||||
/**
|
||||
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
|
||||
* management.
|
||||
*/
|
||||
int (*dpm_set_vcn_enable)(struct smu_context *smu, bool enable);
|
||||
|
||||
/**
|
||||
* @dpm_set_jpeg_enable: Enable/disable JPEG engine dynamic power
|
||||
* management.
|
||||
*/
|
||||
int (*dpm_set_jpeg_enable)(struct smu_context *smu, bool enable);
|
||||
|
||||
/**
|
||||
* @read_sensor: Read data from a sensor.
|
||||
* &sensor: Sensor to read data from.
|
||||
* &data: Sensor reading.
|
||||
* &size: Size of &data.
|
||||
*/
|
||||
int (*read_sensor)(struct smu_context *smu, enum amd_pp_sensors sensor,
|
||||
void *data, uint32_t *size);
|
||||
|
||||
/**
|
||||
* @pre_display_config_changed: Prepare GPU for a display configuration
|
||||
* change.
|
||||
*
|
||||
* Disable display tracking and pin memory clock speed to maximum. Used
|
||||
* in display component synchronization.
|
||||
*/
|
||||
int (*pre_display_config_changed)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @display_config_changed: Notify the SMU of the current display
|
||||
* configuration.
|
||||
*
|
||||
* Allows SMU to properly track blanking periods for memory clock
|
||||
* adjustment. Used in display component synchronization.
|
||||
*/
|
||||
int (*display_config_changed)(struct smu_context *smu);
|
||||
|
||||
int (*apply_clocks_adjust_rules)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @notify_smc_display_config: Applies display requirements to the
|
||||
* current power state.
|
||||
*
|
||||
* Optimize deep sleep DCEFclk and mclk for the current display
|
||||
* configuration. Used in display component synchronization.
|
||||
*/
|
||||
int (*notify_smc_display_config)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @is_dpm_running: Check if DPM is running.
|
||||
*
|
||||
* Return: True if DPM is running, false otherwise.
|
||||
*/
|
||||
bool (*is_dpm_running)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_fan_speed_rpm: Get the current fan speed in RPM.
|
||||
*/
|
||||
int (*get_fan_speed_rpm)(struct smu_context *smu, uint32_t *speed);
|
||||
|
||||
/**
|
||||
* @set_watermarks_table: Configure and upload the watermarks tables to
|
||||
* the SMU.
|
||||
*/
|
||||
int (*set_watermarks_table)(struct smu_context *smu,
|
||||
struct pp_smu_wm_range_sets *clock_ranges);
|
||||
|
||||
/**
|
||||
* @get_thermal_temperature_range: Get safe thermal limits in Celcius.
|
||||
*/
|
||||
int (*get_thermal_temperature_range)(struct smu_context *smu, struct smu_temperature_range *range);
|
||||
|
||||
/**
|
||||
* @get_uclk_dpm_states: Get memory clock DPM levels in kHz.
|
||||
* &clocks_in_khz: Array of DPM levels.
|
||||
* &num_states: Elements in &clocks_in_khz.
|
||||
*/
|
||||
int (*get_uclk_dpm_states)(struct smu_context *smu, uint32_t *clocks_in_khz, uint32_t *num_states);
|
||||
|
||||
/**
|
||||
* @set_default_od_settings: Set the overdrive tables to defaults.
|
||||
*/
|
||||
int (*set_default_od_settings)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_performance_level: Set a performance level.
|
||||
*/
|
||||
int (*set_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level);
|
||||
|
||||
/**
|
||||
* @display_disable_memory_clock_switch: Enable/disable dynamic memory
|
||||
* clock switching.
|
||||
*
|
||||
* Disabling this feature forces memory clock speed to maximum.
|
||||
* Enabling sets the minimum memory clock capable of driving the
|
||||
* current display configuration.
|
||||
*/
|
||||
int (*display_disable_memory_clock_switch)(struct smu_context *smu, bool disable_memory_clock_switch);
|
||||
|
||||
/**
|
||||
* @dump_pptable: Print the power play table to the system log.
|
||||
*/
|
||||
void (*dump_pptable)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_power_limit: Get the device's power limits.
|
||||
*/
|
||||
int (*get_power_limit)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_df_cstate: Set data fabric cstate.
|
||||
*/
|
||||
int (*set_df_cstate)(struct smu_context *smu, enum pp_df_cstate state);
|
||||
|
||||
/**
|
||||
* @allow_xgmi_power_down: Enable/disable external global memory
|
||||
* interconnect power down.
|
||||
*/
|
||||
int (*allow_xgmi_power_down)(struct smu_context *smu, bool en);
|
||||
|
||||
/**
|
||||
* @update_pcie_parameters: Update and upload the system's PCIe
|
||||
* capabilites to the SMU.
|
||||
* &pcie_gen_cap: Maximum allowed PCIe generation.
|
||||
* &pcie_width_cap: Maximum allowed PCIe width.
|
||||
*/
|
||||
int (*update_pcie_parameters)(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap);
|
||||
|
||||
/**
|
||||
* @i2c_init: Initialize i2c.
|
||||
*
|
||||
* The i2c bus is used internally by the SMU voltage regulators and
|
||||
* other devices. The i2c's EEPROM also stores bad page tables on boards
|
||||
* with ECC.
|
||||
*/
|
||||
int (*i2c_init)(struct smu_context *smu, struct i2c_adapter *control);
|
||||
|
||||
/**
|
||||
* @i2c_fini: Tear down i2c.
|
||||
*/
|
||||
void (*i2c_fini)(struct smu_context *smu, struct i2c_adapter *control);
|
||||
|
||||
/**
|
||||
* @get_unique_id: Get the GPU's unique id. Used for asset tracking.
|
||||
*/
|
||||
void (*get_unique_id)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_dpm_clock_table: Get a copy of the DPM clock table.
|
||||
*
|
||||
* Used by display component in bandwidth and watermark calculations.
|
||||
*/
|
||||
int (*get_dpm_clock_table)(struct smu_context *smu, struct dpm_clocks *clock_table);
|
||||
|
||||
/**
|
||||
* @init_microcode: Request the SMU's firmware from the kernel.
|
||||
*/
|
||||
int (*init_microcode)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @load_microcode: Load firmware onto the SMU.
|
||||
*/
|
||||
int (*load_microcode)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @fini_microcode: Release the SMU's firmware.
|
||||
*/
|
||||
void (*fini_microcode)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @init_smc_tables: Initialize the SMU tables.
|
||||
*/
|
||||
int (*init_smc_tables)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @fini_smc_tables: Release the SMU tables.
|
||||
*/
|
||||
int (*fini_smc_tables)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @init_power: Initialize the power gate table context.
|
||||
*/
|
||||
int (*init_power)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @fini_power: Release the power gate table context.
|
||||
*/
|
||||
int (*fini_power)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @check_fw_status: Check the SMU's firmware status.
|
||||
*
|
||||
* Return: Zero if check passes, negative errno on failure.
|
||||
*/
|
||||
int (*check_fw_status)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @setup_pptable: Initialize the power play table and populate it with
|
||||
* default values.
|
||||
*/
|
||||
int (*setup_pptable)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_vbios_bootup_values: Get default boot values from the VBIOS.
|
||||
*/
|
||||
int (*get_vbios_bootup_values)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @check_fw_version: Print driver and SMU interface versions to the
|
||||
* system log.
|
||||
*
|
||||
* Interface mismatch is not a critical failure.
|
||||
*/
|
||||
int (*check_fw_version)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @powergate_sdma: Power up/down system direct memory access.
|
||||
*/
|
||||
int (*powergate_sdma)(struct smu_context *smu, bool gate);
|
||||
|
||||
/**
|
||||
* @set_gfx_cgpg: Enable/disable graphics engine course grain power
|
||||
* gating.
|
||||
*/
|
||||
int (*set_gfx_cgpg)(struct smu_context *smu, bool enable);
|
||||
|
||||
/**
|
||||
* @write_pptable: Write the power play table to the SMU.
|
||||
*/
|
||||
int (*write_pptable)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_driver_table_location: Send the location of the driver table to
|
||||
* the SMU.
|
||||
*/
|
||||
int (*set_driver_table_location)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_tool_table_location: Send the location of the tool table to the
|
||||
* SMU.
|
||||
*/
|
||||
int (*set_tool_table_location)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @notify_memory_pool_location: Send the location of the memory pool to
|
||||
* the SMU.
|
||||
*/
|
||||
int (*notify_memory_pool_location)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @system_features_control: Enable/disable all SMU features.
|
||||
*/
|
||||
int (*system_features_control)(struct smu_context *smu, bool en);
|
||||
|
||||
/**
|
||||
* @send_smc_msg_with_param: Send a message with a parameter to the SMU.
|
||||
* &msg: Type of message.
|
||||
* ¶m: Message parameter.
|
||||
* &read_arg: SMU response (optional).
|
||||
*/
|
||||
int (*send_smc_msg_with_param)(struct smu_context *smu,
|
||||
enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
|
||||
|
||||
/**
|
||||
* @send_smc_msg: Send a message to the SMU.
|
||||
* &msg: Type of message.
|
||||
* &read_arg: SMU response (optional).
|
||||
*/
|
||||
int (*send_smc_msg)(struct smu_context *smu,
|
||||
enum smu_message_type msg,
|
||||
uint32_t *read_arg);
|
||||
|
||||
/**
|
||||
* @init_display_count: Notify the SMU of the number of display
|
||||
* components in current display configuration.
|
||||
*/
|
||||
int (*init_display_count)(struct smu_context *smu, uint32_t count);
|
||||
|
||||
/**
|
||||
* @set_allowed_mask: Notify the SMU of the features currently allowed
|
||||
* by the driver.
|
||||
*/
|
||||
int (*set_allowed_mask)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_enabled_mask: Get a mask of features that are currently enabled
|
||||
* on the SMU.
|
||||
* &feature_mask: Array representing enabled feature mask.
|
||||
* &num: Elements in &feature_mask.
|
||||
*/
|
||||
int (*get_enabled_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num);
|
||||
|
||||
/**
|
||||
* @feature_is_enabled: Test if a feature is enabled.
|
||||
*
|
||||
* Return: One if enabled, zero if disabled.
|
||||
*/
|
||||
int (*feature_is_enabled)(struct smu_context *smu, enum smu_feature_mask mask);
|
||||
|
||||
/**
|
||||
* @disable_all_features_with_exception: Disable all features with
|
||||
* exception to those in &mask.
|
||||
*/
|
||||
int (*disable_all_features_with_exception)(struct smu_context *smu, enum smu_feature_mask mask);
|
||||
|
||||
/**
|
||||
* @notify_display_change: Enable fast memory clock switching.
|
||||
*
|
||||
* Allows for fine grained memory clock switching but has more stringent
|
||||
* timing requirements.
|
||||
*/
|
||||
int (*notify_display_change)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_power_limit: Set power limit in watts.
|
||||
*/
|
||||
int (*set_power_limit)(struct smu_context *smu, uint32_t n);
|
||||
|
||||
/**
|
||||
* @init_max_sustainable_clocks: Populate max sustainable clock speed
|
||||
* table with values from the SMU.
|
||||
*/
|
||||
int (*init_max_sustainable_clocks)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @enable_thermal_alert: Enable thermal alert interrupts.
|
||||
*/
|
||||
int (*enable_thermal_alert)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @disable_thermal_alert: Disable thermal alert interrupts.
|
||||
*/
|
||||
int (*disable_thermal_alert)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_min_dcef_deep_sleep: Set a minimum display fabric deep sleep
|
||||
* clock speed in MHz.
|
||||
*/
|
||||
int (*set_min_dcef_deep_sleep)(struct smu_context *smu, uint32_t clk);
|
||||
|
||||
/**
|
||||
* @display_clock_voltage_request: Set a hard minimum frequency
|
||||
* for a clock domain.
|
||||
*/
|
||||
int (*display_clock_voltage_request)(struct smu_context *smu, struct
|
||||
pp_display_clock_request
|
||||
*clock_req);
|
||||
|
||||
/**
|
||||
* @get_fan_control_mode: Get the current fan control mode.
|
||||
*/
|
||||
uint32_t (*get_fan_control_mode)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_fan_control_mode: Set the fan control mode.
|
||||
*/
|
||||
int (*set_fan_control_mode)(struct smu_context *smu, uint32_t mode);
|
||||
|
||||
/**
|
||||
* @set_fan_speed_rpm: Set a static fan speed in RPM.
|
||||
*/
|
||||
int (*set_fan_speed_rpm)(struct smu_context *smu, uint32_t speed);
|
||||
|
||||
/**
|
||||
* @set_xgmi_pstate: Set inter-chip global memory interconnect pstate.
|
||||
* &pstate: Pstate to set. D0 if Nonzero, D3 otherwise.
|
||||
*/
|
||||
int (*set_xgmi_pstate)(struct smu_context *smu, uint32_t pstate);
|
||||
|
||||
/**
|
||||
* @gfx_off_control: Enable/disable graphics engine poweroff.
|
||||
*/
|
||||
int (*gfx_off_control)(struct smu_context *smu, bool enable);
|
||||
|
||||
|
||||
/**
|
||||
* @get_gfx_off_status: Get graphics engine poweroff status.
|
||||
*
|
||||
* Return:
|
||||
* 0 - GFXOFF(default).
|
||||
* 1 - Transition out of GFX State.
|
||||
* 2 - Not in GFXOFF.
|
||||
* 3 - Transition into GFXOFF.
|
||||
*/
|
||||
uint32_t (*get_gfx_off_status)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @register_irq_handler: Register interupt request handlers.
|
||||
*/
|
||||
int (*register_irq_handler)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @set_azalia_d3_pme: Wake the audio decode engine from d3 sleep.
|
||||
*/
|
||||
int (*set_azalia_d3_pme)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_max_sustainable_clocks_by_dc: Get a copy of the max sustainable
|
||||
* clock speeds table.
|
||||
*
|
||||
* Provides a way for the display component (DC) to get the max
|
||||
* sustainable clocks from the SMU.
|
||||
*/
|
||||
int (*get_max_sustainable_clocks_by_dc)(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks);
|
||||
|
||||
/**
|
||||
* @baco_is_support: Check if GPU supports BACO (Bus Active, Chip Off).
|
||||
*/
|
||||
bool (*baco_is_support)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @baco_get_state: Get the current BACO state.
|
||||
*
|
||||
* Return: Current BACO state.
|
||||
*/
|
||||
enum smu_baco_state (*baco_get_state)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @baco_set_state: Enter/exit BACO.
|
||||
*/
|
||||
int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state);
|
||||
|
||||
/**
|
||||
* @baco_enter: Enter BACO.
|
||||
*/
|
||||
int (*baco_enter)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @baco_exit: Exit Baco.
|
||||
*/
|
||||
int (*baco_exit)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @mode1_reset_is_support: Check if GPU supports mode1 reset.
|
||||
*/
|
||||
bool (*mode1_reset_is_support)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @mode1_reset: Perform mode1 reset.
|
||||
*
|
||||
* Complete GPU reset.
|
||||
*/
|
||||
int (*mode1_reset)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @mode2_reset: Perform mode2 reset.
|
||||
*
|
||||
* Mode2 reset generally does not reset as many IPs as mode1 reset. The
|
||||
* IPs reset varies by asic.
|
||||
*/
|
||||
int (*mode2_reset)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_dpm_ultimate_freq: Get the hard frequency range of a clock
|
||||
* domain in MHz.
|
||||
*/
|
||||
int (*get_dpm_ultimate_freq)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max);
|
||||
|
||||
/**
|
||||
* @set_soft_freq_limited_range: Set the soft frequency range of a clock
|
||||
* domain in MHz.
|
||||
*/
|
||||
int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max);
|
||||
|
||||
/**
|
||||
* @set_power_source: Notify the SMU of the current power source.
|
||||
*/
|
||||
int (*set_power_source)(struct smu_context *smu, enum smu_power_src_type power_src);
|
||||
|
||||
/**
|
||||
* @log_thermal_throttling_event: Print a thermal throttling warning to
|
||||
* the system's log.
|
||||
*/
|
||||
void (*log_thermal_throttling_event)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @get_pp_feature_mask: Print a human readable table of enabled
|
||||
* features to buffer.
|
||||
*/
|
||||
size_t (*get_pp_feature_mask)(struct smu_context *smu, char *buf);
|
||||
|
||||
/**
|
||||
* @set_pp_feature_mask: Request the SMU enable/disable features to
|
||||
* match those enabled in &new_mask.
|
||||
*/
|
||||
int (*set_pp_feature_mask)(struct smu_context *smu, uint64_t new_mask);
|
||||
|
||||
/**
|
||||
* @get_gpu_metrics: Get a copy of the GPU metrics table from the SMU.
|
||||
*
|
||||
* Return: Size of &table
|
||||
*/
|
||||
ssize_t (*get_gpu_metrics)(struct smu_context *smu, void **table);
|
||||
|
||||
/**
|
||||
* @enable_mgpu_fan_boost: Enable multi-GPU fan boost.
|
||||
*/
|
||||
int (*enable_mgpu_fan_boost)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @gfx_ulv_control: Enable/disable ultra low voltage.
|
||||
*/
|
||||
int (*gfx_ulv_control)(struct smu_context *smu, bool enablement);
|
||||
|
||||
/**
|
||||
* @deep_sleep_control: Enable/disable deep sleep.
|
||||
*/
|
||||
int (*deep_sleep_control)(struct smu_context *smu, bool enablement);
|
||||
|
||||
/**
|
||||
* @get_fan_parameters: Get fan parameters.
|
||||
*
|
||||
* Get maximum fan speed from the power play table.
|
||||
*/
|
||||
int (*get_fan_parameters)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @post_init: Helper function for asic specific workarounds.
|
||||
*/
|
||||
int (*post_init)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @interrupt_work: Work task scheduled from SMU interrupt handler.
|
||||
*/
|
||||
void (*interrupt_work)(struct smu_context *smu);
|
||||
|
||||
/**
|
||||
* @gpo_control: Enable/disable graphics power optimization if supported.
|
||||
*/
|
||||
int (*gpo_control)(struct smu_context *smu, bool enablement);
|
||||
|
||||
/**
|
||||
* @gfx_state_change_set: Send the current graphics state to the SMU.
|
||||
*/
|
||||
int (*gfx_state_change_set)(struct smu_context *smu, uint32_t state);
|
||||
|
||||
/**
|
||||
* @set_fine_grain_gfx_freq_parameters: Set fine grain graphics clock
|
||||
* parameters to defaults.
|
||||
*/
|
||||
int (*set_fine_grain_gfx_freq_parameters)(struct smu_context *smu);
|
||||
};
|
||||
|
||||
@ -636,6 +1165,12 @@ enum smu_cmn2asic_mapping_type {
|
||||
#define FEA_MAP(fea) \
|
||||
[SMU_FEATURE_##fea##_BIT] = {1, FEATURE_##fea##_BIT}
|
||||
|
||||
#define FEA_MAP_REVERSE(fea) \
|
||||
[SMU_FEATURE_DPM_##fea##_BIT] = {1, FEATURE_##fea##_DPM_BIT}
|
||||
|
||||
#define FEA_MAP_HALF_REVERSE(fea) \
|
||||
[SMU_FEATURE_DPM_##fea##CLK_BIT] = {1, FEATURE_##fea##_DPM_BIT}
|
||||
|
||||
#define TAB_MAP(tab) \
|
||||
[SMU_TABLE_##tab] = {1, TABLE_##tab}
|
||||
|
||||
|
@ -141,7 +141,6 @@ typedef struct {
|
||||
uint32_t MaxGfxClk;
|
||||
|
||||
uint8_t NumDfPstatesEnabled;
|
||||
uint8_t NumDpmLevelsEnabled;
|
||||
uint8_t NumDcfclkLevelsEnabled;
|
||||
uint8_t NumDispClkLevelsEnabled; //applies to both dispclk and dppclk
|
||||
uint8_t NumSocClkLevelsEnabled;
|
||||
|
@ -211,6 +211,7 @@
|
||||
__SMU_DUMMY_MAP(SetGpoFeaturePMask), \
|
||||
__SMU_DUMMY_MAP(DisallowGpo), \
|
||||
__SMU_DUMMY_MAP(Enable2ndUSB20Port), \
|
||||
__SMU_DUMMY_MAP(RequestActiveWgp), \
|
||||
|
||||
#undef __SMU_DUMMY_MAP
|
||||
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type
|
||||
@ -240,6 +241,7 @@ enum smu_clk_type {
|
||||
SMU_OD_MCLK,
|
||||
SMU_OD_VDDC_CURVE,
|
||||
SMU_OD_RANGE,
|
||||
SMU_OD_VDDGFX_OFFSET,
|
||||
SMU_CLK_COUNT,
|
||||
};
|
||||
|
||||
|
@ -251,7 +251,7 @@ static int smu10_set_hard_min_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t cl
|
||||
smu10_data->gfx_actual_soft_min_freq = clock;
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
smu10_data->gfx_actual_soft_min_freq,
|
||||
clock,
|
||||
NULL);
|
||||
}
|
||||
return 0;
|
||||
@ -558,7 +558,8 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
|
||||
|
||||
/* enable the pp_od_clk_voltage sysfs file */
|
||||
hwmgr->od_enabled = 1;
|
||||
|
||||
/* disabled fine grain tuning function by default */
|
||||
data->fine_grain_enabled = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -597,6 +598,7 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
uint32_t min_mclk = hwmgr->display_config->min_mem_set_clock/100;
|
||||
uint32_t index_fclk = data->clock_vol_info.vdd_dep_on_fclk->count - 1;
|
||||
uint32_t index_socclk = data->clock_vol_info.vdd_dep_on_socclk->count - 1;
|
||||
uint32_t fine_grain_min_freq = 0, fine_grain_max_freq = 0;
|
||||
|
||||
if (hwmgr->smu_version < 0x1E3700) {
|
||||
pr_info("smu firmware version too old, can not set dpm level\n");
|
||||
@ -613,6 +615,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
switch (level) {
|
||||
case AMD_DPM_FORCED_LEVEL_HIGH:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
|
||||
data->fine_grain_enabled = 0;
|
||||
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &fine_grain_min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &fine_grain_max_freq);
|
||||
|
||||
data->gfx_actual_soft_min_freq = fine_grain_min_freq;
|
||||
data->gfx_actual_soft_max_freq = fine_grain_max_freq;
|
||||
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
data->gfx_max_freq_limit/100,
|
||||
@ -648,6 +658,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
NULL);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
|
||||
data->fine_grain_enabled = 0;
|
||||
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &fine_grain_min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &fine_grain_max_freq);
|
||||
|
||||
data->gfx_actual_soft_min_freq = fine_grain_min_freq;
|
||||
data->gfx_actual_soft_max_freq = fine_grain_max_freq;
|
||||
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
min_sclk,
|
||||
@ -658,6 +676,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
NULL);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
|
||||
data->fine_grain_enabled = 0;
|
||||
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &fine_grain_min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &fine_grain_max_freq);
|
||||
|
||||
data->gfx_actual_soft_min_freq = fine_grain_min_freq;
|
||||
data->gfx_actual_soft_max_freq = fine_grain_max_freq;
|
||||
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinFclkByFreq,
|
||||
min_mclk,
|
||||
@ -668,6 +694,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
NULL);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
|
||||
data->fine_grain_enabled = 0;
|
||||
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &fine_grain_min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &fine_grain_max_freq);
|
||||
|
||||
data->gfx_actual_soft_min_freq = fine_grain_min_freq;
|
||||
data->gfx_actual_soft_max_freq = fine_grain_max_freq;
|
||||
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
SMU10_UMD_PSTATE_GFXCLK,
|
||||
@ -703,6 +737,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
NULL);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_AUTO:
|
||||
data->fine_grain_enabled = 0;
|
||||
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &fine_grain_min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &fine_grain_max_freq);
|
||||
|
||||
data->gfx_actual_soft_min_freq = fine_grain_min_freq;
|
||||
data->gfx_actual_soft_max_freq = fine_grain_max_freq;
|
||||
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
min_sclk,
|
||||
@ -741,6 +783,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
NULL);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_LOW:
|
||||
data->fine_grain_enabled = 0;
|
||||
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &fine_grain_min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &fine_grain_max_freq);
|
||||
|
||||
data->gfx_actual_soft_min_freq = fine_grain_min_freq;
|
||||
data->gfx_actual_soft_max_freq = fine_grain_max_freq;
|
||||
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
data->gfx_min_freq_limit/100,
|
||||
@ -759,6 +809,7 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
||||
NULL);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_MANUAL:
|
||||
data->fine_grain_enabled = 1;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
|
||||
default:
|
||||
break;
|
||||
@ -948,6 +999,8 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
|
||||
struct smu10_voltage_dependency_table *mclk_table =
|
||||
data->clock_vol_info.vdd_dep_on_fclk;
|
||||
uint32_t i, now, size = 0;
|
||||
uint32_t min_freq, max_freq = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (type) {
|
||||
case PP_SCLK:
|
||||
@ -983,18 +1036,28 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
|
||||
break;
|
||||
case OD_SCLK:
|
||||
if (hwmgr->od_enabled) {
|
||||
size = sprintf(buf, "%s:\n", "OD_SCLK");
|
||||
ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
size = sprintf(buf, "%s:\n", "OD_SCLK");
|
||||
size += sprintf(buf + size, "0: %10uMhz\n",
|
||||
(data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : data->gfx_min_freq_limit/100);
|
||||
size += sprintf(buf + size, "1: %10uMhz\n", data->gfx_max_freq_limit/100);
|
||||
(data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : min_freq);
|
||||
size += sprintf(buf + size, "1: %10uMhz\n",
|
||||
(data->gfx_actual_soft_max_freq > 0) ? data->gfx_actual_soft_max_freq : max_freq);
|
||||
}
|
||||
break;
|
||||
case OD_RANGE:
|
||||
if (hwmgr->od_enabled) {
|
||||
uint32_t min_freq, max_freq = 0;
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
|
||||
ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
size = sprintf(buf, "%s:\n", "OD_RANGE");
|
||||
size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
|
||||
@ -1414,23 +1477,96 @@ static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr,
|
||||
enum PP_OD_DPM_TABLE_COMMAND type,
|
||||
long *input, uint32_t size)
|
||||
{
|
||||
uint32_t min_freq, max_freq = 0;
|
||||
struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
|
||||
int ret = 0;
|
||||
|
||||
if (!hwmgr->od_enabled) {
|
||||
pr_err("Fine grain not support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (size != 2) {
|
||||
pr_err("Input parameter number not correct\n");
|
||||
if (!smu10_data->fine_grain_enabled) {
|
||||
pr_err("Fine grain not started\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
|
||||
if (input[0] == 0)
|
||||
smu10_set_hard_min_gfxclk_by_freq(hwmgr, input[1]);
|
||||
else if (input[0] == 1)
|
||||
smu10_set_soft_max_gfxclk_by_freq(hwmgr, input[1]);
|
||||
else
|
||||
if (size != 2) {
|
||||
pr_err("Input parameter number not correct\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (input[0] == 0) {
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
|
||||
if (input[1] < min_freq) {
|
||||
pr_err("Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
|
||||
input[1], min_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
smu10_data->gfx_actual_soft_min_freq = input[1];
|
||||
} else if (input[0] == 1) {
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
|
||||
if (input[1] > max_freq) {
|
||||
pr_err("Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
|
||||
input[1], max_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
smu10_data->gfx_actual_soft_max_freq = input[1];
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (type == PP_OD_RESTORE_DEFAULT_TABLE) {
|
||||
if (size != 0) {
|
||||
pr_err("Input parameter number not correct\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
|
||||
|
||||
smu10_data->gfx_actual_soft_min_freq = min_freq;
|
||||
smu10_data->gfx_actual_soft_max_freq = max_freq;
|
||||
|
||||
ret = smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
min_freq,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetSoftMaxGfxClk,
|
||||
max_freq,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (type == PP_OD_COMMIT_DPM_TABLE) {
|
||||
if (size != 0) {
|
||||
pr_err("Input parameter number not correct\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (smu10_data->gfx_actual_soft_min_freq > smu10_data->gfx_actual_soft_max_freq) {
|
||||
pr_err("The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
|
||||
smu10_data->gfx_actual_soft_min_freq, smu10_data->gfx_actual_soft_max_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetHardMinGfxClk,
|
||||
smu10_data->gfx_actual_soft_min_freq,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smum_send_msg_to_smc_with_parameter(hwmgr,
|
||||
PPSMC_MSG_SetSoftMaxGfxClk,
|
||||
smu10_data->gfx_actual_soft_max_freq,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -283,6 +283,7 @@ struct smu10_hwmgr {
|
||||
uint32_t vclk_soft_min;
|
||||
uint32_t dclk_soft_min;
|
||||
uint32_t gfx_actual_soft_min_freq;
|
||||
uint32_t gfx_actual_soft_max_freq;
|
||||
uint32_t gfx_min_freq_limit;
|
||||
uint32_t gfx_max_freq_limit; /* in 10Khz*/
|
||||
|
||||
@ -299,6 +300,8 @@ struct smu10_hwmgr {
|
||||
bool need_min_deep_sleep_dcefclk;
|
||||
uint32_t deep_sleep_dcefclk;
|
||||
uint32_t num_active_display;
|
||||
|
||||
bool fine_grain_enabled;
|
||||
};
|
||||
|
||||
struct pp_hwmgr;
|
||||
|
@ -402,6 +402,10 @@ static int smu_set_funcs(struct amdgpu_device *adev)
|
||||
break;
|
||||
case CHIP_RENOIR:
|
||||
renoir_set_ppt_funcs(smu);
|
||||
/* enable the fine grain tuning function by default */
|
||||
smu->fine_grain_enabled = true;
|
||||
/* close the fine grain tuning function by default */
|
||||
smu->fine_grain_started = false;
|
||||
break;
|
||||
case CHIP_VANGOGH:
|
||||
vangogh_set_ppt_funcs(smu);
|
||||
@ -478,9 +482,6 @@ static int smu_late_init(void *handle)
|
||||
|
||||
smu_set_fine_grain_gfx_freq_parameters(smu);
|
||||
|
||||
if (adev->asic_type == CHIP_VANGOGH)
|
||||
return 0;
|
||||
|
||||
if (!smu->pm_enabled)
|
||||
return 0;
|
||||
|
||||
@ -490,6 +491,9 @@ static int smu_late_init(void *handle)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (adev->asic_type == CHIP_VANGOGH)
|
||||
return 0;
|
||||
|
||||
ret = smu_set_default_od_settings(smu);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "Failed to setup default OD settings!\n");
|
||||
|
@ -1673,7 +1673,7 @@ static int navi10_read_sensor(struct smu_context *smu,
|
||||
*size = 4;
|
||||
break;
|
||||
case AMDGPU_PP_SENSOR_GFX_SCLK:
|
||||
ret = navi10_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data);
|
||||
ret = navi10_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXCLK, (uint32_t *)data);
|
||||
*(uint32_t *)data *= 100;
|
||||
*size = 4;
|
||||
break;
|
||||
|
@ -314,6 +314,12 @@ static int sienna_cichlid_check_powerplay_table(struct smu_context *smu)
|
||||
table_context->thermal_controller_type =
|
||||
powerplay_table->thermal_controller_type;
|
||||
|
||||
/*
|
||||
* Instead of having its own buffer space and get overdrive_table copied,
|
||||
* smu->od_settings just points to the actual overdrive_table
|
||||
*/
|
||||
smu->od_settings = &powerplay_table->overdrive_table;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -907,6 +913,22 @@ static bool sienna_cichlid_is_support_fine_grained_dpm(struct smu_context *smu,
|
||||
return dpm_desc->SnapToDiscrete == 0 ? true : false;
|
||||
}
|
||||
|
||||
static bool sienna_cichlid_is_od_feature_supported(struct smu_11_0_7_overdrive_table *od_table,
|
||||
enum SMU_11_0_7_ODFEATURE_CAP cap)
|
||||
{
|
||||
return od_table->cap[cap];
|
||||
}
|
||||
|
||||
static void sienna_cichlid_get_od_setting_range(struct smu_11_0_7_overdrive_table *od_table,
|
||||
enum SMU_11_0_7_ODSETTING_ID setting,
|
||||
uint32_t *min, uint32_t *max)
|
||||
{
|
||||
if (min)
|
||||
*min = od_table->min[setting];
|
||||
if (max)
|
||||
*max = od_table->max[setting];
|
||||
}
|
||||
|
||||
static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type, char *buf)
|
||||
{
|
||||
@ -915,11 +937,16 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
|
||||
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
|
||||
struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
|
||||
PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
|
||||
struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings;
|
||||
OverDriveTable_t *od_table =
|
||||
(OverDriveTable_t *)table_context->overdrive_table;
|
||||
int i, size = 0, ret = 0;
|
||||
uint32_t cur_value = 0, value = 0, count = 0;
|
||||
uint32_t freq_values[3] = {0};
|
||||
uint32_t mark_index = 0;
|
||||
uint32_t gen_speed, lane_width;
|
||||
uint32_t min_value, max_value;
|
||||
uint32_t smu_version;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_GFXCLK:
|
||||
@ -995,6 +1022,70 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
|
||||
(lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
|
||||
"*" : "");
|
||||
break;
|
||||
case SMU_OD_SCLK:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS))
|
||||
break;
|
||||
|
||||
size += sprintf(buf + size, "OD_SCLK:\n");
|
||||
size += sprintf(buf + size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
|
||||
break;
|
||||
|
||||
case SMU_OD_MCLK:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS))
|
||||
break;
|
||||
|
||||
size += sprintf(buf + size, "OD_MCLK:\n");
|
||||
size += sprintf(buf + size, "0: %uMhz\n1: %uMHz\n", od_table->UclkFmin, od_table->UclkFmax);
|
||||
break;
|
||||
|
||||
case SMU_OD_VDDGFX_OFFSET:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
/*
|
||||
* OD GFX Voltage Offset functionality is supported only by 58.41.0
|
||||
* and onwards SMU firmwares.
|
||||
*/
|
||||
smu_cmn_get_smc_version(smu, NULL, &smu_version);
|
||||
if ((adev->asic_type == CHIP_SIENNA_CICHLID) &&
|
||||
(smu_version < 0x003a2900))
|
||||
break;
|
||||
|
||||
size += sprintf(buf + size, "OD_VDDGFX_OFFSET:\n");
|
||||
size += sprintf(buf + size, "%dmV\n", od_table->VddGfxOffset);
|
||||
break;
|
||||
|
||||
case SMU_OD_RANGE:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
size = sprintf(buf, "%s:\n", "OD_RANGE");
|
||||
|
||||
if (sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS)) {
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMIN,
|
||||
&min_value, NULL);
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMAX,
|
||||
NULL, &max_value);
|
||||
size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
|
||||
min_value, max_value);
|
||||
}
|
||||
|
||||
if (sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS)) {
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_UCLKFMIN,
|
||||
&min_value, NULL);
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_UCLKFMAX,
|
||||
NULL, &max_value);
|
||||
size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
|
||||
min_value, max_value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1694,6 +1785,243 @@ static int sienna_cichlid_get_dpm_ultimate_freq(struct smu_context *smu,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sienna_cichlid_dump_od_table(struct smu_context *smu,
|
||||
OverDriveTable_t *od_table)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
uint32_t smu_version;
|
||||
|
||||
dev_dbg(smu->adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin,
|
||||
od_table->GfxclkFmax);
|
||||
dev_dbg(smu->adev->dev, "OD: Uclk: (%d, %d)\n", od_table->UclkFmin,
|
||||
od_table->UclkFmax);
|
||||
|
||||
smu_cmn_get_smc_version(smu, NULL, &smu_version);
|
||||
if (!((adev->asic_type == CHIP_SIENNA_CICHLID) &&
|
||||
(smu_version < 0x003a2900)))
|
||||
dev_dbg(smu->adev->dev, "OD: VddGfxOffset: %d\n", od_table->VddGfxOffset);
|
||||
}
|
||||
|
||||
static int sienna_cichlid_set_default_od_settings(struct smu_context *smu)
|
||||
{
|
||||
OverDriveTable_t *od_table =
|
||||
(OverDriveTable_t *)smu->smu_table.overdrive_table;
|
||||
OverDriveTable_t *boot_od_table =
|
||||
(OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
|
||||
int ret = 0;
|
||||
|
||||
ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
|
||||
0, (void *)od_table, false);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));
|
||||
|
||||
sienna_cichlid_dump_od_table(smu, od_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sienna_cichlid_od_setting_check_range(struct smu_context *smu,
|
||||
struct smu_11_0_7_overdrive_table *od_table,
|
||||
enum SMU_11_0_7_ODSETTING_ID setting,
|
||||
uint32_t value)
|
||||
{
|
||||
if (value < od_table->min[setting]) {
|
||||
dev_warn(smu->adev->dev, "OD setting (%d, %d) is less than the minimum allowed (%d)\n",
|
||||
setting, value, od_table->min[setting]);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (value > od_table->max[setting]) {
|
||||
dev_warn(smu->adev->dev, "OD setting (%d, %d) is greater than the maximum allowed (%d)\n",
|
||||
setting, value, od_table->max[setting]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sienna_cichlid_od_edit_dpm_table(struct smu_context *smu,
|
||||
enum PP_OD_DPM_TABLE_COMMAND type,
|
||||
long input[], uint32_t size)
|
||||
{
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
OverDriveTable_t *od_table =
|
||||
(OverDriveTable_t *)table_context->overdrive_table;
|
||||
struct smu_11_0_7_overdrive_table *od_settings =
|
||||
(struct smu_11_0_7_overdrive_table *)smu->od_settings;
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
enum SMU_11_0_7_ODSETTING_ID freq_setting;
|
||||
uint16_t *freq_ptr;
|
||||
int i, ret = 0;
|
||||
uint32_t smu_version;
|
||||
|
||||
if (!smu->od_enabled) {
|
||||
dev_warn(smu->adev->dev, "OverDrive is not enabled!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!smu->od_settings) {
|
||||
dev_err(smu->adev->dev, "OD board limits are not set!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) {
|
||||
dev_err(smu->adev->dev, "Overdrive table was not initialized!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PP_OD_EDIT_SCLK_VDDC_TABLE:
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings,
|
||||
SMU_11_0_7_ODCAP_GFXCLK_LIMITS)) {
|
||||
dev_warn(smu->adev->dev, "GFXCLK_LIMITS not supported!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += 2) {
|
||||
if (i + 2 > size) {
|
||||
dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (input[i]) {
|
||||
case 0:
|
||||
if (input[i + 1] > od_table->GfxclkFmax) {
|
||||
dev_info(smu->adev->dev, "GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n",
|
||||
input[i + 1], od_table->GfxclkFmax);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_GFXCLKFMIN;
|
||||
freq_ptr = &od_table->GfxclkFmin;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (input[i + 1] < od_table->GfxclkFmin) {
|
||||
dev_info(smu->adev->dev, "GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n",
|
||||
input[i + 1], od_table->GfxclkFmin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_GFXCLKFMAX;
|
||||
freq_ptr = &od_table->GfxclkFmax;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(smu->adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]);
|
||||
dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sienna_cichlid_od_setting_check_range(smu, od_settings,
|
||||
freq_setting, input[i + 1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*freq_ptr = (uint16_t)input[i + 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_OD_EDIT_MCLK_VDDC_TABLE:
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS)) {
|
||||
dev_warn(smu->adev->dev, "UCLK_LIMITS not supported!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += 2) {
|
||||
if (i + 2 > size) {
|
||||
dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (input[i]) {
|
||||
case 0:
|
||||
if (input[i + 1] > od_table->UclkFmax) {
|
||||
dev_info(smu->adev->dev, "UclkFmin (%ld) must be <= UclkFmax (%u)!\n",
|
||||
input[i + 1], od_table->UclkFmax);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_UCLKFMIN;
|
||||
freq_ptr = &od_table->UclkFmin;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (input[i + 1] < od_table->UclkFmin) {
|
||||
dev_info(smu->adev->dev, "UclkFmax (%ld) must be >= UclkFmin (%u)!\n",
|
||||
input[i + 1], od_table->UclkFmin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_UCLKFMAX;
|
||||
freq_ptr = &od_table->UclkFmax;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(smu->adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[i]);
|
||||
dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sienna_cichlid_od_setting_check_range(smu, od_settings,
|
||||
freq_setting, input[i + 1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*freq_ptr = (uint16_t)input[i + 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_OD_RESTORE_DEFAULT_TABLE:
|
||||
memcpy(table_context->overdrive_table,
|
||||
table_context->boot_overdrive_table,
|
||||
sizeof(OverDriveTable_t));
|
||||
fallthrough;
|
||||
|
||||
case PP_OD_COMMIT_DPM_TABLE:
|
||||
sienna_cichlid_dump_od_table(smu, od_table);
|
||||
|
||||
ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
|
||||
0, (void *)od_table, true);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_OD_EDIT_VDDGFX_OFFSET:
|
||||
if (size != 1) {
|
||||
dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* OD GFX Voltage Offset functionality is supported only by 58.41.0
|
||||
* and onwards SMU firmwares.
|
||||
*/
|
||||
smu_cmn_get_smc_version(smu, NULL, &smu_version);
|
||||
if ((adev->asic_type == CHIP_SIENNA_CICHLID) &&
|
||||
(smu_version < 0x003a2900)) {
|
||||
dev_err(smu->adev->dev, "OD GFX Voltage offset functionality is supported "
|
||||
"only by 58.41.0 and onwards SMU firmwares!\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
od_table->VddGfxOffset = (int16_t)input[0];
|
||||
|
||||
sienna_cichlid_dump_od_table(smu, od_table);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sienna_cichlid_run_btc(struct smu_context *smu)
|
||||
{
|
||||
return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL);
|
||||
@ -2372,7 +2700,7 @@ static void sienna_cichlid_fill_i2c_req(SwI2cRequest_t *req, bool write,
|
||||
{
|
||||
int i;
|
||||
|
||||
req->I2CcontrollerPort = 0;
|
||||
req->I2CcontrollerPort = 1;
|
||||
req->I2CSpeed = 2;
|
||||
req->SlaveAddress = address;
|
||||
req->NumCmds = numbytes;
|
||||
@ -2817,6 +3145,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
|
||||
.mode1_reset = smu_v11_0_mode1_reset,
|
||||
.get_dpm_ultimate_freq = sienna_cichlid_get_dpm_ultimate_freq,
|
||||
.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
|
||||
.set_default_od_settings = sienna_cichlid_set_default_od_settings,
|
||||
.od_edit_dpm_table = sienna_cichlid_od_edit_dpm_table,
|
||||
.run_btc = sienna_cichlid_run_btc,
|
||||
.set_power_source = smu_v11_0_set_power_source,
|
||||
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
|
||||
|
@ -31,6 +31,9 @@
|
||||
#include "smu_v11_5_ppsmc.h"
|
||||
#include "smu_v11_5_pmfw.h"
|
||||
#include "smu_cmn.h"
|
||||
#include "soc15_common.h"
|
||||
#include "asic_reg/gc/gc_10_3_0_offset.h"
|
||||
#include "asic_reg/gc/gc_10_3_0_sh_mask.h"
|
||||
|
||||
/*
|
||||
* DO NOT use these for err/warn/info/debug messages.
|
||||
@ -118,6 +121,7 @@ static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
|
||||
MSG_MAP(StopDramLogging, PPSMC_MSG_StopDramLogging, 0),
|
||||
MSG_MAP(SetSoftMinCclk, PPSMC_MSG_SetSoftMinCclk, 0),
|
||||
MSG_MAP(SetSoftMaxCclk, PPSMC_MSG_SetSoftMaxCclk, 0),
|
||||
MSG_MAP(RequestActiveWgp, PPSMC_MSG_RequestActiveWgp, 0),
|
||||
};
|
||||
|
||||
static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
|
||||
@ -162,6 +166,9 @@ static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
|
||||
FEA_MAP(A55_DPM),
|
||||
FEA_MAP(CVIP_DSP_DPM),
|
||||
FEA_MAP(MSMU_LOW_POWER),
|
||||
FEA_MAP_REVERSE(SOCCLK),
|
||||
FEA_MAP_REVERSE(FCLK),
|
||||
FEA_MAP_HALF_REVERSE(GFX),
|
||||
};
|
||||
|
||||
static struct cmn2asic_mapping vangogh_table_map[SMU_TABLE_COUNT] = {
|
||||
@ -242,6 +249,12 @@ static int vangogh_get_smu_metrics_data(struct smu_context *smu,
|
||||
case METRICS_AVERAGE_SOCCLK:
|
||||
*value = metrics->SocclkFrequency;
|
||||
break;
|
||||
case METRICS_AVERAGE_VCLK:
|
||||
*value = metrics->VclkFrequency;
|
||||
break;
|
||||
case METRICS_AVERAGE_DCLK:
|
||||
*value = metrics->DclkFrequency;
|
||||
break;
|
||||
case METRICS_AVERAGE_UCLK:
|
||||
*value = metrics->MemclkFrequency;
|
||||
break;
|
||||
@ -252,7 +265,8 @@ static int vangogh_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->UvdActivity;
|
||||
break;
|
||||
case METRICS_AVERAGE_SOCKETPOWER:
|
||||
*value = metrics->CurrentSocketPower;
|
||||
*value = (metrics->CurrentSocketPower << 8) /
|
||||
1000 ;
|
||||
break;
|
||||
case METRICS_TEMPERATURE_EDGE:
|
||||
*value = metrics->GfxTemperature / 100 *
|
||||
@ -366,6 +380,10 @@ static int vangogh_get_allowed_feature_mask(struct smu_context *smu,
|
||||
|
||||
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DPM_BIT)
|
||||
| FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)
|
||||
| FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)
|
||||
| FEATURE_MASK(FEATURE_VCN_DPM_BIT)
|
||||
| FEATURE_MASK(FEATURE_FCLK_DPM_BIT)
|
||||
| FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)
|
||||
| FEATURE_MASK(FEATURE_DS_SOCCLK_BIT)
|
||||
| FEATURE_MASK(FEATURE_PPT_BIT)
|
||||
| FEATURE_MASK(FEATURE_TDC_BIT)
|
||||
@ -379,6 +397,12 @@ static int vangogh_get_allowed_feature_mask(struct smu_context *smu,
|
||||
if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
|
||||
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT);
|
||||
|
||||
if (adev->pm.pp_feature & PP_MCLK_DPM_MASK)
|
||||
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FCLK_DPM_BIT);
|
||||
|
||||
if (adev->pm.pp_feature & PP_SCLK_DPM_MASK)
|
||||
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DPM_BIT);
|
||||
|
||||
if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB)
|
||||
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT);
|
||||
|
||||
@ -402,10 +426,63 @@ static bool vangogh_is_dpm_running(struct smu_context *smu)
|
||||
return !!(feature_enabled & SMC_DPM_FEATURE);
|
||||
}
|
||||
|
||||
static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
|
||||
uint32_t dpm_level, uint32_t *freq)
|
||||
{
|
||||
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
|
||||
|
||||
if (!clk_table || clk_type >= SMU_CLK_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_SOCCLK:
|
||||
if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
|
||||
return -EINVAL;
|
||||
*freq = clk_table->SocClocks[dpm_level];
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
if (dpm_level >= clk_table->VcnClkLevelsEnabled)
|
||||
return -EINVAL;
|
||||
*freq = clk_table->VcnClocks[dpm_level].vclk;
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
if (dpm_level >= clk_table->VcnClkLevelsEnabled)
|
||||
return -EINVAL;
|
||||
*freq = clk_table->VcnClocks[dpm_level].dclk;
|
||||
break;
|
||||
case SMU_UCLK:
|
||||
case SMU_MCLK:
|
||||
if (dpm_level >= clk_table->NumDfPstatesEnabled)
|
||||
return -EINVAL;
|
||||
*freq = clk_table->DfPstateTable[dpm_level].memclk;
|
||||
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
if (dpm_level >= clk_table->NumDfPstatesEnabled)
|
||||
return -EINVAL;
|
||||
*freq = clk_table->DfPstateTable[dpm_level].fclk;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vangogh_print_fine_grain_clk(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type, char *buf)
|
||||
{
|
||||
int size = 0;
|
||||
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
|
||||
SmuMetrics_t metrics;
|
||||
int i, size = 0, ret = 0;
|
||||
uint32_t cur_value = 0, value = 0, count = 0;
|
||||
bool cur_value_match_level = false;
|
||||
|
||||
memset(&metrics, 0, sizeof(metrics));
|
||||
|
||||
ret = smu_cmn_get_metrics_table(smu, &metrics, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_OD_SCLK:
|
||||
@ -424,6 +501,54 @@ static int vangogh_print_fine_grain_clk(struct smu_context *smu,
|
||||
smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
|
||||
}
|
||||
break;
|
||||
case SMU_SOCCLK:
|
||||
/* the level 3 ~ 6 of socclk use the same frequency for vangogh */
|
||||
count = clk_table->NumSocClkLevelsEnabled;
|
||||
cur_value = metrics.SocclkFrequency;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
count = clk_table->VcnClkLevelsEnabled;
|
||||
cur_value = metrics.VclkFrequency;
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
count = clk_table->VcnClkLevelsEnabled;
|
||||
cur_value = metrics.DclkFrequency;
|
||||
break;
|
||||
case SMU_MCLK:
|
||||
count = clk_table->NumDfPstatesEnabled;
|
||||
cur_value = metrics.MemclkFrequency;
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
count = clk_table->NumDfPstatesEnabled;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetFclkFrequency, 0, &cur_value);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_SOCCLK:
|
||||
case SMU_VCLK:
|
||||
case SMU_DCLK:
|
||||
case SMU_MCLK:
|
||||
case SMU_FCLK:
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!value)
|
||||
continue;
|
||||
size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
|
||||
cur_value == value ? "*" : "");
|
||||
if (cur_value == value)
|
||||
cur_value_match_level = true;
|
||||
}
|
||||
|
||||
if (!cur_value_match_level)
|
||||
size += sprintf(buf + size, " %uMhz *\n", cur_value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -431,6 +556,678 @@ static int vangogh_print_fine_grain_clk(struct smu_context *smu,
|
||||
return size;
|
||||
}
|
||||
|
||||
static int vangogh_get_profiling_clk_mask(struct smu_context *smu,
|
||||
enum amd_dpm_forced_level level,
|
||||
uint32_t *vclk_mask,
|
||||
uint32_t *dclk_mask,
|
||||
uint32_t *mclk_mask,
|
||||
uint32_t *fclk_mask,
|
||||
uint32_t *soc_mask)
|
||||
{
|
||||
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
|
||||
|
||||
if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
|
||||
if (mclk_mask)
|
||||
*mclk_mask = clk_table->NumDfPstatesEnabled - 1;
|
||||
|
||||
if (fclk_mask)
|
||||
*fclk_mask = clk_table->NumDfPstatesEnabled - 1;
|
||||
|
||||
if (soc_mask)
|
||||
*soc_mask = 0;
|
||||
} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
|
||||
if (mclk_mask)
|
||||
*mclk_mask = 0;
|
||||
|
||||
if (fclk_mask)
|
||||
*fclk_mask = 0;
|
||||
|
||||
if (soc_mask)
|
||||
*soc_mask = 1;
|
||||
|
||||
if (vclk_mask)
|
||||
*vclk_mask = 1;
|
||||
|
||||
if (dclk_mask)
|
||||
*dclk_mask = 1;
|
||||
} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) {
|
||||
if (mclk_mask)
|
||||
*mclk_mask = 0;
|
||||
|
||||
if (fclk_mask)
|
||||
*fclk_mask = 0;
|
||||
|
||||
if (soc_mask)
|
||||
*soc_mask = 1;
|
||||
|
||||
if (vclk_mask)
|
||||
*vclk_mask = 1;
|
||||
|
||||
if (dclk_mask)
|
||||
*dclk_mask = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool vangogh_clk_dpm_is_enabled(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type)
|
||||
{
|
||||
enum smu_feature_mask feature_id = 0;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_MCLK:
|
||||
case SMU_UCLK:
|
||||
case SMU_FCLK:
|
||||
feature_id = SMU_FEATURE_DPM_FCLK_BIT;
|
||||
break;
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
|
||||
break;
|
||||
case SMU_SOCCLK:
|
||||
feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
case SMU_DCLK:
|
||||
feature_id = SMU_FEATURE_VCN_DPM_BIT;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!smu_cmn_feature_is_enabled(smu, feature_id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int vangogh_get_dpm_ultimate_freq(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type,
|
||||
uint32_t *min,
|
||||
uint32_t *max)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t soc_mask;
|
||||
uint32_t vclk_mask;
|
||||
uint32_t dclk_mask;
|
||||
uint32_t mclk_mask;
|
||||
uint32_t fclk_mask;
|
||||
uint32_t clock_limit;
|
||||
|
||||
if (!vangogh_clk_dpm_is_enabled(smu, clk_type)) {
|
||||
switch (clk_type) {
|
||||
case SMU_MCLK:
|
||||
case SMU_UCLK:
|
||||
clock_limit = smu->smu_table.boot_values.uclk;
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
clock_limit = smu->smu_table.boot_values.fclk;
|
||||
break;
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
clock_limit = smu->smu_table.boot_values.gfxclk;
|
||||
break;
|
||||
case SMU_SOCCLK:
|
||||
clock_limit = smu->smu_table.boot_values.socclk;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
clock_limit = smu->smu_table.boot_values.vclk;
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
clock_limit = smu->smu_table.boot_values.dclk;
|
||||
break;
|
||||
default:
|
||||
clock_limit = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* clock in Mhz unit */
|
||||
if (min)
|
||||
*min = clock_limit / 100;
|
||||
if (max)
|
||||
*max = clock_limit / 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (max) {
|
||||
ret = vangogh_get_profiling_clk_mask(smu,
|
||||
AMD_DPM_FORCED_LEVEL_PROFILE_PEAK,
|
||||
&vclk_mask,
|
||||
&dclk_mask,
|
||||
&mclk_mask,
|
||||
&fclk_mask,
|
||||
&soc_mask);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_UCLK:
|
||||
case SMU_MCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, mclk_mask, max);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_SOCCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, soc_mask, max);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, fclk_mask, max);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, vclk_mask, max);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, dclk_mask, max);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
if (min) {
|
||||
switch (clk_type) {
|
||||
case SMU_UCLK:
|
||||
case SMU_MCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, mclk_mask, min);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_SOCCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, soc_mask, min);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, fclk_mask, min);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, vclk_mask, min);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type, dclk_mask, min);
|
||||
if (ret)
|
||||
goto failed;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_get_power_profile_mode(struct smu_context *smu,
|
||||
char *buf)
|
||||
{
|
||||
static const char *profile_name[] = {
|
||||
"FULL_SCREEN_3D",
|
||||
"VIDEO",
|
||||
"VR",
|
||||
"COMPUTE",
|
||||
"CUSTOM"};
|
||||
uint32_t i, size = 0;
|
||||
int16_t workload_type = 0;
|
||||
|
||||
if (!buf)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
|
||||
/*
|
||||
* Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
|
||||
* Not all profile modes are supported on vangogh.
|
||||
*/
|
||||
workload_type = smu_cmn_to_asic_specific_index(smu,
|
||||
CMN2ASIC_MAPPING_WORKLOAD,
|
||||
i);
|
||||
|
||||
if (workload_type < 0)
|
||||
continue;
|
||||
|
||||
size += sprintf(buf + size, "%2d %14s%s\n",
|
||||
i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
|
||||
{
|
||||
int workload_type, ret;
|
||||
uint32_t profile_mode = input[size];
|
||||
|
||||
if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
|
||||
dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
|
||||
workload_type = smu_cmn_to_asic_specific_index(smu,
|
||||
CMN2ASIC_MAPPING_WORKLOAD,
|
||||
profile_mode);
|
||||
if (workload_type < 0) {
|
||||
dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
|
||||
profile_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
|
||||
1 << workload_type,
|
||||
NULL);
|
||||
if (ret) {
|
||||
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
|
||||
workload_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
smu->power_profile_mode = profile_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type,
|
||||
uint32_t min,
|
||||
uint32_t max)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!vangogh_clk_dpm_is_enabled(smu, clk_type))
|
||||
return 0;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinGfxClk,
|
||||
min, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxGfxClk,
|
||||
max, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
case SMU_MCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinFclkByFreq,
|
||||
min, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxFclkByFreq,
|
||||
max, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SMU_SOCCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinSocclkByFreq,
|
||||
min, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxSocclkByFreq,
|
||||
max, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinVcn,
|
||||
min << 16, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxVcn,
|
||||
max << 16, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinVcn,
|
||||
min, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxVcn,
|
||||
max, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_force_clk_levels(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type, uint32_t mask)
|
||||
{
|
||||
uint32_t soft_min_level = 0, soft_max_level = 0;
|
||||
uint32_t min_freq = 0, max_freq = 0;
|
||||
int ret = 0 ;
|
||||
|
||||
soft_min_level = mask ? (ffs(mask) - 1) : 0;
|
||||
soft_max_level = mask ? (fls(mask) - 1) : 0;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_SOCCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type,
|
||||
soft_min_level, &min_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = vangogh_get_dpm_clk_limited(smu, clk_type,
|
||||
soft_max_level, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxSocclkByFreq,
|
||||
max_freq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinSocclkByFreq,
|
||||
min_freq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SMU_MCLK:
|
||||
case SMU_FCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu,
|
||||
clk_type, soft_min_level, &min_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = vangogh_get_dpm_clk_limited(smu,
|
||||
clk_type, soft_max_level, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxFclkByFreq,
|
||||
max_freq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinFclkByFreq,
|
||||
min_freq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu,
|
||||
clk_type, soft_min_level, &min_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_get_dpm_clk_limited(smu,
|
||||
clk_type, soft_max_level, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinVcn,
|
||||
min_freq << 16, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxVcn,
|
||||
max_freq << 16, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
ret = vangogh_get_dpm_clk_limited(smu,
|
||||
clk_type, soft_min_level, &min_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_get_dpm_clk_limited(smu,
|
||||
clk_type, soft_max_level, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinVcn,
|
||||
min_freq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxVcn,
|
||||
max_freq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_force_dpm_limit_value(struct smu_context *smu, bool highest)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
uint32_t min_freq, max_freq, force_freq;
|
||||
enum smu_clk_type clk_type;
|
||||
|
||||
enum smu_clk_type clks[] = {
|
||||
SMU_SOCCLK,
|
||||
SMU_VCLK,
|
||||
SMU_DCLK,
|
||||
SMU_MCLK,
|
||||
SMU_FCLK,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clks); i++) {
|
||||
clk_type = clks[i];
|
||||
ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
force_freq = highest ? max_freq : min_freq;
|
||||
ret = vangogh_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_unforce_dpm_levels(struct smu_context *smu)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
uint32_t min_freq, max_freq;
|
||||
enum smu_clk_type clk_type;
|
||||
|
||||
struct clk_feature_map {
|
||||
enum smu_clk_type clk_type;
|
||||
uint32_t feature;
|
||||
} clk_feature_map[] = {
|
||||
{SMU_MCLK, SMU_FEATURE_DPM_FCLK_BIT},
|
||||
{SMU_FCLK, SMU_FEATURE_DPM_FCLK_BIT},
|
||||
{SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
|
||||
{SMU_VCLK, SMU_FEATURE_VCN_DPM_BIT},
|
||||
{SMU_DCLK, SMU_FEATURE_VCN_DPM_BIT},
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
|
||||
|
||||
if (!smu_cmn_feature_is_enabled(smu, clk_feature_map[i].feature))
|
||||
continue;
|
||||
|
||||
clk_type = clk_feature_map[i].clk_type;
|
||||
|
||||
ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_set_peak_clock_by_device(struct smu_context *smu)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t socclk_freq = 0, fclk_freq = 0;
|
||||
uint32_t vclk_freq = 0, dclk_freq = 0;
|
||||
|
||||
ret = vangogh_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_freq, fclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_freq, socclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_freq, vclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_freq, dclk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_set_performance_level(struct smu_context *smu,
|
||||
enum amd_dpm_forced_level level)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t soc_mask, mclk_mask, fclk_mask;
|
||||
uint32_t vclk_mask = 0, dclk_mask = 0;
|
||||
|
||||
switch (level) {
|
||||
case AMD_DPM_FORCED_LEVEL_HIGH:
|
||||
ret = vangogh_force_dpm_limit_value(smu, true);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_LOW:
|
||||
ret = vangogh_force_dpm_limit_value(smu, false);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_AUTO:
|
||||
ret = vangogh_unforce_dpm_levels(smu);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinGfxClk,
|
||||
VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxGfxClk,
|
||||
VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_get_profiling_clk_mask(smu, level,
|
||||
&vclk_mask,
|
||||
&dclk_mask,
|
||||
&mclk_mask,
|
||||
&fclk_mask,
|
||||
&soc_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
|
||||
vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
|
||||
vangogh_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
|
||||
vangogh_force_clk_levels(smu, SMU_VCLK, 1 << vclk_mask);
|
||||
vangogh_force_clk_levels(smu, SMU_DCLK, 1 << dclk_mask);
|
||||
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn,
|
||||
VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn,
|
||||
VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
|
||||
ret = vangogh_get_profiling_clk_mask(smu, level,
|
||||
NULL,
|
||||
NULL,
|
||||
&mclk_mask,
|
||||
&fclk_mask,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
|
||||
vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
|
||||
VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
|
||||
VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vangogh_set_peak_clock_by_device(smu);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_MANUAL:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vangogh_read_sensor(struct smu_context *smu,
|
||||
enum amd_pp_sensors sensor,
|
||||
void *data, uint32_t *size)
|
||||
@ -513,7 +1310,7 @@ static int vangogh_set_watermarks_table(struct smu_context *smu,
|
||||
|
||||
if (clock_ranges) {
|
||||
if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
|
||||
clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
|
||||
clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
|
||||
@ -631,14 +1428,16 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB
|
||||
|
||||
if (input[0] == 0) {
|
||||
if (input[1] < smu->gfx_default_hard_min_freq) {
|
||||
dev_warn(smu->adev->dev, "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
|
||||
dev_warn(smu->adev->dev,
|
||||
"Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
|
||||
input[1], smu->gfx_default_hard_min_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
smu->gfx_actual_hard_min_freq = input[1];
|
||||
} else if (input[0] == 1) {
|
||||
if (input[1] > smu->gfx_default_soft_max_freq) {
|
||||
dev_warn(smu->adev->dev, "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
|
||||
dev_warn(smu->adev->dev,
|
||||
"Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
|
||||
input[1], smu->gfx_default_soft_max_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -676,8 +1475,10 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
|
||||
dev_err(smu->adev->dev, "The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
|
||||
smu->gfx_actual_hard_min_freq, smu->gfx_actual_soft_max_freq);
|
||||
dev_err(smu->adev->dev,
|
||||
"The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
|
||||
smu->gfx_actual_hard_min_freq,
|
||||
smu->gfx_actual_soft_max_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -722,6 +1523,33 @@ static int vangogh_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vangogh_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
|
||||
{
|
||||
DpmClocks_t *table = smu->smu_table.clocks_table;
|
||||
int i;
|
||||
|
||||
if (!clock_table || !table)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
|
||||
clock_table->SocClocks[i].Freq = table->SocClocks[i];
|
||||
clock_table->SocClocks[i].Vol = table->SocVoltage[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
|
||||
clock_table->FClocks[i].Freq = table->DfPstateTable[i].fclk;
|
||||
clock_table->FClocks[i].Vol = table->DfPstateTable[i].voltage;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
|
||||
clock_table->MemClocks[i].Freq = table->DfPstateTable[i].memclk;
|
||||
clock_table->MemClocks[i].Vol = table->DfPstateTable[i].voltage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vangogh_system_features_control(struct smu_context *smu, bool en)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
@ -733,6 +1561,38 @@ static int vangogh_system_features_control(struct smu_context *smu, bool en)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vangogh_post_smu_init(struct smu_context *smu)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
uint32_t tmp;
|
||||
uint8_t aon_bits = 0;
|
||||
/* Two CUs in one WGP */
|
||||
uint32_t req_active_wgps = adev->gfx.cu_info.number/2;
|
||||
uint32_t total_cu = adev->gfx.config.max_cu_per_sh *
|
||||
adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
|
||||
|
||||
/* if all CUs are active, no need to power off any WGPs */
|
||||
if (total_cu == adev->gfx.cu_info.number)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Calculate the total bits number of always on WGPs for all SA/SEs in
|
||||
* RLC_PG_ALWAYS_ON_WGP_MASK.
|
||||
*/
|
||||
tmp = RREG32_KIQ(SOC15_REG_OFFSET(GC, 0, mmRLC_PG_ALWAYS_ON_WGP_MASK));
|
||||
tmp &= RLC_PG_ALWAYS_ON_WGP_MASK__AON_WGP_MASK_MASK;
|
||||
|
||||
aon_bits = hweight32(tmp) * adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
|
||||
|
||||
/* Do not request any WGPs less than set in the AON_WGP_MASK */
|
||||
if (aon_bits > req_active_wgps) {
|
||||
dev_info(adev->dev, "Number of always on WGPs greater than active WGPs: WGP power save not requested.\n");
|
||||
return 0;
|
||||
} else {
|
||||
return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestActiveWgp, req_active_wgps, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pptable_funcs vangogh_ppt_funcs = {
|
||||
|
||||
.check_fw_status = smu_v11_0_check_fw_status,
|
||||
@ -761,6 +1621,13 @@ static const struct pptable_funcs vangogh_ppt_funcs = {
|
||||
.set_default_dpm_table = vangogh_set_default_dpm_tables,
|
||||
.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
|
||||
.system_features_control = vangogh_system_features_control,
|
||||
.feature_is_enabled = smu_cmn_feature_is_enabled,
|
||||
.set_power_profile_mode = vangogh_set_power_profile_mode,
|
||||
.get_power_profile_mode = vangogh_get_power_profile_mode,
|
||||
.get_dpm_clock_table = vangogh_get_dpm_clock_table,
|
||||
.force_clk_levels = vangogh_force_clk_levels,
|
||||
.set_performance_level = vangogh_set_performance_level,
|
||||
.post_init = vangogh_post_smu_init,
|
||||
};
|
||||
|
||||
void vangogh_set_ppt_funcs(struct smu_context *smu)
|
||||
|
@ -28,9 +28,29 @@
|
||||
extern void vangogh_set_ppt_funcs(struct smu_context *smu);
|
||||
|
||||
/* UMD PState Vangogh Msg Parameters in MHz */
|
||||
#define VANGOGH_UMD_PSTATE_GFXCLK 700
|
||||
#define VANGOGH_UMD_PSTATE_SOCCLK 678
|
||||
#define VANGOGH_UMD_PSTATE_FCLK 800
|
||||
#define VANGOGH_UMD_PSTATE_STANDARD_GFXCLK 1100
|
||||
#define VANGOGH_UMD_PSTATE_STANDARD_SOCCLK 600
|
||||
#define VANGOGH_UMD_PSTATE_STANDARD_FCLK 800
|
||||
#define VANGOGH_UMD_PSTATE_STANDARD_VCLK 705
|
||||
#define VANGOGH_UMD_PSTATE_STANDARD_DCLK 600
|
||||
|
||||
#define VANGOGH_UMD_PSTATE_PEAK_GFXCLK 1300
|
||||
#define VANGOGH_UMD_PSTATE_PEAK_SOCCLK 600
|
||||
#define VANGOGH_UMD_PSTATE_PEAK_FCLK 800
|
||||
#define VANGOGH_UMD_PSTATE_PEAK_VCLK 705
|
||||
#define VANGOGH_UMD_PSTATE_PEAK_DCLK 600
|
||||
|
||||
#define VANGOGH_UMD_PSTATE_MIN_SCLK_GFXCLK 400
|
||||
#define VANGOGH_UMD_PSTATE_MIN_SCLK_SOCCLK 1000
|
||||
#define VANGOGH_UMD_PSTATE_MIN_SCLK_FCLK 800
|
||||
#define VANGOGH_UMD_PSTATE_MIN_SCLK_VCLK 1000
|
||||
#define VANGOGH_UMD_PSTATE_MIN_SCLK_DCLK 800
|
||||
|
||||
#define VANGOGH_UMD_PSTATE_MIN_MCLK_GFXCLK 1100
|
||||
#define VANGOGH_UMD_PSTATE_MIN_MCLK_SOCCLK 1000
|
||||
#define VANGOGH_UMD_PSTATE_MIN_MCLK_FCLK 400
|
||||
#define VANGOGH_UMD_PSTATE_MIN_MCLK_VCLK 1000
|
||||
#define VANGOGH_UMD_PSTATE_MIN_MCLK_DCLK 800
|
||||
|
||||
/* RLC Power Status */
|
||||
#define RLC_STATUS_OFF 0
|
||||
|
@ -188,6 +188,7 @@ static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type
|
||||
return -EINVAL;
|
||||
*freq = clk_table->SocClocks[dpm_level].Freq;
|
||||
break;
|
||||
case SMU_UCLK:
|
||||
case SMU_MCLK:
|
||||
if (dpm_level >= NUM_FCLK_DPM_LEVELS)
|
||||
return -EINVAL;
|
||||
@ -343,6 +344,138 @@ failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int renoir_od_edit_dpm_table(struct smu_context *smu,
|
||||
enum PP_OD_DPM_TABLE_COMMAND type,
|
||||
long input[], uint32_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!smu->fine_grain_enabled) {
|
||||
dev_warn(smu->adev->dev, "Fine grain is not enabled!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!smu->fine_grain_started) {
|
||||
dev_warn(smu->adev->dev, "Fine grain is enabled but not started!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PP_OD_EDIT_SCLK_VDDC_TABLE:
|
||||
if (size != 2) {
|
||||
dev_err(smu->adev->dev, "Input parameter number not correct\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (input[0] == 0) {
|
||||
if (input[1] < smu->gfx_default_hard_min_freq) {
|
||||
dev_warn(smu->adev->dev,
|
||||
"Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
|
||||
input[1], smu->gfx_default_hard_min_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
smu->gfx_actual_hard_min_freq = input[1];
|
||||
} else if (input[0] == 1) {
|
||||
if (input[1] > smu->gfx_default_soft_max_freq) {
|
||||
dev_warn(smu->adev->dev,
|
||||
"Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
|
||||
input[1], smu->gfx_default_soft_max_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
smu->gfx_actual_soft_max_freq = input[1];
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case PP_OD_RESTORE_DEFAULT_TABLE:
|
||||
if (size != 0) {
|
||||
dev_err(smu->adev->dev, "Input parameter number not correct\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinGfxClk,
|
||||
smu->gfx_actual_hard_min_freq,
|
||||
NULL);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Restore the default hard min sclk failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxGfxClk,
|
||||
smu->gfx_actual_soft_max_freq,
|
||||
NULL);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Restore the default soft max sclk failed!");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case PP_OD_COMMIT_DPM_TABLE:
|
||||
if (size != 0) {
|
||||
dev_err(smu->adev->dev, "Input parameter number not correct\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
|
||||
dev_err(smu->adev->dev,
|
||||
"The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
|
||||
smu->gfx_actual_hard_min_freq,
|
||||
smu->gfx_actual_soft_max_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinGfxClk,
|
||||
smu->gfx_actual_hard_min_freq,
|
||||
NULL);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Set hard min sclk failed!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetSoftMaxGfxClk,
|
||||
smu->gfx_actual_soft_max_freq,
|
||||
NULL);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Set soft max sclk failed!");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
|
||||
{
|
||||
uint32_t min = 0, max = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_GetMinGfxclkFrequency,
|
||||
0, &min);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_GetMaxGfxclkFrequency,
|
||||
0, &max);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smu->gfx_default_hard_min_freq = min;
|
||||
smu->gfx_default_soft_max_freq = max;
|
||||
smu->gfx_actual_hard_min_freq = 0;
|
||||
smu->gfx_actual_soft_max_freq = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renoir_print_clk_levels(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type, char *buf)
|
||||
{
|
||||
@ -358,6 +491,30 @@ static int renoir_print_clk_levels(struct smu_context *smu,
|
||||
return ret;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_OD_RANGE:
|
||||
if (smu->fine_grain_enabled) {
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_GetMinGfxclkFrequency,
|
||||
0, &min);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_GetMaxGfxclkFrequency,
|
||||
0, &max);
|
||||
if (ret)
|
||||
return ret;
|
||||
size += sprintf(buf + size, "OD_RANGE\nSCLK: %10uMhz %10uMhz\n", min, max);
|
||||
}
|
||||
break;
|
||||
case SMU_OD_SCLK:
|
||||
if (smu->fine_grain_enabled) {
|
||||
min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
|
||||
max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
|
||||
size += sprintf(buf + size, "OD_SCLK\n");
|
||||
size += sprintf(buf + size, "0:%10uMhz\n", min);
|
||||
size += sprintf(buf + size, "1:%10uMhz\n", max);
|
||||
}
|
||||
break;
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
/* retirve table returned paramters unit is MHz */
|
||||
@ -398,23 +555,35 @@ static int renoir_print_clk_levels(struct smu_context *smu,
|
||||
cur_value = metrics.ClockFrequency[CLOCK_FCLK];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!value)
|
||||
continue;
|
||||
size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
|
||||
cur_value == value ? "*" : "");
|
||||
if (cur_value == value)
|
||||
cur_value_match_level = true;
|
||||
}
|
||||
switch (clk_type) {
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
case SMU_SOCCLK:
|
||||
case SMU_MCLK:
|
||||
case SMU_DCEFCLK:
|
||||
case SMU_FCLK:
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!value)
|
||||
continue;
|
||||
size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
|
||||
cur_value == value ? "*" : "");
|
||||
if (cur_value == value)
|
||||
cur_value_match_level = true;
|
||||
}
|
||||
|
||||
if (!cur_value_match_level)
|
||||
size += sprintf(buf + size, " %uMhz *\n", cur_value);
|
||||
if (!cur_value_match_level)
|
||||
size += sprintf(buf + size, " %uMhz *\n", cur_value);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -724,15 +893,31 @@ static int renoir_set_performance_level(struct smu_context *smu,
|
||||
|
||||
switch (level) {
|
||||
case AMD_DPM_FORCED_LEVEL_HIGH:
|
||||
smu->fine_grain_started = 0;
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = renoir_force_dpm_limit_value(smu, true);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_LOW:
|
||||
smu->fine_grain_started = 0;
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = renoir_force_dpm_limit_value(smu, false);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_AUTO:
|
||||
smu->fine_grain_started = 0;
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = renoir_unforce_dpm_levels(smu);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
|
||||
smu->fine_grain_started = 0;
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetHardMinGfxClk,
|
||||
RENOIR_UMD_PSTATE_GFXCLK,
|
||||
@ -785,6 +970,10 @@ static int renoir_set_performance_level(struct smu_context *smu,
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
|
||||
smu->fine_grain_started = 0;
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = renoir_get_profiling_clk_mask(smu, level,
|
||||
&sclk_mask,
|
||||
&mclk_mask,
|
||||
@ -796,9 +985,14 @@ static int renoir_set_performance_level(struct smu_context *smu,
|
||||
renoir_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
|
||||
smu->fine_grain_started = 0;
|
||||
smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
|
||||
smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
|
||||
|
||||
ret = renoir_set_peak_clock_by_device(smu);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_MANUAL:
|
||||
smu->fine_grain_started = 1;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
|
||||
default:
|
||||
break;
|
||||
@ -1159,6 +1353,8 @@ static const struct pptable_funcs renoir_ppt_funcs = {
|
||||
.set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
|
||||
.get_gpu_metrics = renoir_get_gpu_metrics,
|
||||
.gfx_state_change_set = renoir_gfx_state_change_set,
|
||||
.set_fine_grain_gfx_freq_parameters = renoir_set_fine_grain_gfx_freq_parameters,
|
||||
.od_edit_dpm_table = renoir_od_edit_dpm_table,
|
||||
};
|
||||
|
||||
void renoir_set_ppt_funcs(struct smu_context *smu)
|
||||
|
@ -225,6 +225,7 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
case SMU_MCLK:
|
||||
case SMU_UCLK:
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -220,7 +220,7 @@ int r600_fmt_get_nblocksx(u32 format, u32 w)
|
||||
if (bw == 0)
|
||||
return 0;
|
||||
|
||||
return (w + bw - 1) / bw;
|
||||
return DIV_ROUND_UP(w, bw);
|
||||
}
|
||||
|
||||
int r600_fmt_get_nblocksy(u32 format, u32 h)
|
||||
@ -234,7 +234,7 @@ int r600_fmt_get_nblocksy(u32 format, u32 h)
|
||||
if (bh == 0)
|
||||
return 0;
|
||||
|
||||
return (h + bh - 1) / bh;
|
||||
return DIV_ROUND_UP(h, bh);
|
||||
}
|
||||
|
||||
struct array_mode_checker {
|
||||
|
@ -781,7 +781,7 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
|
||||
uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
|
||||
RADEON_GPU_PAGE_SIZE;
|
||||
|
||||
uint32_t *msg = rdev->uvd.cpu_addr + offs;
|
||||
uint32_t __iomem *msg = (void __iomem *)(rdev->uvd.cpu_addr + offs);
|
||||
uint64_t addr = rdev->uvd.gpu_addr + offs;
|
||||
|
||||
int r, i;
|
||||
@ -791,19 +791,19 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
|
||||
return r;
|
||||
|
||||
/* stitch together an UVD create msg */
|
||||
msg[0] = cpu_to_le32(0x00000de4);
|
||||
msg[1] = cpu_to_le32(0x00000000);
|
||||
msg[2] = cpu_to_le32(handle);
|
||||
msg[3] = cpu_to_le32(0x00000000);
|
||||
msg[4] = cpu_to_le32(0x00000000);
|
||||
msg[5] = cpu_to_le32(0x00000000);
|
||||
msg[6] = cpu_to_le32(0x00000000);
|
||||
msg[7] = cpu_to_le32(0x00000780);
|
||||
msg[8] = cpu_to_le32(0x00000440);
|
||||
msg[9] = cpu_to_le32(0x00000000);
|
||||
msg[10] = cpu_to_le32(0x01b37000);
|
||||
writel(cpu_to_le32(0x00000de4), &msg[0]);
|
||||
writel(0x0, (void __iomem *)&msg[1]);
|
||||
writel(cpu_to_le32(handle), &msg[2]);
|
||||
writel(0x0, &msg[3]);
|
||||
writel(0x0, &msg[4]);
|
||||
writel(0x0, &msg[5]);
|
||||
writel(0x0, &msg[6]);
|
||||
writel(cpu_to_le32(0x00000780), &msg[7]);
|
||||
writel(cpu_to_le32(0x00000440), &msg[8]);
|
||||
writel(0x0, &msg[9]);
|
||||
writel(cpu_to_le32(0x01b37000), &msg[10]);
|
||||
for (i = 11; i < 1024; ++i)
|
||||
msg[i] = cpu_to_le32(0x0);
|
||||
writel(0x0, &msg[i]);
|
||||
|
||||
r = radeon_uvd_send_msg(rdev, ring, addr, fence);
|
||||
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
|
||||
@ -817,7 +817,7 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
|
||||
uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
|
||||
RADEON_GPU_PAGE_SIZE;
|
||||
|
||||
uint32_t *msg = rdev->uvd.cpu_addr + offs;
|
||||
uint32_t __iomem *msg = (void __iomem *)(rdev->uvd.cpu_addr + offs);
|
||||
uint64_t addr = rdev->uvd.gpu_addr + offs;
|
||||
|
||||
int r, i;
|
||||
@ -827,12 +827,12 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
|
||||
return r;
|
||||
|
||||
/* stitch together an UVD destroy msg */
|
||||
msg[0] = cpu_to_le32(0x00000de4);
|
||||
msg[1] = cpu_to_le32(0x00000002);
|
||||
msg[2] = cpu_to_le32(handle);
|
||||
msg[3] = cpu_to_le32(0x00000000);
|
||||
writel(cpu_to_le32(0x00000de4), &msg[0]);
|
||||
writel(cpu_to_le32(0x00000002), &msg[1]);
|
||||
writel(cpu_to_le32(handle), &msg[2]);
|
||||
writel(0x0, &msg[3]);
|
||||
for (i = 4; i < 1024; ++i)
|
||||
msg[i] = cpu_to_le32(0x0);
|
||||
writel(0x0, &msg[i]);
|
||||
|
||||
r = radeon_uvd_send_msg(rdev, ring, addr, fence);
|
||||
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
|
||||
|
Loading…
Reference in New Issue
Block a user