mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 21:53:44 +00:00
Merge tag 'amd-drm-next-6.5-2023-06-16' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-6.5-2023-06-16: amdgpu: - Misc display fixes - W=1 fixes - Improve scheduler naming - DCN 3.1.4 fixes - kdoc fixes - Enable W=1 - VCN 4.0 fix - xgmi fixes - TOPDOWN fix for large BAR systems - eDP fix - PSR fixes - SubVP fixes - Freesync fix - DPIA fix - SMU 13.0.5 fixes - vblflash fix - RAS fixes - SDMA 4 fix - BO locking fix - BO backing store fix - NBIO 7.9 fixes - GC 9.4.3 fixes - GPU reset recovery fixes - HMM fix amdkfd: - Fix NULL check - Trap fixes - Queue count fix - Add event age tracking radeon: - fbdev client fix scheduler: - Avoid an infinite loop UAPI: - Add KFD event age tracking: Proposed ROCT-Thunk-Interface:efdbf6cfbc
1820ae0a2d
Proposed ROCR-Runtime: https://github.com/RadeonOpenCompute/ROCR-Runtime/compare/master...zhums:ROCR-Runtime:new_event_wait_reviewe1f5bdb88e
7d26afd141
drm: - DP MST fix Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230616163548.7706-1-alexander.deucher@amd.com
This commit is contained in:
commit
bcbede6fbe
@ -40,7 +40,18 @@ ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \
|
||||
-I$(FULL_AMD_PATH)/amdkfd
|
||||
|
||||
subdir-ccflags-y := -Wextra
|
||||
subdir-ccflags-y += $(call cc-option, -Wunused-but-set-variable)
|
||||
subdir-ccflags-y += -Wunused
|
||||
subdir-ccflags-y += -Wmissing-prototypes
|
||||
subdir-ccflags-y += -Wmissing-declarations
|
||||
subdir-ccflags-y += -Wmissing-include-dirs
|
||||
subdir-ccflags-y += -Wold-style-definition
|
||||
subdir-ccflags-y += -Wmissing-format-attribute
|
||||
# Need this to avoid recursive variable evaluation issues
|
||||
cond-flags := $(call cc-option, -Wunused-but-set-variable) \
|
||||
$(call cc-option, -Wunused-const-variable) \
|
||||
$(call cc-option, -Wstringop-truncation) \
|
||||
$(call cc-option, -Wpacked-not-aligned)
|
||||
subdir-ccflags-y += $(cond-flags)
|
||||
subdir-ccflags-y += -Wno-unused-parameter
|
||||
subdir-ccflags-y += -Wno-type-limits
|
||||
subdir-ccflags-y += -Wno-sign-compare
|
||||
|
@ -309,7 +309,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
|
||||
}
|
||||
p->gang_leader = p->jobs[p->gang_leader_idx];
|
||||
|
||||
if (p->ctx->vram_lost_counter != p->gang_leader->vram_lost_counter) {
|
||||
if (p->ctx->generation != p->gang_leader->generation) {
|
||||
ret = -ECANCELED;
|
||||
goto free_all_kdata;
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority,
|
||||
|
||||
ctx->reset_counter = atomic_read(&mgr->adev->gpu_reset_counter);
|
||||
ctx->reset_counter_query = ctx->reset_counter;
|
||||
ctx->vram_lost_counter = atomic_read(&mgr->adev->vram_lost_counter);
|
||||
ctx->generation = amdgpu_vm_generation(mgr->adev, &fpriv->vm);
|
||||
ctx->init_priority = priority;
|
||||
ctx->override_priority = AMDGPU_CTX_PRIORITY_UNSET;
|
||||
|
||||
@ -432,6 +432,7 @@ int amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance,
|
||||
u32 ring, struct drm_sched_entity **entity)
|
||||
{
|
||||
int r;
|
||||
struct drm_sched_entity *ctx_entity;
|
||||
|
||||
if (hw_ip >= AMDGPU_HW_IP_NUM) {
|
||||
DRM_ERROR("unknown HW IP type: %d\n", hw_ip);
|
||||
@ -455,7 +456,14 @@ int amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance,
|
||||
return r;
|
||||
}
|
||||
|
||||
*entity = &ctx->entities[hw_ip][ring]->entity;
|
||||
ctx_entity = &ctx->entities[hw_ip][ring]->entity;
|
||||
r = drm_sched_entity_error(ctx_entity);
|
||||
if (r) {
|
||||
DRM_DEBUG("error entity %p\n", ctx_entity);
|
||||
return r;
|
||||
}
|
||||
|
||||
*entity = ctx_entity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -586,7 +594,7 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
|
||||
if (ctx->reset_counter != atomic_read(&adev->gpu_reset_counter))
|
||||
out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RESET;
|
||||
|
||||
if (ctx->vram_lost_counter != atomic_read(&adev->vram_lost_counter))
|
||||
if (ctx->generation != amdgpu_vm_generation(adev, &fpriv->vm))
|
||||
out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST;
|
||||
|
||||
if (atomic_read(&ctx->guilty))
|
||||
|
@ -47,7 +47,7 @@ struct amdgpu_ctx {
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
unsigned reset_counter;
|
||||
unsigned reset_counter_query;
|
||||
uint32_t vram_lost_counter;
|
||||
uint64_t generation;
|
||||
spinlock_t ring_lock;
|
||||
struct amdgpu_ctx_entity *entities[AMDGPU_HW_IP_NUM][AMDGPU_MAX_ENTITY_NUM];
|
||||
bool preamble_presented;
|
||||
|
@ -1515,6 +1515,7 @@ static int amdgpu_discovery_get_mall_info(struct amdgpu_device *adev)
|
||||
mall_size += mall_size_per_umc;
|
||||
}
|
||||
adev->gmc.mall_size = mall_size;
|
||||
adev->gmc.m_half_use = half_use;
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
@ -1896,6 +1897,8 @@ static int amdgpu_discovery_set_gc_ip_blocks(struct amdgpu_device *adev)
|
||||
amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(9, 4, 3):
|
||||
if (!amdgpu_exp_hw_support)
|
||||
return -EINVAL;
|
||||
amdgpu_device_ip_block_add(adev, &gfx_v9_4_3_ip_block);
|
||||
break;
|
||||
case IP_VERSION(10, 1, 10):
|
||||
|
@ -691,6 +691,30 @@ void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_driver_set_error - set error code on fences
|
||||
* @ring: the ring which contains the fences
|
||||
* @error: the error code to set
|
||||
*
|
||||
* Set an error code to all the fences pending on the ring.
|
||||
*/
|
||||
void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error)
|
||||
{
|
||||
struct amdgpu_fence_driver *drv = &ring->fence_drv;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&drv->lock, flags);
|
||||
for (unsigned int i = 0; i <= drv->num_fences_mask; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(drv->fences[i],
|
||||
lockdep_is_held(&drv->lock));
|
||||
if (fence && !dma_fence_is_signaled_locked(fence))
|
||||
dma_fence_set_error(fence, error);
|
||||
}
|
||||
spin_unlock_irqrestore(&drv->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_driver_force_completion - force signal latest fence of ring
|
||||
*
|
||||
@ -699,6 +723,7 @@ void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
|
||||
*/
|
||||
void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
|
||||
{
|
||||
amdgpu_fence_driver_set_error(ring, -ECANCELED);
|
||||
amdgpu_fence_write(ring, ring->fence_drv.sync_seq);
|
||||
amdgpu_fence_process(ring);
|
||||
}
|
||||
|
@ -301,6 +301,8 @@ struct amdgpu_gmc {
|
||||
|
||||
/* MALL size */
|
||||
u64 mall_size;
|
||||
uint32_t m_half_use;
|
||||
|
||||
/* number of UMC instances */
|
||||
int num_umc;
|
||||
/* mode2 save restore */
|
||||
|
@ -190,8 +190,8 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
||||
pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
|
||||
hmm_range->start, hmm_range->end);
|
||||
|
||||
/* Assuming 512MB takes maxmium 1 second to fault page address */
|
||||
timeout = max((hmm_range->end - hmm_range->start) >> 29, 1UL);
|
||||
/* Assuming 128MB takes maximum 1 second to fault page address */
|
||||
timeout = max((hmm_range->end - hmm_range->start) >> 27, 1UL);
|
||||
timeout *= HMM_RANGE_DEFAULT_TIMEOUT;
|
||||
timeout = jiffies + msecs_to_jiffies(timeout);
|
||||
|
||||
|
@ -467,7 +467,8 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
|
||||
handled = true;
|
||||
|
||||
} else {
|
||||
DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
|
||||
DRM_DEBUG("Unregistered interrupt src_id: %d of client_id:%d\n",
|
||||
src_id, client_id);
|
||||
}
|
||||
|
||||
/* Send it to amdkfd as well if it isn't already handled */
|
||||
|
@ -109,7 +109,7 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
(*job)->vm = vm;
|
||||
|
||||
amdgpu_sync_create(&(*job)->explicit_sync);
|
||||
(*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter);
|
||||
(*job)->generation = amdgpu_vm_generation(adev, vm);
|
||||
(*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET;
|
||||
|
||||
if (!entity)
|
||||
@ -258,16 +258,27 @@ amdgpu_job_prepare_job(struct drm_sched_job *sched_job,
|
||||
struct dma_fence *fence = NULL;
|
||||
int r;
|
||||
|
||||
/* Ignore soft recovered fences here */
|
||||
r = drm_sched_entity_error(s_entity);
|
||||
if (r && r != -ENODATA)
|
||||
goto error;
|
||||
|
||||
if (!fence && job->gang_submit)
|
||||
fence = amdgpu_device_switch_gang(ring->adev, job->gang_submit);
|
||||
|
||||
while (!fence && job->vm && !job->vmid) {
|
||||
r = amdgpu_vmid_grab(job->vm, ring, job, &fence);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("Error getting VM ID (%d)\n", r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return fence;
|
||||
|
||||
error:
|
||||
dma_fence_set_error(&job->base.s_fence->finished, r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
|
||||
@ -284,7 +295,7 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
|
||||
trace_amdgpu_sched_run_job(job);
|
||||
|
||||
/* Skip job if VRAM is lost and never resubmit gangs */
|
||||
if (job->vram_lost_counter != atomic_read(&adev->vram_lost_counter) ||
|
||||
if (job->generation != amdgpu_vm_generation(adev, job->vm) ||
|
||||
(job->job_run_counter && job->gang_submit))
|
||||
dma_fence_set_error(finished, -ECANCELED);
|
||||
|
||||
|
@ -61,7 +61,7 @@ struct amdgpu_job {
|
||||
uint32_t gds_base, gds_size;
|
||||
uint32_t gws_base, gws_size;
|
||||
uint32_t oa_base, oa_size;
|
||||
uint32_t vram_lost_counter;
|
||||
uint64_t generation;
|
||||
|
||||
/* user fence handling */
|
||||
uint64_t uf_addr;
|
||||
|
@ -99,8 +99,6 @@ struct amdgpu_nbio_funcs {
|
||||
int (*get_compute_partition_mode)(struct amdgpu_device *adev);
|
||||
u32 (*get_memory_partition_mode)(struct amdgpu_device *adev,
|
||||
u32 *supp_modes);
|
||||
void (*set_compute_partition_mode)(struct amdgpu_device *adev,
|
||||
enum amdgpu_gfx_partition mode);
|
||||
};
|
||||
|
||||
struct amdgpu_nbio {
|
||||
|
@ -150,7 +150,7 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
|
||||
|
||||
if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
|
||||
places[c].lpfn = min_not_zero(places[c].lpfn, visible_pfn);
|
||||
else if (adev->gmc.real_vram_size != adev->gmc.visible_vram_size)
|
||||
else
|
||||
places[c].flags |= TTM_PL_FLAG_TOPDOWN;
|
||||
|
||||
if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
|
||||
@ -1282,8 +1282,12 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
|
||||
void amdgpu_bo_get_memory(struct amdgpu_bo *bo,
|
||||
struct amdgpu_mem_stats *stats)
|
||||
{
|
||||
unsigned int domain;
|
||||
uint64_t size = amdgpu_bo_size(bo);
|
||||
unsigned int domain;
|
||||
|
||||
/* Abort if the BO doesn't currently have a backing store */
|
||||
if (!bo->tbo.resource)
|
||||
return;
|
||||
|
||||
domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type);
|
||||
switch (domain) {
|
||||
|
@ -569,6 +569,26 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
int psp_wait_for_spirom_update(struct psp_context *psp, uint32_t reg_index,
|
||||
uint32_t reg_val, uint32_t mask, uint32_t msec_timeout)
|
||||
{
|
||||
uint32_t val;
|
||||
int i;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
if (psp->adev->no_hw_access)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < msec_timeout; i++) {
|
||||
val = RREG32(reg_index);
|
||||
if ((val & mask) == reg_val)
|
||||
return 0;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static const char *psp_gfx_cmd_name(enum psp_gfx_cmd_id cmd_id)
|
||||
{
|
||||
switch (cmd_id) {
|
||||
@ -1653,10 +1673,11 @@ int psp_ras_initialize(struct psp_context *psp)
|
||||
|
||||
if (amdgpu_ras_is_poison_mode_supported(adev))
|
||||
ras_cmd->ras_in_message.init_flags.poison_mode_en = 1;
|
||||
if (!adev->gmc.xgmi.connected_to_cpu)
|
||||
if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu)
|
||||
ras_cmd->ras_in_message.init_flags.dgpu_mode = 1;
|
||||
ras_cmd->ras_in_message.init_flags.xcc_mask =
|
||||
adev->gfx.xcc_mask;
|
||||
ras_cmd->ras_in_message.init_flags.channel_dis_num = hweight32(adev->gmc.m_half_use) * 2;
|
||||
|
||||
ret = psp_ta_load(psp, &psp->ras_context.context);
|
||||
|
||||
|
@ -455,6 +455,8 @@ extern const struct amdgpu_ip_block_version psp_v13_0_4_ip_block;
|
||||
|
||||
extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
|
||||
uint32_t field_val, uint32_t mask, bool check_changed);
|
||||
extern int psp_wait_for_spirom_update(struct psp_context *psp, uint32_t reg_index,
|
||||
uint32_t field_val, uint32_t mask, uint32_t msec_timeout);
|
||||
|
||||
int psp_gpu_reset(struct amdgpu_device *adev);
|
||||
int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx,
|
||||
|
@ -171,8 +171,7 @@ static int amdgpu_reserve_page_direct(struct amdgpu_device *adev, uint64_t addre
|
||||
|
||||
memset(&err_rec, 0x0, sizeof(struct eeprom_table_record));
|
||||
err_data.err_addr = &err_rec;
|
||||
amdgpu_umc_fill_error_record(&err_data, address,
|
||||
(address >> AMDGPU_GPU_PAGE_SHIFT), 0, 0);
|
||||
amdgpu_umc_fill_error_record(&err_data, address, address, 0, 0);
|
||||
|
||||
if (amdgpu_bad_page_threshold != 0) {
|
||||
amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
|
||||
@ -490,7 +489,8 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f,
|
||||
ret = amdgpu_ras_feature_enable(adev, &data.head, 1);
|
||||
break;
|
||||
case 2:
|
||||
if ((data.inject.address >= adev->gmc.mc_vram_size) ||
|
||||
if ((data.inject.address >= adev->gmc.mc_vram_size &&
|
||||
adev->gmc.mc_vram_size) ||
|
||||
(data.inject.address >= RAS_UMC_INJECT_ADDR_LIMIT)) {
|
||||
dev_warn(adev->dev, "RAS WARN: input address "
|
||||
"0x%llx is invalid.",
|
||||
@ -1491,6 +1491,7 @@ static int amdgpu_ras_sysfs_remove_all(struct amdgpu_device *adev)
|
||||
static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct amdgpu_ras_eeprom_control *eeprom = &con->eeprom_control;
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
struct dentry *dir;
|
||||
|
||||
@ -1501,6 +1502,7 @@ static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *
|
||||
&amdgpu_ras_debugfs_eeprom_ops);
|
||||
debugfs_create_u32("bad_page_cnt_threshold", 0444, dir,
|
||||
&con->bad_page_cnt_threshold);
|
||||
debugfs_create_u32("ras_num_recs", 0444, dir, &eeprom->ras_num_recs);
|
||||
debugfs_create_x32("ras_hw_enabled", 0444, dir, &adev->ras_hw_enabled);
|
||||
debugfs_create_x32("ras_enabled", 0444, dir, &adev->ras_enabled);
|
||||
debugfs_create_file("ras_eeprom_size", S_IRUGO, dir, adev,
|
||||
@ -1685,8 +1687,7 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager *
|
||||
}
|
||||
}
|
||||
|
||||
if (!adev->gmc.xgmi.connected_to_cpu)
|
||||
amdgpu_umc_poison_handler(adev, false);
|
||||
amdgpu_umc_poison_handler(adev, false);
|
||||
|
||||
if (block_obj->hw_ops && block_obj->hw_ops->handle_poison_consumption)
|
||||
poison_stat = block_obj->hw_ops->handle_poison_consumption(adev);
|
||||
@ -2451,11 +2452,10 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
adev->ras_hw_enabled = adev->ras_enabled = 0;
|
||||
|
||||
if (!adev->is_atom_fw ||
|
||||
!amdgpu_ras_asic_supported(adev))
|
||||
if (!amdgpu_ras_asic_supported(adev))
|
||||
return;
|
||||
|
||||
if (!adev->gmc.xgmi.connected_to_cpu) {
|
||||
if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
|
||||
if (amdgpu_atomfirmware_mem_ecc_supported(adev)) {
|
||||
dev_info(adev->dev, "MEM ECC is active.\n");
|
||||
adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__UMC |
|
||||
|
@ -72,7 +72,7 @@
|
||||
/* Bad GPU tag ‘BADG’ */
|
||||
#define RAS_TABLE_HDR_BAD 0x42414447
|
||||
|
||||
/**
|
||||
/*
|
||||
* EEPROM Table structure v1
|
||||
* ---------------------------------
|
||||
* | |
|
||||
@ -94,7 +94,7 @@
|
||||
#define RAS_MAX_RECORD_COUNT ((RAS_TBL_SIZE_BYTES - RAS_TABLE_HEADER_SIZE) \
|
||||
/ RAS_TABLE_RECORD_SIZE)
|
||||
|
||||
/**
|
||||
/*
|
||||
* EEPROM Table structrue v2.1
|
||||
* ---------------------------------
|
||||
* | |
|
||||
|
@ -433,11 +433,18 @@ void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring,
|
||||
bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid,
|
||||
struct dma_fence *fence)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
ktime_t deadline = ktime_add_us(ktime_get(), 10000);
|
||||
|
||||
if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence)
|
||||
return false;
|
||||
|
||||
spin_lock_irqsave(fence->lock, flags);
|
||||
if (!dma_fence_is_signaled_locked(fence))
|
||||
dma_fence_set_error(fence, -ENODATA);
|
||||
spin_unlock_irqrestore(fence->lock, flags);
|
||||
|
||||
atomic_inc(&ring->adev->gpu_reset_counter);
|
||||
while (!dma_fence_is_signaled(fence) &&
|
||||
ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0)
|
||||
@ -561,6 +568,17 @@ static const struct file_operations amdgpu_debugfs_mqd_fops = {
|
||||
.llseek = default_llseek
|
||||
};
|
||||
|
||||
static int amdgpu_debugfs_ring_error(void *data, u64 val)
|
||||
{
|
||||
struct amdgpu_ring *ring = data;
|
||||
|
||||
amdgpu_fence_driver_set_error(ring, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(amdgpu_debugfs_error_fops, NULL,
|
||||
amdgpu_debugfs_ring_error, "%lld\n");
|
||||
|
||||
#endif
|
||||
|
||||
void amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
|
||||
@ -582,6 +600,11 @@ void amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
|
||||
&amdgpu_debugfs_mqd_fops,
|
||||
ring->mqd_size);
|
||||
}
|
||||
|
||||
sprintf(name, "amdgpu_error_%s", ring->name);
|
||||
debugfs_create_file(name, 0200, root, ring,
|
||||
&amdgpu_debugfs_error_fops);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -126,6 +126,7 @@ struct amdgpu_fence_driver {
|
||||
extern const struct drm_sched_backend_ops amdgpu_sched_ops;
|
||||
|
||||
void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
|
||||
void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error);
|
||||
void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
|
||||
|
||||
int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring);
|
||||
|
@ -228,7 +228,7 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
|
||||
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
|
||||
num_bytes = num_pages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
|
||||
|
||||
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
|
||||
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
num_dw * 4 + num_bytes,
|
||||
AMDGPU_IB_POOL_DELAYED, &job);
|
||||
@ -1456,7 +1456,7 @@ static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo,
|
||||
memcpy(adev->mman.sdma_access_ptr, buf, len);
|
||||
|
||||
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
|
||||
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
|
||||
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
num_dw * 4, AMDGPU_IB_POOL_DELAYED,
|
||||
&job);
|
||||
@ -2032,7 +2032,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
|
||||
|
||||
ring = adev->mman.buffer_funcs_ring;
|
||||
sched = &ring->sched;
|
||||
r = drm_sched_entity_init(&adev->mman.entity,
|
||||
r = drm_sched_entity_init(&adev->mman.high_pr,
|
||||
DRM_SCHED_PRIORITY_KERNEL, &sched,
|
||||
1, NULL);
|
||||
if (r) {
|
||||
@ -2041,7 +2041,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
|
||||
return;
|
||||
}
|
||||
|
||||
r = drm_sched_entity_init(&adev->mman.delayed,
|
||||
r = drm_sched_entity_init(&adev->mman.low_pr,
|
||||
DRM_SCHED_PRIORITY_NORMAL, &sched,
|
||||
1, NULL);
|
||||
if (r) {
|
||||
@ -2050,8 +2050,8 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
|
||||
goto error_free_entity;
|
||||
}
|
||||
} else {
|
||||
drm_sched_entity_destroy(&adev->mman.entity);
|
||||
drm_sched_entity_destroy(&adev->mman.delayed);
|
||||
drm_sched_entity_destroy(&adev->mman.high_pr);
|
||||
drm_sched_entity_destroy(&adev->mman.low_pr);
|
||||
dma_fence_put(man->move);
|
||||
man->move = NULL;
|
||||
}
|
||||
@ -2067,7 +2067,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
|
||||
return;
|
||||
|
||||
error_free_entity:
|
||||
drm_sched_entity_destroy(&adev->mman.entity);
|
||||
drm_sched_entity_destroy(&adev->mman.high_pr);
|
||||
}
|
||||
|
||||
static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
|
||||
@ -2082,8 +2082,8 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
|
||||
AMDGPU_IB_POOL_DIRECT :
|
||||
AMDGPU_IB_POOL_DELAYED;
|
||||
int r;
|
||||
struct drm_sched_entity *entity = delayed ? &adev->mman.delayed :
|
||||
&adev->mman.entity;
|
||||
struct drm_sched_entity *entity = delayed ? &adev->mman.low_pr :
|
||||
&adev->mman.high_pr;
|
||||
r = amdgpu_job_alloc_with_ib(adev, entity,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
num_dw * 4, pool, job);
|
||||
|
@ -59,10 +59,10 @@ struct amdgpu_mman {
|
||||
bool buffer_funcs_enabled;
|
||||
|
||||
struct mutex gtt_window_lock;
|
||||
/* Scheduler entity for buffer moves */
|
||||
struct drm_sched_entity entity;
|
||||
/* Scheduler entity for VRAM clearing */
|
||||
struct drm_sched_entity delayed;
|
||||
/* High priority scheduler entity for buffer moves */
|
||||
struct drm_sched_entity high_pr;
|
||||
/* Low priority scheduler entity for VRAM clearing */
|
||||
struct drm_sched_entity low_pr;
|
||||
|
||||
struct amdgpu_vram_mgr vram_mgr;
|
||||
struct amdgpu_gtt_mgr gtt_mgr;
|
||||
|
@ -169,27 +169,31 @@ int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset)
|
||||
{
|
||||
int ret = AMDGPU_RAS_SUCCESS;
|
||||
|
||||
if (!amdgpu_sriov_vf(adev)) {
|
||||
if (!adev->gmc.xgmi.connected_to_cpu) {
|
||||
struct ras_err_data err_data = {0, 0, 0, NULL};
|
||||
struct ras_common_if head = {
|
||||
.block = AMDGPU_RAS_BLOCK__UMC,
|
||||
};
|
||||
struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
|
||||
|
||||
ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset);
|
||||
|
||||
if (ret == AMDGPU_RAS_SUCCESS && obj) {
|
||||
obj->err_data.ue_count += err_data.ue_count;
|
||||
obj->err_data.ce_count += err_data.ce_count;
|
||||
}
|
||||
} else if (reset) {
|
||||
if (adev->gmc.xgmi.connected_to_cpu ||
|
||||
adev->gmc.is_app_apu) {
|
||||
if (reset) {
|
||||
/* MCA poison handler is only responsible for GPU reset,
|
||||
* let MCA notifier do page retirement.
|
||||
*/
|
||||
kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
|
||||
amdgpu_ras_reset_gpu(adev);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!amdgpu_sriov_vf(adev)) {
|
||||
struct ras_err_data err_data = {0, 0, 0, NULL};
|
||||
struct ras_common_if head = {
|
||||
.block = AMDGPU_RAS_BLOCK__UMC,
|
||||
};
|
||||
struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
|
||||
|
||||
ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset);
|
||||
|
||||
if (ret == AMDGPU_RAS_SUCCESS && obj) {
|
||||
obj->err_data.ue_count += err_data.ue_count;
|
||||
obj->err_data.ce_count += err_data.ce_count;
|
||||
}
|
||||
} else {
|
||||
if (adev->virt.ops && adev->virt.ops->ras_poison_handler)
|
||||
adev->virt.ops->ras_poison_handler(adev);
|
||||
|
@ -266,6 +266,32 @@ static void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo)
|
||||
spin_unlock(&vm_bo->vm->status_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_bo_reset_state_machine - reset the vm_bo state machine
|
||||
* @vm: the VM which state machine to reset
|
||||
*
|
||||
* Move all vm_bo object in the VM into a state where they will be updated
|
||||
* again during validation.
|
||||
*/
|
||||
static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm)
|
||||
{
|
||||
struct amdgpu_vm_bo_base *vm_bo, *tmp;
|
||||
|
||||
spin_lock(&vm->status_lock);
|
||||
list_splice_init(&vm->done, &vm->invalidated);
|
||||
list_for_each_entry(vm_bo, &vm->invalidated, vm_status)
|
||||
vm_bo->moved = true;
|
||||
list_for_each_entry_safe(vm_bo, tmp, &vm->idle, vm_status) {
|
||||
struct amdgpu_bo *bo = vm_bo->bo;
|
||||
|
||||
if (!bo || bo->tbo.type != ttm_bo_type_kernel)
|
||||
list_move(&vm_bo->vm_status, &vm_bo->vm->moved);
|
||||
else if (bo->parent)
|
||||
list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
|
||||
}
|
||||
spin_unlock(&vm->status_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_bo_base_init - Adds bo to the list of bos associated with the vm
|
||||
*
|
||||
@ -351,6 +377,58 @@ void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
|
||||
spin_unlock(&adev->mman.bdev.lru_lock);
|
||||
}
|
||||
|
||||
/* Create scheduler entities for page table updates */
|
||||
static int amdgpu_vm_init_entities(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = drm_sched_entity_init(&vm->immediate, DRM_SCHED_PRIORITY_NORMAL,
|
||||
adev->vm_manager.vm_pte_scheds,
|
||||
adev->vm_manager.vm_pte_num_scheds, NULL);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
return drm_sched_entity_init(&vm->delayed, DRM_SCHED_PRIORITY_NORMAL,
|
||||
adev->vm_manager.vm_pte_scheds,
|
||||
adev->vm_manager.vm_pte_num_scheds, NULL);
|
||||
|
||||
error:
|
||||
drm_sched_entity_destroy(&vm->immediate);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Destroy the entities for page table updates again */
|
||||
static void amdgpu_vm_fini_entities(struct amdgpu_vm *vm)
|
||||
{
|
||||
drm_sched_entity_destroy(&vm->immediate);
|
||||
drm_sched_entity_destroy(&vm->delayed);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_generation - return the page table re-generation counter
|
||||
* @adev: the amdgpu_device
|
||||
* @vm: optional VM to check, might be NULL
|
||||
*
|
||||
* Returns a page table re-generation token to allow checking if submissions
|
||||
* are still valid to use this VM. The VM parameter might be NULL in which case
|
||||
* just the VRAM lost counter will be used.
|
||||
*/
|
||||
uint64_t amdgpu_vm_generation(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
||||
{
|
||||
uint64_t result = (u64)atomic_read(&adev->vram_lost_counter) << 32;
|
||||
|
||||
if (!vm)
|
||||
return result;
|
||||
|
||||
result += vm->generation;
|
||||
/* Add one if the page tables will be re-generated on next CS */
|
||||
if (drm_sched_entity_error(&vm->delayed))
|
||||
++result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_validate_pt_bos - validate the page table BOs
|
||||
*
|
||||
@ -373,6 +451,15 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
struct amdgpu_bo *bo;
|
||||
int r;
|
||||
|
||||
if (drm_sched_entity_error(&vm->delayed)) {
|
||||
++vm->generation;
|
||||
amdgpu_vm_bo_reset_state_machine(vm);
|
||||
amdgpu_vm_fini_entities(vm);
|
||||
r = amdgpu_vm_init_entities(adev, vm);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
spin_lock(&vm->status_lock);
|
||||
while (!list_empty(&vm->evicted)) {
|
||||
bo_base = list_first_entry(&vm->evicted,
|
||||
@ -920,42 +1007,51 @@ int amdgpu_vm_update_range(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
return r;
|
||||
}
|
||||
|
||||
static void amdgpu_vm_bo_get_memory(struct amdgpu_bo_va *bo_va,
|
||||
struct amdgpu_mem_stats *stats)
|
||||
{
|
||||
struct amdgpu_vm *vm = bo_va->base.vm;
|
||||
struct amdgpu_bo *bo = bo_va->base.bo;
|
||||
|
||||
if (!bo)
|
||||
return;
|
||||
|
||||
/*
|
||||
* For now ignore BOs which are currently locked and potentially
|
||||
* changing their location.
|
||||
*/
|
||||
if (bo->tbo.base.resv != vm->root.bo->tbo.base.resv &&
|
||||
!dma_resv_trylock(bo->tbo.base.resv))
|
||||
return;
|
||||
|
||||
amdgpu_bo_get_memory(bo, stats);
|
||||
if (bo->tbo.base.resv != vm->root.bo->tbo.base.resv)
|
||||
dma_resv_unlock(bo->tbo.base.resv);
|
||||
}
|
||||
|
||||
void amdgpu_vm_get_memory(struct amdgpu_vm *vm,
|
||||
struct amdgpu_mem_stats *stats)
|
||||
{
|
||||
struct amdgpu_bo_va *bo_va, *tmp;
|
||||
|
||||
spin_lock(&vm->status_lock);
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) {
|
||||
if (!bo_va->base.bo)
|
||||
continue;
|
||||
amdgpu_bo_get_memory(bo_va->base.bo, stats);
|
||||
}
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status) {
|
||||
if (!bo_va->base.bo)
|
||||
continue;
|
||||
amdgpu_bo_get_memory(bo_va->base.bo, stats);
|
||||
}
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status) {
|
||||
if (!bo_va->base.bo)
|
||||
continue;
|
||||
amdgpu_bo_get_memory(bo_va->base.bo, stats);
|
||||
}
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) {
|
||||
if (!bo_va->base.bo)
|
||||
continue;
|
||||
amdgpu_bo_get_memory(bo_va->base.bo, stats);
|
||||
}
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) {
|
||||
if (!bo_va->base.bo)
|
||||
continue;
|
||||
amdgpu_bo_get_memory(bo_va->base.bo, stats);
|
||||
}
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status) {
|
||||
if (!bo_va->base.bo)
|
||||
continue;
|
||||
amdgpu_bo_get_memory(bo_va->base.bo, stats);
|
||||
}
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status)
|
||||
amdgpu_vm_bo_get_memory(bo_va, stats);
|
||||
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status)
|
||||
amdgpu_vm_bo_get_memory(bo_va, stats);
|
||||
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status)
|
||||
amdgpu_vm_bo_get_memory(bo_va, stats);
|
||||
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status)
|
||||
amdgpu_vm_bo_get_memory(bo_va, stats);
|
||||
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status)
|
||||
amdgpu_vm_bo_get_memory(bo_va, stats);
|
||||
|
||||
list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status)
|
||||
amdgpu_vm_bo_get_memory(bo_va, stats);
|
||||
spin_unlock(&vm->status_lock);
|
||||
}
|
||||
|
||||
@ -2039,19 +2135,10 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
||||
INIT_LIST_HEAD(&vm->pt_freed);
|
||||
INIT_WORK(&vm->pt_free_work, amdgpu_vm_pt_free_work);
|
||||
|
||||
/* create scheduler entities for page table updates */
|
||||
r = drm_sched_entity_init(&vm->immediate, DRM_SCHED_PRIORITY_NORMAL,
|
||||
adev->vm_manager.vm_pte_scheds,
|
||||
adev->vm_manager.vm_pte_num_scheds, NULL);
|
||||
r = amdgpu_vm_init_entities(adev, vm);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = drm_sched_entity_init(&vm->delayed, DRM_SCHED_PRIORITY_NORMAL,
|
||||
adev->vm_manager.vm_pte_scheds,
|
||||
adev->vm_manager.vm_pte_num_scheds, NULL);
|
||||
if (r)
|
||||
goto error_free_immediate;
|
||||
|
||||
vm->pte_support_ats = false;
|
||||
vm->is_compute_context = false;
|
||||
|
||||
@ -2072,6 +2159,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
||||
vm->last_update = dma_fence_get_stub();
|
||||
vm->last_unlocked = dma_fence_get_stub();
|
||||
vm->last_tlb_flush = dma_fence_get_stub();
|
||||
vm->generation = 0;
|
||||
|
||||
mutex_init(&vm->eviction_lock);
|
||||
vm->evicting = false;
|
||||
@ -2112,10 +2200,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
||||
error_free_delayed:
|
||||
dma_fence_put(vm->last_tlb_flush);
|
||||
dma_fence_put(vm->last_unlocked);
|
||||
drm_sched_entity_destroy(&vm->delayed);
|
||||
|
||||
error_free_immediate:
|
||||
drm_sched_entity_destroy(&vm->immediate);
|
||||
amdgpu_vm_fini_entities(vm);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -2268,8 +2353,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
||||
amdgpu_bo_unref(&root);
|
||||
WARN_ON(vm->root.bo);
|
||||
|
||||
drm_sched_entity_destroy(&vm->immediate);
|
||||
drm_sched_entity_destroy(&vm->delayed);
|
||||
amdgpu_vm_fini_entities(vm);
|
||||
|
||||
if (!RB_EMPTY_ROOT(&vm->va.rb_root)) {
|
||||
dev_err(adev->dev, "still active bo inside vm\n");
|
||||
|
@ -295,6 +295,9 @@ struct amdgpu_vm {
|
||||
atomic64_t tlb_seq;
|
||||
struct dma_fence *last_tlb_flush;
|
||||
|
||||
/* How many times we had to re-generate the page tables */
|
||||
uint64_t generation;
|
||||
|
||||
/* Last unlocked submission to the scheduler entities */
|
||||
struct dma_fence *last_unlocked;
|
||||
|
||||
@ -397,6 +400,7 @@ void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
|
||||
struct list_head *validated,
|
||||
struct amdgpu_bo_list_entry *entry);
|
||||
bool amdgpu_vm_ready(struct amdgpu_vm *vm);
|
||||
uint64_t amdgpu_vm_generation(struct amdgpu_device *adev, struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
int (*callback)(void *p, struct amdgpu_bo *bo),
|
||||
void *param);
|
||||
|
@ -325,6 +325,36 @@ static ssize_t amdgpu_xgmi_show_device_id(struct device *dev,
|
||||
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_xgmi_show_num_hops(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);
|
||||
struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < top->num_nodes; i++)
|
||||
sprintf(buf + 3 * i, "%02x ", top->nodes[i].num_hops);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", buf);
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_xgmi_show_num_links(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);
|
||||
struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < top->num_nodes; i++)
|
||||
sprintf(buf + 3 * i, "%02x ", top->nodes[i].num_links);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", buf);
|
||||
}
|
||||
|
||||
#define AMDGPU_XGMI_SET_FICAA(o) ((o) | 0x456801)
|
||||
static ssize_t amdgpu_xgmi_show_error(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@ -361,6 +391,8 @@ static ssize_t amdgpu_xgmi_show_error(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(xgmi_device_id, S_IRUGO, amdgpu_xgmi_show_device_id, NULL);
|
||||
static DEVICE_ATTR(xgmi_error, S_IRUGO, amdgpu_xgmi_show_error, NULL);
|
||||
static DEVICE_ATTR(xgmi_num_hops, S_IRUGO, amdgpu_xgmi_show_num_hops, NULL);
|
||||
static DEVICE_ATTR(xgmi_num_links, S_IRUGO, amdgpu_xgmi_show_num_links, NULL);
|
||||
|
||||
static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev,
|
||||
struct amdgpu_hive_info *hive)
|
||||
@ -380,6 +412,15 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev,
|
||||
if (ret)
|
||||
pr_err("failed to create xgmi_error\n");
|
||||
|
||||
/* Create xgmi num hops file */
|
||||
ret = device_create_file(adev->dev, &dev_attr_xgmi_num_hops);
|
||||
if (ret)
|
||||
pr_err("failed to create xgmi_num_hops\n");
|
||||
|
||||
/* Create xgmi num links file */
|
||||
ret = device_create_file(adev->dev, &dev_attr_xgmi_num_links);
|
||||
if (ret)
|
||||
pr_err("failed to create xgmi_num_links\n");
|
||||
|
||||
/* Create sysfs link to hive info folder on the first device */
|
||||
if (hive->kobj.parent != (&adev->dev->kobj)) {
|
||||
@ -407,6 +448,9 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev,
|
||||
|
||||
remove_file:
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_device_id);
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_error);
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_num_hops);
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_num_links);
|
||||
|
||||
success:
|
||||
return ret;
|
||||
@ -420,6 +464,8 @@ static void amdgpu_xgmi_sysfs_rem_dev_info(struct amdgpu_device *adev,
|
||||
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_device_id);
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_error);
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_num_hops);
|
||||
device_remove_file(adev->dev, &dev_attr_xgmi_num_links);
|
||||
|
||||
if (hive->kobj.parent != (&adev->dev->kobj))
|
||||
sysfs_remove_link(&adev->dev->kobj,"xgmi_hive_info");
|
||||
|
@ -518,9 +518,6 @@ static int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr,
|
||||
adev->gfx.funcs->switch_partition_mode(xcp_mgr->adev,
|
||||
num_xcc_per_xcp);
|
||||
|
||||
if (adev->nbio.funcs->set_compute_partition_mode)
|
||||
adev->nbio.funcs->set_compute_partition_mode(adev, mode);
|
||||
|
||||
/* Init info about new xcps */
|
||||
*num_xcps = num_xcc / num_xcc_per_xcp;
|
||||
amdgpu_xcp_init(xcp_mgr, *num_xcps, mode);
|
||||
|
@ -623,22 +623,16 @@ static void gfx_v9_4_3_select_me_pipe_q(struct amdgpu_device *adev,
|
||||
static int gfx_v9_4_3_switch_compute_partition(struct amdgpu_device *adev,
|
||||
int num_xccs_per_xcp)
|
||||
{
|
||||
int i, num_xcc;
|
||||
u32 tmp = 0;
|
||||
int ret;
|
||||
|
||||
num_xcc = NUM_XCC(adev->gfx.xcc_mask);
|
||||
|
||||
for (i = 0; i < num_xcc; i++) {
|
||||
tmp = REG_SET_FIELD(tmp, CP_HYP_XCP_CTL, NUM_XCC_IN_XCP,
|
||||
num_xccs_per_xcp);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HYP_XCP_CTL, VIRTUAL_XCC_ID,
|
||||
i % num_xccs_per_xcp);
|
||||
WREG32_SOC15(GC, GET_INST(GC, i), regCP_HYP_XCP_CTL, tmp);
|
||||
}
|
||||
ret = psp_spatial_partition(&adev->psp, NUM_XCC(adev->gfx.xcc_mask) /
|
||||
num_xccs_per_xcp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adev->gfx.num_xcc_per_xcp = num_xccs_per_xcp;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gfx_v9_4_3_ih_to_xcc_inst(struct amdgpu_device *adev, int ih_node)
|
||||
|
@ -382,7 +382,7 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
* translation. Avoid this by doing the invalidation from the SDMA
|
||||
* itself.
|
||||
*/
|
||||
r = amdgpu_job_alloc_with_ib(ring->adev, &adev->mman.entity,
|
||||
r = amdgpu_job_alloc_with_ib(ring->adev, &adev->mman.high_pr,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
16 * 4, AMDGPU_IB_POOL_IMMEDIATE,
|
||||
&job);
|
||||
|
@ -2107,6 +2107,7 @@ static int gmc_v9_0_sw_init(void *handle)
|
||||
bitmap_or(adev->vmhubs_mask, adev->vmhubs_mask, &inst_mask, 32);
|
||||
|
||||
amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
|
||||
adev->gmc.translate_further = adev->vm_manager.num_level > 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -390,22 +390,7 @@ static int nbio_v7_9_get_compute_partition_mode(struct amdgpu_device *adev)
|
||||
px = REG_GET_FIELD(tmp, BIF_BX_PF0_PARTITION_COMPUTE_STATUS,
|
||||
PARTITION_MODE);
|
||||
|
||||
return ffs(px);
|
||||
}
|
||||
|
||||
static void nbio_v7_9_set_compute_partition_mode(struct amdgpu_device *adev,
|
||||
enum amdgpu_gfx_partition mode)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* Each bit represents DPX,TPX,QPX,CPX mode. No bit set means default
|
||||
* SPX mode.
|
||||
*/
|
||||
tmp = RREG32_SOC15(NBIO, 0, regBIF_BX_PF0_PARTITION_COMPUTE_STATUS);
|
||||
tmp = REG_SET_FIELD(tmp, BIF_BX_PF0_PARTITION_COMPUTE_STATUS,
|
||||
PARTITION_MODE, mode ? BIT(mode - 1) : mode);
|
||||
|
||||
WREG32_SOC15(NBIO, 0, regBIF_BX_PF0_PARTITION_COMPUTE_STATUS, tmp);
|
||||
return px;
|
||||
}
|
||||
|
||||
static u32 nbio_v7_9_get_memory_partition_mode(struct amdgpu_device *adev,
|
||||
@ -463,7 +448,6 @@ const struct amdgpu_nbio_funcs nbio_v7_9_funcs = {
|
||||
.ih_control = nbio_v7_9_ih_control,
|
||||
.remap_hdp_registers = nbio_v7_9_remap_hdp_registers,
|
||||
.get_compute_partition_mode = nbio_v7_9_get_compute_partition_mode,
|
||||
.set_compute_partition_mode = nbio_v7_9_set_compute_partition_mode,
|
||||
.get_memory_partition_mode = nbio_v7_9_get_memory_partition_mode,
|
||||
.init_registers = nbio_v7_9_init_registers,
|
||||
};
|
||||
|
@ -624,10 +624,11 @@ static int psp_v13_0_exec_spi_cmd(struct psp_context *psp, int cmd)
|
||||
WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_73, 1);
|
||||
|
||||
if (cmd == C2PMSG_CMD_SPI_UPDATE_FLASH_IMAGE)
|
||||
return 0;
|
||||
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_115),
|
||||
MBOX_READY_FLAG, MBOX_READY_MASK, false);
|
||||
ret = psp_wait_for_spirom_update(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_115),
|
||||
MBOX_READY_FLAG, MBOX_READY_MASK, PSP_SPIROM_UPDATE_TIMEOUT);
|
||||
else
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_115),
|
||||
MBOX_READY_FLAG, MBOX_READY_MASK, false);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "SPI cmd %x timed out, ret = %d", cmd, ret);
|
||||
return ret;
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include "amdgpu_psp.h"
|
||||
|
||||
#define PSP_SPIROM_UPDATE_TIMEOUT 60000 /* 60s */
|
||||
|
||||
void psp_v13_0_set_psp_funcs(struct psp_context *psp);
|
||||
|
||||
#endif
|
||||
|
@ -2312,7 +2312,7 @@ const struct amd_ip_funcs sdma_v4_0_ip_funcs = {
|
||||
|
||||
static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = {
|
||||
.type = AMDGPU_RING_TYPE_SDMA,
|
||||
.align_mask = 0xf,
|
||||
.align_mask = 0xff,
|
||||
.nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
|
||||
.support_64bit_ptrs = true,
|
||||
.secure_submission_supported = true,
|
||||
@ -2344,7 +2344,7 @@ static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = {
|
||||
|
||||
static const struct amdgpu_ring_funcs sdma_v4_0_page_ring_funcs = {
|
||||
.type = AMDGPU_RING_TYPE_SDMA,
|
||||
.align_mask = 0xf,
|
||||
.align_mask = 0xff,
|
||||
.nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
|
||||
.support_64bit_ptrs = true,
|
||||
.secure_submission_supported = true,
|
||||
|
@ -1434,9 +1434,11 @@ static int sdma_v4_4_2_hw_fini(void *handle)
|
||||
return 0;
|
||||
|
||||
inst_mask = GENMASK(adev->sdma.num_instances - 1, 0);
|
||||
for (i = 0; i < adev->sdma.num_instances; i++) {
|
||||
amdgpu_irq_put(adev, &adev->sdma.ecc_irq,
|
||||
AMDGPU_SDMA_IRQ_INSTANCE0 + i);
|
||||
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) {
|
||||
for (i = 0; i < adev->sdma.num_instances; i++) {
|
||||
amdgpu_irq_put(adev, &adev->sdma.ecc_irq,
|
||||
AMDGPU_SDMA_IRQ_INSTANCE0 + i);
|
||||
}
|
||||
}
|
||||
|
||||
sdma_v4_4_2_inst_ctx_switch_enable(adev, false, inst_mask);
|
||||
@ -1823,7 +1825,7 @@ const struct amd_ip_funcs sdma_v4_4_2_ip_funcs = {
|
||||
|
||||
static const struct amdgpu_ring_funcs sdma_v4_4_2_ring_funcs = {
|
||||
.type = AMDGPU_RING_TYPE_SDMA,
|
||||
.align_mask = 0xf,
|
||||
.align_mask = 0xff,
|
||||
.nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
|
||||
.support_64bit_ptrs = true,
|
||||
.get_rptr = sdma_v4_4_2_ring_get_rptr,
|
||||
@ -1854,7 +1856,7 @@ static const struct amdgpu_ring_funcs sdma_v4_4_2_ring_funcs = {
|
||||
|
||||
static const struct amdgpu_ring_funcs sdma_v4_4_2_page_ring_funcs = {
|
||||
.type = AMDGPU_RING_TYPE_SDMA,
|
||||
.align_mask = 0xf,
|
||||
.align_mask = 0xff,
|
||||
.nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
|
||||
.support_64bit_ptrs = true,
|
||||
.get_rptr = sdma_v4_4_2_ring_get_rptr,
|
||||
@ -2073,9 +2075,11 @@ static int sdma_v4_4_2_xcp_suspend(void *handle, uint32_t inst_mask)
|
||||
uint32_t tmp_mask = inst_mask;
|
||||
int i;
|
||||
|
||||
for_each_inst(i, tmp_mask) {
|
||||
amdgpu_irq_put(adev, &adev->sdma.ecc_irq,
|
||||
AMDGPU_SDMA_IRQ_INSTANCE0 + i);
|
||||
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) {
|
||||
for_each_inst(i, tmp_mask) {
|
||||
amdgpu_irq_put(adev, &adev->sdma.ecc_irq,
|
||||
AMDGPU_SDMA_IRQ_INSTANCE0 + i);
|
||||
}
|
||||
}
|
||||
|
||||
sdma_v4_4_2_inst_ctx_switch_enable(adev, false, inst_mask);
|
||||
|
@ -130,6 +130,7 @@ struct ta_ras_init_flags {
|
||||
uint8_t poison_mode_en;
|
||||
uint8_t dgpu_mode;
|
||||
uint16_t xcc_mask;
|
||||
uint8_t channel_dis_num;
|
||||
};
|
||||
|
||||
struct ta_ras_output_flags {
|
||||
|
@ -33,7 +33,8 @@
|
||||
|
||||
/* Total channel instances for all available umc nodes */
|
||||
#define UMC_V8_10_TOTAL_CHANNEL_NUM(adev) \
|
||||
(UMC_V8_10_CHANNEL_INSTANCE_NUM * UMC_V8_10_UMC_INSTANCE_NUM * (adev)->gmc.num_umc)
|
||||
(UMC_V8_10_CHANNEL_INSTANCE_NUM * UMC_V8_10_UMC_INSTANCE_NUM * \
|
||||
(adev)->gmc.num_umc - hweight32((adev)->gmc.m_half_use) * 2)
|
||||
|
||||
/* UMC regiser per channel offset */
|
||||
#define UMC_V8_10_PER_CHANNEL_OFFSET 0x400
|
||||
|
@ -129,7 +129,11 @@ static int vcn_v4_0_sw_init(void *handle)
|
||||
if (adev->vcn.harvest_config & (1 << i))
|
||||
continue;
|
||||
|
||||
atomic_set(&adev->vcn.inst[i].sched_score, 0);
|
||||
/* Init instance 0 sched_score to 1, so it's scheduled after other instances */
|
||||
if (i == 0)
|
||||
atomic_set(&adev->vcn.inst[i].sched_score, 1);
|
||||
else
|
||||
atomic_set(&adev->vcn.inst[i].sched_score, 0);
|
||||
|
||||
/* VCN UNIFIED TRAP */
|
||||
r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
|
||||
|
@ -30,9 +30,6 @@
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
|
||||
/* Fixme: Fake 32GB for 1PNPS1 mode bringup */
|
||||
#define DUMMY_VRAM_SIZE 31138512896
|
||||
|
||||
/* GPU Processor ID base for dGPUs for which VCRAT needs to be created.
|
||||
* GPU processor ID are expressed with Bit[31]=1.
|
||||
* The base is set to 0x8000_0000 + 0x1000 to avoid collision with GPU IDs
|
||||
@ -1056,8 +1053,6 @@ static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem,
|
||||
|
||||
props->heap_type = heap_type;
|
||||
props->flags = flags;
|
||||
if (size_in_bytes == 0)
|
||||
size_in_bytes = DUMMY_VRAM_SIZE; /* Fixme: TBD */
|
||||
props->size_in_bytes = size_in_bytes;
|
||||
props->width = width;
|
||||
|
||||
|
@ -1097,7 +1097,7 @@ void kfd_dbg_set_enabled_debug_exception_mask(struct kfd_process *target,
|
||||
|
||||
pqm = &target->pqm;
|
||||
list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
|
||||
if (!pqn)
|
||||
if (!pqn->q)
|
||||
continue;
|
||||
|
||||
found_mask |= pqn->q->properties.exception_status;
|
||||
|
@ -227,7 +227,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
|
||||
queue_input.tba_addr = qpd->tba_addr;
|
||||
queue_input.tma_addr = qpd->tma_addr;
|
||||
queue_input.trap_en = KFD_GC_VERSION(q->device) < IP_VERSION(11, 0, 0) ||
|
||||
KFD_GC_VERSION(q->device) >= IP_VERSION(12, 0, 0);
|
||||
KFD_GC_VERSION(q->device) > IP_VERSION(11, 0, 3);
|
||||
queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled;
|
||||
|
||||
queue_type = convert_to_mes_queue_type(q->properties.type);
|
||||
@ -1807,7 +1807,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
|
||||
q->properties.is_evicted = !!qpd->evicted;
|
||||
q->properties.is_dbg_wa = qpd->pqm->process->debug_trap_enabled &&
|
||||
KFD_GC_VERSION(q->device) >= IP_VERSION(11, 0, 0) &&
|
||||
KFD_GC_VERSION(q->device) < IP_VERSION(12, 0, 0);
|
||||
KFD_GC_VERSION(q->device) <= IP_VERSION(11, 0, 3);
|
||||
|
||||
if (qd)
|
||||
mqd_mgr->restore_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj, &q->gart_mqd_addr,
|
||||
@ -2089,8 +2089,8 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
|
||||
list_del(&q->list);
|
||||
qpd->queue_count--;
|
||||
if (q->properties.is_active) {
|
||||
decrement_queue_count(dqm, qpd, q);
|
||||
if (!dqm->dev->kfd->shared_resources.enable_mes) {
|
||||
decrement_queue_count(dqm, qpd, q);
|
||||
retval = execute_queues_cpsch(dqm,
|
||||
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
|
||||
USE_DEFAULT_GRACE_PERIOD);
|
||||
|
@ -41,6 +41,7 @@ struct kfd_event_waiter {
|
||||
wait_queue_entry_t wait;
|
||||
struct kfd_event *event; /* Event to wait for */
|
||||
bool activated; /* Becomes true when event is signaled */
|
||||
bool event_age_enabled; /* set to true when last_event_age is non-zero */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -431,6 +432,7 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p,
|
||||
if (!ret) {
|
||||
*event_id = ev->event_id;
|
||||
*event_trigger_data = ev->event_id;
|
||||
ev->event_age = 1;
|
||||
} else {
|
||||
kfree(ev);
|
||||
}
|
||||
@ -629,6 +631,11 @@ static void set_event(struct kfd_event *ev)
|
||||
* updating the wait queues in kfd_wait_on_events.
|
||||
*/
|
||||
ev->signaled = !ev->auto_reset || !waitqueue_active(&ev->wq);
|
||||
if (!(++ev->event_age)) {
|
||||
/* Never wrap back to reserved/default event age 0/1 */
|
||||
ev->event_age = 2;
|
||||
WARN_ONCE(1, "event_age wrap back!");
|
||||
}
|
||||
|
||||
list_for_each_entry(waiter, &ev->wq.head, wait.entry)
|
||||
WRITE_ONCE(waiter->activated, true);
|
||||
@ -791,9 +798,9 @@ static struct kfd_event_waiter *alloc_event_waiters(uint32_t num_events)
|
||||
|
||||
static int init_event_waiter(struct kfd_process *p,
|
||||
struct kfd_event_waiter *waiter,
|
||||
uint32_t event_id)
|
||||
struct kfd_event_data *event_data)
|
||||
{
|
||||
struct kfd_event *ev = lookup_event_by_id(p, event_id);
|
||||
struct kfd_event *ev = lookup_event_by_id(p, event_data->event_id);
|
||||
|
||||
if (!ev)
|
||||
return -EINVAL;
|
||||
@ -802,6 +809,15 @@ static int init_event_waiter(struct kfd_process *p,
|
||||
waiter->event = ev;
|
||||
waiter->activated = ev->signaled;
|
||||
ev->signaled = ev->signaled && !ev->auto_reset;
|
||||
|
||||
/* last_event_age = 0 reserved for backward compatible */
|
||||
if (waiter->event->type == KFD_EVENT_TYPE_SIGNAL &&
|
||||
event_data->signal_event_data.last_event_age) {
|
||||
waiter->event_age_enabled = true;
|
||||
if (ev->event_age != event_data->signal_event_data.last_event_age)
|
||||
waiter->activated = true;
|
||||
}
|
||||
|
||||
if (!waiter->activated)
|
||||
add_wait_queue(&ev->wq, &waiter->wait);
|
||||
spin_unlock(&ev->lock);
|
||||
@ -849,22 +865,29 @@ static int copy_signaled_event_data(uint32_t num_events,
|
||||
struct kfd_event_waiter *event_waiters,
|
||||
struct kfd_event_data __user *data)
|
||||
{
|
||||
struct kfd_hsa_memory_exception_data *src;
|
||||
struct kfd_hsa_memory_exception_data __user *dst;
|
||||
void *src;
|
||||
void __user *dst;
|
||||
struct kfd_event_waiter *waiter;
|
||||
struct kfd_event *event;
|
||||
uint32_t i;
|
||||
uint32_t i, size = 0;
|
||||
|
||||
for (i = 0; i < num_events; i++) {
|
||||
waiter = &event_waiters[i];
|
||||
event = waiter->event;
|
||||
if (!event)
|
||||
return -EINVAL; /* event was destroyed */
|
||||
if (waiter->activated && event->type == KFD_EVENT_TYPE_MEMORY) {
|
||||
dst = &data[i].memory_exception_data;
|
||||
src = &event->memory_exception_data;
|
||||
if (copy_to_user(dst, src,
|
||||
sizeof(struct kfd_hsa_memory_exception_data)))
|
||||
if (waiter->activated) {
|
||||
if (event->type == KFD_EVENT_TYPE_MEMORY) {
|
||||
dst = &data[i].memory_exception_data;
|
||||
src = &event->memory_exception_data;
|
||||
size = sizeof(struct kfd_hsa_memory_exception_data);
|
||||
} else if (event->type == KFD_EVENT_TYPE_SIGNAL &&
|
||||
waiter->event_age_enabled) {
|
||||
dst = &data[i].signal_event_data.last_event_age;
|
||||
src = &event->event_age;
|
||||
size = sizeof(u64);
|
||||
}
|
||||
if (size && copy_to_user(dst, src, size))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
@ -942,8 +965,7 @@ int kfd_wait_on_events(struct kfd_process *p,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = init_event_waiter(p, &event_waiters[i],
|
||||
event_data.event_id);
|
||||
ret = init_event_waiter(p, &event_waiters[i], &event_data);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ struct signal_page;
|
||||
|
||||
struct kfd_event {
|
||||
u32 event_id;
|
||||
u64 event_age;
|
||||
|
||||
bool signaled;
|
||||
bool auto_reset;
|
||||
|
@ -64,7 +64,7 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages,
|
||||
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
|
||||
num_bytes = npages * 8;
|
||||
|
||||
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity,
|
||||
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
num_dw * 4 + num_bytes,
|
||||
AMDGPU_IB_POOL_DELAYED,
|
||||
|
@ -3267,6 +3267,7 @@ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
|
||||
|
||||
while (dret == dpcd_bytes_to_read &&
|
||||
process_count < max_process_count) {
|
||||
u8 ack[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = {};
|
||||
u8 retry;
|
||||
dret = 0;
|
||||
|
||||
@ -3275,28 +3276,29 @@ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
|
||||
DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
|
||||
/* handle HPD short pulse irq */
|
||||
if (aconnector->mst_mgr.mst_state)
|
||||
drm_dp_mst_hpd_irq(
|
||||
&aconnector->mst_mgr,
|
||||
esi,
|
||||
&new_irq_handled);
|
||||
drm_dp_mst_hpd_irq_handle_event(&aconnector->mst_mgr,
|
||||
esi,
|
||||
ack,
|
||||
&new_irq_handled);
|
||||
|
||||
if (new_irq_handled) {
|
||||
/* ACK at DPCD to notify down stream */
|
||||
const int ack_dpcd_bytes_to_write =
|
||||
dpcd_bytes_to_read - 1;
|
||||
|
||||
for (retry = 0; retry < 3; retry++) {
|
||||
u8 wret;
|
||||
ssize_t wret;
|
||||
|
||||
wret = drm_dp_dpcd_write(
|
||||
&aconnector->dm_dp_aux.aux,
|
||||
dpcd_addr + 1,
|
||||
&esi[1],
|
||||
ack_dpcd_bytes_to_write);
|
||||
if (wret == ack_dpcd_bytes_to_write)
|
||||
wret = drm_dp_dpcd_writeb(&aconnector->dm_dp_aux.aux,
|
||||
dpcd_addr + 1,
|
||||
ack[1]);
|
||||
if (wret == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (retry == 3) {
|
||||
DRM_ERROR("Failed to ack MST event.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
drm_dp_mst_hpd_irq_send_new_request(&aconnector->mst_mgr);
|
||||
/* check if there is new irq to be handled */
|
||||
dret = drm_dp_dpcd_read(
|
||||
&aconnector->dm_dp_aux.aux,
|
||||
@ -7256,7 +7258,13 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
|
||||
drm_add_modes_noedid(connector, 1920, 1080);
|
||||
} else {
|
||||
amdgpu_dm_connector_ddc_get_modes(connector, edid);
|
||||
amdgpu_dm_connector_add_common_modes(encoder, connector);
|
||||
/* most eDP supports only timings from its edid,
|
||||
* usually only detailed timings are available
|
||||
* from eDP edid. timings which are not from edid
|
||||
* may damage eDP
|
||||
*/
|
||||
if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
|
||||
amdgpu_dm_connector_add_common_modes(encoder, connector);
|
||||
amdgpu_dm_connector_add_freesync_modes(connector, edid);
|
||||
}
|
||||
amdgpu_dm_fbc_init(connector);
|
||||
@ -8273,6 +8281,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
|
||||
if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
|
||||
bundle->stream_update.abm_level = &acrtc_state->abm_level;
|
||||
|
||||
mutex_lock(&dm->dc_lock);
|
||||
if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
|
||||
acrtc_state->stream->link->psr_settings.psr_allow_active)
|
||||
amdgpu_dm_psr_disable(acrtc_state->stream);
|
||||
mutex_unlock(&dm->dc_lock);
|
||||
|
||||
/*
|
||||
* If FreeSync state on the stream has changed then we need to
|
||||
* re-adjust the min/max bounds now that DC doesn't handle this
|
||||
@ -8286,10 +8300,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
|
||||
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
|
||||
}
|
||||
mutex_lock(&dm->dc_lock);
|
||||
if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
|
||||
acrtc_state->stream->link->psr_settings.psr_allow_active)
|
||||
amdgpu_dm_psr_disable(acrtc_state->stream);
|
||||
|
||||
update_planes_and_stream_adapter(dm->dc,
|
||||
acrtc_state->update_type,
|
||||
planes_count,
|
||||
@ -8951,10 +8961,17 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_cleanup_planes(dev, state);
|
||||
|
||||
/* return the stolen vga memory back to VRAM */
|
||||
if (!adev->mman.keep_stolen_vga_memory)
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
|
||||
/* Don't free the memory if we are hitting this as part of suspend.
|
||||
* This way we don't free any memory during suspend; see
|
||||
* amdgpu_bo_free_kernel(). The memory will be freed in the first
|
||||
* non-suspend modeset or when the driver is torn down.
|
||||
*/
|
||||
if (!adev->in_suspend) {
|
||||
/* return the stolen vga memory back to VRAM */
|
||||
if (!adev->mman.keep_stolen_vga_memory)
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, drop a runtime PM reference for each newly disabled CRTC,
|
||||
|
@ -2760,6 +2760,32 @@ static int psr_read_residency(void *data, u64 *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read allow_edp_hotplug_detection */
|
||||
static int allow_edp_hotplug_detection_get(void *data, u64 *val)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = data;
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
|
||||
*val = adev->dm.dc->config.allow_edp_hotplug_detection;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set allow_edp_hotplug_detection */
|
||||
static int allow_edp_hotplug_detection_set(void *data, u64 val)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = data;
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
|
||||
adev->dm.dc->config.allow_edp_hotplug_detection = (uint32_t) val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set dmcub trace event IRQ enable or disable.
|
||||
* Usage to enable dmcub trace event IRQ: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en
|
||||
@ -2798,6 +2824,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(psr_fops, psr_get, NULL, "%llu\n");
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(psr_residency_fops, psr_read_residency, NULL,
|
||||
"%llu\n");
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(allow_edp_hotplug_detection_fops,
|
||||
allow_edp_hotplug_detection_get,
|
||||
allow_edp_hotplug_detection_set, "%llu\n");
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(current_backlight);
|
||||
DEFINE_SHOW_ATTRIBUTE(target_backlight);
|
||||
|
||||
@ -2968,6 +2998,8 @@ void connector_debugfs_init(struct amdgpu_dm_connector *connector)
|
||||
&target_backlight_fops);
|
||||
debugfs_create_file("ilr_setting", 0644, dir, connector,
|
||||
&edp_ilr_debugfs_fops);
|
||||
debugfs_create_file("allow_edp_hotplug_detection", 0644, dir, connector,
|
||||
&allow_edp_hotplug_detection_fops);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(connector_debugfs_entries); i++) {
|
||||
|
@ -44,9 +44,6 @@
|
||||
#include "dm_helpers.h"
|
||||
#include "ddc_service_types.h"
|
||||
|
||||
/* MST Dock */
|
||||
static const uint8_t SYNAPTICS_DEVICE_ID[] = "SYNA";
|
||||
|
||||
/* dm_helpers_parse_edid_caps
|
||||
*
|
||||
* Parse edid caps
|
||||
@ -702,6 +699,9 @@ static void apply_synaptics_fifo_reset_wa(struct drm_dp_aux *aux)
|
||||
DC_LOG_DC("Done apply_synaptics_fifo_reset_wa\n");
|
||||
}
|
||||
|
||||
/* MST Dock */
|
||||
static const uint8_t SYNAPTICS_DEVICE_ID[] = "SYNA";
|
||||
|
||||
static uint8_t write_dsc_enable_synaptics_non_virtual_dpcd_mst(
|
||||
struct drm_dp_aux *aux,
|
||||
const struct dc_stream_state *stream,
|
||||
|
@ -1296,7 +1296,7 @@ static void disable_vbios_mode_if_required(
|
||||
|
||||
if (pix_clk_100hz != requested_pix_clk_100hz) {
|
||||
dc->link_srv->set_dpms_off(pipe);
|
||||
pipe->stream->dpms_off = true;
|
||||
pipe->stream->dpms_off = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3480,23 +3480,21 @@ static void build_dmub_update_dirty_rect(
|
||||
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* build_dmub_cmd_list: Build an array of DMCUB commands to be sent to DMCUB
|
||||
* build_dmub_cmd_list() - Build an array of DMCUB commands to be sent to DMCUB
|
||||
*
|
||||
* @param [in]: dc: Current DC state
|
||||
* @param [in]: srf_updates: Array of surface updates
|
||||
* @param [in]: surface_count: Number of surfaces that have an updated
|
||||
* @param [in]: stream: Correponding stream to be updated in the current flip
|
||||
* @param [in]: context: New DC state to be programmed
|
||||
* @dc: Current DC state
|
||||
* @srf_updates: Array of surface updates
|
||||
* @surface_count: Number of surfaces that have an updated
|
||||
* @stream: Corresponding stream to be updated in the current flip
|
||||
* @context: New DC state to be programmed
|
||||
*
|
||||
* @param [out]: dc_dmub_cmd: Array of DMCUB commands to be sent to DMCUB
|
||||
* @param [out]: dmub_cmd_count: Count indicating the number of DMCUB commands in dc_dmub_cmd array
|
||||
* @dc_dmub_cmd: Array of DMCUB commands to be sent to DMCUB
|
||||
* @dmub_cmd_count: Count indicating the number of DMCUB commands in dc_dmub_cmd array
|
||||
*
|
||||
* This function builds an array of DMCUB commands to be sent to DMCUB. This function is required
|
||||
* to build an array of commands and have them sent while the OTG lock is acquired.
|
||||
*
|
||||
* @return: void
|
||||
* ************************************************************************************************
|
||||
* Return: void
|
||||
*/
|
||||
static void build_dmub_cmd_list(struct dc *dc,
|
||||
struct dc_surface_update *srf_updates,
|
||||
@ -4201,20 +4199,18 @@ static bool commit_minimal_transition_state(struct dc *dc,
|
||||
}
|
||||
|
||||
/**
|
||||
* *******************************************************************************
|
||||
* update_seamless_boot_flags: Helper function for updating seamless boot flags
|
||||
* update_seamless_boot_flags() - Helper function for updating seamless boot flags
|
||||
*
|
||||
* @param [in]: dc: Current DC state
|
||||
* @param [in]: context: New DC state to be programmed
|
||||
* @param [in]: surface_count: Number of surfaces that have an updated
|
||||
* @param [in]: stream: Correponding stream to be updated in the current flip
|
||||
* @dc: Current DC state
|
||||
* @context: New DC state to be programmed
|
||||
* @surface_count: Number of surfaces that have an updated
|
||||
* @stream: Corresponding stream to be updated in the current flip
|
||||
*
|
||||
* Updating seamless boot flags do not need to be part of the commit sequence. This
|
||||
* helper function will update the seamless boot flags on each flip (if required)
|
||||
* outside of the HW commit sequence (fast or slow).
|
||||
*
|
||||
* @return: void
|
||||
* *******************************************************************************
|
||||
* Return: void
|
||||
*/
|
||||
static void update_seamless_boot_flags(struct dc *dc,
|
||||
struct dc_state *context,
|
||||
|
@ -562,6 +562,29 @@ void hwss_build_fast_sequence(struct dc *dc,
|
||||
(*num_steps)++;
|
||||
}
|
||||
|
||||
if (current_mpc_pipe->stream->update_flags.bits.out_csc) {
|
||||
block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.mpc = dc->res_pool->mpc;
|
||||
block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
|
||||
block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.power_on = true;
|
||||
block_sequence[*num_steps].func = MPC_POWER_ON_MPC_MEM_PWR;
|
||||
(*num_steps)++;
|
||||
|
||||
if (current_mpc_pipe->stream->csc_color_matrix.enable_adjustment == true) {
|
||||
block_sequence[*num_steps].params.set_output_csc_params.mpc = dc->res_pool->mpc;
|
||||
block_sequence[*num_steps].params.set_output_csc_params.opp_id = current_mpc_pipe->stream_res.opp->inst;
|
||||
block_sequence[*num_steps].params.set_output_csc_params.regval = current_mpc_pipe->stream->csc_color_matrix.matrix;
|
||||
block_sequence[*num_steps].params.set_output_csc_params.ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
|
||||
block_sequence[*num_steps].func = MPC_SET_OUTPUT_CSC;
|
||||
(*num_steps)++;
|
||||
} else {
|
||||
block_sequence[*num_steps].params.set_ocsc_default_params.mpc = dc->res_pool->mpc;
|
||||
block_sequence[*num_steps].params.set_ocsc_default_params.opp_id = current_mpc_pipe->stream_res.opp->inst;
|
||||
block_sequence[*num_steps].params.set_ocsc_default_params.color_space = current_mpc_pipe->stream->output_color_space;
|
||||
block_sequence[*num_steps].params.set_ocsc_default_params.ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
|
||||
block_sequence[*num_steps].func = MPC_SET_OCSC_DEFAULT;
|
||||
(*num_steps)++;
|
||||
}
|
||||
}
|
||||
current_mpc_pipe = current_mpc_pipe->bottom_pipe;
|
||||
}
|
||||
current_pipe = current_pipe->next_odm_pipe;
|
||||
@ -661,6 +684,15 @@ void hwss_execute_sequence(struct dc *dc,
|
||||
params->update_visual_confirm_params.pipe_ctx,
|
||||
params->update_visual_confirm_params.mpcc_id);
|
||||
break;
|
||||
case MPC_POWER_ON_MPC_MEM_PWR:
|
||||
hwss_power_on_mpc_mem_pwr(params);
|
||||
break;
|
||||
case MPC_SET_OUTPUT_CSC:
|
||||
hwss_set_output_csc(params);
|
||||
break;
|
||||
case MPC_SET_OCSC_DEFAULT:
|
||||
hwss_set_ocsc_default(params);
|
||||
break;
|
||||
case DMUB_SEND_DMCUB_CMD:
|
||||
hwss_send_dmcub_cmd(params);
|
||||
break;
|
||||
@ -718,6 +750,44 @@ void hwss_program_bias_and_scale(union block_sequence_params *params)
|
||||
dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
|
||||
}
|
||||
|
||||
void hwss_power_on_mpc_mem_pwr(union block_sequence_params *params)
|
||||
{
|
||||
struct mpc *mpc = params->power_on_mpc_mem_pwr_params.mpc;
|
||||
int mpcc_id = params->power_on_mpc_mem_pwr_params.mpcc_id;
|
||||
bool power_on = params->power_on_mpc_mem_pwr_params.power_on;
|
||||
|
||||
if (mpc->funcs->power_on_mpc_mem_pwr)
|
||||
mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, power_on);
|
||||
}
|
||||
|
||||
void hwss_set_output_csc(union block_sequence_params *params)
|
||||
{
|
||||
struct mpc *mpc = params->set_output_csc_params.mpc;
|
||||
int opp_id = params->set_output_csc_params.opp_id;
|
||||
const uint16_t *matrix = params->set_output_csc_params.regval;
|
||||
enum mpc_output_csc_mode ocsc_mode = params->set_output_csc_params.ocsc_mode;
|
||||
|
||||
if (mpc->funcs->set_output_csc != NULL)
|
||||
mpc->funcs->set_output_csc(mpc,
|
||||
opp_id,
|
||||
matrix,
|
||||
ocsc_mode);
|
||||
}
|
||||
|
||||
void hwss_set_ocsc_default(union block_sequence_params *params)
|
||||
{
|
||||
struct mpc *mpc = params->set_ocsc_default_params.mpc;
|
||||
int opp_id = params->set_ocsc_default_params.opp_id;
|
||||
enum dc_color_space colorspace = params->set_ocsc_default_params.color_space;
|
||||
enum mpc_output_csc_mode ocsc_mode = params->set_ocsc_default_params.ocsc_mode;
|
||||
|
||||
if (mpc->funcs->set_ocsc_default != NULL)
|
||||
mpc->funcs->set_ocsc_default(mpc,
|
||||
opp_id,
|
||||
colorspace,
|
||||
ocsc_mode);
|
||||
}
|
||||
|
||||
void get_mclk_switch_visual_confirm_color(
|
||||
struct dc *dc,
|
||||
struct dc_state *context,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-14 Advanced Micro Devices, Inc.
|
||||
* Copyright 2012-2023 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"),
|
||||
@ -45,7 +45,7 @@ struct aux_payload;
|
||||
struct set_config_cmd_payload;
|
||||
struct dmub_notification;
|
||||
|
||||
#define DC_VER "3.2.237"
|
||||
#define DC_VER "3.2.239"
|
||||
|
||||
#define MAX_SURFACES 3
|
||||
#define MAX_PLANES 6
|
||||
@ -60,7 +60,9 @@ struct dc_versions {
|
||||
};
|
||||
|
||||
enum dp_protocol_version {
|
||||
DP_VERSION_1_4,
|
||||
DP_VERSION_1_4 = 0,
|
||||
DP_VERSION_2_1,
|
||||
DP_VERSION_UNKNOWN,
|
||||
};
|
||||
|
||||
enum dc_plane_type {
|
||||
@ -264,6 +266,7 @@ struct dc_caps {
|
||||
uint16_t subvp_pstate_allow_width_us;
|
||||
uint16_t subvp_vertical_int_margin_us;
|
||||
bool seamless_odm;
|
||||
uint32_t max_v_total;
|
||||
uint8_t subvp_drr_vblank_start_margin_us;
|
||||
};
|
||||
|
||||
|
@ -61,7 +61,7 @@ enum dc_link_rate {
|
||||
*/
|
||||
LINK_RATE_UHBR10 = 1000, // UHBR10 - 10.0 Gbps/Lane
|
||||
LINK_RATE_UHBR13_5 = 1350, // UHBR13.5 - 13.5 Gbps/Lane
|
||||
LINK_RATE_UHBR20 = 2000, // UHBR10 - 20.0 Gbps/Lane
|
||||
LINK_RATE_UHBR20 = 2000, // UHBR20 - 20.0 Gbps/Lane
|
||||
};
|
||||
|
||||
enum dc_link_spread {
|
||||
|
@ -597,6 +597,7 @@ enum dc_psr_state {
|
||||
PSR_STATE4b_FULL_FRAME,
|
||||
PSR_STATE4c_FULL_FRAME,
|
||||
PSR_STATE4_FULL_FRAME_POWERUP,
|
||||
PSR_STATE4_FULL_FRAME_HW_LOCK,
|
||||
PSR_STATE5,
|
||||
PSR_STATE5a,
|
||||
PSR_STATE5b,
|
||||
|
@ -87,6 +87,8 @@ static enum dc_psr_state convert_psr_state(uint32_t raw_state)
|
||||
state = PSR_STATE4c_FULL_FRAME;
|
||||
else if (raw_state == 0x4E)
|
||||
state = PSR_STATE4_FULL_FRAME_POWERUP;
|
||||
else if (raw_state == 0x4F)
|
||||
state = PSR_STATE4_FULL_FRAME_HW_LOCK;
|
||||
else if (raw_state == 0x60)
|
||||
state = PSR_STATE_HWLOCK_MGR;
|
||||
else if (raw_state == 0x61)
|
||||
|
@ -37,14 +37,14 @@
|
||||
#define CTX \
|
||||
oppn10->base.ctx
|
||||
|
||||
|
||||
/************* FORMATTER ************/
|
||||
|
||||
/**
|
||||
* set_truncation
|
||||
* opp1_set_truncation():
|
||||
* 1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
|
||||
* 2) enable truncation
|
||||
* 3) HW remove 12bit FMT support for DCE11 power saving reason.
|
||||
*
|
||||
* @oppn10: output_pixel_processor struct instance for dcn10.
|
||||
* @params: pointer to bit_depth_reduction_params.
|
||||
*/
|
||||
static void opp1_set_truncation(
|
||||
struct dcn10_opp *oppn10,
|
||||
@ -149,11 +149,12 @@ void opp1_program_bit_depth_reduction(
|
||||
}
|
||||
|
||||
/**
|
||||
* set_pixel_encoding
|
||||
*
|
||||
* Set Pixel Encoding
|
||||
* opp1_set_pixel_encoding():
|
||||
* 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
|
||||
* 1: YCbCr 4:2:2
|
||||
*
|
||||
* @oppn10: output_pixel_processor struct instance for dcn10.
|
||||
* @params: pointer to clamping_and_pixel_encoding_params.
|
||||
*/
|
||||
static void opp1_set_pixel_encoding(
|
||||
struct dcn10_opp *oppn10,
|
||||
@ -180,13 +181,16 @@ static void opp1_set_pixel_encoding(
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Clamping
|
||||
* opp1_set_clamping():
|
||||
* 1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
|
||||
* 1 for 8 bpc
|
||||
* 2 for 10 bpc
|
||||
* 3 for 12 bpc
|
||||
* 7 for programable
|
||||
* 2) Enable clamp if Limited range requested
|
||||
*
|
||||
* @oppn10: output_pixel_processor struct instance for dcn10.
|
||||
* @params: pointer to clamping_and_pixel_encoding_params.
|
||||
*/
|
||||
static void opp1_set_clamping(
|
||||
struct dcn10_opp *oppn10,
|
||||
|
@ -42,11 +42,13 @@
|
||||
#define STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN 0x100
|
||||
|
||||
/**
|
||||
* apply_front_porch_workaround TODO FPGA still need?
|
||||
*
|
||||
* This is a workaround for a bug that has existed since R5xx and has not been
|
||||
* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
|
||||
*/
|
||||
* apply_front_porch_workaround() - This is a workaround for a bug that has
|
||||
* existed since R5xx and has not been fixed
|
||||
* keep Front porch at minimum 2 for Interlaced
|
||||
* mode or 1 for progressive.
|
||||
*
|
||||
* @timing: Timing parameters used to configure DCN blocks.
|
||||
*/
|
||||
static void apply_front_porch_workaround(struct dc_crtc_timing *timing)
|
||||
{
|
||||
if (timing->flags.INTERLACE == 1) {
|
||||
@ -133,9 +135,20 @@ void optc1_setup_vertical_interrupt2(
|
||||
}
|
||||
|
||||
/**
|
||||
* program_timing_generator used by mode timing set
|
||||
* Program CRTC Timing Registers - OTG_H_*, OTG_V_*, Pixel repetition.
|
||||
* Including SYNC. Call BIOS command table to program Timings.
|
||||
* optc1_program_timing() - used by mode timing set Program
|
||||
* CRTC Timing Registers - OTG_H_*,
|
||||
* OTG_V_*, Pixel repetition.
|
||||
* Including SYNC. Call BIOS command table to program Timings.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
* @dc_crtc_timing: Timing parameters used to configure DCN blocks.
|
||||
* @vready_offset: Vready's starting position.
|
||||
* @vstartup_start: Vstartup period.
|
||||
* @vupdate_offset: Vupdate starting position.
|
||||
* @vupdate_width: Vupdate duration.
|
||||
* @signal: DC signal types.
|
||||
* @use_vbios: to program timings from BIOS command table.
|
||||
*
|
||||
*/
|
||||
void optc1_program_timing(
|
||||
struct timing_generator *optc,
|
||||
@ -385,6 +398,9 @@ void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enab
|
||||
* Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN,
|
||||
* VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
* @enable: Enable DRR double buffering control if true, disable otherwise.
|
||||
*
|
||||
* Options: any time, start of frame, dp start of frame (range timing)
|
||||
*/
|
||||
void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable)
|
||||
@ -397,8 +413,9 @@ void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable)
|
||||
}
|
||||
|
||||
/**
|
||||
* unblank_crtc
|
||||
* Call ASIC Control Object to UnBlank CRTC.
|
||||
* optc1_unblank_crtc() - Call ASIC Control Object to UnBlank CRTC.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
*/
|
||||
static void optc1_unblank_crtc(struct timing_generator *optc)
|
||||
{
|
||||
@ -419,8 +436,9 @@ static void optc1_unblank_crtc(struct timing_generator *optc)
|
||||
}
|
||||
|
||||
/**
|
||||
* blank_crtc
|
||||
* Call ASIC Control Object to Blank CRTC.
|
||||
* optc1_blank_crtc() - Call ASIC Control Object to Blank CRTC.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
*/
|
||||
|
||||
static void optc1_blank_crtc(struct timing_generator *optc)
|
||||
@ -493,8 +511,9 @@ void optc1_enable_optc_clock(struct timing_generator *optc, bool enable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable CRTC
|
||||
* Enable CRTC - call ASIC Control Object to enable Timing generator.
|
||||
* optc1_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
*/
|
||||
static bool optc1_enable_crtc(struct timing_generator *optc)
|
||||
{
|
||||
@ -890,15 +909,11 @@ static void optc1_program_manual_trigger(struct timing_generator *optc)
|
||||
MANUAL_FLOW_CONTROL, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* Function: set_drr
|
||||
* optc1_set_drr() - Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*.
|
||||
*
|
||||
* @brief
|
||||
* Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*.
|
||||
*
|
||||
*****************************************************************************
|
||||
* @optc: timing_generator instance.
|
||||
* @params: parameters used for Dynamic Refresh Rate.
|
||||
*/
|
||||
void optc1_set_drr(
|
||||
struct timing_generator *optc,
|
||||
|
@ -1741,17 +1741,6 @@ static void dcn20_program_pipe(
|
||||
|
||||
if (hws->funcs.setup_vupdate_interrupt)
|
||||
hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
|
||||
|
||||
if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
|
||||
unsigned int k1_div, k2_div;
|
||||
|
||||
hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
|
||||
|
||||
dc->res_pool->dccg->funcs->set_pixel_rate_div(
|
||||
dc->res_pool->dccg,
|
||||
pipe_ctx->stream_res.tg->inst,
|
||||
k1_div, k2_div);
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe_ctx->update_flags.bits.odm)
|
||||
|
@ -279,6 +279,9 @@ static void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, in
|
||||
* Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN,
|
||||
* VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
* @enable: Enable DRR double buffering control if true, disable otherwise.
|
||||
*
|
||||
* Options: any time, start of frame, dp start of frame (range timing)
|
||||
*/
|
||||
static void optc3_set_timing_double_buffer(struct timing_generator *optc, bool enable)
|
||||
|
@ -2328,6 +2328,7 @@ static bool dcn30_resource_construct(
|
||||
dc->caps.color.mpc.ocsc = 1;
|
||||
|
||||
dc->caps.dp_hdmi21_pcon_support = true;
|
||||
dc->caps.max_v_total = (1 << 15) - 1;
|
||||
|
||||
/* read VBIOS LTTPR caps */
|
||||
{
|
||||
|
@ -1227,6 +1227,7 @@ static bool dcn302_resource_construct(
|
||||
dc->caps.force_dp_tps4_for_cp2520 = true;
|
||||
dc->caps.extended_aux_timeout_support = true;
|
||||
dc->caps.dmcub_support = true;
|
||||
dc->caps.max_v_total = (1 << 15) - 1;
|
||||
|
||||
/* Color pipeline capabilities */
|
||||
dc->caps.color.dpp.dcn_arch = 1;
|
||||
|
@ -1152,6 +1152,7 @@ static bool dcn303_resource_construct(
|
||||
dc->caps.force_dp_tps4_for_cp2520 = true;
|
||||
dc->caps.extended_aux_timeout_support = true;
|
||||
dc->caps.dmcub_support = true;
|
||||
dc->caps.max_v_total = (1 << 15) - 1;
|
||||
|
||||
/* Color pipeline capabilities */
|
||||
dc->caps.color.dpp.dcn_arch = 1;
|
||||
|
@ -47,6 +47,14 @@ void dccg31_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk)
|
||||
{
|
||||
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
|
||||
|
||||
if (dccg->dpp_clock_gated[dpp_inst]) {
|
||||
/*
|
||||
* Do not update the DPPCLK DTO if the clock is stopped.
|
||||
* It is treated the same as if the pipe itself were in PG.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (dccg->ref_dppclk && req_dppclk) {
|
||||
int ref_dppclk = dccg->ref_dppclk;
|
||||
int modulo, phase;
|
||||
|
@ -332,6 +332,9 @@ static void dccg314_dpp_root_clock_control(
|
||||
{
|
||||
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
|
||||
|
||||
if (dccg->dpp_clock_gated[dpp_inst] == clock_on)
|
||||
return;
|
||||
|
||||
if (clock_on) {
|
||||
/* turn off the DTO and leave phase/modulo at max */
|
||||
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 0);
|
||||
@ -345,6 +348,8 @@ static void dccg314_dpp_root_clock_control(
|
||||
DPPCLK0_DTO_PHASE, 0,
|
||||
DPPCLK0_DTO_MODULO, 1);
|
||||
}
|
||||
|
||||
dccg->dpp_clock_gated[dpp_inst] = !clock_on;
|
||||
}
|
||||
|
||||
static const struct dccg_funcs dccg314_funcs = {
|
||||
|
@ -337,14 +337,13 @@ void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable)
|
||||
REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
|
||||
}
|
||||
|
||||
unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
|
||||
void dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
|
||||
{
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
unsigned int odm_combine_factor = 0;
|
||||
bool two_pix_per_container = false;
|
||||
|
||||
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
|
||||
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
|
||||
get_odm_config(pipe_ctx, NULL);
|
||||
|
||||
if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
|
||||
*k1_div = PIXEL_RATE_DIV_BY_1;
|
||||
@ -362,15 +361,11 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
|
||||
} else {
|
||||
*k1_div = PIXEL_RATE_DIV_BY_1;
|
||||
*k2_div = PIXEL_RATE_DIV_BY_4;
|
||||
if (odm_combine_factor == 2)
|
||||
*k2_div = PIXEL_RATE_DIV_BY_2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA))
|
||||
ASSERT(false);
|
||||
|
||||
return odm_combine_factor;
|
||||
}
|
||||
|
||||
void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
|
||||
|
@ -37,7 +37,7 @@ void dcn314_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool po
|
||||
|
||||
void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable);
|
||||
|
||||
unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
|
||||
void dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
|
||||
|
||||
void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx);
|
||||
|
||||
|
@ -874,8 +874,8 @@ static const struct dc_debug_options debug_defaults_drv = {
|
||||
.force_abm_enable = false,
|
||||
.timing_trace = false,
|
||||
.clock_trace = true,
|
||||
.disable_dpp_power_gate = true,
|
||||
.disable_hubp_power_gate = true,
|
||||
.disable_dpp_power_gate = false,
|
||||
.disable_hubp_power_gate = false,
|
||||
.disable_pplib_clock_request = false,
|
||||
.pipe_split_policy = MPC_SPLIT_DYNAMIC,
|
||||
.force_single_disp_pipe_split = false,
|
||||
@ -904,6 +904,22 @@ static const struct dc_debug_options debug_defaults_drv = {
|
||||
.afmt = true,
|
||||
}
|
||||
},
|
||||
|
||||
.root_clock_optimization = {
|
||||
.bits = {
|
||||
.dpp = true,
|
||||
.dsc = false,
|
||||
.hdmistream = false,
|
||||
.hdmichar = false,
|
||||
.dpstream = false,
|
||||
.symclk32_se = false,
|
||||
.symclk32_le = false,
|
||||
.symclk_fe = false,
|
||||
.physymclk = false,
|
||||
.dpiasymclk = false,
|
||||
}
|
||||
},
|
||||
|
||||
.seamless_boot_odm_combine = true
|
||||
};
|
||||
|
||||
@ -1867,6 +1883,13 @@ static bool dcn314_resource_construct(
|
||||
/* Use pipe context based otg sync logic */
|
||||
dc->config.use_pipe_ctx_sync_logic = true;
|
||||
|
||||
/* Disable pipe power gating when unsupported */
|
||||
if (ctx->asic_id.hw_internal_rev == 0x01 ||
|
||||
ctx->asic_id.hw_internal_rev == 0x80) {
|
||||
dc->debug.disable_dpp_power_gate = true;
|
||||
dc->debug.disable_hubp_power_gate = true;
|
||||
}
|
||||
|
||||
/* read VBIOS LTTPR caps */
|
||||
{
|
||||
if (ctx->dc_bios->funcs->get_lttpr_caps) {
|
||||
|
@ -1742,6 +1742,7 @@ static int dcn315_populate_dml_pipes_from_context(
|
||||
/* Do not use asymetric crb if not enough for pstate support */
|
||||
if (remaining_det_segs < 0) {
|
||||
pipes[pipe_cnt].pipe.src.det_size_override = 0;
|
||||
pipe_cnt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1141,10 +1141,9 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
|
||||
void dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
|
||||
{
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
unsigned int odm_combine_factor = 0;
|
||||
bool two_pix_per_container = false;
|
||||
|
||||
// For phantom pipes, use the same programming as the main pipes
|
||||
@ -1152,7 +1151,6 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
|
||||
stream = pipe_ctx->stream->mall_stream_config.paired_stream;
|
||||
}
|
||||
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
|
||||
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
|
||||
|
||||
if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
|
||||
*k1_div = PIXEL_RATE_DIV_BY_1;
|
||||
@ -1170,15 +1168,13 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
|
||||
} else {
|
||||
*k1_div = PIXEL_RATE_DIV_BY_1;
|
||||
*k2_div = PIXEL_RATE_DIV_BY_4;
|
||||
if ((odm_combine_factor == 2) || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
|
||||
if (dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
|
||||
*k2_div = PIXEL_RATE_DIV_BY_2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA))
|
||||
ASSERT(false);
|
||||
|
||||
return odm_combine_factor;
|
||||
}
|
||||
|
||||
void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
|
||||
@ -1211,7 +1207,8 @@ void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_
|
||||
if (pipe->top_pipe || pipe->prev_odm_pipe)
|
||||
continue;
|
||||
|
||||
if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) {
|
||||
if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))
|
||||
&& pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
|
||||
pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg);
|
||||
reset_sync_context_for_pipe(dc, context, i);
|
||||
otg_disabled[i] = true;
|
||||
|
@ -71,7 +71,7 @@ void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context);
|
||||
|
||||
void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx);
|
||||
|
||||
unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
|
||||
void dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
|
||||
|
||||
void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx);
|
||||
|
||||
|
@ -106,8 +106,11 @@ void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool man
|
||||
OTG_H_TIMING_DIV_MODE_MANUAL, manual_mode ? 1 : 0);
|
||||
}
|
||||
/**
|
||||
* Enable CRTC
|
||||
* Enable CRTC - call ASIC Control Object to enable Timing generator.
|
||||
* optc32_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator.
|
||||
*
|
||||
* @optc: timing_generator instance.
|
||||
*
|
||||
* Return: If CRTC is enabled, return true.
|
||||
*/
|
||||
static bool optc32_enable_crtc(struct timing_generator *optc)
|
||||
{
|
||||
|
@ -728,7 +728,7 @@ static const struct dc_debug_options debug_defaults_drv = {
|
||||
.fpo_vactive_margin_us = 2000, // 2000us
|
||||
.disable_fpo_vactive = false,
|
||||
.disable_boot_optimizations = false,
|
||||
.disable_subvp_high_refresh = true,
|
||||
.disable_subvp_high_refresh = false,
|
||||
.disable_dp_plus_plus_wa = true,
|
||||
.fpo_vactive_min_active_margin_us = 200,
|
||||
.fpo_vactive_max_blank_us = 1000,
|
||||
@ -2175,6 +2175,7 @@ static bool dcn32_resource_construct(
|
||||
dc->caps.extended_aux_timeout_support = true;
|
||||
dc->caps.dmcub_support = true;
|
||||
dc->caps.seamless_odm = true;
|
||||
dc->caps.max_v_total = (1 << 15) - 1;
|
||||
|
||||
/* Color pipeline capabilities */
|
||||
dc->caps.color.dpp.dcn_arch = 1;
|
||||
|
@ -169,6 +169,10 @@ double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *conte
|
||||
|
||||
bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int width, unsigned int height);
|
||||
|
||||
bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context);
|
||||
|
||||
bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int vlevel);
|
||||
|
||||
/* definitions for run time init of reg offsets */
|
||||
|
||||
/* CLK SRC */
|
||||
|
@ -255,8 +255,6 @@ bool dcn32_is_psr_capable(struct pipe_ctx *pipe)
|
||||
return psr_capable;
|
||||
}
|
||||
|
||||
#define DCN3_2_NEW_DET_OVERRIDE_MIN_MULTIPLIER 7
|
||||
|
||||
/**
|
||||
* dcn32_determine_det_override(): Determine DET allocation for each pipe
|
||||
*
|
||||
@ -267,6 +265,7 @@ bool dcn32_is_psr_capable(struct pipe_ctx *pipe)
|
||||
* If there is a plane that's driven by more than 1 pipe (i.e. pipe split), then the
|
||||
* number of DET for that given plane will be split among the pipes driving that plane.
|
||||
*
|
||||
*
|
||||
* High level algorithm:
|
||||
* 1. Split total DET among number of streams
|
||||
* 2. For each stream, split DET among the planes
|
||||
@ -274,18 +273,6 @@ bool dcn32_is_psr_capable(struct pipe_ctx *pipe)
|
||||
* among those pipes.
|
||||
* 4. Assign the DET override to the DML pipes.
|
||||
*
|
||||
* Special cases:
|
||||
*
|
||||
* For two displays that have a large difference in pixel rate, we may experience
|
||||
* underflow on the larger display when we divide the DET equally. For this, we
|
||||
* will implement a modified algorithm to assign more DET to larger display.
|
||||
*
|
||||
* 1. Calculate difference in pixel rates ( multiplier ) between two displays
|
||||
* 2. If the multiplier exceeds DCN3_2_NEW_DET_OVERRIDE_MIN_MULTIPLIER, then
|
||||
* implement the modified DET override algorithm.
|
||||
* 3. Assign smaller DET size for lower pixel display and higher DET size for
|
||||
* higher pixel display
|
||||
*
|
||||
* @dc: Current DC state
|
||||
* @context: New DC state to be programmed
|
||||
* @pipes: Array of DML pipes
|
||||
@ -303,31 +290,10 @@ void dcn32_determine_det_override(struct dc *dc,
|
||||
struct dc_plane_state *current_plane = NULL;
|
||||
uint8_t stream_count = 0;
|
||||
|
||||
int phy_pix_clk_mult, lower_mode_stream_index;
|
||||
int phy_pix_clk[MAX_PIPES] = {0};
|
||||
bool use_new_det_override_algorithm = false;
|
||||
|
||||
for (i = 0; i < context->stream_count; i++) {
|
||||
/* Don't count SubVP streams for DET allocation */
|
||||
if (context->streams[i]->mall_stream_config.type != SUBVP_PHANTOM) {
|
||||
phy_pix_clk[i] = context->streams[i]->phy_pix_clk;
|
||||
if (context->streams[i]->mall_stream_config.type != SUBVP_PHANTOM)
|
||||
stream_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for special case with two displays, one with much higher pixel rate */
|
||||
if (stream_count == 2) {
|
||||
ASSERT((phy_pix_clk[0] > 0) && (phy_pix_clk[1] > 0));
|
||||
if (phy_pix_clk[0] < phy_pix_clk[1]) {
|
||||
lower_mode_stream_index = 0;
|
||||
phy_pix_clk_mult = phy_pix_clk[1] / phy_pix_clk[0];
|
||||
} else {
|
||||
lower_mode_stream_index = 1;
|
||||
phy_pix_clk_mult = phy_pix_clk[0] / phy_pix_clk[1];
|
||||
}
|
||||
|
||||
if (phy_pix_clk_mult >= DCN3_2_NEW_DET_OVERRIDE_MIN_MULTIPLIER)
|
||||
use_new_det_override_algorithm = true;
|
||||
}
|
||||
|
||||
if (stream_count > 0) {
|
||||
@ -336,13 +302,6 @@ void dcn32_determine_det_override(struct dc *dc,
|
||||
if (context->streams[i]->mall_stream_config.type == SUBVP_PHANTOM)
|
||||
continue;
|
||||
|
||||
if (use_new_det_override_algorithm) {
|
||||
if (i == lower_mode_stream_index)
|
||||
stream_segments = 4;
|
||||
else
|
||||
stream_segments = 14;
|
||||
}
|
||||
|
||||
if (context->stream_status[i].plane_count > 0)
|
||||
plane_segments = stream_segments / context->stream_status[i].plane_count;
|
||||
else
|
||||
@ -660,3 +619,105 @@ bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int widt
|
||||
|
||||
return is_native_scaling;
|
||||
}
|
||||
|
||||
/**
|
||||
* dcn32_subvp_drr_admissable() - Determine if SubVP + DRR config is admissible
|
||||
*
|
||||
* @dc: Current DC state
|
||||
* @context: New DC state to be programmed
|
||||
*
|
||||
* SubVP + DRR is admissible under the following conditions:
|
||||
* - Config must have 2 displays (i.e., 2 non-phantom master pipes)
|
||||
* - One display is SubVP
|
||||
* - Other display must have Freesync enabled
|
||||
* - The potential DRR display must not be PSR capable
|
||||
*
|
||||
* Return: True if admissible, false otherwise
|
||||
*/
|
||||
bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context)
|
||||
{
|
||||
bool result = false;
|
||||
uint32_t i;
|
||||
uint8_t subvp_count = 0;
|
||||
uint8_t non_subvp_pipes = 0;
|
||||
bool drr_pipe_found = false;
|
||||
bool drr_psr_capable = false;
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (!pipe->stream)
|
||||
continue;
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe) {
|
||||
if (pipe->stream->mall_stream_config.type == SUBVP_MAIN)
|
||||
subvp_count++;
|
||||
if (pipe->stream->mall_stream_config.type == SUBVP_NONE) {
|
||||
non_subvp_pipes++;
|
||||
drr_psr_capable = (drr_psr_capable || dcn32_is_psr_capable(pipe));
|
||||
if (pipe->stream->ignore_msa_timing_param &&
|
||||
(pipe->stream->allow_freesync || pipe->stream->vrr_active_variable)) {
|
||||
drr_pipe_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subvp_count == 1 && non_subvp_pipes == 1 && drr_pipe_found && !drr_psr_capable)
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* dcn32_subvp_vblank_admissable() - Determine if SubVP + Vblank config is admissible
|
||||
*
|
||||
* @dc: Current DC state
|
||||
* @context: New DC state to be programmed
|
||||
* @vlevel: Voltage level calculated by DML
|
||||
*
|
||||
* SubVP + Vblank is admissible under the following conditions:
|
||||
* - Config must have 2 displays (i.e., 2 non-phantom master pipes)
|
||||
* - One display is SubVP
|
||||
* - Other display must not have Freesync capability
|
||||
* - DML must have output DRAM clock change support as SubVP + Vblank
|
||||
* - The potential vblank display must not be PSR capable
|
||||
*
|
||||
* Return: True if admissible, false otherwise
|
||||
*/
|
||||
bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int vlevel)
|
||||
{
|
||||
bool result = false;
|
||||
uint32_t i;
|
||||
uint8_t subvp_count = 0;
|
||||
uint8_t non_subvp_pipes = 0;
|
||||
bool drr_pipe_found = false;
|
||||
struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
|
||||
bool vblank_psr_capable = false;
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (!pipe->stream)
|
||||
continue;
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe) {
|
||||
if (pipe->stream->mall_stream_config.type == SUBVP_MAIN)
|
||||
subvp_count++;
|
||||
if (pipe->stream->mall_stream_config.type == SUBVP_NONE) {
|
||||
non_subvp_pipes++;
|
||||
vblank_psr_capable = (vblank_psr_capable || dcn32_is_psr_capable(pipe));
|
||||
if (pipe->stream->ignore_msa_timing_param &&
|
||||
(pipe->stream->allow_freesync || pipe->stream->vrr_active_variable)) {
|
||||
drr_pipe_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subvp_count == 1 && non_subvp_pipes == 1 && !drr_pipe_found && !vblank_psr_capable &&
|
||||
vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vblank_w_mall_sub_vp)
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -727,7 +727,7 @@ static const struct dc_debug_options debug_defaults_drv = {
|
||||
.fpo_vactive_margin_us = 2000, // 2000us
|
||||
.disable_fpo_vactive = false,
|
||||
.disable_boot_optimizations = false,
|
||||
.disable_subvp_high_refresh = true,
|
||||
.disable_subvp_high_refresh = false,
|
||||
.fpo_vactive_min_active_margin_us = 200,
|
||||
.fpo_vactive_max_blank_us = 1000,
|
||||
};
|
||||
@ -1718,6 +1718,7 @@ static bool dcn321_resource_construct(
|
||||
dc->caps.edp_dsc_support = true;
|
||||
dc->caps.extended_aux_timeout_support = true;
|
||||
dc->caps.dmcub_support = true;
|
||||
dc->caps.max_v_total = (1 << 15) - 1;
|
||||
|
||||
/* Color pipeline capabilities */
|
||||
dc->caps.color.dpp.dcn_arch = 1;
|
||||
|
@ -5557,6 +5557,65 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = v->soc.num_states; i >= 0; i--) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
enum dm_validation_status status = DML_VALIDATION_OK;
|
||||
|
||||
if (!v->ScaleRatioAndTapsSupport) {
|
||||
status = DML_FAIL_SCALE_RATIO_TAP;
|
||||
} else if (!v->SourceFormatPixelAndScanSupport) {
|
||||
status = DML_FAIL_SOURCE_PIXEL_FORMAT;
|
||||
} else if (!v->ViewportSizeSupport[i][j]) {
|
||||
status = DML_FAIL_VIEWPORT_SIZE;
|
||||
} else if (P2IWith420) {
|
||||
status = DML_FAIL_P2I_WITH_420;
|
||||
} else if (DSCOnlyIfNecessaryWithBPP) {
|
||||
status = DML_FAIL_DSC_ONLY_IF_NECESSARY_WITH_BPP;
|
||||
} else if (DSC422NativeNotSupported) {
|
||||
status = DML_FAIL_NOT_DSC422_NATIVE;
|
||||
} else if (!v->ODMCombine4To1SupportCheckOK[i]) {
|
||||
status = DML_FAIL_ODM_COMBINE4TO1;
|
||||
} else if (v->NotEnoughDSCUnits[i]) {
|
||||
status = DML_FAIL_NOT_ENOUGH_DSC;
|
||||
} else if (!v->ROBSupport[i][j]) {
|
||||
status = DML_FAIL_REORDERING_BUFFER;
|
||||
} else if (!v->DISPCLK_DPPCLK_Support[i][j]) {
|
||||
status = DML_FAIL_DISPCLK_DPPCLK;
|
||||
} else if (!v->TotalAvailablePipesSupport[i][j]) {
|
||||
status = DML_FAIL_TOTAL_AVAILABLE_PIPES;
|
||||
} else if (!EnoughWritebackUnits) {
|
||||
status = DML_FAIL_ENOUGH_WRITEBACK_UNITS;
|
||||
} else if (!v->WritebackLatencySupport) {
|
||||
status = DML_FAIL_WRITEBACK_LATENCY;
|
||||
} else if (!v->WritebackScaleRatioAndTapsSupport) {
|
||||
status = DML_FAIL_WRITEBACK_SCALE_RATIO_TAP;
|
||||
} else if (!v->CursorSupport) {
|
||||
status = DML_FAIL_CURSOR_SUPPORT;
|
||||
} else if (!v->PitchSupport) {
|
||||
status = DML_FAIL_PITCH_SUPPORT;
|
||||
} else if (ViewportExceedsSurface) {
|
||||
status = DML_FAIL_VIEWPORT_EXCEEDS_SURFACE;
|
||||
} else if (!v->PrefetchSupported[i][j]) {
|
||||
status = DML_FAIL_PREFETCH_SUPPORT;
|
||||
} else if (!v->DynamicMetadataSupported[i][j]) {
|
||||
status = DML_FAIL_DYNAMIC_METADATA;
|
||||
} else if (!v->TotalVerticalActiveBandwidthSupport[i][j]) {
|
||||
status = DML_FAIL_TOTAL_V_ACTIVE_BW;
|
||||
} else if (!v->VRatioInPrefetchSupported[i][j]) {
|
||||
status = DML_FAIL_V_RATIO_PREFETCH;
|
||||
} else if (!v->PTEBufferSizeNotExceeded[i][j]) {
|
||||
status = DML_FAIL_PTE_BUFFER_SIZE;
|
||||
} else if (v->NonsupportedDSCInputBPC) {
|
||||
status = DML_FAIL_DSC_INPUT_BPC;
|
||||
} else if ((v->HostVMEnable
|
||||
&& !v->ImmediateFlipSupportedForState[i][j])) {
|
||||
status = DML_FAIL_HOST_VM_IMMEDIATE_FLIP;
|
||||
} else if (FMTBufferExceeded) {
|
||||
status = DML_FAIL_FMT_BUFFER_EXCEEDED;
|
||||
}
|
||||
mode_lib->vba.ValidationStatus[i] = status;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int MaximumMPCCombine = 0;
|
||||
|
@ -679,7 +679,6 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
|
||||
unsigned int max_frame_time = 0;
|
||||
bool valid_assignment_found = false;
|
||||
unsigned int free_pipes = dcn32_get_num_free_pipes(dc, context);
|
||||
bool current_assignment_freesync = false;
|
||||
struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
|
||||
|
||||
for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
@ -720,19 +719,10 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
|
||||
struct dc_stream_state *stream = pipe->stream;
|
||||
unsigned int frame_us = (stream->timing.v_total * stream->timing.h_total /
|
||||
(double)(stream->timing.pix_clk_100hz * 100)) * 1000000;
|
||||
if (frame_us > max_frame_time && !stream->ignore_msa_timing_param) {
|
||||
if (frame_us > max_frame_time) {
|
||||
*index = i;
|
||||
max_frame_time = frame_us;
|
||||
valid_assignment_found = true;
|
||||
current_assignment_freesync = false;
|
||||
/* For the 2-Freesync display case, still choose the one with the
|
||||
* longest frame time
|
||||
*/
|
||||
} else if (stream->ignore_msa_timing_param && (!valid_assignment_found ||
|
||||
(current_assignment_freesync && frame_us > max_frame_time))) {
|
||||
*index = i;
|
||||
valid_assignment_found = true;
|
||||
current_assignment_freesync = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -864,10 +854,9 @@ static bool subvp_subvp_schedulable(struct dc *dc, struct dc_state *context)
|
||||
}
|
||||
|
||||
/**
|
||||
* subvp_drr_schedulable - Determine if SubVP + DRR config is schedulable
|
||||
* subvp_drr_schedulable() - Determine if SubVP + DRR config is schedulable
|
||||
* @dc: current dc state
|
||||
* @context: new dc state
|
||||
* @drr_pipe: DRR pipe_ctx for the SubVP + DRR config
|
||||
*
|
||||
* High level algorithm:
|
||||
* 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe
|
||||
@ -878,11 +867,12 @@ static bool subvp_subvp_schedulable(struct dc *dc, struct dc_state *context)
|
||||
*
|
||||
* Return: True if the SubVP + DRR config is schedulable, false otherwise
|
||||
*/
|
||||
static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context, struct pipe_ctx *drr_pipe)
|
||||
static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
|
||||
{
|
||||
bool schedulable = false;
|
||||
uint32_t i;
|
||||
struct pipe_ctx *pipe = NULL;
|
||||
struct pipe_ctx *drr_pipe = NULL;
|
||||
struct dc_crtc_timing *main_timing = NULL;
|
||||
struct dc_crtc_timing *phantom_timing = NULL;
|
||||
struct dc_crtc_timing *drr_timing = NULL;
|
||||
@ -908,6 +898,19 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context, struc
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the DRR pipe
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
drr_pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
// We check for master pipe only
|
||||
if (!drr_pipe->stream || !drr_pipe->plane_state || drr_pipe->top_pipe || drr_pipe->prev_odm_pipe)
|
||||
continue;
|
||||
|
||||
if (drr_pipe->stream->mall_stream_config.type == SUBVP_NONE && drr_pipe->stream->ignore_msa_timing_param &&
|
||||
(drr_pipe->stream->allow_freesync || drr_pipe->stream->vrr_active_variable))
|
||||
break;
|
||||
}
|
||||
|
||||
main_timing = &pipe->stream->timing;
|
||||
phantom_timing = &pipe->stream->mall_stream_config.paired_stream->timing;
|
||||
drr_timing = &drr_pipe->stream->timing;
|
||||
@ -993,13 +996,7 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
|
||||
if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN)
|
||||
subvp_pipe = pipe;
|
||||
}
|
||||
// Use ignore_msa_timing_param and VRR active, or Freesync flag to identify as DRR On
|
||||
if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param &&
|
||||
(context->res_ctx.pipe_ctx[vblank_index].stream->allow_freesync ||
|
||||
context->res_ctx.pipe_ctx[vblank_index].stream->vrr_active_variable)) {
|
||||
// SUBVP + DRR case -- only allowed if run through DRR validation path
|
||||
schedulable = false;
|
||||
} else if (found) {
|
||||
if (found) {
|
||||
main_timing = &subvp_pipe->stream->timing;
|
||||
phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
|
||||
vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing;
|
||||
@ -1028,6 +1025,53 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
/**
|
||||
* subvp_subvp_admissable() - Determine if subvp + subvp config is admissible
|
||||
*
|
||||
* @dc: Current DC state
|
||||
* @context: New DC state to be programmed
|
||||
*
|
||||
* SubVP + SubVP is admissible under the following conditions:
|
||||
* - All SubVP pipes are < 120Hz OR
|
||||
* - All SubVP pipes are >= 120hz
|
||||
*
|
||||
* Return: True if admissible, false otherwise
|
||||
*/
|
||||
static bool subvp_subvp_admissable(struct dc *dc,
|
||||
struct dc_state *context)
|
||||
{
|
||||
bool result = false;
|
||||
uint32_t i;
|
||||
uint8_t subvp_count = 0;
|
||||
uint32_t min_refresh = subvp_high_refresh_list.min_refresh, max_refresh = 0;
|
||||
uint32_t refresh_rate = 0;
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (!pipe->stream)
|
||||
continue;
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe &&
|
||||
pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
|
||||
refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 +
|
||||
pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1)
|
||||
/ (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total);
|
||||
if (refresh_rate < min_refresh)
|
||||
min_refresh = refresh_rate;
|
||||
if (refresh_rate > max_refresh)
|
||||
max_refresh = refresh_rate;
|
||||
subvp_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (subvp_count == 2 && ((min_refresh < 120 && max_refresh < 120) ||
|
||||
(min_refresh >= 120 && max_refresh >= 120)))
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* subvp_validate_static_schedulability - Check which SubVP case is calculated
|
||||
* and handle static analysis based on the case.
|
||||
@ -1046,11 +1090,12 @@ static bool subvp_validate_static_schedulability(struct dc *dc,
|
||||
struct dc_state *context,
|
||||
int vlevel)
|
||||
{
|
||||
bool schedulable = true; // true by default for single display case
|
||||
bool schedulable = false;
|
||||
struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
|
||||
uint32_t i, pipe_idx;
|
||||
uint8_t subvp_count = 0;
|
||||
uint8_t vactive_count = 0;
|
||||
uint8_t non_subvp_pipes = 0;
|
||||
|
||||
for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
@ -1058,14 +1103,18 @@ static bool subvp_validate_static_schedulability(struct dc *dc,
|
||||
if (!pipe->stream)
|
||||
continue;
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe &&
|
||||
pipe->stream->mall_stream_config.type == SUBVP_MAIN)
|
||||
subvp_count++;
|
||||
if (pipe->plane_state && !pipe->top_pipe) {
|
||||
if (pipe->stream->mall_stream_config.type == SUBVP_MAIN)
|
||||
subvp_count++;
|
||||
if (pipe->stream->mall_stream_config.type == SUBVP_NONE) {
|
||||
non_subvp_pipes++;
|
||||
}
|
||||
}
|
||||
|
||||
// Count how many planes that aren't SubVP/phantom are capable of VACTIVE
|
||||
// switching (SubVP + VACTIVE unsupported). In situations where we force
|
||||
// SubVP for a VACTIVE plane, we don't want to increment the vactive_count.
|
||||
if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0 &&
|
||||
if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vlevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 &&
|
||||
pipe->stream->mall_stream_config.type == SUBVP_NONE) {
|
||||
vactive_count++;
|
||||
}
|
||||
@ -1074,13 +1123,14 @@ static bool subvp_validate_static_schedulability(struct dc *dc,
|
||||
|
||||
if (subvp_count == 2) {
|
||||
// Static schedulability check for SubVP + SubVP case
|
||||
schedulable = subvp_subvp_schedulable(dc, context);
|
||||
} else if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vblank_w_mall_sub_vp) {
|
||||
// Static schedulability check for SubVP + VBLANK case. Also handle the case where
|
||||
// DML outputs SubVP + VBLANK + VACTIVE (DML will report as SubVP + VBLANK)
|
||||
if (vactive_count > 0)
|
||||
schedulable = false;
|
||||
else
|
||||
schedulable = subvp_subvp_admissable(dc, context) && subvp_subvp_schedulable(dc, context);
|
||||
} else if (subvp_count == 1 && non_subvp_pipes == 0) {
|
||||
// Single SubVP configs will be supported by default as long as it's suppported by DML
|
||||
schedulable = true;
|
||||
} else if (subvp_count == 1 && non_subvp_pipes == 1) {
|
||||
if (dcn32_subvp_drr_admissable(dc, context))
|
||||
schedulable = subvp_drr_schedulable(dc, context);
|
||||
else if (dcn32_subvp_vblank_admissable(dc, context, vlevel))
|
||||
schedulable = subvp_vblank_schedulable(dc, context);
|
||||
} else if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vactive_w_mall_sub_vp &&
|
||||
vactive_count > 0) {
|
||||
@ -1104,10 +1154,6 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
|
||||
unsigned int dc_pipe_idx = 0;
|
||||
int i = 0;
|
||||
bool found_supported_config = false;
|
||||
struct pipe_ctx *pipe = NULL;
|
||||
uint32_t non_subvp_pipes = 0;
|
||||
bool drr_pipe_found = false;
|
||||
uint32_t drr_pipe_index = 0;
|
||||
|
||||
dc_assert_fp_enabled();
|
||||
|
||||
@ -1197,31 +1243,12 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
|
||||
}
|
||||
}
|
||||
|
||||
if (*vlevel < context->bw_ctx.dml.soc.num_states &&
|
||||
vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported
|
||||
&& subvp_validate_static_schedulability(dc, context, *vlevel)) {
|
||||
if (*vlevel < context->bw_ctx.dml.soc.num_states
|
||||
&& subvp_validate_static_schedulability(dc, context, *vlevel))
|
||||
found_supported_config = true;
|
||||
} else if (*vlevel < context->bw_ctx.dml.soc.num_states) {
|
||||
/* Case where 1 SubVP is added, and DML reports MCLK unsupported or DRR is allowed.
|
||||
* This handles the case for SubVP + DRR, where the DRR display does not support MCLK
|
||||
* switch at it's native refresh rate / timing, or DRR is allowed for the non-subvp
|
||||
* display.
|
||||
*/
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
pipe = &context->res_ctx.pipe_ctx[i];
|
||||
if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
|
||||
pipe->stream->mall_stream_config.type == SUBVP_NONE) {
|
||||
non_subvp_pipes++;
|
||||
// Use ignore_msa_timing_param flag to identify as DRR
|
||||
if (pipe->stream->ignore_msa_timing_param && pipe->stream->allow_freesync) {
|
||||
drr_pipe_found = true;
|
||||
drr_pipe_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there is only 1 remaining non SubVP pipe that is DRR, check static
|
||||
// schedulability for SubVP + DRR.
|
||||
if (non_subvp_pipes == 1 && drr_pipe_found) {
|
||||
if (found_supported_config) {
|
||||
// For SubVP + DRR cases, we can force the lowest vlevel that supports the mode
|
||||
if (dcn32_subvp_drr_admissable(dc, context) && subvp_drr_schedulable(dc, context)) {
|
||||
/* find lowest vlevel that supports the config */
|
||||
for (i = *vlevel; i >= 0; i--) {
|
||||
if (vba->ModeSupport[i][vba->maxMpcComb]) {
|
||||
@ -1230,9 +1257,6 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
found_supported_config = subvp_drr_schedulable(dc, context,
|
||||
&context->res_ctx.pipe_ctx[drr_pipe_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2882,16 +2906,34 @@ bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context
|
||||
{
|
||||
bool allow = false;
|
||||
uint32_t refresh_rate = 0;
|
||||
uint32_t min_refresh = subvp_high_refresh_list.min_refresh;
|
||||
uint32_t max_refresh = subvp_high_refresh_list.max_refresh;
|
||||
uint32_t subvp_min_refresh = subvp_high_refresh_list.min_refresh;
|
||||
uint32_t subvp_max_refresh = subvp_high_refresh_list.max_refresh;
|
||||
uint32_t min_refresh = subvp_max_refresh;
|
||||
uint32_t i;
|
||||
|
||||
if (!dc->debug.disable_subvp_high_refresh && pipe->stream &&
|
||||
/* Only allow SubVP on high refresh displays if all connected displays
|
||||
* are considered "high refresh" (i.e. >= 120hz). We do not want to
|
||||
* allow combinations such as 120hz (SubVP) + 60hz (SubVP).
|
||||
*/
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (!pipe_ctx->stream)
|
||||
continue;
|
||||
refresh_rate = (pipe_ctx->stream->timing.pix_clk_100hz * 100 +
|
||||
pipe_ctx->stream->timing.v_total * pipe_ctx->stream->timing.h_total - 1)
|
||||
/ (double)(pipe_ctx->stream->timing.v_total * pipe_ctx->stream->timing.h_total);
|
||||
|
||||
if (refresh_rate < min_refresh)
|
||||
min_refresh = refresh_rate;
|
||||
}
|
||||
|
||||
if (!dc->debug.disable_subvp_high_refresh && min_refresh >= subvp_min_refresh && pipe->stream &&
|
||||
pipe->plane_state && !(pipe->stream->vrr_active_variable || pipe->stream->vrr_active_fixed)) {
|
||||
refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 +
|
||||
pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1)
|
||||
/ (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total);
|
||||
if (refresh_rate >= min_refresh && refresh_rate <= max_refresh) {
|
||||
if (refresh_rate >= subvp_min_refresh && refresh_rate <= subvp_max_refresh) {
|
||||
for (i = 0; i < SUBVP_HIGH_REFRESH_LIST_LEN; i++) {
|
||||
uint32_t width = subvp_high_refresh_list.res[i].width;
|
||||
uint32_t height = subvp_high_refresh_list.res[i].height;
|
||||
|
@ -190,6 +190,14 @@ enum dm_validation_status {
|
||||
DML_FAIL_DSC_INPUT_BPC,
|
||||
DML_FAIL_PREFETCH_SUPPORT,
|
||||
DML_FAIL_V_RATIO_PREFETCH,
|
||||
DML_FAIL_P2I_WITH_420,
|
||||
DML_FAIL_DSC_ONLY_IF_NECESSARY_WITH_BPP,
|
||||
DML_FAIL_NOT_DSC422_NATIVE,
|
||||
DML_FAIL_ODM_COMBINE4TO1,
|
||||
DML_FAIL_ENOUGH_WRITEBACK_UNITS,
|
||||
DML_FAIL_VIEWPORT_EXCEEDS_SURFACE,
|
||||
DML_FAIL_DYNAMIC_METADATA,
|
||||
DML_FAIL_FMT_BUFFER_EXCEEDED,
|
||||
};
|
||||
|
||||
enum writeback_config {
|
||||
|
@ -68,6 +68,7 @@ struct dccg {
|
||||
const struct dccg_funcs *funcs;
|
||||
int pipe_dppclk_khz[MAX_PIPES];
|
||||
int ref_dppclk;
|
||||
bool dpp_clock_gated[MAX_PIPES];
|
||||
//int dtbclk_khz[MAX_PIPES];/* TODO needs to be removed */
|
||||
//int audio_dtbclk_khz;/* TODO needs to be removed */
|
||||
//int ref_dtbclk_khz;/* TODO needs to be removed */
|
||||
|
@ -114,6 +114,26 @@ struct update_visual_confirm_params {
|
||||
int mpcc_id;
|
||||
};
|
||||
|
||||
struct power_on_mpc_mem_pwr_params {
|
||||
struct mpc *mpc;
|
||||
int mpcc_id;
|
||||
bool power_on;
|
||||
};
|
||||
|
||||
struct set_output_csc_params {
|
||||
struct mpc *mpc;
|
||||
int opp_id;
|
||||
const uint16_t *regval;
|
||||
enum mpc_output_csc_mode ocsc_mode;
|
||||
};
|
||||
|
||||
struct set_ocsc_default_params {
|
||||
struct mpc *mpc;
|
||||
int opp_id;
|
||||
enum dc_color_space color_space;
|
||||
enum mpc_output_csc_mode ocsc_mode;
|
||||
};
|
||||
|
||||
union block_sequence_params {
|
||||
struct update_plane_addr_params update_plane_addr_params;
|
||||
struct subvp_pipe_control_lock_fast_params subvp_pipe_control_lock_fast_params;
|
||||
@ -128,6 +148,9 @@ union block_sequence_params {
|
||||
struct program_bias_and_scale_params program_bias_and_scale_params;
|
||||
struct set_output_transfer_func_params set_output_transfer_func_params;
|
||||
struct update_visual_confirm_params update_visual_confirm_params;
|
||||
struct power_on_mpc_mem_pwr_params power_on_mpc_mem_pwr_params;
|
||||
struct set_output_csc_params set_output_csc_params;
|
||||
struct set_ocsc_default_params set_ocsc_default_params;
|
||||
};
|
||||
|
||||
enum block_sequence_func {
|
||||
@ -144,6 +167,9 @@ enum block_sequence_func {
|
||||
DPP_PROGRAM_BIAS_AND_SCALE,
|
||||
DPP_SET_OUTPUT_TRANSFER_FUNC,
|
||||
MPC_UPDATE_VISUAL_CONFIRM,
|
||||
MPC_POWER_ON_MPC_MEM_PWR,
|
||||
MPC_SET_OUTPUT_CSC,
|
||||
MPC_SET_OCSC_DEFAULT,
|
||||
};
|
||||
|
||||
struct block_sequence {
|
||||
@ -439,4 +465,10 @@ void hwss_setup_dpp(union block_sequence_params *params);
|
||||
|
||||
void hwss_program_bias_and_scale(union block_sequence_params *params);
|
||||
|
||||
void hwss_power_on_mpc_mem_pwr(union block_sequence_params *params);
|
||||
|
||||
void hwss_set_output_csc(union block_sequence_params *params);
|
||||
|
||||
void hwss_set_ocsc_default(union block_sequence_params *params);
|
||||
|
||||
#endif /* __DC_HW_SEQUENCER_H__ */
|
||||
|
@ -156,7 +156,7 @@ struct hwseq_private_funcs {
|
||||
void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context);
|
||||
void (*update_force_pstate)(struct dc *dc, struct dc_state *context);
|
||||
void (*update_mall_sel)(struct dc *dc, struct dc_state *context);
|
||||
unsigned int (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx,
|
||||
void (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx,
|
||||
unsigned int *k1_div,
|
||||
unsigned int *k2_div);
|
||||
void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx);
|
||||
|
@ -984,6 +984,11 @@ static bool detect_link_and_local_sink(struct dc_link *link,
|
||||
(link->dpcd_caps.dongle_type !=
|
||||
DISPLAY_DONGLE_DP_HDMI_CONVERTER))
|
||||
converter_disable_audio = true;
|
||||
|
||||
/* limited link rate to HBR3 for DPIA until we implement USB4 V2 */
|
||||
if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
|
||||
link->reported_link_cap.link_rate > LINK_RATE_HIGH3)
|
||||
link->reported_link_cap.link_rate = LINK_RATE_HIGH3;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 Advanced Micro Devices, Inc.
|
||||
* Copyright 2016-2023 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"),
|
||||
@ -989,6 +989,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
|
||||
unsigned int refresh_range = 0;
|
||||
unsigned long long min_refresh_in_uhz = 0;
|
||||
unsigned long long max_refresh_in_uhz = 0;
|
||||
unsigned long long min_hardware_refresh_in_uhz = 0;
|
||||
|
||||
if (mod_freesync == NULL)
|
||||
return;
|
||||
@ -999,7 +1000,13 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
|
||||
nominal_field_rate_in_uhz =
|
||||
mod_freesync_calc_nominal_field_rate(stream);
|
||||
|
||||
min_refresh_in_uhz = in_config->min_refresh_in_uhz;
|
||||
if (stream->ctx->dc->caps.max_v_total != 0 && stream->timing.h_total != 0) {
|
||||
min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL),
|
||||
(stream->timing.h_total * stream->ctx->dc->caps.max_v_total));
|
||||
}
|
||||
/* Limit minimum refresh rate to what can be supported by hardware */
|
||||
min_refresh_in_uhz = min_hardware_refresh_in_uhz > in_config->min_refresh_in_uhz ?
|
||||
min_hardware_refresh_in_uhz : in_config->min_refresh_in_uhz;
|
||||
max_refresh_in_uhz = in_config->max_refresh_in_uhz;
|
||||
|
||||
/* Full range may be larger than current video timing, so cap at nominal */
|
||||
|
@ -431,7 +431,13 @@ static int sienna_cichlid_append_powerplay_table(struct smu_context *smu)
|
||||
{
|
||||
struct atom_smc_dpm_info_v4_9 *smc_dpm_table;
|
||||
int index, ret;
|
||||
I2cControllerConfig_t *table_member;
|
||||
PPTable_beige_goby_t *ppt_beige_goby;
|
||||
PPTable_t *ppt;
|
||||
|
||||
if (smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 13))
|
||||
ppt_beige_goby = smu->smu_table.driver_pptable;
|
||||
else
|
||||
ppt = smu->smu_table.driver_pptable;
|
||||
|
||||
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
smc_dpm_info);
|
||||
@ -440,9 +446,13 @@ static int sienna_cichlid_append_powerplay_table(struct smu_context *smu)
|
||||
(uint8_t **)&smc_dpm_table);
|
||||
if (ret)
|
||||
return ret;
|
||||
GET_PPTABLE_MEMBER(I2cControllers, &table_member);
|
||||
memcpy(table_member, smc_dpm_table->I2cControllers,
|
||||
sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header));
|
||||
|
||||
if (smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 13))
|
||||
smu_memcpy_trailing(ppt_beige_goby, I2cControllers, BoardReserved,
|
||||
smc_dpm_table, I2cControllers);
|
||||
else
|
||||
smu_memcpy_trailing(ppt, I2cControllers, BoardReserved,
|
||||
smc_dpm_table, I2cControllers);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "asic_reg/mp/mp_13_0_0_sh_mask.h"
|
||||
#include "smu_cmn.h"
|
||||
#include "amdgpu_ras.h"
|
||||
#include "umc_v8_10.h"
|
||||
|
||||
/*
|
||||
* DO NOT use these for err/warn/info/debug messages.
|
||||
@ -2609,7 +2608,7 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu,
|
||||
|
||||
ecc_table = (EccInfoTable_t *)smu_table->ecc_table;
|
||||
|
||||
for (i = 0; i < UMC_V8_10_TOTAL_CHANNEL_NUM(adev); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(ecc_table->EccInfo); i++) {
|
||||
ecc_info_per_channel = &(eccinfo->ecc[i]);
|
||||
ecc_info_per_channel->ce_count_lo_chip =
|
||||
ecc_table->EccInfo[i].ce_count_lo_chip;
|
||||
|
@ -831,6 +831,8 @@ static int smu_v13_0_5_set_soft_freq_limited_range(struct smu_context *smu,
|
||||
uint32_t max)
|
||||
{
|
||||
enum smu_message_type msg_set_min, msg_set_max;
|
||||
uint32_t min_clk = min;
|
||||
uint32_t max_clk = max;
|
||||
int ret = 0;
|
||||
|
||||
if (!smu_v13_0_5_clk_dpm_is_enabled(smu, clk_type))
|
||||
@ -851,11 +853,16 @@ static int smu_v13_0_5_set_soft_freq_limited_range(struct smu_context *smu,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL);
|
||||
if (clk_type == SMU_VCLK) {
|
||||
min_clk = min << SMU_13_VCLK_SHIFT;
|
||||
max_clk = max << SMU_13_VCLK_SHIFT;
|
||||
}
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL);
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max_clk, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -971,31 +978,79 @@ static int smu_v13_0_5_force_clk_levels(struct smu_context *smu,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smu_v13_0_5_get_dpm_profile_freq(struct smu_context *smu,
|
||||
enum amd_dpm_forced_level level,
|
||||
enum smu_clk_type clk_type,
|
||||
uint32_t *min_clk,
|
||||
uint32_t *max_clk)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t clk_limit = 0;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
clk_limit = SMU_13_0_5_UMD_PSTATE_GFXCLK;
|
||||
if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit);
|
||||
else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL);
|
||||
break;
|
||||
case SMU_VCLK:
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit);
|
||||
break;
|
||||
case SMU_DCLK:
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
*min_clk = *max_clk = clk_limit;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smu_v13_0_5_set_performance_level(struct smu_context *smu,
|
||||
enum amd_dpm_forced_level level)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
uint32_t sclk_min = 0, sclk_max = 0;
|
||||
uint32_t vclk_min = 0, vclk_max = 0;
|
||||
uint32_t dclk_min = 0, dclk_max = 0;
|
||||
int ret = 0;
|
||||
|
||||
switch (level) {
|
||||
case AMD_DPM_FORCED_LEVEL_HIGH:
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max);
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);
|
||||
sclk_min = sclk_max;
|
||||
vclk_min = vclk_max;
|
||||
dclk_min = dclk_max;
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_LOW:
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL);
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);
|
||||
sclk_max = sclk_min;
|
||||
vclk_max = vclk_min;
|
||||
dclk_max = dclk_min;
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_AUTO:
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max);
|
||||
smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
|
||||
/* Temporarily do nothing since the optimal clocks haven't been provided yet */
|
||||
smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max);
|
||||
smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max);
|
||||
smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);
|
||||
break;
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
|
||||
dev_err(adev->dev, "The performance level profile_min_mclk is not supported.");
|
||||
return -EOPNOTSUPP;
|
||||
case AMD_DPM_FORCED_LEVEL_MANUAL:
|
||||
case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
|
||||
return 0;
|
||||
@ -1016,6 +1071,23 @@ static int smu_v13_0_5_set_performance_level(struct smu_context *smu,
|
||||
smu->gfx_actual_soft_max_freq = sclk_max;
|
||||
}
|
||||
|
||||
if (vclk_min && vclk_max) {
|
||||
ret = smu_v13_0_5_set_soft_freq_limited_range(smu,
|
||||
SMU_VCLK,
|
||||
vclk_min,
|
||||
vclk_max);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dclk_min && dclk_max) {
|
||||
ret = smu_v13_0_5_set_soft_freq_limited_range(smu,
|
||||
SMU_DCLK,
|
||||
dclk_min,
|
||||
dclk_max);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,6 @@
|
||||
#define __SMU_V13_0_5_PPT_H__
|
||||
|
||||
extern void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu);
|
||||
#define SMU_13_0_5_UMD_PSTATE_GFXCLK 1100
|
||||
#define SMU_13_0_5_UMD_PSTATE_GFXCLK 700
|
||||
|
||||
#endif
|
||||
|
@ -4053,17 +4053,28 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_dp_mst_hpd_irq() - MST hotplug IRQ notify
|
||||
* drm_dp_mst_hpd_irq_handle_event() - MST hotplug IRQ handle MST event
|
||||
* @mgr: manager to notify irq for.
|
||||
* @esi: 4 bytes from SINK_COUNT_ESI
|
||||
* @ack: 4 bytes used to ack events starting from SINK_COUNT_ESI
|
||||
* @handled: whether the hpd interrupt was consumed or not
|
||||
*
|
||||
* This should be called from the driver when it detects a short IRQ,
|
||||
* This should be called from the driver when it detects a HPD IRQ,
|
||||
* along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The
|
||||
* topology manager will process the sideband messages received as a result
|
||||
* of this.
|
||||
* topology manager will process the sideband messages received
|
||||
* as indicated in the DEVICE_SERVICE_IRQ_VECTOR_ESI0 and set the
|
||||
* corresponding flags that Driver has to ack the DP receiver later.
|
||||
*
|
||||
* Note that driver shall also call
|
||||
* drm_dp_mst_hpd_irq_send_new_request() if the 'handled' is set
|
||||
* after calling this function, to try to kick off a new request in
|
||||
* the queue if the previous message transaction is completed.
|
||||
*
|
||||
* See also:
|
||||
* drm_dp_mst_hpd_irq_send_new_request()
|
||||
*/
|
||||
int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled)
|
||||
int drm_dp_mst_hpd_irq_handle_event(struct drm_dp_mst_topology_mgr *mgr, const u8 *esi,
|
||||
u8 *ack, bool *handled)
|
||||
{
|
||||
int ret = 0;
|
||||
int sc;
|
||||
@ -4078,18 +4089,47 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handl
|
||||
if (esi[1] & DP_DOWN_REP_MSG_RDY) {
|
||||
ret = drm_dp_mst_handle_down_rep(mgr);
|
||||
*handled = true;
|
||||
ack[1] |= DP_DOWN_REP_MSG_RDY;
|
||||
}
|
||||
|
||||
if (esi[1] & DP_UP_REQ_MSG_RDY) {
|
||||
ret |= drm_dp_mst_handle_up_req(mgr);
|
||||
*handled = true;
|
||||
ack[1] |= DP_UP_REQ_MSG_RDY;
|
||||
}
|
||||
|
||||
drm_dp_mst_kick_tx(mgr);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
|
||||
EXPORT_SYMBOL(drm_dp_mst_hpd_irq_handle_event);
|
||||
|
||||
/**
|
||||
* drm_dp_mst_hpd_irq_send_new_request() - MST hotplug IRQ kick off new request
|
||||
* @mgr: manager to notify irq for.
|
||||
*
|
||||
* This should be called from the driver when mst irq event is handled
|
||||
* and acked. Note that new down request should only be sent when
|
||||
* previous message transaction is completed. Source is not supposed to generate
|
||||
* interleaved message transactions.
|
||||
*/
|
||||
void drm_dp_mst_hpd_irq_send_new_request(struct drm_dp_mst_topology_mgr *mgr)
|
||||
{
|
||||
struct drm_dp_sideband_msg_tx *txmsg;
|
||||
bool kick = true;
|
||||
|
||||
mutex_lock(&mgr->qlock);
|
||||
txmsg = list_first_entry_or_null(&mgr->tx_msg_downq,
|
||||
struct drm_dp_sideband_msg_tx, next);
|
||||
/* If last transaction is not completed yet*/
|
||||
if (!txmsg ||
|
||||
txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND ||
|
||||
txmsg->state == DRM_DP_SIDEBAND_TX_SENT)
|
||||
kick = false;
|
||||
mutex_unlock(&mgr->qlock);
|
||||
|
||||
if (kick)
|
||||
drm_dp_mst_kick_tx(mgr);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_mst_hpd_irq_send_new_request);
|
||||
/**
|
||||
* drm_dp_mst_detect_port() - get connection status for an MST port
|
||||
* @connector: DRM connector for this port
|
||||
|
@ -4069,9 +4069,7 @@ intel_dp_mst_hpd_irq(struct intel_dp *intel_dp, u8 *esi, u8 *ack)
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
|
||||
if (handled)
|
||||
ack[1] |= esi[1] & (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY);
|
||||
drm_dp_mst_hpd_irq_handle_event(&intel_dp->mst_mgr, esi, ack, &handled);
|
||||
|
||||
if (esi[1] & DP_CP_IRQ) {
|
||||
intel_hdcp_handle_cp_irq(intel_dp->attached_connector);
|
||||
@ -4146,6 +4144,9 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
|
||||
if (!intel_dp_ack_sink_irq_esi(intel_dp, ack))
|
||||
drm_dbg_kms(&i915->drm, "Failed to ack ESI\n");
|
||||
|
||||
if (ack[1] & (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY))
|
||||
drm_dp_mst_hpd_irq_send_new_request(&intel_dp->mst_mgr);
|
||||
}
|
||||
|
||||
return link_ok;
|
||||
|
@ -1359,22 +1359,26 @@ nv50_mstm_service(struct nouveau_drm *drm,
|
||||
u8 esi[8] = {};
|
||||
|
||||
while (handled) {
|
||||
u8 ack[8] = {};
|
||||
|
||||
rc = drm_dp_dpcd_read(aux, DP_SINK_COUNT_ESI, esi, 8);
|
||||
if (rc != 8) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
drm_dp_mst_hpd_irq(&mstm->mgr, esi, &handled);
|
||||
drm_dp_mst_hpd_irq_handle_event(&mstm->mgr, esi, ack, &handled);
|
||||
if (!handled)
|
||||
break;
|
||||
|
||||
rc = drm_dp_dpcd_write(aux, DP_SINK_COUNT_ESI + 1, &esi[1],
|
||||
3);
|
||||
if (rc != 3) {
|
||||
rc = drm_dp_dpcd_writeb(aux, DP_SINK_COUNT_ESI + 1, ack[1]);
|
||||
|
||||
if (rc != 1) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
drm_dp_mst_hpd_irq_send_new_request(&mstm->mgr);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
|
@ -453,4 +453,13 @@ struct acpi_bus_event;
|
||||
* BYTE - number of active lanes
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_VGA_SWITCHEROO)
|
||||
void radeon_register_atpx_handler(void);
|
||||
void radeon_unregister_atpx_handler(void);
|
||||
bool radeon_has_atpx_dgpu_power_cntl(void);
|
||||
bool radeon_is_atpx_hybrid(void);
|
||||
bool radeon_has_atpx(void);
|
||||
bool radeon_atpx_dgpu_req_power_for_displays(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -147,7 +147,7 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_atpx_validate_functions - validate ATPX functions
|
||||
* radeon_atpx_validate() - validate ATPX functions
|
||||
*
|
||||
* @atpx: radeon atpx struct
|
||||
*
|
||||
|
@ -304,6 +304,7 @@ static void radeon_fbdev_client_unregister(struct drm_client_dev *client)
|
||||
|
||||
if (fb_helper->info) {
|
||||
vga_switcheroo_client_fb_set(rdev->pdev, NULL);
|
||||
drm_helper_force_disable_all(dev);
|
||||
drm_fb_helper_unregister_info(fb_helper);
|
||||
} else {
|
||||
drm_client_release(&fb_helper->client);
|
||||
|
@ -384,7 +384,7 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity)
|
||||
}
|
||||
|
||||
s_fence = to_drm_sched_fence(fence);
|
||||
if (s_fence && s_fence->sched == sched &&
|
||||
if (!fence->error && s_fence && s_fence->sched == sched &&
|
||||
!test_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &fence->flags)) {
|
||||
|
||||
/*
|
||||
|
@ -810,8 +810,11 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr);
|
||||
bool drm_dp_read_mst_cap(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
||||
int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state);
|
||||
|
||||
int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
|
||||
|
||||
int drm_dp_mst_hpd_irq_handle_event(struct drm_dp_mst_topology_mgr *mgr,
|
||||
const u8 *esi,
|
||||
u8 *ack,
|
||||
bool *handled);
|
||||
void drm_dp_mst_hpd_irq_send_new_request(struct drm_dp_mst_topology_mgr *mgr);
|
||||
|
||||
int
|
||||
drm_dp_mst_detect_port(struct drm_connector *connector,
|
||||
|
@ -39,9 +39,10 @@
|
||||
* - 1.11 - Add unified memory for ctx save/restore area
|
||||
* - 1.12 - Add DMA buf export ioctl
|
||||
* - 1.13 - Add debugger API
|
||||
* - 1.14 - Update kfd_event_data
|
||||
*/
|
||||
#define KFD_IOCTL_MAJOR_VERSION 1
|
||||
#define KFD_IOCTL_MINOR_VERSION 13
|
||||
#define KFD_IOCTL_MINOR_VERSION 14
|
||||
|
||||
struct kfd_ioctl_get_version_args {
|
||||
__u32 major_version; /* from KFD */
|
||||
@ -320,12 +321,20 @@ struct kfd_hsa_hw_exception_data {
|
||||
__u32 gpu_id;
|
||||
};
|
||||
|
||||
/* hsa signal event data */
|
||||
struct kfd_hsa_signal_event_data {
|
||||
__u64 last_event_age; /* to and from KFD */
|
||||
};
|
||||
|
||||
/* Event data */
|
||||
struct kfd_event_data {
|
||||
union {
|
||||
/* From KFD */
|
||||
struct kfd_hsa_memory_exception_data memory_exception_data;
|
||||
struct kfd_hsa_hw_exception_data hw_exception_data;
|
||||
}; /* From KFD */
|
||||
/* To and From KFD */
|
||||
struct kfd_hsa_signal_event_data signal_event_data;
|
||||
};
|
||||
__u64 kfd_event_data_ext; /* pointer to an extension structure
|
||||
for future exception types */
|
||||
__u32 event_id; /* to KFD */
|
||||
|
Loading…
Reference in New Issue
Block a user