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:
Dave Airlie 2021-01-15 09:05:23 +10:00
commit 2ce542e517
100 changed files with 5955 additions and 1297 deletions

View File

@ -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 \ 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 \ 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 \ 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 # add DF block
amdgpu-y += \ amdgpu-y += \
@ -97,6 +97,7 @@ amdgpu-y += \
tonga_ih.o \ tonga_ih.o \
cz_ih.o \ cz_ih.o \
vega10_ih.o \ vega10_ih.o \
vega20_ih.o \
navi10_ih.o navi10_ih.o
# add PSP block # add PSP block

View File

@ -88,6 +88,7 @@
#include "amdgpu_gfx.h" #include "amdgpu_gfx.h"
#include "amdgpu_sdma.h" #include "amdgpu_sdma.h"
#include "amdgpu_nbio.h" #include "amdgpu_nbio.h"
#include "amdgpu_hdp.h"
#include "amdgpu_dm.h" #include "amdgpu_dm.h"
#include "amdgpu_virt.h" #include "amdgpu_virt.h"
#include "amdgpu_csa.h" #include "amdgpu_csa.h"
@ -106,6 +107,7 @@
#include "amdgpu_gfxhub.h" #include "amdgpu_gfxhub.h"
#include "amdgpu_df.h" #include "amdgpu_df.h"
#include "amdgpu_smuio.h" #include "amdgpu_smuio.h"
#include "amdgpu_hdp.h"
#define MAX_GPU_INSTANCE 16 #define MAX_GPU_INSTANCE 16
@ -607,7 +609,6 @@ struct amdgpu_asic_funcs {
/* invalidate hdp read cache */ /* invalidate hdp read cache */
void (*invalidate_hdp)(struct amdgpu_device *adev, void (*invalidate_hdp)(struct amdgpu_device *adev,
struct amdgpu_ring *ring); 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 */ /* check if the asic needs a full reset of if soft reset will work */
bool (*need_full_reset)(struct amdgpu_device *adev); bool (*need_full_reset)(struct amdgpu_device *adev);
/* initialize doorbell layout for specific asic*/ /* initialize doorbell layout for specific asic*/
@ -920,6 +921,9 @@ struct amdgpu_device {
/* nbio */ /* nbio */
struct amdgpu_nbio nbio; struct amdgpu_nbio nbio;
/* hdp */
struct amdgpu_hdp hdp;
/* smuio */ /* smuio */
struct amdgpu_smuio 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_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_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_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_flush_hdp(adev, r) \
#define amdgpu_asic_invalidate_hdp(adev, r) (adev)->asic_funcs->invalidate_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_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_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))) #define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))

View File

@ -23,7 +23,6 @@
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
#include "gc/gc_10_1_0_offset.h" #include "gc/gc_10_1_0_offset.h"
#include "gc/gc_10_1_0_sh_mask.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_offset.h"
#include "athub/athub_2_0_0_sh_mask.h" #include "athub/athub_2_0_0_sh_mask.h"
#include "oss/osssys_5_0_0_offset.h" #include "oss/osssys_5_0_0_offset.h"

View File

@ -24,7 +24,6 @@
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
#include "gc/gc_10_3_0_offset.h" #include "gc/gc_10_3_0_offset.h"
#include "gc/gc_10_3_0_sh_mask.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_offset.h"
#include "oss/osssys_5_0_0_sh_mask.h" #include "oss/osssys_5_0_0_sh_mask.h"
#include "soc15_common.h" #include "soc15_common.h"

View File

@ -155,7 +155,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0}; u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
int len; int len;
if (!adev->asic_funcs->read_bios_from_rom) if (!adev->asic_funcs || !adev->asic_funcs->read_bios_from_rom)
return false; return false;
/* validate VBIOS signature */ /* validate VBIOS signature */
@ -348,7 +348,8 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
if (adev->flags & AMD_IS_APU) if (adev->flags & AMD_IS_APU)
return igp_read_bios_from_vram(adev); return igp_read_bios_from_vram(adev);
else 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 #ifdef CONFIG_ACPI

View File

@ -2548,11 +2548,11 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
if (adev->gmc.xgmi.num_physical_nodes > 1) if (adev->gmc.xgmi.num_physical_nodes > 1)
amdgpu_xgmi_remove_device(adev); amdgpu_xgmi_remove_device(adev);
amdgpu_amdkfd_device_fini(adev);
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
amdgpu_amdkfd_device_fini(adev);
/* need to disable SMC first */ /* need to disable SMC first */
for (i = 0; i < adev->num_ip_blocks; i++) { for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.hw) 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 #endif
default: default:
if (amdgpu_dc > 0) 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"); "but isn't supported by ASIC, ignoring\n");
return false; return false;
} }

View File

@ -40,6 +40,7 @@
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <linux/dma-fence-array.h> #include <linux/dma-fence-array.h>
#include <linux/pci-p2pdma.h> #include <linux/pci-p2pdma.h>
#include <linux/pm_runtime.h>
/** /**
* amdgpu_gem_prime_mmap - &drm_driver.gem_prime_mmap implementation * 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) if (attach->dev->driver == adev->dev->driver)
return 0; return 0;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0)
goto out;
r = amdgpu_bo_reserve(bo, false); r = amdgpu_bo_reserve(bo, false);
if (unlikely(r != 0)) if (unlikely(r != 0))
return r; goto out;
/* /*
* We only create shared fences for internal use, but importers * 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); r = __dma_resv_make_exclusive(bo->tbo.base.resv);
if (r) if (r)
return r; goto out;
bo->prime_shared_count++; bo->prime_shared_count++;
amdgpu_bo_unreserve(bo); amdgpu_bo_unreserve(bo);
return 0; 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) if (attach->dev->driver != adev->dev->driver && bo->prime_shared_count)
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);
} }
/** /**

View 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__ */

View File

@ -205,3 +205,46 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
return IRQ_HANDLED; 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;
}

View File

@ -30,6 +30,18 @@
struct amdgpu_device; struct amdgpu_device;
struct amdgpu_iv_entry; 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 * R6xx+ IH ring
*/ */
@ -53,6 +65,7 @@ struct amdgpu_ih_ring {
bool enabled; bool enabled;
unsigned rptr; unsigned rptr;
atomic_t lock; atomic_t lock;
struct amdgpu_ih_regs ih_regs;
}; };
/* provided by the ih block */ /* 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, void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
unsigned int num_dw); unsigned int num_dw);
int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih); 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 #endif

View File

@ -444,7 +444,8 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
} else if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) { } else if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
DRM_DEBUG("Invalid src_id in IV: %d\n", 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)); generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
} else if (!adev->irq.client[client_id].sources) { } else if (!adev->irq.client[client_id].sources) {

View File

@ -57,7 +57,6 @@ struct amdgpu_nbio_funcs {
u32 (*get_pcie_port_data_offset)(struct amdgpu_device *adev); u32 (*get_pcie_port_data_offset)(struct amdgpu_device *adev);
u32 (*get_rev_id)(struct amdgpu_device *adev); u32 (*get_rev_id)(struct amdgpu_device *adev);
void (*mc_access_enable)(struct amdgpu_device *adev, bool enable); 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); u32 (*get_memsize)(struct amdgpu_device *adev);
void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance, void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance,
bool use_doorbell, int doorbell_index, int doorbell_size); bool use_doorbell, int doorbell_index, int doorbell_size);

View File

@ -249,7 +249,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
{ {
int ret; int ret;
int index; int index;
int timeout = 2000; int timeout = 20000;
bool ras_intr = false; bool ras_intr = false;
bool skip_unsupport = false; bool skip_unsupport = false;
@ -282,7 +282,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
ras_intr = amdgpu_ras_intr_triggered(); ras_intr = amdgpu_ras_intr_triggered();
if (ras_intr) if (ras_intr)
break; break;
msleep(1); usleep_range(10, 100);
amdgpu_asic_invalidate_hdp(psp->adev, NULL); 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. * add workaround to bypass it for sriov now.
* TODO: add version check to make it common * 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; return 0;
cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 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)) if (amdgpu_sriov_vf(psp->adev))
return 0; return 0;
if (!psp->hdcp_context.hdcp_initialized) if (!psp->hdcp_context.hdcp_initialized) {
if (psp->hdcp_context.hdcp_shared_buf)
goto out;
else
return 0; return 0;
}
ret = psp_hdcp_unload(psp); ret = psp_hdcp_unload(psp);
if (ret) if (ret)
@ -1324,6 +1328,7 @@ static int psp_hdcp_terminate(struct psp_context *psp)
psp->hdcp_context.hdcp_initialized = false; psp->hdcp_context.hdcp_initialized = false;
out:
/* free hdcp shared memory */ /* free hdcp shared memory */
amdgpu_bo_free_kernel(&psp->hdcp_context.hdcp_shared_bo, amdgpu_bo_free_kernel(&psp->hdcp_context.hdcp_shared_bo,
&psp->hdcp_context.hdcp_shared_mc_addr, &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)) if (amdgpu_sriov_vf(psp->adev))
return 0; return 0;
if (!psp->dtm_context.dtm_initialized) if (!psp->dtm_context.dtm_initialized) {
if (psp->dtm_context.dtm_shared_buf)
goto out;
else
return 0; return 0;
}
ret = psp_dtm_unload(psp); ret = psp_dtm_unload(psp);
if (ret) if (ret)
@ -1471,6 +1480,7 @@ static int psp_dtm_terminate(struct psp_context *psp)
psp->dtm_context.dtm_initialized = false; psp->dtm_context.dtm_initialized = false;
out:
/* free hdcp shared memory */ /* free hdcp shared memory */
amdgpu_bo_free_kernel(&psp->dtm_context.dtm_shared_bo, amdgpu_bo_free_kernel(&psp->dtm_context.dtm_shared_bo,
&psp->dtm_context.dtm_shared_mc_addr, &psp->dtm_context.dtm_shared_mc_addr,
@ -2593,7 +2603,6 @@ static int parse_ta_bin_descriptor(struct psp_context *psp,
psp->asd_feature_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_start_addr = ucode_start_addr;
psp->asd_fw = psp->ta_fw;
break; break;
case TA_FW_TYPE_PSP_XGMI: case TA_FW_TYPE_PSP_XGMI:
psp->ta_xgmi_ucode_version = le32_to_cpu(desc->fw_version); psp->ta_xgmi_ucode_version = le32_to_cpu(desc->fw_version);

View File

@ -1518,7 +1518,7 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev,
struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_err_handler_data *data; struct ras_err_handler_data *data;
int i = 0; int i = 0;
int ret = 0; int ret = 0, status;
if (!con || !con->eh_data || !bps || !count) if (!con || !con->eh_data || !bps || !count)
return -EINVAL; return -EINVAL;
@ -1543,12 +1543,12 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev,
.size = AMDGPU_GPU_PAGE_SIZE, .size = AMDGPU_GPU_PAGE_SIZE,
.flags = AMDGPU_RAS_RETIRE_PAGE_RESERVED, .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), ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM),
data->bps[i].retired_page); data->bps[i].retired_page);
if (ret == -EBUSY) if (status == -EBUSY)
(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_PENDING; (*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_PENDING;
else if (ret == -ENOENT) else if (status == -ENOENT)
(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_FAULT; (*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_FAULT;
} }

View File

@ -30,6 +30,7 @@
#define EEPROM_I2C_TARGET_ADDR_VEGA20 0xA0 #define EEPROM_I2C_TARGET_ADDR_VEGA20 0xA0
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS 0xA8 #define EEPROM_I2C_TARGET_ADDR_ARCTURUS 0xA8
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0xA0 #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 * 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) static bool __is_ras_eeprom_supported(struct amdgpu_device *adev)
{ {
if ((adev->asic_type == CHIP_VEGA20) || 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 true;
return false; return false;
@ -100,6 +102,10 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
case CHIP_ARCTURUS: case CHIP_ARCTURUS:
return __get_eeprom_i2c_addr_arct(adev, i2c_addr); return __get_eeprom_i2c_addr_arct(adev, i2c_addr);
case CHIP_SIENNA_CICHLID:
*i2c_addr = EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID;
break;
default: default:
return false; return false;
} }

View File

@ -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_ #define _AMDGPU_TRACE_H_
#include <linux/stringify.h> #include <linux/stringify.h>

View File

@ -1170,7 +1170,7 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
int r, i; int r, i;
r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE, r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_DOMAIN_GTT,
&bo, NULL, (void **)&msg); &bo, NULL, (void **)&msg);
if (r) if (r)
return r; return r;
@ -1202,7 +1202,7 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
int r, i; int r, i;
r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE, r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_DOMAIN_GTT,
&bo, NULL, (void **)&msg); &bo, NULL, (void **)&msg);
if (r) if (r)
return r; return r;

View File

