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_review
  e1f5bdb88e
  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:
Dave Airlie 2023-06-19 11:57:25 +10:00
commit bcbede6fbe
93 changed files with 1221 additions and 430 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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))

View File

@ -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;

View File

@ -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):

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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) {

View File

@ -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);

View File

@ -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,

View File

@ -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 |

View File

@ -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
* ---------------------------------
* | |

View File

@ -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
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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],

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -53,6 +53,7 @@ struct signal_page;
struct kfd_event {
u32 event_id;
u64 event_age;
bool signaled;
bool auto_reset;

View File

@ -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,

View File

@ -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,

View File

@ -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++) {

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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;
};

View File

@ -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 {

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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)

View File

@ -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 */
{

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 = {

View File

@ -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)

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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 */

View File

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

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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
*

View File

@ -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);

View File

@ -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)) {
/*

View File

@ -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,

View File

@ -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 */