@ -27,7 +27,6 @@
#include "athub/athub_2_0_0_offset.h" #include "athub/athub_2_0_0_offset.h"
#include "athub/athub_2_0_0_sh_mask.h" #include "athub/athub_2_0_0_sh_mask.h"
#include "athub/athub_2_0_0_default.h" #include "athub/athub_2_0_0_default.h"
#include "navi10_enum.h"
#include "soc15_common.h" #include "soc15_common.h"

View File

@ -26,7 +26,6 @@
#include "athub/athub_2_1_0_offset.h" #include "athub/athub_2_1_0_offset.h"
#include "athub/athub_2_1_0_sh_mask.h" #include "athub/athub_2_1_0_sh_mask.h"
#include "navi10_enum.h"
#include "soc15_common.h" #include "soc15_common.h"

View File

@ -194,8 +194,17 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev,
wptr = le32_to_cpu(*ih->wptr_cpu); wptr = le32_to_cpu(*ih->wptr_cpu);
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) { 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); wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
* this should allow us to catchup. * this should allow us to catchup.
@ -206,7 +215,9 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev,
tmp = RREG32(mmIH_RB_CNTL); tmp = RREG32(mmIH_RB_CNTL);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32(mmIH_RB_CNTL, tmp); WREG32(mmIH_RB_CNTL, tmp);
}
out:
return (wptr & ih->ptr_mask); return (wptr & ih->ptr_mask);
} }

View File

@ -294,7 +294,7 @@ static int dce_virtual_get_modes(struct drm_connector *connector)
static const struct mode_size { static const struct mode_size {
int w; int w;
int h; int h;
} common_modes[21] = { } common_modes[] = {
{ 640, 480}, { 640, 480},
{ 720, 480}, { 720, 480},
{ 800, 600}, { 800, 600},
@ -312,13 +312,14 @@ static int dce_virtual_get_modes(struct drm_connector *connector)
{1600, 1200}, {1600, 1200},
{1920, 1080}, {1920, 1080},
{1920, 1200}, {1920, 1200},
{2560, 1440},
{4096, 3112}, {4096, 3112},
{3656, 2664}, {3656, 2664},
{3840, 2160}, {3840, 2160},
{4096, 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); mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
drm_mode_probed_add(connector, mode); drm_mode_probed_add(connector, mode);
} }

View File

@ -38,7 +38,6 @@
#include "smuio/smuio_11_0_0_offset.h" #include "smuio/smuio_11_0_0_offset.h"
#include "smuio/smuio_11_0_0_sh_mask.h" #include "smuio/smuio_11_0_0_sh_mask.h"
#include "navi10_enum.h" #include "navi10_enum.h"
#include "hdp/hdp_5_0_0_offset.h"
#include "ivsrcid/gfx/irqsrcs_gfx_10_1.h" #include "ivsrcid/gfx/irqsrcs_gfx_10_1.h"
#include "soc15.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) 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 = RREG32_SOC15(GC, 0, mmCP_PFP_IC_BASE_CNTL);
tmp = REG_SET_FIELD(tmp, CP_PFP_IC_BASE_CNTL, VMID, 0); 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) 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 = RREG32_SOC15(GC, 0, mmCP_CE_IC_BASE_CNTL);
tmp = REG_SET_FIELD(tmp, CP_CE_IC_BASE_CNTL, VMID, 0); 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) 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 = RREG32_SOC15(GC, 0, mmCP_ME_IC_BASE_CNTL);
tmp = REG_SET_FIELD(tmp, CP_ME_IC_BASE_CNTL, VMID, 0); 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) 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 = RREG32_SOC15(GC, 0, mmCP_CPC_IC_BASE_CNTL);
tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0); tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);

View File

@ -38,7 +38,6 @@
#include "gc/gc_9_0_sh_mask.h" #include "gc/gc_9_0_sh_mask.h"
#include "vega10_enum.h" #include "vega10_enum.h"
#include "hdp/hdp_4_0_offset.h"
#include "soc15_common.h" #include "soc15_common.h"
#include "clearstate_gfx9.h" #include "clearstate_gfx9.h"

View File

@ -27,8 +27,6 @@
#include "gmc_v10_0.h" #include "gmc_v10_0.h"
#include "umc_v8_7.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_sh_mask.h"
#include "athub/athub_2_0_0_offset.h" #include "athub/athub_2_0_0_offset.h"
#include "dcn/dcn_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; int r;
/* flush hdp cache */ /* 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 /* For SRIOV run time, driver shouldn't access the register through MMIO
* Directly use kiq to do the vm invalidation instead * 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; int r;
bool value; bool value;
u32 tmp;
if (adev->gart.bo == NULL) { if (adev->gart.bo == NULL) {
dev_err(adev->dev, "No VRAM object for PCIE GART.\n"); 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) if (r)
return r; return r;
tmp = RREG32_SOC15(HDP, 0, mmHDP_MISC_CNTL); adev->hdp.funcs->init_registers(adev);
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);
/* Flush HDP after it is initialized */ /* 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) ? value = (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) ?
false : true; false : true;

View File

@ -31,8 +31,6 @@
#include "amdgpu_atomfirmware.h" #include "amdgpu_atomfirmware.h"
#include "amdgpu_gem.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 "gc/gc_9_0_sh_mask.h"
#include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_offset.h"
#include "dce/dce_12_0_sh_mask.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", [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[] = static const struct soc15_reg_golden golden_settings_mmhub_1_0_0[] =
{ {
SOC15_REG_GOLDEN_VALUE(MMHUB, 0, mmDAGB1_WRCLI2, 0x00000007, 0xfe5fe0fa), 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; struct amdgpu_device *adev = (struct amdgpu_device *)handle;
bool value; bool value;
int r, i; int r, i;
u32 tmp;
/* The sequence of these two function calls matters.*/ /* The sequence of these two function calls matters.*/
gmc_v9_0_init_golden_registers(adev); 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); 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) if (adev->mmhub.funcs->update_power_gating)
adev->mmhub.funcs->update_power_gating(adev, true); adev->mmhub.funcs->update_power_gating(adev, true);
switch (adev->asic_type) { adev->hdp.funcs->init_registers(adev);
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));
/* After HDP is initialized, flush HDP.*/ /* 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) if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS)
value = false; value = false;

View 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,
};

View 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

View 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,
};

View 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

View File

@ -194,7 +194,15 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev,
wptr = le32_to_cpu(*ih->wptr_cpu); wptr = le32_to_cpu(*ih->wptr_cpu);
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) { 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); wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
@ -206,7 +214,9 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev,
tmp = RREG32(mmIH_RB_CNTL); tmp = RREG32(mmIH_RB_CNTL);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32(mmIH_RB_CNTL, tmp); WREG32(mmIH_RB_CNTL, tmp);
}
out:
return (wptr & ih->ptr_mask); return (wptr & ih->ptr_mask);
} }

View File

@ -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. */ /* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL, tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry); !adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_CNTL, WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp); i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32, WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,

View File

@ -39,6 +39,53 @@
static void navi10_ih_set_interrupt_funcs(struct amdgpu_device *adev); 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 * 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 * @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_regs = &ih->ih_regs;
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) { tmp = RREG32(ih_regs->ih_rb_cntl);
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); /* enable_intr field is only valid in ring0 */
return; 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 { } 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; return 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, 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;
} }
/** /**
* navi10_ih_disable_interrupts - Disable the interrupt ring buffer * navi10_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
* *
* @adev: amdgpu_device pointer * @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); for (i = 0; i < ARRAY_SIZE(ih); i++) {
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0); if (ih[i]->ring_size) {
if (amdgpu_sriov_vf(adev) && adev->asic_type < CHIP_NAVI10) { r = navi10_ih_toggle_ring_interrupts(adev, ih[i], enable);
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { if (r)
DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); return r;
return;
} }
} 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) 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; 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; uint32_t tmp;
/* Reroute to IH ring 1 for VMC */ ih_regs = &ih->ih_regs;
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 UMC */ /* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B); WREG32(ih_regs->ih_rb_base, ih->gpu_addr >> 8);
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA); WREG32(ih_regs->ih_rb_base_hi, (ih->gpu_addr >> 40) & 0xff);
tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp); 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) static int navi10_ih_irq_init(struct amdgpu_device *adev)
{ {
struct amdgpu_ih_ring *ih = &adev->irq.ih; struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
u32 ih_rb_cntl, ih_chicken; u32 ih_chicken;
u32 tmp; u32 tmp;
int ret;
int i;
/* disable irqs */ /* disable irqs */
navi10_ih_disable_interrupts(adev); ret = navi10_ih_toggle_interrupts(adev, false);
if (ret)
return ret;
adev->nbio.funcs->ih_control(adev); 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 (unlikely(adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT)) {
if (ih->use_bus_addr) { if (ih[0]->use_bus_addr) {
switch (adev->asic_type) { switch (adev->asic_type) {
case CHIP_SIENNA_CICHLID: case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER: 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 */ for (i = 0; i < ARRAY_SIZE(ih); i++) {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO, if (ih[i]->ring_size) {
lower_32_bits(ih->wptr_addr)); ret = navi10_ih_enable_ring(adev, ih[i]);
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, if (ret)
upper_32_bits(ih->wptr_addr) & 0xFFFF); return ret;
/* 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);
}
/* 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 = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);
tmp = REG_SET_FIELD(tmp, IH_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); pci_set_master(adev->pdev);
/* enable interrupts */ /* 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 */ /* enable wptr force update for self int */
force_update_wptr_for_self_int(adev, 0, 8, true); 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; 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) static void navi10_ih_irq_disable(struct amdgpu_device *adev)
{ {
force_update_wptr_for_self_int(adev, 0, 8, false); 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 */ /* Wait and acknowledge irq */
mdelay(1); 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, static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) 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); wptr = le32_to_cpu(*ih->wptr_cpu);
ih_regs = &ih->ih_regs;
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
goto out; goto out;
if (ih == &adev->irq.ih) wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
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);
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
goto out; goto out;
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0); 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); wptr, ih->rptr, tmp);
ih->rptr = tmp; ih->rptr = tmp;
if (ih == &adev->irq.ih) tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
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 = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); 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: out:
return (wptr & ih->ptr_mask); 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 * 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, static void navi10_ih_irq_rearm(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) struct amdgpu_ih_ring *ih)
{ {
uint32_t reg_rptr = 0;
uint32_t v = 0; uint32_t v = 0;
uint32_t i = 0; uint32_t i = 0;
struct amdgpu_ih_regs *ih_regs;
if (ih == &adev->irq.ih) ih_regs = &ih->ih_regs;
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;
/* Rearm IRQ / re-write doorbell if doorbell write is lost */ /* Rearm IRQ / re-write doorbell if doorbell write is lost */
for (i = 0; i < MAX_REARM_RETRY; i++) { 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)) if ((v < ih->ring_size) && (v != ih->rptr))
WDOORBELL32(ih->doorbell_index, ih->rptr); WDOORBELL32(ih->doorbell_index, ih->rptr);
else 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, static void navi10_ih_set_rptr(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) struct amdgpu_ih_ring *ih)
{ {
struct amdgpu_ih_regs *ih_regs;
if (ih->use_doorbell) { if (ih->use_doorbell) {
/* XXX check if swapping is necessary on BE */ /* XXX check if swapping is necessary on BE */
*ih->rptr_cpu = ih->rptr; *ih->rptr_cpu = ih->rptr;
@ -598,12 +469,9 @@ static void navi10_ih_set_rptr(struct amdgpu_device *adev,
if (amdgpu_sriov_vf(adev)) if (amdgpu_sriov_vf(adev))
navi10_ih_irq_rearm(adev, ih); navi10_ih_irq_rearm(adev, ih);
} else if (ih == &adev->irq.ih) { } else {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr); ih_regs = &ih->ih_regs;
} else if (ih == &adev->irq.ih1) { WREG32(ih_regs->ih_rb_rptr, ih->rptr);
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);
} }
} }
@ -685,23 +553,8 @@ static int navi10_ih_sw_init(void *handle)
adev->irq.ih1.ring_size = 0; adev->irq.ih1.ring_size = 0;
adev->irq.ih2.ring_size = 0; adev->irq.ih2.ring_size = 0;
if (adev->asic_type < CHIP_NAVI10) { /* initialize ih control registers offset */
r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true); navi10_ih_init_register_offset(adev);
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;
}
r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true); r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
if (r) if (r)
@ -717,6 +570,7 @@ static int navi10_ih_sw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_device *adev = (struct amdgpu_device *)handle;
amdgpu_irq_fini(adev); 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.ih2);
amdgpu_ih_ring_fini(adev, &adev->irq.ih1); amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
amdgpu_ih_ring_fini(adev, &adev->irq.ih); 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 = { static const struct amdgpu_ih_funcs navi10_ih_funcs = {
.get_wptr = navi10_ih_get_wptr, .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 .set_rptr = navi10_ih_set_rptr
}; };

View File

@ -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); 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) static u32 nbio_v2_3_get_memsize(struct amdgpu_device *adev)
{ {
return RREG32_SOC15(NBIO, 0, mmRCC_DEV0_EPF0_RCC_CONFIG_MEMSIZE); 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_pcie_data_offset = nbio_v2_3_get_pcie_data_offset,
.get_rev_id = nbio_v2_3_get_rev_id, .get_rev_id = nbio_v2_3_get_rev_id,
.mc_access_enable = nbio_v2_3_mc_access_enable, .mc_access_enable = nbio_v2_3_mc_access_enable,
.hdp_flush = nbio_v2_3_hdp_flush,
.get_memsize = nbio_v2_3_get_memsize, .get_memsize = nbio_v2_3_get_memsize,
.sdma_doorbell_range = nbio_v2_3_sdma_doorbell_range, .sdma_doorbell_range = nbio_v2_3_sdma_doorbell_range,
.vcn_doorbell_range = nbio_v2_3_vcn_doorbell_range, .vcn_doorbell_range = nbio_v2_3_vcn_doorbell_range,

View File

@ -29,6 +29,15 @@
#include "nbio/nbio_6_1_sh_mask.h" #include "nbio/nbio_6_1_sh_mask.h"
#include "nbio/nbio_6_1_smn.h" #include "nbio/nbio_6_1_smn.h"
#include "vega10_enum.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) 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); 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) static u32 nbio_v6_1_get_memsize(struct amdgpu_device *adev)
{ {
return RREG32_SOC15(NBIO, 0, mmRCC_PF_0_0_RCC_CONFIG_MEMSIZE); 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_pcie_data_offset = nbio_v6_1_get_pcie_data_offset,
.get_rev_id = nbio_v6_1_get_rev_id, .get_rev_id = nbio_v6_1_get_rev_id,
.mc_access_enable = nbio_v6_1_mc_access_enable, .mc_access_enable = nbio_v6_1_mc_access_enable,
.hdp_flush = nbio_v6_1_hdp_flush,
.get_memsize = nbio_v6_1_get_memsize, .get_memsize = nbio_v6_1_get_memsize,
.sdma_doorbell_range = nbio_v6_1_sdma_doorbell_range, .sdma_doorbell_range = nbio_v6_1_sdma_doorbell_range,
.enable_doorbell_aperture = nbio_v6_1_enable_doorbell_aperture, .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, .get_clockgating_state = nbio_v6_1_get_clockgating_state,
.ih_control = nbio_v6_1_ih_control, .ih_control = nbio_v6_1_ih_control,
.init_registers = nbio_v6_1_init_registers, .init_registers = nbio_v6_1_init_registers,
.remap_hdp_registers = nbio_v6_1_remap_hdp_registers,
}; };

View File

@ -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); 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) static u32 nbio_v7_0_get_memsize(struct amdgpu_device *adev)
{ {
return RREG32_SOC15(NBIO, 0, mmRCC_CONFIG_MEMSIZE); 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_pcie_data_offset = nbio_v7_0_get_pcie_data_offset,
.get_rev_id = nbio_v7_0_get_rev_id, .get_rev_id = nbio_v7_0_get_rev_id,
.mc_access_enable = nbio_v7_0_mc_access_enable, .mc_access_enable = nbio_v7_0_mc_access_enable,
.hdp_flush = nbio_v7_0_hdp_flush,
.get_memsize = nbio_v7_0_get_memsize, .get_memsize = nbio_v7_0_get_memsize,
.sdma_doorbell_range = nbio_v7_0_sdma_doorbell_range, .sdma_doorbell_range = nbio_v7_0_sdma_doorbell_range,
.vcn_doorbell_range = nbio_v7_0_vcn_doorbell_range, .vcn_doorbell_range = nbio_v7_0_vcn_doorbell_range,

View File

@ -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); 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) static u32 nbio_v7_2_get_memsize(struct amdgpu_device *adev)
{ {
return RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF0_0_RCC_CONFIG_MEMSIZE); 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_pcie_port_data_offset = nbio_v7_2_get_pcie_port_data_offset,
.get_rev_id = nbio_v7_2_get_rev_id, .get_rev_id = nbio_v7_2_get_rev_id,
.mc_access_enable = nbio_v7_2_mc_access_enable, .mc_access_enable = nbio_v7_2_mc_access_enable,
.hdp_flush = nbio_v7_2_hdp_flush,
.get_memsize = nbio_v7_2_get_memsize, .get_memsize = nbio_v7_2_get_memsize,
.sdma_doorbell_range = nbio_v7_2_sdma_doorbell_range, .sdma_doorbell_range = nbio_v7_2_sdma_doorbell_range,
.vcn_doorbell_range = nbio_v7_2_vcn_doorbell_range, .vcn_doorbell_range = nbio_v7_2_vcn_doorbell_range,

View File

@ -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); 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) static u32 nbio_v7_4_get_memsize(struct amdgpu_device *adev)
{ {
return RREG32_SOC15(NBIO, 0, mmRCC_CONFIG_MEMSIZE); 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_pcie_data_offset = nbio_v7_4_get_pcie_data_offset,
.get_rev_id = nbio_v7_4_get_rev_id, .get_rev_id = nbio_v7_4_get_rev_id,
.mc_access_enable = nbio_v7_4_mc_access_enable, .mc_access_enable = nbio_v7_4_mc_access_enable,
.hdp_flush = nbio_v7_4_hdp_flush,
.get_memsize = nbio_v7_4_get_memsize, .get_memsize = nbio_v7_4_get_memsize,
.sdma_doorbell_range = nbio_v7_4_sdma_doorbell_range, .sdma_doorbell_range = nbio_v7_4_sdma_doorbell_range,
.vcn_doorbell_range = nbio_v7_4_vcn_doorbell_range, .vcn_doorbell_range = nbio_v7_4_vcn_doorbell_range,

View File

@ -38,8 +38,6 @@
#include "gc/gc_10_1_0_offset.h" #include "gc/gc_10_1_0_offset.h"
#include "gc/gc_10_1_0_sh_mask.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 "smuio/smuio_11_0_0_offset.h"
#include "mp/mp_11_0_offset.h" #include "mp/mp_11_0_offset.h"
@ -50,6 +48,7 @@
#include "mmhub_v2_0.h" #include "mmhub_v2_0.h"
#include "nbio_v2_3.h" #include "nbio_v2_3.h"
#include "nbio_v7_2.h" #include "nbio_v7_2.h"
#include "hdp_v5_0.h"
#include "nv.h" #include "nv.h"
#include "navi10_ih.h" #include "navi10_ih.h"
#include "gfx_v10_0.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.funcs = &nbio_v2_3_funcs;
adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg; 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) if (adev->asic_type == CHIP_SIENNA_CICHLID)
adev->gmc.xgmi.supported = true; 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); 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) static bool nv_need_full_reset(struct amdgpu_device *adev)
{ {
return true; return true;
@ -788,8 +772,6 @@ static const struct amdgpu_asic_funcs nv_asic_funcs =
.set_uvd_clocks = &nv_set_uvd_clocks, .set_uvd_clocks = &nv_set_uvd_clocks,
.set_vce_clocks = &nv_set_vce_clocks, .set_vce_clocks = &nv_set_vce_clocks,
.get_config_memsize = &nv_get_config_memsize, .get_config_memsize = &nv_get_config_memsize,
.flush_hdp = &nv_flush_hdp,
.invalidate_hdp = &nv_invalidate_hdp,
.init_doorbell_index = &nv_init_doorbell_index, .init_doorbell_index = &nv_init_doorbell_index,
.need_full_reset = &nv_need_full_reset, .need_full_reset = &nv_need_full_reset,
.need_reset_on_init = &nv_need_reset_on_init, .need_reset_on_init = &nv_need_reset_on_init,
@ -1080,120 +1062,6 @@ static int nv_common_soft_reset(void *handle)
return 0; 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, static int nv_common_set_clockgating_state(void *handle,
enum amd_clockgating_state state) enum amd_clockgating_state state)
{ {
@ -1213,9 +1081,7 @@ static int nv_common_set_clockgating_state(void *handle,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
adev->nbio.funcs->update_medium_grain_light_sleep(adev, adev->nbio.funcs->update_medium_grain_light_sleep(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
nv_update_hdp_mem_power_gating(adev, adev->hdp.funcs->update_clock_gating(adev,
state == AMD_CG_STATE_GATE);
nv_update_hdp_clock_gating(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
break; break;
default: 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) static void nv_common_get_clockgating_state(void *handle, u32 *flags)
{ {
struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_device *adev = (struct amdgpu_device *)handle;
uint32_t tmp;
if (amdgpu_sriov_vf(adev)) if (amdgpu_sriov_vf(adev))
*flags = 0; *flags = 0;
adev->nbio.funcs->get_clockgating_state(adev, flags); adev->nbio.funcs->get_clockgating_state(adev, flags);
/* AMD_CG_SUPPORT_HDP_MGCG */ adev->hdp.funcs->get_clock_gating_state(adev, flags);
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;
return; return;
} }

View File

@ -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_DISABLE_INT = 0x00060000, /* disable PSP-to-Gfx interrupt */
GFX_CTRL_CMD_ID_MODE1_RST = 0x00070000, /* trigger the Mode 1 reset */ 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_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_DESTROY_GPCOM_RING = 0x000C0000, /* destroy GPCOM ring */
GFX_CTRL_CMD_ID_MAX = 0x000F0000, /* max command ID */ GFX_CTRL_CMD_ID_MAX = 0x000F0000, /* max command ID */

View File

@ -392,37 +392,6 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
return ret; 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, static int psp_v11_0_ring_init(struct psp_context *psp,
enum psp_ring_type ring_type) 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 psp_ring *ring;
struct amdgpu_device *adev = psp->adev; 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 = &psp->km_ring;
ring->ring_type = ring_type; 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); 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); vfree(buf);
} }

View File

@ -46,7 +46,6 @@
#include "sdma6/sdma6_4_2_2_sh_mask.h" #include "sdma6/sdma6_4_2_2_sh_mask.h"
#include "sdma7/sdma7_4_2_2_offset.h" #include "sdma7/sdma7_4_2_2_offset.h"
#include "sdma7/sdma7_4_2_2_sh_mask.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 "sdma0/sdma0_4_1_default.h"
#include "soc15_common.h" #include "soc15_common.h"

View File

@ -32,7 +32,6 @@
#include "gc/gc_10_1_0_offset.h" #include "gc/gc_10_1_0_offset.h"
#include "gc/gc_10_1_0_sh_mask.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/sdma0/irqsrcs_sdma0_5_0.h"
#include "ivsrcid/sdma1/irqsrcs_sdma1_5_0.h" #include "ivsrcid/sdma1/irqsrcs_sdma1_5_0.h"

View File

@ -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) static void sdma_v5_2_destroy_inst_ctx(struct amdgpu_device *adev)
{ {
int i; release_firmware(adev->sdma.instance[0].fw);
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;
}
memset((void *)adev->sdma.instance, 0, memset((void *)adev->sdma.instance, 0,
sizeof(struct amdgpu_sdma_instance) * AMDGPU_MAX_SDMA_INSTANCES); 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) if (err)
goto out; goto out;
for (i = 1; i < adev->sdma.num_instances; i++) { 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], memcpy((void *)&adev->sdma.instance[i],
(void *)&adev->sdma.instance[0], (void *)&adev->sdma.instance[0],
sizeof(struct amdgpu_sdma_instance)); 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;
}
}
DRM_DEBUG("psp_load == '%s'\n", DRM_DEBUG("psp_load == '%s'\n",
adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false"); adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false");

View File

@ -40,8 +40,6 @@
#include "gc/gc_9_0_sh_mask.h" #include "gc/gc_9_0_sh_mask.h"
#include "sdma0/sdma0_4_0_offset.h" #include "sdma0/sdma0_4_0_offset.h"
#include "sdma1/sdma1_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_default.h"
#include "nbio/nbio_7_0_offset.h" #include "nbio/nbio_7_0_offset.h"
#include "nbio/nbio_7_0_sh_mask.h" #include "nbio/nbio_7_0_sh_mask.h"
@ -59,7 +57,9 @@
#include "nbio_v6_1.h" #include "nbio_v6_1.h"
#include "nbio_v7_0.h" #include "nbio_v7_0.h"
#include "nbio_v7_4.h" #include "nbio_v7_4.h"
#include "hdp_v4_0.h"
#include "vega10_ih.h" #include "vega10_ih.h"
#include "vega20_ih.h"
#include "navi10_ih.h" #include "navi10_ih.h"
#include "sdma_v4_0.h" #include "sdma_v4_0.h"
#include "uvd_v7_0.h" #include "uvd_v7_0.h"
@ -83,14 +83,6 @@
#define mmMP0_MISC_LIGHT_SLEEP_CTRL 0x01ba #define mmMP0_MISC_LIGHT_SLEEP_CTRL 0x01ba
#define mmMP0_MISC_LIGHT_SLEEP_CTRL_BASE_IDX 0 #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 * 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.funcs = &nbio_v6_1_funcs;
adev->nbio.hdp_flush_reg = &nbio_v6_1_hdp_flush_reg; 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) if (adev->asic_type == CHIP_VEGA20 || adev->asic_type == CHIP_ARCTURUS)
adev->df.funcs = &df_v3_6_funcs; 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); amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block);
} }
if (adev->asic_type == CHIP_VEGA20) 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 else
amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
} else { } else {
if (adev->asic_type == CHIP_VEGA20) 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 else
amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) { 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 (amdgpu_sriov_vf(adev)) {
if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) 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, &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 { } 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)) 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, &psp_v11_0_ip_block);
} }
@ -834,35 +827,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
return 0; 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) static bool soc15_need_full_reset(struct amdgpu_device *adev)
{ {
/* change this when we implement soft reset */ /* change this when we implement soft reset */
return true; 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, static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
uint64_t *count1) uint64_t *count1)
{ {
@ -1011,8 +981,6 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs =
.set_uvd_clocks = &soc15_set_uvd_clocks, .set_uvd_clocks = &soc15_set_uvd_clocks,
.set_vce_clocks = &soc15_set_vce_clocks, .set_vce_clocks = &soc15_set_vce_clocks,
.get_config_memsize = &soc15_get_config_memsize, .get_config_memsize = &soc15_get_config_memsize,
.flush_hdp = &soc15_flush_hdp,
.invalidate_hdp = &soc15_invalidate_hdp,
.need_full_reset = &soc15_need_full_reset, .need_full_reset = &soc15_need_full_reset,
.init_doorbell_index = &vega10_doorbell_index_init, .init_doorbell_index = &vega10_doorbell_index_init,
.get_pcie_usage = &soc15_get_pcie_usage, .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_uvd_clocks = &soc15_set_uvd_clocks,
.set_vce_clocks = &soc15_set_vce_clocks, .set_vce_clocks = &soc15_set_vce_clocks,
.get_config_memsize = &soc15_get_config_memsize, .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, .need_full_reset = &soc15_need_full_reset,
.init_doorbell_index = &vega20_doorbell_index_init, .init_doorbell_index = &vega20_doorbell_index_init,
.get_pcie_usage = &vega20_get_pcie_usage, .get_pcie_usage = &vega20_get_pcie_usage,
@ -1293,9 +1258,8 @@ static int soc15_common_late_init(void *handle)
if (amdgpu_sriov_vf(adev)) if (amdgpu_sriov_vf(adev))
xgpu_ai_mailbox_get_irq(adev); xgpu_ai_mailbox_get_irq(adev);
if (adev->asic_funcs && if (adev->hdp.funcs->reset_ras_error_count)
adev->asic_funcs->reset_hdp_ras_error_count) adev->hdp.funcs->reset_ras_error_count(adev);
adev->asic_funcs->reset_hdp_ras_error_count(adev);
if (adev->nbio.funcs->ras_late_init) if (adev->nbio.funcs->ras_late_init)
r = adev->nbio.funcs->ras_late_init(adev); r = adev->nbio.funcs->ras_late_init(adev);
@ -1421,41 +1385,6 @@ static int soc15_common_soft_reset(void *handle)
return 0; 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) static void soc15_update_drm_clock_gating(struct amdgpu_device *adev, bool enable)
{ {
uint32_t def, data; uint32_t def, data;
@ -1516,7 +1445,7 @@ static int soc15_common_set_clockgating_state(void *handle,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
adev->nbio.funcs->update_medium_grain_light_sleep(adev, adev->nbio.funcs->update_medium_grain_light_sleep(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
soc15_update_hdp_light_sleep(adev, adev->hdp.funcs->update_clock_gating(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
soc15_update_drm_clock_gating(adev, soc15_update_drm_clock_gating(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
@ -1533,7 +1462,7 @@ static int soc15_common_set_clockgating_state(void *handle,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
adev->nbio.funcs->update_medium_grain_light_sleep(adev, adev->nbio.funcs->update_medium_grain_light_sleep(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
soc15_update_hdp_light_sleep(adev, adev->hdp.funcs->update_clock_gating(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
soc15_update_drm_clock_gating(adev, soc15_update_drm_clock_gating(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
@ -1541,7 +1470,7 @@ static int soc15_common_set_clockgating_state(void *handle,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
break; break;
case CHIP_ARCTURUS: case CHIP_ARCTURUS:
soc15_update_hdp_light_sleep(adev, adev->hdp.funcs->update_clock_gating(adev,
state == AMD_CG_STATE_GATE); state == AMD_CG_STATE_GATE);
break; break;
default: default:
@ -1560,10 +1489,7 @@ static void soc15_common_get_clockgating_state(void *handle, u32 *flags)
adev->nbio.funcs->get_clockgating_state(adev, flags); adev->nbio.funcs->get_clockgating_state(adev, flags);
/* AMD_CG_SUPPORT_HDP_LS */ adev->hdp.funcs->get_clock_gating_state(adev, flags);
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;
/* AMD_CG_SUPPORT_DRM_MGCG */ /* AMD_CG_SUPPORT_DRM_MGCG */
data = RREG32(SOC15_REG_OFFSET(MP0, 0, mmMP0_MISC_CGTT_CTRL0)); data = RREG32(SOC15_REG_OFFSET(MP0, 0, mmMP0_MISC_CGTT_CTRL0));

View File

@ -196,19 +196,30 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev,
wptr = le32_to_cpu(*ih->wptr_cpu); wptr = le32_to_cpu(*ih->wptr_cpu);
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) { 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); wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
* this should allow us to catchup. * this should allow us to catchup.
*/ */
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
wptr, ih->rptr, (wptr + 16) & ih->ptr_mask); wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
ih->rptr = (wptr + 16) & ih->ptr_mask; ih->rptr = (wptr + 16) & ih->ptr_mask;
tmp = RREG32(mmIH_RB_CNTL); tmp = RREG32(mmIH_RB_CNTL);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32(mmIH_RB_CNTL, tmp); WREG32(mmIH_RB_CNTL, tmp);
}
out:
return (wptr & ih->ptr_mask); return (wptr & ih->ptr_mask);
} }

View File

@ -36,7 +36,6 @@
#include "vce/vce_4_0_default.h" #include "vce/vce_4_0_default.h"
#include "vce/vce_4_0_sh_mask.h" #include "vce/vce_4_0_sh_mask.h"
#include "nbif/nbif_6_1_offset.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_offset.h"
#include "mmhub/mmhub_1_0_sh_mask.h" #include "mmhub/mmhub_1_0_sh_mask.h"
#include "ivsrcid/uvd/irqsrcs_uvd_7_0.h" #include "ivsrcid/uvd/irqsrcs_uvd_7_0.h"

View File

@ -32,7 +32,6 @@
#include "vcn/vcn_1_0_offset.h" #include "vcn/vcn_1_0_offset.h"
#include "vcn/vcn_1_0_sh_mask.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_offset.h"
#include "mmhub/mmhub_9_1_sh_mask.h" #include "mmhub/mmhub_9_1_sh_mask.h"

View File

@ -38,134 +38,122 @@
static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev); 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 * @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); if (adev->irq.ih.ring_size) {
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1); ih_regs = &adev->irq.ih.ih_regs;
if (amdgpu_sriov_vf(adev)) { ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE);
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI);
DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
return; 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;
} }
} else {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
}
adev->irq.ih.enabled = true;
if (adev->irq.ih1.ring_size) { if (adev->irq.ih1.ring_size) {
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1); ih_regs = &adev->irq.ih1.ih_regs;
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1, ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING1);
RB_ENABLE, 1); ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING1);
if (amdgpu_sriov_vf(adev)) { ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING1, ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
ih_rb_cntl)) { ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
DRM_ERROR("program IH_RB_CNTL_RING1 failed!\n"); ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1);
return; ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING1;
}
} else {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
}
adev->irq.ih1.enabled = true;
} }
if (adev->irq.ih2.ring_size) { if (adev->irq.ih2.ring_size) {
ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2); ih_regs = &adev->irq.ih2.ih_regs;
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2, ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING2);
RB_ENABLE, 1); ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING2);
if (amdgpu_sriov_vf(adev)) { ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL_RING2, ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
ih_rb_cntl)) { ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
DRM_ERROR("program IH_RB_CNTL_RING2 failed!\n"); ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2);
return; ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING2;
} }
} 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;
} }
/** /**
* vega10_ih_disable_interrupts - Disable the interrupt ring buffer * vega10_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
* *
* @adev: amdgpu_device pointer * @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_regs = &ih->ih_regs;
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0);
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 (amdgpu_sriov_vf(adev)) {
if (psp_reg_program(&adev->psp, PSP_REG_IH_RB_CNTL, ih_rb_cntl)) { if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
DRM_ERROR("PSP program IH_RB_CNTL failed!\n"); dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
return; return -ETIMEDOUT;
} }
} else { } else {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); WREG32(ih_regs->ih_rb_cntl, tmp);
} }
/* set rptr, wptr to 0 */ if (enable) {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0); ih->enabled = true;
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 { } else {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
}
/* set rptr, wptr to 0 */ /* set rptr, wptr to 0 */
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0); WREG32(ih_regs->ih_rb_rptr, 0);
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0); WREG32(ih_regs->ih_rb_wptr, 0);
adev->irq.ih1.enabled = false; ih->enabled = false;
adev->irq.ih1.rptr = 0; ih->rptr = 0;
} }
if (adev->irq.ih2.ring_size) { return 0;
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);
} }
/* set rptr, wptr to 0 */ /**
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0); * vega10_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0); *
adev->irq.ih2.enabled = false; * @adev: amdgpu_device pointer
adev->irq.ih2.rptr = 0; * @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;
} }
} }
return 0;
}
static uint32_t vega10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl) static uint32_t vega10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
{ {
int rb_bufsz = order_base_2(ih->ring_size / 4); int rb_bufsz = order_base_2(ih->ring_size / 4);
@ -208,6 +196,58 @@ static uint32_t vega10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
return ih_doorbell_rtpr; 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 * 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) static int vega10_ih_irq_init(struct amdgpu_device *adev)
{ {
struct amdgpu_ih_ring *ih; struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
u32 ih_rb_cntl, ih_chicken; u32 ih_chicken;
int ret = 0; int ret;
int i;
u32 tmp; u32 tmp;
/* disable irqs */ /* disable irqs */
vega10_ih_disable_interrupts(adev); ret = vega10_ih_toggle_interrupts(adev, false);
if (ret)
return ret;
adev->nbio.funcs->ih_control(adev); adev->nbio.funcs->ih_control(adev);
ih = &adev->irq.ih; if (adev->asic_type == CHIP_RENOIR) {
/* 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) {
ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN); ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN);
if (adev->irq.ih.use_bus_addr) { if (adev->irq.ih.use_bus_addr) {
ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN, ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
MC_SPACE_GPA_ENABLE, 1); 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); WREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN, ih_chicken);
} }
/* set the writeback address whether it's enabled or not */ for (i = 0; i < ARRAY_SIZE(ih); i++) {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO, if (ih[i]->ring_size) {
lower_32_bits(ih->wptr_addr)); ret = vega10_ih_enable_ring(adev, ih[i]);
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, if (ret)
upper_32_bits(ih->wptr_addr) & 0xFFFF); return ret;
/* 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);
}
/* 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); 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); pci_set_master(adev->pdev);
/* enable interrupts */ /* 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) 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 */ /* Wait and acknowledge irq */
mdelay(1); 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, static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) 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); wptr = le32_to_cpu(*ih->wptr_cpu);
ih_regs = &ih->ih_regs;
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
goto out; goto out;
/* Double check that the overflow wasn't already cleared. */ /* Double check that the overflow wasn't already cleared. */
wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
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);
if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
goto out; goto out;
@ -413,68 +368,14 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
wptr, ih->rptr, tmp); wptr, ih->rptr, tmp);
ih->rptr = tmp; ih->rptr = tmp;
if (ih == &adev->irq.ih) tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
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 = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); 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: out:
return (wptr & ih->ptr_mask); 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 * 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, static void vega10_ih_irq_rearm(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) struct amdgpu_ih_ring *ih)
{ {
uint32_t reg_rptr = 0;
uint32_t v = 0; uint32_t v = 0;
uint32_t i = 0; uint32_t i = 0;
struct amdgpu_ih_regs *ih_regs;
if (ih == &adev->irq.ih) ih_regs = &ih->ih_regs;
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;
/* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */ /* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
for (i = 0; i < MAX_REARM_RETRY; i++) { 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)) if ((v < ih->ring_size) && (v != ih->rptr))
WDOORBELL32(ih->doorbell_index, ih->rptr); WDOORBELL32(ih->doorbell_index, ih->rptr);
else 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, static void vega10_ih_set_rptr(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih) struct amdgpu_ih_ring *ih)
{ {
struct amdgpu_ih_regs *ih_regs;
if (ih->use_doorbell) { if (ih->use_doorbell) {
/* XXX check if swapping is necessary on BE */ /* XXX check if swapping is necessary on BE */
*ih->rptr_cpu = ih->rptr; *ih->rptr_cpu = ih->rptr;
@ -526,12 +421,9 @@ static void vega10_ih_set_rptr(struct amdgpu_device *adev,
if (amdgpu_sriov_vf(adev)) if (amdgpu_sriov_vf(adev))
vega10_ih_irq_rearm(adev, ih); vega10_ih_irq_rearm(adev, ih);
} else if (ih == &adev->irq.ih) { } else {
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr); ih_regs = &ih->ih_regs;
} else if (ih == &adev->irq.ih1) { WREG32(ih_regs->ih_rb_rptr, ih->rptr);
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);
} }
} }
@ -600,6 +492,7 @@ static int vega10_ih_sw_init(void *handle)
adev->irq.ih.use_doorbell = true; adev->irq.ih.use_doorbell = true;
adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1; adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
if (!(adev->flags & AMD_IS_APU)) {
r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true); r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
if (r) if (r)
return r; return r;
@ -613,6 +506,9 @@ static int vega10_ih_sw_init(void *handle)
adev->irq.ih2.use_doorbell = true; adev->irq.ih2.use_doorbell = true;
adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1; 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); r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
if (r) if (r)
@ -628,6 +524,7 @@ static int vega10_ih_sw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_device *adev = (struct amdgpu_device *)handle;
amdgpu_irq_fini(adev); 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.ih2);
amdgpu_ih_ring_fini(adev, &adev->irq.ih1); amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
amdgpu_ih_ring_fini(adev, &adev->irq.ih); 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); def = data = RREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL);
field_val = enable ? 0 : 1; field_val = enable ? 0 : 1;
/** /**
* Vega10 does not have IH_RETRY_INT_CAM_MEM_CLK_SOFT_OVERRIDE * Vega10/12 and RAVEN don't have IH_BUFFER_MEM_CLK_SOFT_OVERRIDE field.
* and IH_BUFFER_MEM_CLK_SOFT_OVERRIDE field.
*/ */
if (adev->asic_type > CHIP_VEGA10) { if (adev->asic_type == CHIP_RENOIR)
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, data = REG_SET_FIELD(data, IH_CLK_CTRL,
IH_BUFFER_MEM_CLK_SOFT_OVERRIDE, field_val); IH_BUFFER_MEM_CLK_SOFT_OVERRIDE, field_val);
}
data = REG_SET_FIELD(data, IH_CLK_CTRL, data = REG_SET_FIELD(data, IH_CLK_CTRL,
DBUS_MUX_CLK_SOFT_OVERRIDE, field_val); 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 = { static const struct amdgpu_ih_funcs vega10_ih_funcs = {
.get_wptr = vega10_ih_get_wptr, .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 .set_rptr = vega10_ih_set_rptr
}; };

View 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,
};

View 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

View File

@ -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); client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
pasid = SOC15_PASID_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 /* 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 * in the interrupt payload, so we need to find out the pasid on our
* own. * own.
@ -96,15 +115,28 @@ static void event_interrupt_wq_v9(struct kfd_dev *dev,
vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry); vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry);
context_id = SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry); context_id = SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry);
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) if (source_id == SOC15_INTSRC_CP_END_OF_PIPE)
kfd_signal_event_interrupt(pasid, context_id, 32); 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) else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG)
kfd_signal_event_interrupt(pasid, context_id & 0xffffff, 24); kfd_signal_event_interrupt(pasid, context_id & 0xffffff, 24);
else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE) else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE)
kfd_signal_hw_exception_event(pasid); kfd_signal_hw_exception_event(pasid);
else if (client_id == SOC15_IH_CLIENTID_VMC || } 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_VMC1 ||
client_id == SOC15_IH_CLIENTID_UTCL2) { client_id == SOC15_IH_CLIENTID_UTCL2) {
struct kfd_vm_fault_info info = {0}; struct kfd_vm_fault_info info = {0};

View File

@ -6,7 +6,7 @@ config DRM_AMD_DC
bool "AMD DC - Enable new display engine" bool "AMD DC - Enable new display engine"
default y default y
select SND_HDA_COMPONENT if SND_HDA_CORE 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 help
Choose this option if you want to use the new display engine Choose this option if you want to use the new display engine
support for AMDGPU. This adds required support for Vega and support for AMDGPU. This adds required support for Vega and

View File

@ -60,7 +60,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pci.h> #include <linux/pci.h>
@ -2386,8 +2385,7 @@ void amdgpu_dm_update_connector_after_detect(
drm_connector_update_edid_property(connector, drm_connector_update_edid_property(connector,
aconnector->edid); aconnector->edid);
aconnector->num_modes = drm_add_edid_modes(connector, aconnector->edid); drm_add_edid_modes(connector, aconnector->edid);
drm_connector_list_update(connector);
if (aconnector->dc_link->aux_mode) if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, 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, static int fill_dc_scaling_info(const struct drm_plane_state *state,
struct dc_scaling_info *scaling_info) 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)); 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. */ /* DRM doesn't specify clipping on destination output. */
scaling_info->clip_rect = scaling_info->dst_rect; 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 / scale_w = scaling_info->dst_rect.width * 1000 /
scaling_info->src_rect.width; scaling_info->src_rect.width;
if (scale_w < 250 || scale_w > 16000) if (scale_w < min_downscale || scale_w > max_upscale)
return -EINVAL; return -EINVAL;
scale_h = scaling_info->dst_rect.height * 1000 / scale_h = scaling_info->dst_rect.height * 1000 /
scaling_info->src_rect.height; scaling_info->src_rect.height;
if (scale_h < 250 || scale_h > 16000) if (scale_h < min_downscale || scale_h > max_upscale)
return -EINVAL; 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_crtc *acrtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
struct amdgpu_display_manager *dm = &adev->dm;
int rc = 0; int rc = 0;
if (enable) { if (enable) {
@ -5429,7 +5479,27 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
return rc; return rc;
irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; 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) 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, static int dm_plane_helper_check_state(struct drm_plane_state *state,
struct drm_crtc_state *new_crtc_state) struct drm_crtc_state *new_crtc_state)
{ {
int max_downscale = 0; struct drm_framebuffer *fb = state->fb;
int max_upscale = INT_MAX; 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( 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, 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; acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
manage_dm_interrupts(adev, acrtc, true); manage_dm_interrupts(adev, acrtc, true);
} }
#ifdef CONFIG_DEBUG_FS if (IS_ENABLED(CONFIG_DEBUG_FS) && new_crtc_state->active &&
if (new_crtc_state->active &&
amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) { amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) {
/** /**
* Frontend may have changed so reapply the CRC capture * 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( amdgpu_dm_crtc_configure_crc_source(
crtc, dm_new_crtc_state, dm_new_crtc_state->crc_src); crtc, dm_new_crtc_state, dm_new_crtc_state->crc_src);
} }
#endif
} }
for_each_new_crtc_in_state(state, crtc, new_crtc_state, j) for_each_new_crtc_in_state(state, crtc, new_crtc_state, j)

View File

@ -336,6 +336,13 @@ struct amdgpu_display_manager {
*/ */
const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; 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 #ifdef CONFIG_DEBUG_FS
/** /**
* @crc_win_x_start_property: * @crc_win_x_start_property:

View File

@ -46,13 +46,13 @@ static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source
} }
/* amdgpu_dm_crc.c */ /* 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_is_default(struct dm_crtc_state *dm_crtc_state);
bool amdgpu_dm_crc_window_changed(struct dm_crtc_state *dm_new_crtc_state, bool amdgpu_dm_crc_window_changed(struct dm_crtc_state *dm_new_crtc_state,
struct dm_crtc_state *dm_old_crtc_state); struct dm_crtc_state *dm_old_crtc_state);
int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
struct dm_crtc_state *dm_crtc_state, struct dm_crtc_state *dm_crtc_state,
enum amdgpu_dm_pipe_crc_source source); 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_set_crc_source(struct drm_crtc *crtc, const char *src_name);
int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc,
const char *src_name, const char *src_name,

View File

@ -25,7 +25,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/version.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>

View File

@ -23,7 +23,6 @@
* *
*/ */
#include <linux/version.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_mst_helper.h> #include <drm/drm_dp_mst_helper.h>

View File

@ -33,10 +33,6 @@ ifdef CONFIG_PPC64
calcs_ccflags := -mhard-float -maltivec calcs_ccflags := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
calcs_rcflags := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -104,13 +104,6 @@ ifdef CONFIG_PPC64
CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := $(call cc-option,-mno-gnu-attribute) CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
endif 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_DAL_CLK_MGR_DCN21 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn21/,$(CLK_MGR_DCN21))
AMD_DISPLAY_FILES += $(AMD_DAL_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) CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn30/dcn30_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
endif 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_DAL_CLK_MGR_DCN30 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn30/,$(CLK_MGR_DCN30))
AMD_DISPLAY_FILES += $(AMD_DAL_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) CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn301/vg_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
endif 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_DAL_CLK_MGR_DCN301 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn301/,$(CLK_MGR_DCN301))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN301) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN301)

View File

@ -964,19 +964,15 @@ struct dc *dc_create(const struct dc_init_data *init_params)
struct dc *dc = kzalloc(sizeof(*dc), GFP_KERNEL); struct dc *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
unsigned int full_pipe_count; unsigned int full_pipe_count;
if (NULL == dc) if (!dc)
goto alloc_fail; return NULL;
if (init_params->dce_environment == DCE_ENV_VIRTUAL_HW) { if (init_params->dce_environment == DCE_ENV_VIRTUAL_HW) {
if (false == dc_construct_ctx(dc, init_params)) { if (!dc_construct_ctx(dc, init_params))
dc_destruct(dc); goto destruct_dc;
goto construct_fail;
}
} else { } else {
if (false == dc_construct(dc, init_params)) { if (!dc_construct(dc, init_params))
dc_destruct(dc); goto destruct_dc;
goto construct_fail;
}
full_pipe_count = dc->res_pool->pipe_count; full_pipe_count = dc->res_pool->pipe_count;
if (dc->res_pool->underlay_pipe_index != NO_UNDERLAY_PIPE) 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; return dc;
construct_fail: destruct_dc:
dc_destruct(dc);
kfree(dc); kfree(dc);
alloc_fail:
return NULL; return NULL;
} }
@ -1493,7 +1488,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context)
enum dc_status result = DC_ERROR_UNEXPECTED; enum dc_status result = DC_ERROR_UNEXPECTED;
int i; int i;
if (false == context_changed(dc, context)) if (!context_changed(dc, context))
return DC_OK; return DC_OK;
DC_LOG_DC("%s: %d streams\n", DC_LOG_DC("%s: %d streams\n",
@ -1540,7 +1535,7 @@ bool dc_acquire_release_mpc_3dlut(
if (found_pipe_idx) { if (found_pipe_idx) {
if (acquire && pool->funcs->acquire_post_bldn_3dlut) if (acquire && pool->funcs->acquire_post_bldn_3dlut)
ret = pool->funcs->acquire_post_bldn_3dlut(res_ctx, pool, mpcc_id, lut, shaper); 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); 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]); 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, bool dc_is_plane_eligible_for_idle_optimizaitons(struct dc *dc, struct dc_plane_state *plane)
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; return false;
} }

View File

@ -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) static struct abm *get_abm_from_stream_res(const struct dc_link *link)
{ {
int i; int i;
struct dc *dc = link->ctx->dc; struct dc *dc = NULL;
struct abm *abm = NULL; struct abm *abm = NULL;
if (!link || !link->ctx)
return NULL;
dc = link->ctx->dc;
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i]; struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
struct dc_stream_state *stream = pipe_ctx.stream; struct dc_stream_state *stream = pipe_ctx.stream;

View File

@ -171,6 +171,9 @@ struct dc_caps {
bool dmcub_support; bool dmcub_support;
uint32_t num_of_internal_disp; uint32_t num_of_internal_disp;
enum dp_protocol_version max_dp_protocol_version; 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_plane_cap planes[MAX_PLANES];
struct dc_color_caps color; struct dc_color_caps color;
}; };
@ -499,6 +502,7 @@ struct dc_debug_options {
bool dmcub_emulation; bool dmcub_emulation;
#if defined(CONFIG_DRM_AMD_DC_DCN) #if defined(CONFIG_DRM_AMD_DC_DCN)
bool disable_idle_power_optimizations; bool disable_idle_power_optimizations;
unsigned int mall_size_override;
#endif #endif
bool dmub_command_table; /* for testing only */ bool dmub_command_table; /* for testing only */
struct dc_bw_validation_profile bw_val_profile; struct dc_bw_validation_profile bw_val_profile;

View File

@ -71,6 +71,7 @@ struct dc_plane_address {
union { union {
struct{ struct{
PHYSICAL_ADDRESS_LOC addr; PHYSICAL_ADDRESS_LOC addr;
PHYSICAL_ADDRESS_LOC cursor_cache_addr;
PHYSICAL_ADDRESS_LOC meta_addr; PHYSICAL_ADDRESS_LOC meta_addr;
union large_integer dcc_const_color; union large_integer dcc_const_color;
} grph; } grph;

View File

@ -385,7 +385,7 @@ static const struct dc_plane_cap plane_cap = {
.pixel_format_support = { .pixel_format_support = {
.argb8888 = true, .argb8888 = true,
.nv12 = false, .nv12 = false,
.fp16 = false .fp16 = true
}, },
.max_upscale_factor = { .max_upscale_factor = {

View File

@ -410,7 +410,7 @@ static const struct dc_plane_cap plane_cap = {
.pixel_format_support = { .pixel_format_support = {
.argb8888 = true, .argb8888 = true,
.nv12 = false, .nv12 = false,
.fp16 = false .fp16 = true
}, },
.max_upscale_factor = { .max_upscale_factor = {

View File

@ -402,7 +402,7 @@ static const struct dc_plane_cap plane_cap = {
.pixel_format_support = { .pixel_format_support = {
.argb8888 = true, .argb8888 = true,
.nv12 = false, .nv12 = false,
.fp16 = false .fp16 = true
}, },
.max_upscale_factor = { .max_upscale_factor = {

View File

@ -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)) 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) AMD_DISPLAY_FILES += $(AMD_DAL_DCN10)

View File

@ -1534,15 +1534,8 @@ static bool dcn10_resource_construct(
memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults));
memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_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 */ /* Other architectures we build for build this with soft-float */
dcn10_resource_construct_fp(dc); dcn10_resource_construct_fp(dc);
#endif
pool->base.pp_smu = dcn10_pp_smu_create(ctx); pool->base.pp_smu = dcn10_pp_smu_create(ctx);

View File

@ -17,10 +17,6 @@ ifdef CONFIG_PPC64
CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -maltivec CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -13,10 +13,6 @@ ifdef CONFIG_PPC64
CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -maltivec CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -41,11 +41,6 @@ CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mhard-float -maltivec
CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -maltivec CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -maltivec
endif 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 ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -814,6 +814,19 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
return true; 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) void dcn30_hardware_release(struct dc *dc)
{ {
/* if pstate unsupported, force it supported */ /* if pstate unsupported, force it supported */

View File

@ -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_update_info_frame(struct pipe_ctx *pipe_ctx);
void dcn30_program_dmdata_engine(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); bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable);
void dcn30_hardware_release(struct dc *dc); void dcn30_hardware_release(struct dc *dc);

View File

@ -91,6 +91,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position, .calc_vupdate_position = dcn10_calc_vupdate_position,
.apply_idle_power_optimizations = dcn30_apply_idle_power_optimizations, .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_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.hardware_release = dcn30_hardware_release, .hardware_release = dcn30_hardware_release,

View File

@ -2631,6 +2631,10 @@ static bool dcn30_resource_construct(
dc->caps.max_cursor_size = 256; dc->caps.max_cursor_size = 256;
dc->caps.min_horizontal_blanking_period = 80; dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048; 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.max_slave_planes = 1;
dc->caps.post_blend_color_processing = true; dc->caps.post_blend_color_processing = true;

View File

@ -21,10 +21,6 @@ ifdef CONFIG_PPC64
CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mhard-float -maltivec CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -20,10 +20,6 @@ ifdef CONFIG_PPC64
CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mhard-float -maltivec CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -53,6 +53,7 @@
#include "dce/dce_i2c_hw.h" #include "dce/dce_i2c_hw.h"
#include "dce/dce_panel_cntl.h" #include "dce/dce_panel_cntl.h"
#include "dce/dmub_abm.h" #include "dce/dmub_abm.h"
#include "dce/dmub_psr.h"
#include "hw_sequencer_private.h" #include "hw_sequencer_private.h"
#include "reg_helper.h" #include "reg_helper.h"
@ -238,6 +239,7 @@ static const struct dc_debug_options debug_defaults_diags = {
.dwb_fi_phase = -1, // -1 = disable .dwb_fi_phase = -1, // -1 = disable
.dmub_command_table = true, .dmub_command_table = true,
.enable_tri_buf = true, .enable_tri_buf = true,
.disable_psr = true,
}; };
enum dcn302_clk_src_array_id { 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]); dce_abm_destroy(&pool->multiple_abms[i]);
} }
if (pool->psr != NULL)
dmub_psr_destroy(&pool->psr);
if (pool->dccg != NULL) if (pool->dccg != NULL)
dcn_dccg_destroy(&pool->dccg); dcn_dccg_destroy(&pool->dccg);
} }
@ -1354,8 +1359,6 @@ static bool dcn302_resource_construct(
if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
dc->debug = debug_defaults_drv; dc->debug = debug_defaults_drv;
else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)
dc->debug = debug_defaults_diags;
else else
dc->debug = debug_defaults_diags; dc->debug = debug_defaults_diags;
@ -1469,6 +1472,14 @@ static bool dcn302_resource_construct(
} }
pool->timing_generator_count = i; 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 */ /* ABMs */
for (i = 0; i < pool->res_cap->num_timing_generator; i++) { 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); pool->multiple_abms[i] = dmub_abm_create(ctx, &abm_regs[i], &abm_shift, &abm_mask);

View File

@ -33,10 +33,6 @@ ifdef CONFIG_PPC64
dml_ccflags := -mhard-float -maltivec dml_ccflags := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
dml_rcflags := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -10,10 +10,6 @@ ifdef CONFIG_PPC64
dsc_ccflags := -mhard-float -maltivec dsc_ccflags := -mhard-float -maltivec
endif endif
ifdef CONFIG_ARM64
dsc_rcflags := -mgeneral-regs-only
endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
ifeq ($(call cc-ifversion, -lt, 0701, y), y) ifeq ($(call cc-ifversion, -lt, 0701, y), y)
IS_OLD_GCC = 1 IS_OLD_GCC = 1

View File

@ -217,6 +217,8 @@ struct hw_sequencer_funcs {
/* Idle Optimization Related */ /* Idle Optimization Related */
bool (*apply_idle_power_optimizations)(struct dc *dc, bool enable); 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, bool (*is_abm_supported)(struct dc *dc,
struct dc_state *context, struct dc_stream_state *stream); struct dc_state *context, struct dc_stream_state *stream);

View File

@ -55,10 +55,6 @@
#include <asm/fpu/api.h> #include <asm/fpu/api.h>
#define DC_FP_START() kernel_fpu_begin() #define DC_FP_START() kernel_fpu_begin()
#define DC_FP_END() kernel_fpu_end() #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) #elif defined(CONFIG_PPC64)
#include <asm/switch_to.h> #include <asm/switch_to.h>
#include <asm/cputable.h> #include <asm/cputable.h>

View 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

File diff suppressed because it is too large Load Diff

View File

@ -157,7 +157,8 @@ enum PP_OD_DPM_TABLE_COMMAND {
PP_OD_EDIT_MCLK_VDDC_TABLE, PP_OD_EDIT_MCLK_VDDC_TABLE,
PP_OD_EDIT_VDDC_CURVE, PP_OD_EDIT_VDDC_CURVE,
PP_OD_RESTORE_DEFAULT_TABLE, PP_OD_RESTORE_DEFAULT_TABLE,
PP_OD_COMMIT_DPM_TABLE PP_OD_COMMIT_DPM_TABLE,
PP_OD_EDIT_VDDGFX_OFFSET
}; };
struct pp_states_info { struct pp_states_info {

View File

@ -730,11 +730,18 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
* *
* - minimum and maximum engine clock labeled OD_SCLK * - 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. * - three <frequency, voltage> points labeled OD_VDDC_CURVE.
* They can be used to calibrate the sclk voltage 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 * - a list of valid ranges for sclk, mclk, and voltage curve points
* labeled OD_RANGE * 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 * 600mV. "vc 2 1000 1000" will update point3 with clock set
* as 1000Mhz and voltage 1000mV. * 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) * - When you have edited all of the states as needed, write "c" (commit)
* to the file to commit your changes * 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; type = PP_OD_COMMIT_DPM_TABLE;
else if (!strncmp(buf, "vc", 2)) else if (!strncmp(buf, "vc", 2))
type = PP_OD_EDIT_VDDC_CURVE; type = PP_OD_EDIT_VDDC_CURVE;
else if (!strncmp(buf, "vo", 2))
type = PP_OD_EDIT_VDDGFX_OFFSET;
else else
return -EINVAL; return -EINVAL;
@ -802,7 +816,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
tmp_str = buf_cpy; 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++; tmp_str++;
while (isspace(*++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_SCLK, buf);
size += smu_print_clk_levels(&adev->smu, SMU_OD_MCLK, buf+size); 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_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); size += smu_print_clk_levels(&adev->smu, SMU_OD_RANGE, buf+size);
} else if (adev->powerplay.pp_funcs->print_clock_levels) { } else if (adev->powerplay.pp_funcs->print_clock_levels) {
size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf); 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; 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, static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) 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_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_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_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_dcefclk, ATTR_FLAG_BASIC),
AMDGPU_DEVICE_ATTR_RW(pp_dpm_pcie, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RW(pp_dpm_pcie, ATTR_FLAG_BASIC),
AMDGPU_DEVICE_ATTR_RW(pp_sclk_od, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RW(pp_sclk_od, ATTR_FLAG_BASIC),
@ -2067,6 +2217,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
} else if (DEVICE_ATTR_IS(pp_od_clk_voltage)) { } else if (DEVICE_ATTR_IS(pp_od_clk_voltage)) {
*states = ATTR_STATE_UNSUPPORTED; *states = ATTR_STATE_UNSUPPORTED;
if ((is_support_sw_smu(adev) && adev->smu.od_enabled) || if ((is_support_sw_smu(adev) && adev->smu.od_enabled) ||
(is_support_sw_smu(adev) && adev->smu.fine_grain_enabled) ||
(!is_support_sw_smu(adev) && hwmgr->od_enabled)) (!is_support_sw_smu(adev) && hwmgr->od_enabled))
*states = ATTR_STATE_SUPPORTED; *states = ATTR_STATE_SUPPORTED;
} else if (DEVICE_ATTR_IS(mem_busy_percent)) { } else if (DEVICE_ATTR_IS(mem_busy_percent)) {
@ -2087,6 +2238,12 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
} else if (DEVICE_ATTR_IS(gpu_metrics)) { } else if (DEVICE_ATTR_IS(gpu_metrics)) {
if (asic_type < CHIP_VEGA12) if (asic_type < CHIP_VEGA12)
*states = ATTR_STATE_UNSUPPORTED; *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) { if (asic_type == CHIP_ARCTURUS) {

View File

@ -465,124 +465,653 @@ struct smu_context
uint32_t gfx_default_soft_max_freq; uint32_t gfx_default_soft_max_freq;
uint32_t gfx_actual_hard_min_freq; uint32_t gfx_actual_hard_min_freq;
uint32_t gfx_actual_soft_max_freq; uint32_t gfx_actual_soft_max_freq;
bool fine_grain_enabled;
bool fine_grain_started;
}; };
struct i2c_adapter; struct i2c_adapter;
/**
* struct pptable_funcs - Callbacks used to interact with the SMU.
*/
struct pptable_funcs { 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); 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); 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); 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_default_dpm_table)(struct smu_context *smu);
int (*set_power_state)(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); 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); 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); 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, int (*od_edit_dpm_table)(struct smu_context *smu,
enum PP_OD_DPM_TABLE_COMMAND type, enum PP_OD_DPM_TABLE_COMMAND type,
long *input, uint32_t size); 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, int (*get_clock_by_type_with_latency)(struct smu_context *smu,
enum smu_clk_type clk_type, enum smu_clk_type clk_type,
struct struct
pp_clock_levels_with_latency pp_clock_levels_with_latency
*clocks); *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); 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); 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); 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); 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, int (*read_sensor)(struct smu_context *smu, enum amd_pp_sensors sensor,
void *data, uint32_t *size); 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); 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 (*display_config_changed)(struct smu_context *smu);
int (*apply_clocks_adjust_rules)(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); 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); 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); 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, int (*set_watermarks_table)(struct smu_context *smu,
struct pp_smu_wm_range_sets *clock_ranges); 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); 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); 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); 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); 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); 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); void (*dump_pptable)(struct smu_context *smu);
/**
* @get_power_limit: Get the device's power limits.
*/
int (*get_power_limit)(struct smu_context *smu); 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); 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); 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); 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); 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); 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); 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); 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); int (*init_microcode)(struct smu_context *smu);
/**
* @load_microcode: Load firmware onto the SMU.
*/
int (*load_microcode)(struct smu_context *smu); int (*load_microcode)(struct smu_context *smu);
/**
* @fini_microcode: Release the SMU's firmware.
*/
void (*fini_microcode)(struct smu_context *smu); void (*fini_microcode)(struct smu_context *smu);
/**
* @init_smc_tables: Initialize the SMU tables.
*/
int (*init_smc_tables)(struct smu_context *smu); int (*init_smc_tables)(struct smu_context *smu);
/**
* @fini_smc_tables: Release the SMU tables.
*/
int (*fini_smc_tables)(struct smu_context *smu); int (*fini_smc_tables)(struct smu_context *smu);
/**
* @init_power: Initialize the power gate table context.
*/
int (*init_power)(struct smu_context *smu); int (*init_power)(struct smu_context *smu);
/**
* @fini_power: Release the power gate table context.
*/
int (*fini_power)(struct smu_context *smu); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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.
* &param: Message parameter.
* &read_arg: SMU response (optional).
*/
int (*send_smc_msg_with_param)(struct smu_context *smu, int (*send_smc_msg_with_param)(struct smu_context *smu,
enum smu_message_type msg, uint32_t param, uint32_t *read_arg); 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, int (*send_smc_msg)(struct smu_context *smu,
enum smu_message_type msg, enum smu_message_type msg,
uint32_t *read_arg); 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); 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); 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); 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); 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); 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); 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); 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); int (*init_max_sustainable_clocks)(struct smu_context *smu);
/**
* @enable_thermal_alert: Enable thermal alert interrupts.
*/
int (*enable_thermal_alert)(struct smu_context *smu); int (*enable_thermal_alert)(struct smu_context *smu);
/**
* @disable_thermal_alert: Disable thermal alert interrupts.
*/
int (*disable_thermal_alert)(struct smu_context *smu); 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); 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 int (*display_clock_voltage_request)(struct smu_context *smu, struct
pp_display_clock_request pp_display_clock_request
*clock_req); *clock_req);
/**
* @get_fan_control_mode: Get the current fan control mode.
*/
uint32_t (*get_fan_control_mode)(struct smu_context *smu); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state);
/**
* @baco_enter: Enter BACO.
*/
int (*baco_enter)(struct smu_context *smu); int (*baco_enter)(struct smu_context *smu);
/**
* @baco_exit: Exit Baco.
*/
int (*baco_exit)(struct smu_context *smu); 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); bool (*mode1_reset_is_support)(struct smu_context *smu);
/**
* @mode1_reset: Perform mode1 reset.
*
* Complete GPU reset.
*/
int (*mode1_reset)(struct smu_context *smu); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); int (*get_fan_parameters)(struct smu_context *smu);
/**
* @post_init: Helper function for asic specific workarounds.
*/
int (*post_init)(struct smu_context *smu); int (*post_init)(struct smu_context *smu);
/**
* @interrupt_work: Work task scheduled from SMU interrupt handler.
*/
void (*interrupt_work)(struct smu_context *smu); 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); 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); 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); int (*set_fine_grain_gfx_freq_parameters)(struct smu_context *smu);
}; };
@ -636,6 +1165,12 @@ enum smu_cmn2asic_mapping_type {
#define FEA_MAP(fea) \ #define FEA_MAP(fea) \
[SMU_FEATURE_##fea##_BIT] = {1, FEATURE_##fea##_BIT} [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) \ #define TAB_MAP(tab) \
[SMU_TABLE_##tab] = {1, TABLE_##tab} [SMU_TABLE_##tab] = {1, TABLE_##tab}

View File

@ -141,7 +141,6 @@ typedef struct {
uint32_t MaxGfxClk; uint32_t MaxGfxClk;
uint8_t NumDfPstatesEnabled; uint8_t NumDfPstatesEnabled;
uint8_t NumDpmLevelsEnabled;
uint8_t NumDcfclkLevelsEnabled; uint8_t NumDcfclkLevelsEnabled;
uint8_t NumDispClkLevelsEnabled; //applies to both dispclk and dppclk uint8_t NumDispClkLevelsEnabled; //applies to both dispclk and dppclk
uint8_t NumSocClkLevelsEnabled; uint8_t NumSocClkLevelsEnabled;

View File

@ -211,6 +211,7 @@
__SMU_DUMMY_MAP(SetGpoFeaturePMask), \ __SMU_DUMMY_MAP(SetGpoFeaturePMask), \
__SMU_DUMMY_MAP(DisallowGpo), \ __SMU_DUMMY_MAP(DisallowGpo), \
__SMU_DUMMY_MAP(Enable2ndUSB20Port), \ __SMU_DUMMY_MAP(Enable2ndUSB20Port), \
__SMU_DUMMY_MAP(RequestActiveWgp), \
#undef __SMU_DUMMY_MAP #undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type #define __SMU_DUMMY_MAP(type) SMU_MSG_##type
@ -240,6 +241,7 @@ enum smu_clk_type {
SMU_OD_MCLK, SMU_OD_MCLK,
SMU_OD_VDDC_CURVE, SMU_OD_VDDC_CURVE,
SMU_OD_RANGE, SMU_OD_RANGE,
SMU_OD_VDDGFX_OFFSET,
SMU_CLK_COUNT, SMU_CLK_COUNT,
}; };

View File

@ -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; smu10_data->gfx_actual_soft_min_freq = clock;
smum_send_msg_to_smc_with_parameter(hwmgr, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk,
smu10_data->gfx_actual_soft_min_freq, clock,
NULL); NULL);
} }
return 0; return 0;
@ -558,7 +558,8 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
/* enable the pp_od_clk_voltage sysfs file */ /* enable the pp_od_clk_voltage sysfs file */
hwmgr->od_enabled = 1; hwmgr->od_enabled = 1;
/* disabled fine grain tuning function by default */
data->fine_grain_enabled = 0;
return result; 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 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_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 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) { if (hwmgr->smu_version < 0x1E3700) {
pr_info("smu firmware version too old, can not set dpm level\n"); 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) { switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH: case AMD_DPM_FORCED_LEVEL_HIGH:
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: 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, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk,
data->gfx_max_freq_limit/100, data->gfx_max_freq_limit/100,
@ -648,6 +658,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
NULL); NULL);
break; break;
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: 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, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk,
min_sclk, min_sclk,
@ -658,6 +676,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
NULL); NULL);
break; break;
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: 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, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq,
min_mclk, min_mclk,
@ -668,6 +694,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
NULL); NULL);
break; break;
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: 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, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk,
SMU10_UMD_PSTATE_GFXCLK, SMU10_UMD_PSTATE_GFXCLK,
@ -703,6 +737,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
NULL); NULL);
break; break;
case AMD_DPM_FORCED_LEVEL_AUTO: 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, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk,
min_sclk, min_sclk,
@ -741,6 +783,14 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
NULL); NULL);
break; break;
case AMD_DPM_FORCED_LEVEL_LOW: 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, smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk,
data->gfx_min_freq_limit/100, data->gfx_min_freq_limit/100,
@ -759,6 +809,7 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
NULL); NULL);
break; break;
case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_MANUAL:
data->fine_grain_enabled = 1;
case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
default: default:
break; break;
@ -948,6 +999,8 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
struct smu10_voltage_dependency_table *mclk_table = struct smu10_voltage_dependency_table *mclk_table =
data->clock_vol_info.vdd_dep_on_fclk; data->clock_vol_info.vdd_dep_on_fclk;
uint32_t i, now, size = 0; uint32_t i, now, size = 0;
uint32_t min_freq, max_freq = 0;
uint32_t ret = 0;
switch (type) { switch (type) {
case PP_SCLK: case PP_SCLK:
@ -983,18 +1036,28 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
break; break;
case OD_SCLK: case OD_SCLK:
if (hwmgr->od_enabled) { 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", 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); (data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : min_freq);
size += sprintf(buf + size, "1: %10uMhz\n", data->gfx_max_freq_limit/100); size += sprintf(buf + size, "1: %10uMhz\n",
(data->gfx_actual_soft_max_freq > 0) ? data->gfx_actual_soft_max_freq : max_freq);
} }
break; break;
case OD_RANGE: case OD_RANGE:
if (hwmgr->od_enabled) { if (hwmgr->od_enabled) {
uint32_t min_freq, max_freq = 0; ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq); if (ret)
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq); 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, "%s:\n", "OD_RANGE");
size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n", size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
@ -1414,22 +1477,95 @@ static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr,
enum PP_OD_DPM_TABLE_COMMAND type, enum PP_OD_DPM_TABLE_COMMAND type,
long *input, uint32_t size) 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) { if (!hwmgr->od_enabled) {
pr_err("Fine grain not support\n"); pr_err("Fine grain not support\n");
return -EINVAL; return -EINVAL;
} }
if (!smu10_data->fine_grain_enabled) {
pr_err("Fine grain not started\n");
return -EINVAL;
}
if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
if (size != 2) { if (size != 2) {
pr_err("Input parameter number not correct\n"); pr_err("Input parameter number not correct\n");
return -EINVAL; return -EINVAL;
} }
if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) { if (input[0] == 0) {
if (input[0] == 0) smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
smu10_set_hard_min_gfxclk_by_freq(hwmgr, input[1]); if (input[1] < min_freq) {
else if (input[0] == 1) pr_err("Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
smu10_set_soft_max_gfxclk_by_freq(hwmgr, input[1]); input[1], min_freq);
else 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 -EINVAL;
} }

View File

@ -283,6 +283,7 @@ struct smu10_hwmgr {
uint32_t vclk_soft_min; uint32_t vclk_soft_min;
uint32_t dclk_soft_min; uint32_t dclk_soft_min;
uint32_t gfx_actual_soft_min_freq; uint32_t gfx_actual_soft_min_freq;
uint32_t gfx_actual_soft_max_freq;
uint32_t gfx_min_freq_limit; uint32_t gfx_min_freq_limit;
uint32_t gfx_max_freq_limit; /* in 10Khz*/ uint32_t gfx_max_freq_limit; /* in 10Khz*/
@ -299,6 +300,8 @@ struct smu10_hwmgr {
bool need_min_deep_sleep_dcefclk; bool need_min_deep_sleep_dcefclk;
uint32_t deep_sleep_dcefclk; uint32_t deep_sleep_dcefclk;
uint32_t num_active_display; uint32_t num_active_display;
bool fine_grain_enabled;
}; };
struct pp_hwmgr; struct pp_hwmgr;

View File

@ -402,6 +402,10 @@ static int smu_set_funcs(struct amdgpu_device *adev)
break; break;
case CHIP_RENOIR: case CHIP_RENOIR:
renoir_set_ppt_funcs(smu); 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; break;
case CHIP_VANGOGH: case CHIP_VANGOGH:
vangogh_set_ppt_funcs(smu); vangogh_set_ppt_funcs(smu);
@ -478,9 +482,6 @@ static int smu_late_init(void *handle)
smu_set_fine_grain_gfx_freq_parameters(smu); smu_set_fine_grain_gfx_freq_parameters(smu);
if (adev->asic_type == CHIP_VANGOGH)
return 0;
if (!smu->pm_enabled) if (!smu->pm_enabled)
return 0; return 0;
@ -490,6 +491,9 @@ static int smu_late_init(void *handle)
return ret; return ret;
} }
if (adev->asic_type == CHIP_VANGOGH)
return 0;
ret = smu_set_default_od_settings(smu); ret = smu_set_default_od_settings(smu);
if (ret) { if (ret) {
dev_err(adev->dev, "Failed to setup default OD settings!\n"); dev_err(adev->dev, "Failed to setup default OD settings!\n");

View File

@ -1673,7 +1673,7 @@ static int navi10_read_sensor(struct smu_context *smu,
*size = 4; *size = 4;
break; break;
case AMDGPU_PP_SENSOR_GFX_SCLK: 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; *(uint32_t *)data *= 100;
*size = 4; *size = 4;
break; break;

View File

@ -314,6 +314,12 @@ static int sienna_cichlid_check_powerplay_table(struct smu_context *smu)
table_context->thermal_controller_type = table_context->thermal_controller_type =
powerplay_table->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; 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; 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, static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, char *buf) 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_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; 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; int i, size = 0, ret = 0;
uint32_t cur_value = 0, value = 0, count = 0; uint32_t cur_value = 0, value = 0, count = 0;
uint32_t freq_values[3] = {0}; uint32_t freq_values[3] = {0};
uint32_t mark_index = 0; uint32_t mark_index = 0;
uint32_t gen_speed, lane_width; uint32_t gen_speed, lane_width;
uint32_t min_value, max_value;
uint32_t smu_version;
switch (clk_type) { switch (clk_type) {
case SMU_GFXCLK: 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]) ? (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
"*" : ""); "*" : "");
break; 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: default:
break; break;
} }
@ -1694,6 +1785,243 @@ static int sienna_cichlid_get_dpm_ultimate_freq(struct smu_context *smu,
return ret; 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) static int sienna_cichlid_run_btc(struct smu_context *smu)
{ {
return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); 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; int i;
req->I2CcontrollerPort = 0; req->I2CcontrollerPort = 1;
req->I2CSpeed = 2; req->I2CSpeed = 2;
req->SlaveAddress = address; req->SlaveAddress = address;
req->NumCmds = numbytes; req->NumCmds = numbytes;
@ -2817,6 +3145,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.mode1_reset = smu_v11_0_mode1_reset, .mode1_reset = smu_v11_0_mode1_reset,
.get_dpm_ultimate_freq = sienna_cichlid_get_dpm_ultimate_freq, .get_dpm_ultimate_freq = sienna_cichlid_get_dpm_ultimate_freq,
.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .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, .run_btc = sienna_cichlid_run_btc,
.set_power_source = smu_v11_0_set_power_source, .set_power_source = smu_v11_0_set_power_source,
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,

View File

@ -31,6 +31,9 @@
#include "smu_v11_5_ppsmc.h" #include "smu_v11_5_ppsmc.h"
#include "smu_v11_5_pmfw.h" #include "smu_v11_5_pmfw.h"
#include "smu_cmn.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. * 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(StopDramLogging, PPSMC_MSG_StopDramLogging, 0),
MSG_MAP(SetSoftMinCclk, PPSMC_MSG_SetSoftMinCclk, 0), MSG_MAP(SetSoftMinCclk, PPSMC_MSG_SetSoftMinCclk, 0),
MSG_MAP(SetSoftMaxCclk, PPSMC_MSG_SetSoftMaxCclk, 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] = { 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(A55_DPM),
FEA_MAP(CVIP_DSP_DPM), FEA_MAP(CVIP_DSP_DPM),
FEA_MAP(MSMU_LOW_POWER), 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] = { 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: case METRICS_AVERAGE_SOCCLK:
*value = metrics->SocclkFrequency; *value = metrics->SocclkFrequency;
break; break;
case METRICS_AVERAGE_VCLK:
*value = metrics->VclkFrequency;
break;
case METRICS_AVERAGE_DCLK:
*value = metrics->DclkFrequency;
break;
case METRICS_AVERAGE_UCLK: case METRICS_AVERAGE_UCLK:
*value = metrics->MemclkFrequency; *value = metrics->MemclkFrequency;
break; break;
@ -252,7 +265,8 @@ static int vangogh_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity; *value = metrics->UvdActivity;
break; break;
case METRICS_AVERAGE_SOCKETPOWER: case METRICS_AVERAGE_SOCKETPOWER:
*value = metrics->CurrentSocketPower; *value = (metrics->CurrentSocketPower << 8) /
1000 ;
break; break;
case METRICS_TEMPERATURE_EDGE: case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 * *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) *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DPM_BIT)
| FEATURE_MASK(FEATURE_MP0CLK_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_DS_SOCCLK_BIT)
| FEATURE_MASK(FEATURE_PPT_BIT) | FEATURE_MASK(FEATURE_PPT_BIT)
| FEATURE_MASK(FEATURE_TDC_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) if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT); *(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) if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB)
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); *(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); 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, static int vangogh_print_fine_grain_clk(struct smu_context *smu,
enum smu_clk_type clk_type, char *buf) 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) { switch (clk_type) {
case SMU_OD_SCLK: 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); smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
} }
break; 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: default:
break; break;
} }
@ -431,6 +556,678 @@ static int vangogh_print_fine_grain_clk(struct smu_context *smu,
return size; 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, static int vangogh_read_sensor(struct smu_context *smu,
enum amd_pp_sensors sensor, enum amd_pp_sensors sensor,
void *data, uint32_t *size) void *data, uint32_t *size)
@ -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[0] == 0) {
if (input[1] < smu->gfx_default_hard_min_freq) { 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); input[1], smu->gfx_default_hard_min_freq);
return -EINVAL; return -EINVAL;
} }
smu->gfx_actual_hard_min_freq = input[1]; smu->gfx_actual_hard_min_freq = input[1];
} else if (input[0] == 1) { } else if (input[0] == 1) {
if (input[1] > smu->gfx_default_soft_max_freq) { 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); input[1], smu->gfx_default_soft_max_freq);
return -EINVAL; return -EINVAL;
} }
@ -676,8 +1475,10 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB
return -EINVAL; return -EINVAL;
} else { } else {
if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) { 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", dev_err(smu->adev->dev,
smu->gfx_actual_hard_min_freq, smu->gfx_actual_soft_max_freq); "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; return -EINVAL;
} }
@ -722,6 +1523,33 @@ static int vangogh_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
return 0; 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) static int vangogh_system_features_control(struct smu_context *smu, bool en)
{ {
struct amdgpu_device *adev = smu->adev; struct amdgpu_device *adev = smu->adev;
@ -733,6 +1561,38 @@ static int vangogh_system_features_control(struct smu_context *smu, bool en)
return 0; 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 = { static const struct pptable_funcs vangogh_ppt_funcs = {
.check_fw_status = smu_v11_0_check_fw_status, .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_default_dpm_table = vangogh_set_default_dpm_tables,
.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters, .set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
.system_features_control = vangogh_system_features_control, .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) void vangogh_set_ppt_funcs(struct smu_context *smu)

View File

@ -28,9 +28,29 @@
extern void vangogh_set_ppt_funcs(struct smu_context *smu); extern void vangogh_set_ppt_funcs(struct smu_context *smu);
/* UMD PState Vangogh Msg Parameters in MHz */ /* UMD PState Vangogh Msg Parameters in MHz */
#define VANGOGH_UMD_PSTATE_GFXCLK 700 #define VANGOGH_UMD_PSTATE_STANDARD_GFXCLK 1100
#define VANGOGH_UMD_PSTATE_SOCCLK 678 #define VANGOGH_UMD_PSTATE_STANDARD_SOCCLK 600
#define VANGOGH_UMD_PSTATE_FCLK 800 #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 */ /* RLC Power Status */
#define RLC_STATUS_OFF 0 #define RLC_STATUS_OFF 0

View File

@ -188,6 +188,7 @@ static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type
return -EINVAL; return -EINVAL;
*freq = clk_table->SocClocks[dpm_level].Freq; *freq = clk_table->SocClocks[dpm_level].Freq;
break; break;
case SMU_UCLK:
case SMU_MCLK: case SMU_MCLK:
if (dpm_level >= NUM_FCLK_DPM_LEVELS) if (dpm_level >= NUM_FCLK_DPM_LEVELS)
return -EINVAL; return -EINVAL;
@ -343,6 +344,138 @@ static int renoir_get_dpm_ultimate_freq(struct smu_context *smu,
return ret; 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, static int renoir_print_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, char *buf) enum smu_clk_type clk_type, char *buf)
{ {
@ -358,6 +491,30 @@ static int renoir_print_clk_levels(struct smu_context *smu,
return ret; return ret;
switch (clk_type) { 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_GFXCLK:
case SMU_SCLK: case SMU_SCLK:
/* retirve table returned paramters unit is MHz */ /* retirve table returned paramters unit is MHz */
@ -398,9 +555,16 @@ static int renoir_print_clk_levels(struct smu_context *smu,
cur_value = metrics.ClockFrequency[CLOCK_FCLK]; cur_value = metrics.ClockFrequency[CLOCK_FCLK];
break; break;
default: default:
return -EINVAL; break;
} }
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++) { for (i = 0; i < count; i++) {
ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value); ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value);
if (ret) if (ret)
@ -416,6 +580,11 @@ static int renoir_print_clk_levels(struct smu_context *smu,
if (!cur_value_match_level) if (!cur_value_match_level)
size += sprintf(buf + size, " %uMhz *\n", cur_value); size += sprintf(buf + size, " %uMhz *\n", cur_value);
break;
default:
break;
}
return size; return size;
} }
@ -724,15 +893,31 @@ static int renoir_set_performance_level(struct smu_context *smu,
switch (level) { switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH: 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); ret = renoir_force_dpm_limit_value(smu, true);
break; break;
case AMD_DPM_FORCED_LEVEL_LOW: 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); ret = renoir_force_dpm_limit_value(smu, false);
break; break;
case AMD_DPM_FORCED_LEVEL_AUTO: 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); ret = renoir_unforce_dpm_levels(smu);
break; break;
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: 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, ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetHardMinGfxClk, SMU_MSG_SetHardMinGfxClk,
RENOIR_UMD_PSTATE_GFXCLK, RENOIR_UMD_PSTATE_GFXCLK,
@ -785,6 +970,10 @@ static int renoir_set_performance_level(struct smu_context *smu,
break; break;
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: 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, ret = renoir_get_profiling_clk_mask(smu, level,
&sclk_mask, &sclk_mask,
&mclk_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); renoir_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
break; break;
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: 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); ret = renoir_set_peak_clock_by_device(smu);
break; break;
case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_MANUAL:
smu->fine_grain_started = 1;
case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
default: default:
break; break;
@ -1159,6 +1353,8 @@ static const struct pptable_funcs renoir_ppt_funcs = {
.set_pp_feature_mask = smu_cmn_set_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
.get_gpu_metrics = renoir_get_gpu_metrics, .get_gpu_metrics = renoir_get_gpu_metrics,
.gfx_state_change_set = renoir_gfx_state_change_set, .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) void renoir_set_ppt_funcs(struct smu_context *smu)

View File

@ -225,6 +225,7 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_
break; break;
case SMU_FCLK: case SMU_FCLK:
case SMU_MCLK: case SMU_MCLK:
case SMU_UCLK:
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL);
if (ret) if (ret)
return ret; return ret;

View File

@ -220,7 +220,7 @@ int r600_fmt_get_nblocksx(u32 format, u32 w)
if (bw == 0) if (bw == 0)
return 0; return 0;
return (w + bw - 1) / bw; return DIV_ROUND_UP(w, bw);
} }
int r600_fmt_get_nblocksy(u32 format, u32 h) 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) if (bh == 0)
return 0; return 0;
return (h + bh - 1) / bh; return DIV_ROUND_UP(h, bh);
} }
struct array_mode_checker { struct array_mode_checker {

View File

@ -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) - uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
RADEON_GPU_PAGE_SIZE; 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; uint64_t addr = rdev->uvd.gpu_addr + offs;
int r, i; int r, i;
@ -791,19 +791,19 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
return r; return r;
/* stitch together an UVD create msg */ /* stitch together an UVD create msg */
msg[0] = cpu_to_le32(0x00000de4); writel(cpu_to_le32(0x00000de4), &msg[0]);
msg[1] = cpu_to_le32(0x00000000); writel(0x0, (void __iomem *)&msg[1]);
msg[2] = cpu_to_le32(handle); writel(cpu_to_le32(handle), &msg[2]);
msg[3] = cpu_to_le32(0x00000000); writel(0x0, &msg[3]);
msg[4] = cpu_to_le32(0x00000000); writel(0x0, &msg[4]);
msg[5] = cpu_to_le32(0x00000000); writel(0x0, &msg[5]);
msg[6] = cpu_to_le32(0x00000000); writel(0x0, &msg[6]);
msg[7] = cpu_to_le32(0x00000780); writel(cpu_to_le32(0x00000780), &msg[7]);
msg[8] = cpu_to_le32(0x00000440); writel(cpu_to_le32(0x00000440), &msg[8]);
msg[9] = cpu_to_le32(0x00000000); writel(0x0, &msg[9]);
msg[10] = cpu_to_le32(0x01b37000); writel(cpu_to_le32(0x01b37000), &msg[10]);
for (i = 11; i < 1024; ++i) 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); r = radeon_uvd_send_msg(rdev, ring, addr, fence);
radeon_bo_unreserve(rdev->uvd.vcpu_bo); 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) - uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
RADEON_GPU_PAGE_SIZE; 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; uint64_t addr = rdev->uvd.gpu_addr + offs;
int r, i; int r, i;
@ -827,12 +827,12 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
return r; return r;
/* stitch together an UVD destroy msg */ /* stitch together an UVD destroy msg */
msg[0] = cpu_to_le32(0x00000de4); writel(cpu_to_le32(0x00000de4), &msg[0]);
msg[1] = cpu_to_le32(0x00000002); writel(cpu_to_le32(0x00000002), &msg[1]);
msg[2] = cpu_to_le32(handle); writel(cpu_to_le32(handle), &msg[2]);
msg[3] = cpu_to_le32(0x00000000); writel(0x0, &msg[3]);
for (i = 4; i < 1024; ++i) 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); r = radeon_uvd_send_msg(rdev, ring, addr, fence);
radeon_bo_unreserve(rdev->uvd.vcpu_bo); radeon_bo_unreserve(rdev->uvd.vcpu_bo);